[client] renderer interface improvements and use gl lists for opengl

This commit is contained in:
Geoffrey McRae 2017-12-11 03:47:07 +11:00
parent fcfea1b65d
commit 0ad1f21ffb
4 changed files with 86 additions and 73 deletions

View file

@ -65,8 +65,8 @@ typedef const char * (* LG_RendererGetName )();
typedef bool (* LG_RendererInitialize )(void ** opaque, const LG_RendererParams params, const LG_RendererFormat format); typedef bool (* LG_RendererInitialize )(void ** opaque, const LG_RendererParams params, const LG_RendererFormat format);
typedef void (* LG_RendererDeInitialize)(void * opaque); typedef void (* LG_RendererDeInitialize)(void * opaque);
typedef bool (* LG_RendererIsCompatible)(void * opaque, const LG_RendererFormat format); typedef bool (* LG_RendererIsCompatible)(void * opaque, const LG_RendererFormat format);
typedef void (* LG_RendererOnResize )(void * opaque, const int width, const int height); typedef void (* LG_RendererOnResize )(void * opaque, const int width, const int height, const LG_RendererRect destRect);
typedef bool (* LG_RendererRender )(void * opaque, const LG_RendererRect destRect, const uint8_t * data, bool resample); typedef bool (* LG_RendererRender )(void * opaque, const uint8_t * data, bool resample);
typedef struct LG_Renderer typedef struct LG_Renderer
{ {

View file

@ -136,7 +136,7 @@ inline void updatePositionInfo()
state.scaleY = (float)state.srcSize.x / (float)state.dstRect.w; state.scaleY = (float)state.srcSize.x / (float)state.dstRect.w;
if (state.lgr) if (state.lgr)
state.lgr->on_resize(state.lgrData, w, h); state.lgr->on_resize(state.lgrData, w, h, state.dstRect);
} }
int renderThread(void * unused) int renderThread(void * unused)
@ -303,7 +303,6 @@ int renderThread(void * unused)
if (!state.lgr->render( if (!state.lgr->render(
state.lgrData, state.lgrData,
state.dstRect,
(uint8_t *)state.shm + header.dataPos, (uint8_t *)state.shm + header.dataPos,
params.useMipmap params.useMipmap
)) ))
@ -612,11 +611,6 @@ int run()
FcPatternDestroy(pat); FcPatternDestroy(pat);
} }
// while this is related to opengl, it must happen before the window is created
// as such it can not be part of the opengl renderer
if (!params.vsync)
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 0);
state.window = SDL_CreateWindow( state.window = SDL_CreateWindow(
"Looking Glass (Client)", "Looking Glass (Client)",
params.center ? SDL_WINDOWPOS_CENTERED : params.x, params.center ? SDL_WINDOWPOS_CENTERED : params.x,

View file

@ -15,6 +15,7 @@ struct LGR_Basic
size_t dataWidth; size_t dataWidth;
SDL_Renderer * renderer; SDL_Renderer * renderer;
SDL_Texture * texture; SDL_Texture * texture;
SDL_Rect destRect;
}; };
const char * lgr_basic_get_name() const char * lgr_basic_get_name()
@ -110,14 +111,19 @@ bool lgr_basic_is_compatible(void * opaque, const LG_RendererFormat format)
return (memcmp(&this->format, &format, sizeof(LG_RendererFormat)) == 0); return (memcmp(&this->format, &format, sizeof(LG_RendererFormat)) == 0);
} }
void lgr_basic_on_resize(void * opaque, const int width, const int height) void lgr_basic_on_resize(void * opaque, const int width, const int height, const LG_RendererRect destRect)
{ {
const struct LGR_Basic * this = (struct LGR_Basic *)opaque; struct LGR_Basic * this = (struct LGR_Basic *)opaque;
if (!this || !this->initialized) if (!this || !this->initialized)
return; return;
this->destRect.x = destRect.x;
this->destRect.y = destRect.y;
this->destRect.w = destRect.w;
this->destRect.h = destRect.h;
} }
bool lgr_basic_render(void * opaque, const LG_RendererRect destRect, const uint8_t * data, bool resample) bool lgr_basic_render(void * opaque, const uint8_t * data, bool resample)
{ {
struct LGR_Basic * this = (struct LGR_Basic *)opaque; struct LGR_Basic * this = (struct LGR_Basic *)opaque;
if (!this || !this->initialized) if (!this || !this->initialized)
@ -144,14 +150,8 @@ bool lgr_basic_render(void * opaque, const LG_RendererRect destRect, const uint8
} }
} }
SDL_Rect rect;
rect.x = destRect.x;
rect.y = destRect.y;
rect.w = destRect.w;
rect.h = destRect.h;
SDL_UnlockTexture(this->texture); SDL_UnlockTexture(this->texture);
SDL_RenderCopy(this->renderer, this->texture, NULL, &rect); SDL_RenderCopy(this->renderer, this->texture, NULL, &this->destRect);
SDL_RenderPresent(this->renderer); SDL_RenderPresent(this->renderer);
return true; return true;

View file

@ -37,6 +37,9 @@ struct LGR_OpenGL
GLuint vboID[VBO_BUFFERS]; GLuint vboID[VBO_BUFFERS];
uint8_t * texPixels[VBO_BUFFERS]; uint8_t * texPixels[VBO_BUFFERS];
int texIndex; int texIndex;
int texList;
int fpsList;
LG_RendererRect destRect;
bool hasTextures; bool hasTextures;
GLuint vboTex[VBO_BUFFERS + 1]; // extra texture for FPS GLuint vboTex[VBO_BUFFERS + 1]; // extra texture for FPS
@ -49,7 +52,7 @@ struct LGR_OpenGL
SDL_Rect fpsRect; SDL_Rect fpsRect;
}; };
void lgr_opengl_on_resize(void * opaque, const int width, const int height); void lgr_opengl_on_resize(void * opaque, const int width, const int height, const LG_RendererRect destRect);
bool lgr_opengl_check_error(const char * name) bool lgr_opengl_check_error(const char * name)
{ {
@ -139,6 +142,10 @@ bool lgr_opengl_initialize(void ** opaque, const LG_RendererParams params, const
// calculate the texture size in bytes // calculate the texture size in bytes
this->texSize = format.height * format.pitch; this->texSize = format.height * format.pitch;
// generate lists for drawing
this->texList = glGenLists(2);
this->fpsList = glGenLists(1);
// generate the pixel unpack buffers // generate the pixel unpack buffers
glGenBuffers(VBO_BUFFERS, this->vboID); glGenBuffers(VBO_BUFFERS, this->vboID);
if (lgr_opengl_check_error("glGenBuffers")) if (lgr_opengl_check_error("glGenBuffers"))
@ -239,7 +246,7 @@ bool lgr_opengl_is_compatible(void * opaque, const LG_RendererFormat format)
return (memcmp(&this->format, &format, sizeof(LG_RendererFormat)) == 0); return (memcmp(&this->format, &format, sizeof(LG_RendererFormat)) == 0);
} }
void lgr_opengl_on_resize(void * opaque, const int width, const int height) void lgr_opengl_on_resize(void * opaque, const int width, const int height, const LG_RendererRect destRect)
{ {
struct LGR_OpenGL * this = (struct LGR_OpenGL *)opaque; struct LGR_OpenGL * this = (struct LGR_OpenGL *)opaque;
if (!this || !this->initialized) if (!this || !this->initialized)
@ -247,10 +254,12 @@ void lgr_opengl_on_resize(void * opaque, const int width, const int height)
this->params.width = width; this->params.width = width;
this->params.height = height; this->params.height = height;
memcpy(&this->destRect, &destRect, sizeof(LG_RendererRect));
this->resizeWindow = true; this->resizeWindow = true;
} }
bool lgr_opengl_render(void * opaque, const LG_RendererRect destRect, const uint8_t * data, bool resample) bool lgr_opengl_render(void * opaque, const uint8_t * data, bool resample)
{ {
struct LGR_OpenGL * this = (struct LGR_OpenGL *)opaque; struct LGR_OpenGL * this = (struct LGR_OpenGL *)opaque;
if (!this || !this->initialized) if (!this || !this->initialized)
@ -270,11 +279,26 @@ bool lgr_opengl_render(void * opaque, const LG_RendererRect destRect, const uint
glLoadIdentity(); glLoadIdentity();
gluOrtho2D(0, this->params.width, this->params.height, 0); gluOrtho2D(0, this->params.width, this->params.height, 0);
glMatrixMode(GL_MODELVIEW); glMatrixMode(GL_MODELVIEW);
this->resizeWindow = false;
glClear(GL_COLOR_BUFFER_BIT); DEBUG_INFO("resize");
for(int i = 0; i < VBO_BUFFERS; ++i)
{
glNewList(this->texList + i, GL_COMPILE);
glBindTexture(GL_TEXTURE_2D, this->vboTex[i]);
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
glBegin(GL_TRIANGLE_STRIP);
glTexCoord2f(0.0f, 0.0f); glVertex2i(this->destRect.x , this->destRect.y );
glTexCoord2f(1.0f, 0.0f); glVertex2i(this->destRect.x + this->destRect.w, this->destRect.y );
glTexCoord2f(0.0f, 1.0f); glVertex2i(this->destRect.x , this->destRect.y + this->destRect.h);
glTexCoord2f(1.0f, 1.0f); glVertex2i(this->destRect.x + this->destRect.w, this->destRect.y + this->destRect.h);
glEnd();
glEndList();
} }
this->resizeWindow = false;
}
glClear(GL_COLOR_BUFFER_BIT);
if (this->params.showFPS && this->renderTime > 1e9) if (this->params.showFPS && this->renderTime > 1e9)
{ {
char str[128]; char str[128];
@ -320,78 +344,8 @@ bool lgr_opengl_render(void * opaque, const LG_RendererRect destRect, const uint
this->renderTime = 0; this->renderTime = 0;
this->frameCount = 0; this->frameCount = 0;
this->fpsTexture = true; this->fpsTexture = true;
}
// copy the buffer to the texture glNewList(this->fpsList, GL_COMPILE);
memcpySSE(this->texPixels[this->texIndex], data, this->texSize);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, this->vboID[this->texIndex]);
glFlushMappedBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, this->texSize);
// bind the texture and update it
glBindTexture(GL_TEXTURE_2D , this->vboTex[this->texIndex]);
glPixelStorei(GL_UNPACK_ALIGNMENT , 4 );
glPixelStorei(GL_UNPACK_ROW_LENGTH , this->format.width );
// wait until the last frame has been presented
glFlush();
uint count;
glXGetVideoSyncSGI(&count);
if (this->gpuFrameCount == count)
{
uint remainder;
glXWaitVideoSyncSGI(count, 1, &remainder);
this->gpuFrameCount = count + 1;
}
else
this->gpuFrameCount = count;
// update the texture
glTexSubImage2D(
GL_TEXTURE_2D,
0,
0, 0,
this->format.width ,
this->format.height,
this->vboFormat,
GL_UNSIGNED_BYTE,
(void*)0
);
const bool mipmap = resample && (
(this->format.width > destRect.w) ||
(this->format.height > destRect.h));
// unbind the buffer
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
// configure the texture
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
if (mipmap)
{
glGenerateMipmap(GL_TEXTURE_2D);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
}
else
{
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
}
// draw the screen
glBindTexture(GL_TEXTURE_2D, this->vboTex[this->texIndex]);
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
glBegin(GL_TRIANGLE_STRIP);
glTexCoord2f(0.0f, 0.0f); glVertex2i(destRect.x , destRect.y );
glTexCoord2f(1.0f, 0.0f); glVertex2i(destRect.x + destRect.w, destRect.y );
glTexCoord2f(0.0f, 1.0f); glVertex2i(destRect.x , destRect.y + destRect.h);
glTexCoord2f(1.0f, 1.0f); glVertex2i(destRect.x + destRect.w, destRect.y + destRect.h);
glEnd();
if (this->fpsTexture)
{
glEnable(GL_BLEND); glEnable(GL_BLEND);
glDisable(GL_TEXTURE_2D); glDisable(GL_TEXTURE_2D);
glColor4f(0.0f, 0.0f, 1.0f, 0.5f); glColor4f(0.0f, 0.0f, 1.0f, 0.5f);
@ -412,11 +366,76 @@ bool lgr_opengl_render(void * opaque, const LG_RendererRect destRect, const uint
glTexCoord2f(1.0f, 1.0f); glVertex2i(this->fpsRect.x + this->fpsRect.w, this->fpsRect.y + this->fpsRect.h); glTexCoord2f(1.0f, 1.0f); glVertex2i(this->fpsRect.x + this->fpsRect.w, this->fpsRect.y + this->fpsRect.h);
glEnd(); glEnd();
glDisable(GL_BLEND); glDisable(GL_BLEND);
glEndList();
} }
// copy the buffer to the texture
memcpySSE(this->texPixels[this->texIndex], data, this->texSize);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, this->vboID[this->texIndex]);
glFlushMappedBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, this->texSize);
// bind the texture and update it
glBindTexture(GL_TEXTURE_2D , this->vboTex[this->texIndex]);
glPixelStorei(GL_UNPACK_ALIGNMENT , 4 );
glPixelStorei(GL_UNPACK_ROW_LENGTH , this->format.width );
// update the texture
glTexSubImage2D(
GL_TEXTURE_2D,
0,
0, 0,
this->format.width ,
this->format.height,
this->vboFormat,
GL_UNSIGNED_BYTE,
(void*)0
);
const bool mipmap = resample && (
(this->format.width > this->destRect.w) ||
(this->format.height > this->destRect.h));
// unbind the buffer
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
// configure the texture
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
if (mipmap)
{
glGenerateMipmap(GL_TEXTURE_2D);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
}
else
{
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
}
// draw the screen
glCallList(this->texList + this->texIndex);
if (this->fpsTexture)
glCallList(this->fpsList);
++this->frameCount; ++this->frameCount;
if (this->params.vsync)
SDL_GL_SwapWindow(this->params.window); SDL_GL_SwapWindow(this->params.window);
glFlush();
// wait until the frame has been presented, this is to avoid the video card
// buffering frames, we would rather skip a frame then fall behind the guest
uint count;
glXGetVideoSyncSGI(&count);
if (this->gpuFrameCount == count)
{
uint remainder;
glXWaitVideoSyncSGI(count, 1, &remainder);
this->gpuFrameCount = count + 1;
}
else
this->gpuFrameCount = count;
const uint64_t t = nanotime(); const uint64_t t = nanotime();
this->renderTime += t - this->lastFrameTime; this->renderTime += t - this->lastFrameTime;