mirror of
https://github.com/gnif/LookingGlass.git
synced 2024-11-29 00:27:18 +00:00
[client] Added GL_ARB_buffer_storage support
This improves client performance by 4x if the video driver supports this extension. OpenGL 4.1 is required for this feature to be used
This commit is contained in:
parent
9c90a53871
commit
d1ef8d204a
209
client/main.c
209
client/main.c
@ -27,7 +27,9 @@ Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
|
#define GL_GLEXT_PROTOTYPES
|
||||||
#include <GL/gl.h>
|
#include <GL/gl.h>
|
||||||
|
#include <GL/glu.h>
|
||||||
|
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "memcpySSE.h"
|
#include "memcpySSE.h"
|
||||||
@ -37,10 +39,12 @@ Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
#include "kb.h"
|
#include "kb.h"
|
||||||
|
|
||||||
typedef void (*CompFunc)(uint8_t * dst, const uint8_t * src, const size_t len);
|
typedef void (*CompFunc)(uint8_t * dst, const uint8_t * src, const size_t len);
|
||||||
typedef void (*DrawFunc)(CompFunc compFunc, SDL_Texture * texture, uint8_t * dst, const uint8_t * src);
|
typedef void (*DrawFunc)(CompFunc compFunc, uint8_t * dst, const uint8_t * src);
|
||||||
|
|
||||||
struct KVMGFXState
|
struct KVMGFXState
|
||||||
{
|
{
|
||||||
|
bool hasBufferStorage;
|
||||||
|
|
||||||
bool running;
|
bool running;
|
||||||
bool started;
|
bool started;
|
||||||
bool windowChanged;
|
bool windowChanged;
|
||||||
@ -90,66 +94,29 @@ inline bool areFormatsSame(const struct KVMGFXHeader s1, const struct KVMGFXHead
|
|||||||
(s1.height == s2.height );
|
(s1.height == s2.height );
|
||||||
}
|
}
|
||||||
|
|
||||||
void drawFunc_ARGB10(CompFunc compFunc, SDL_Texture * texture, uint8_t * dst, const uint8_t * src)
|
void drawFunc_ARGB(CompFunc compFunc, uint8_t * dst, const uint8_t * src)
|
||||||
{
|
|
||||||
SDL_UpdateTexture(texture, NULL, src, state.shm->stride * 4);
|
|
||||||
ivshmem_kick_irq(state.shm->guestID, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void drawFunc_ARGB(CompFunc compFunc, SDL_Texture * texture, uint8_t * dst, const uint8_t * src)
|
|
||||||
{
|
{
|
||||||
compFunc(dst, src, state.shm->height * state.shm->stride * 4);
|
compFunc(dst, src, state.shm->height * state.shm->stride * 4);
|
||||||
ivshmem_kick_irq(state.shm->guestID, 0);
|
ivshmem_kick_irq(state.shm->guestID, 0);
|
||||||
SDL_UnlockTexture(texture);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void drawFunc_RGB(CompFunc compFunc, SDL_Texture * texture, uint8_t * dst, const uint8_t * src)
|
void drawFunc_RGB(CompFunc compFunc, uint8_t * dst, const uint8_t * src)
|
||||||
{
|
{
|
||||||
compFunc(dst, src, state.shm->height * state.shm->stride * 3);
|
compFunc(dst, src, state.shm->height * state.shm->stride * 3);
|
||||||
ivshmem_kick_irq(state.shm->guestID, 0);
|
ivshmem_kick_irq(state.shm->guestID, 0);
|
||||||
SDL_UnlockTexture(texture);
|
|
||||||
}
|
|
||||||
|
|
||||||
void drawFunc_XOR(CompFunc compFunc, SDL_Texture * texture, uint8_t * dst, const uint8_t * src)
|
|
||||||
{
|
|
||||||
glEnable(GL_COLOR_LOGIC_OP);
|
|
||||||
glLogicOp(GL_XOR);
|
|
||||||
|
|
||||||
compFunc(dst, src, state.shm->height * state.shm->stride * 3);
|
|
||||||
ivshmem_kick_irq(state.shm->guestID, 0);
|
|
||||||
SDL_UnlockTexture(texture);
|
|
||||||
|
|
||||||
// clear the buffer for the next frame
|
|
||||||
memset(dst, 0, state.shm->height * state.shm->stride * 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
void drawFunc_YUV444P(CompFunc compFunc, SDL_Texture * texture, uint8_t * dst, const uint8_t * src)
|
|
||||||
{
|
|
||||||
compFunc(dst, src, state.shm->height * state.shm->stride * 3);
|
|
||||||
ivshmem_kick_irq(state.shm->guestID, 0);
|
|
||||||
SDL_UnlockTexture(texture);
|
|
||||||
}
|
|
||||||
|
|
||||||
void drawFunc_YUV420P(CompFunc compFunc, SDL_Texture * texture, uint8_t * dst, const uint8_t * src)
|
|
||||||
{
|
|
||||||
const unsigned int pixels = state.shm->width * state.shm->height;
|
|
||||||
|
|
||||||
SDL_UpdateYUVTexture(texture, NULL,
|
|
||||||
src , state.shm->stride,
|
|
||||||
src + pixels , state.shm->stride / 2,
|
|
||||||
src + pixels + pixels / 4, state.shm->stride / 2
|
|
||||||
);
|
|
||||||
ivshmem_kick_irq(state.shm->guestID, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int renderThread(void * unused)
|
int renderThread(void * unused)
|
||||||
{
|
{
|
||||||
struct KVMGFXHeader format;
|
struct KVMGFXHeader format;
|
||||||
SDL_Texture *texture = NULL;
|
SDL_Texture *texture = NULL;
|
||||||
uint8_t *pixels = (uint8_t*)state.shm;
|
GLuint vboID[2] = {0, 0};
|
||||||
uint8_t *texPixels = NULL;
|
GLuint vboTex = 0;
|
||||||
DrawFunc drawFunc = NULL;
|
unsigned int texIndex = 0;
|
||||||
CompFunc compFunc = NULL;
|
uint8_t *pixels = (uint8_t*)state.shm;
|
||||||
|
uint8_t *texPixels[2] = {NULL, NULL};
|
||||||
|
DrawFunc drawFunc = NULL;
|
||||||
|
CompFunc compFunc = NULL;
|
||||||
|
|
||||||
format.version = 1;
|
format.version = 1;
|
||||||
format.frameType = FRAME_TYPE_INVALID;
|
format.frameType = FRAME_TYPE_INVALID;
|
||||||
@ -197,21 +164,36 @@ int renderThread(void * unused)
|
|||||||
// if the format is invalid or it has changed
|
// if the format is invalid or it has changed
|
||||||
if (!areFormatsSame(format, *state.shm))
|
if (!areFormatsSame(format, *state.shm))
|
||||||
{
|
{
|
||||||
if (texture)
|
if (state.hasBufferStorage)
|
||||||
{
|
{
|
||||||
SDL_DestroyTexture(texture);
|
if (vboID[0])
|
||||||
texture = NULL;
|
{
|
||||||
|
if (vboTex)
|
||||||
|
{
|
||||||
|
glDeleteTextures(1, &vboTex);
|
||||||
|
vboTex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
glUnmapBuffer(GL_TEXTURE_BUFFER);
|
||||||
|
glDeleteBuffers(2, vboID);
|
||||||
|
memset(vboID, 0, sizeof(vboID));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (texture)
|
||||||
|
{
|
||||||
|
SDL_DestroyTexture(texture);
|
||||||
|
texture = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Uint32 sdlFormat;
|
Uint32 sdlFormat;
|
||||||
|
uint8_t bpp;
|
||||||
switch(state.shm->frameType)
|
switch(state.shm->frameType)
|
||||||
{
|
{
|
||||||
case FRAME_TYPE_ARGB : sdlFormat = SDL_PIXELFORMAT_ARGB8888 ; drawFunc = drawFunc_ARGB ; break;
|
case FRAME_TYPE_ARGB : sdlFormat = SDL_PIXELFORMAT_ARGB8888 ; drawFunc = drawFunc_ARGB ; bpp = 4; break;
|
||||||
case FRAME_TYPE_RGB : sdlFormat = SDL_PIXELFORMAT_RGB24 ; drawFunc = drawFunc_RGB ; break;
|
case FRAME_TYPE_RGB : sdlFormat = SDL_PIXELFORMAT_RGB24 ; drawFunc = drawFunc_RGB ; bpp = 3; break;
|
||||||
case FRAME_TYPE_XOR : sdlFormat = SDL_PIXELFORMAT_RGB24 ; drawFunc = drawFunc_XOR ; break;
|
|
||||||
case FRAME_TYPE_YUV444P: sdlFormat = SDL_PIXELFORMAT_RGB24 ; drawFunc = drawFunc_YUV444P; break; // incorrect for now
|
|
||||||
case FRAME_TYPE_YUV420P: sdlFormat = SDL_PIXELFORMAT_YV12 ; drawFunc = drawFunc_YUV420P; break;
|
|
||||||
case FRAME_TYPE_ARGB10 : sdlFormat = SDL_PIXELFORMAT_ARGB2101010; drawFunc = drawFunc_ARGB10 ; break;
|
|
||||||
default:
|
default:
|
||||||
format.frameType = FRAME_TYPE_INVALID;
|
format.frameType = FRAME_TYPE_INVALID;
|
||||||
continue;
|
continue;
|
||||||
@ -230,25 +212,113 @@ int renderThread(void * unused)
|
|||||||
SDL_SetWindowSize(state.window, state.shm->width, state.shm->height);
|
SDL_SetWindowSize(state.window, state.shm->width, state.shm->height);
|
||||||
SDL_SetWindowPosition(state.window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
|
SDL_SetWindowPosition(state.window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
|
||||||
|
|
||||||
texture = SDL_CreateTexture(state.renderer, sdlFormat, SDL_TEXTUREACCESS_STREAMING, state.shm->width, state.shm->height);
|
if (state.hasBufferStorage)
|
||||||
|
{
|
||||||
|
// setup two buffers so we don't have to use fences
|
||||||
|
const size_t bufferSize = state.shm->width * state.shm->height * bpp;
|
||||||
|
glGenBuffers(2, vboID);
|
||||||
|
for (int i = 0; i < 2; ++i)
|
||||||
|
{
|
||||||
|
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, vboID[i]);
|
||||||
|
glBufferStorage (GL_PIXEL_UNPACK_BUFFER, bufferSize, 0, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT);
|
||||||
|
texPixels[i] = glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, bufferSize, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT);
|
||||||
|
if (!texPixels[i])
|
||||||
|
{
|
||||||
|
DEBUG_ERROR("Failed to map buffer range, turning off buffer storage");
|
||||||
|
state.hasBufferStorage = false;
|
||||||
|
glDeleteBuffers(2, vboID);
|
||||||
|
memset(vboID, 0, sizeof(vboID));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
|
||||||
|
}
|
||||||
|
|
||||||
// this doesnt "lock" anything, pre-fetch the pointers for later use
|
// create the texture
|
||||||
int unused;
|
glGenTextures(1, &vboTex);
|
||||||
SDL_LockTexture(texture, NULL, (void**)&texPixels, &unused);
|
glBindTexture(GL_TEXTURE_2D, vboTex);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S , GL_CLAMP_TO_EDGE);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T , GL_CLAMP_TO_EDGE);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
|
glTexImage2D(
|
||||||
|
GL_TEXTURE_2D,
|
||||||
|
0,
|
||||||
|
GL_RGBA8,
|
||||||
|
state.shm->width, state.shm->height,
|
||||||
|
0,
|
||||||
|
GL_BGRA,
|
||||||
|
GL_UNSIGNED_BYTE,
|
||||||
|
(void*)0
|
||||||
|
);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
texture = SDL_CreateTexture(state.renderer, sdlFormat, SDL_TEXTUREACCESS_STREAMING, state.shm->width, state.shm->height);
|
||||||
|
// this doesnt "lock" anything, pre-fetch the pointers for later use
|
||||||
|
int unused;
|
||||||
|
SDL_LockTexture(texture, NULL, (void**)&texPixels, &unused);
|
||||||
|
}
|
||||||
|
|
||||||
memcpy(&format, state.shm, sizeof(format));
|
memcpy(&format, state.shm, sizeof(format));
|
||||||
state.windowChanged = true;
|
state.windowChanged = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
glDisable(GL_COLOR_LOGIC_OP);
|
if (state.hasBufferStorage)
|
||||||
drawFunc(compFunc, texture, texPixels, pixels + state.shm->dataPos);
|
{
|
||||||
SDL_RenderCopy(state.renderer, texture, NULL, NULL);
|
// update the pixels
|
||||||
|
drawFunc(compFunc, texPixels[texIndex ? 0 : 1], pixels + state.shm->dataPos);
|
||||||
|
|
||||||
|
// update the texture
|
||||||
|
glEnable(GL_TEXTURE_2D);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, vboTex);
|
||||||
|
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, vboID[texIndex ? 0 : 1]);
|
||||||
|
glTexSubImage2D(
|
||||||
|
GL_TEXTURE_2D,
|
||||||
|
0,
|
||||||
|
0, 0,
|
||||||
|
state.shm->width, state.shm->height,
|
||||||
|
GL_BGRA,
|
||||||
|
GL_UNSIGNED_BYTE,
|
||||||
|
(void*)0
|
||||||
|
);
|
||||||
|
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
|
||||||
|
|
||||||
|
// draw the screen
|
||||||
|
glBegin(GL_TRIANGLE_STRIP);
|
||||||
|
glTexCoord2f(0.0f, 0.0f); glVertex2f(0.0f , 0.0f );
|
||||||
|
glTexCoord2f(1.0f, 0.0f); glVertex2f(state.shm->width, 0.0f );
|
||||||
|
glTexCoord2f(0.0f, 1.0f); glVertex2f(0.0f , state.shm->height);
|
||||||
|
glTexCoord2f(1.0f, 1.0f); glVertex2f(state.shm->width, state.shm->height);
|
||||||
|
glEnd();
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
glDisable(GL_TEXTURE_2D);
|
||||||
|
|
||||||
|
// update our texture index
|
||||||
|
if (++texIndex == 2)
|
||||||
|
texIndex = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
drawFunc(compFunc, texPixels[0], pixels + state.shm->dataPos);
|
||||||
|
SDL_UnlockTexture(texture);
|
||||||
|
SDL_RenderCopy(state.renderer, texture, NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
SDL_RenderPresent(state.renderer);
|
SDL_RenderPresent(state.renderer);
|
||||||
|
|
||||||
state.started = true;
|
state.started = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_DestroyTexture(texture);
|
if (state.hasBufferStorage)
|
||||||
|
{
|
||||||
|
glDeleteTextures(1, &vboTex );
|
||||||
|
glUnmapBuffer (GL_TEXTURE_BUFFER);
|
||||||
|
glDeleteBuffers (2, vboID );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
SDL_DestroyTexture(texture);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -476,6 +546,13 @@ int main(int argc, char * argv[])
|
|||||||
state.renderer = SDL_CreateRenderer(state.window, -1,
|
state.renderer = SDL_CreateRenderer(state.window, -1,
|
||||||
SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
|
SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
|
||||||
|
|
||||||
|
const GLubyte * extensions = glGetString(GL_EXTENSIONS);
|
||||||
|
if (gluCheckExtension((const GLubyte *)"GL_ARB_buffer_storage", extensions))
|
||||||
|
{
|
||||||
|
DEBUG_INFO("Using GL_ARB_buffer_storage");
|
||||||
|
state.hasBufferStorage = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (!state.renderer)
|
if (!state.renderer)
|
||||||
{
|
{
|
||||||
DEBUG_ERROR("failed to create window");
|
DEBUG_ERROR("failed to create window");
|
||||||
|
Loading…
Reference in New Issue
Block a user