From 8ec4abc544443c9955829d5c81e131a524f0d16c Mon Sep 17 00:00:00 2001 From: Geoffrey McRae Date: Thu, 14 Dec 2017 17:42:16 +1100 Subject: [PATCH] [client] adjusted renderer interface to allow for APIs such as Vulkan --- client/lg-renderer.h | 17 +++-- client/main.c | 112 +++++++++++++------------------- client/renderers/opengl.c | 133 +++++++++++++++++++++++++++----------- 3 files changed, 151 insertions(+), 111 deletions(-) diff --git a/client/lg-renderer.h b/client/lg-renderer.h index c2b5159f..69f40308 100644 --- a/client/lg-renderer.h +++ b/client/lg-renderer.h @@ -27,6 +27,8 @@ Place, Suite 330, Boston, MA 02111-1307 USA #define IS_LG_RENDERER_VALID(x) \ ((x)->get_name && \ (x)->initialize && \ + (x)->configure && \ + (x)->deconfigure && \ (x)->deinitialize && \ (x)->is_compatible && \ (x)->on_resize && \ @@ -36,12 +38,9 @@ Place, Suite 330, Boston, MA 02111-1307 USA typedef struct LG_RendererParams { - SDL_Window * window; - TTF_Font * font; - bool showFPS; - bool resample; - int width; - int height; + TTF_Font * font; + bool showFPS; + bool resample; } LG_RendererParams; @@ -73,7 +72,9 @@ typedef enum LG_RendererCursor LG_RendererCursor; 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, Uint32 * sdlFlags); +typedef bool (* LG_RendererConfigure )(void * opaque, SDL_Window *window, const LG_RendererFormat format); +typedef void (* LG_RendererDeConfigure )(void * opaque); typedef void (* LG_RendererDeInitialize )(void * opaque); typedef bool (* LG_RendererIsCompatible )(void * opaque, const LG_RendererFormat format); typedef void (* LG_RendererOnResize )(void * opaque, const int width, const int height, const LG_RendererRect destRect); @@ -86,6 +87,8 @@ typedef struct LG_Renderer { LG_RendererGetName get_name; LG_RendererInitialize initialize; + LG_RendererConfigure configure; + LG_RendererDeConfigure deconfigure; LG_RendererDeInitialize deinitialize; LG_RendererIsCompatible is_compatible; LG_RendererOnResize on_resize; diff --git a/client/main.c b/client/main.c index 79f935c7..50fb5af1 100644 --- a/client/main.c +++ b/client/main.c @@ -228,67 +228,17 @@ int renderThread(void * unused) break; } - // check if we have a compatible renderer - if (!state.lgr || !state.lgr->is_compatible(state.lgrData, lgrFormat)) + // check if the renderer needs reconfiguration + if (!state.lgr->is_compatible(state.lgrData, lgrFormat)) { - int width, height; - SDL_GetWindowSize(state.window, &width, &height); - - LG_RendererParams lgrParams; - lgrParams.window = state.window; - lgrParams.font = state.font; - lgrParams.resample = params.useMipmap; - lgrParams.showFPS = params.showFPS; - lgrParams.width = width; - lgrParams.height = height; - DEBUG_INFO("Data Format: w=%u, h=%u, s=%u, p=%u, bpp=%u", lgrFormat.width, lgrFormat.height, lgrFormat.stride, lgrFormat.pitch, lgrFormat.bpp); - // first try to reinitialize any existing renderer - if (state.lgr) + state.lgr->deconfigure(state.lgrData); + if (!state.lgr->configure(state.lgrData, state.window, lgrFormat)) { - state.lgr->deinitialize(state.lgrData); - if (state.lgr->initialize(&state.lgrData, lgrParams, lgrFormat)) - { - DEBUG_INFO("Reinitialized %s", state.lgr->get_name()); - } - else - { - DEBUG_ERROR("Failed to reinitialize %s, trying other renderers", state.lgr->get_name()); - state.lgr->deinitialize(state.lgrData); - state.lgr = NULL; - } - } - - if (!state.lgr) - { - // probe for a a suitable renderer - for(const LG_Renderer **r = &LG_Renderers[0]; *r; ++r) - { - if (!IS_LG_RENDERER_VALID(*r)) - { - DEBUG_ERROR("FIXME: Renderer %d is invalid, skipping", (int)(r - &LG_Renderers[0])); - continue; - } - - state.lgrData = NULL; - if (!(*r)->initialize(&state.lgrData, lgrParams, lgrFormat)) - { - (*r)->deinitialize(state.lgrData); - continue; - } - - state.lgr = *r; - DEBUG_INFO("Initialized %s", (*r)->get_name()); - break; - } - - if (!state.lgr) - { - DEBUG_INFO("Unable to find a suitable renderer"); - return -1; - } + DEBUG_ERROR("Failed to reconfigure %s", state.lgr->get_name()); + break; } state.srcSize.x = header.frame.width; @@ -361,9 +311,6 @@ int renderThread(void * unused) state.lgr->render(state.lgrData); } - if (state.lgr) - state.lgr->deinitialize(state.lgrData); - return 0; } @@ -661,7 +608,39 @@ int run() FcPatternDestroy(pat); } - SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 0); + LG_RendererParams lgrParams; + lgrParams.font = state.font; + lgrParams.resample = params.useMipmap; + lgrParams.showFPS = params.showFPS; + Uint32 sdlFlags; + + // probe for a a suitable renderer + for(const LG_Renderer **r = &LG_Renderers[0]; *r; ++r) + { + if (!IS_LG_RENDERER_VALID(*r)) + { + DEBUG_ERROR("FIXME: Renderer %d is invalid, skipping", (int)(r - &LG_Renderers[0])); + continue; + } + + state.lgrData = NULL; + sdlFlags = 0; + if (!(*r)->initialize(&state.lgrData, lgrParams, &sdlFlags)) + { + (*r)->deinitialize(state.lgrData); + continue; + } + + state.lgr = *r; + DEBUG_INFO("Initialized %s", (*r)->get_name()); + break; + } + + if (!state.lgr) + { + DEBUG_INFO("Unable to find a suitable renderer"); + return -1; + } state.window = SDL_CreateWindow( "Looking Glass (Client)", @@ -670,10 +649,10 @@ int run() params.w, params.h, ( - SDL_WINDOW_SHOWN | - SDL_WINDOW_OPENGL | + SDL_WINDOW_SHOWN | (params.allowResize ? SDL_WINDOW_RESIZABLE : 0) | - (params.borderless ? SDL_WINDOW_BORDERLESS : 0) + (params.borderless ? SDL_WINDOW_BORDERLESS : 0) | + sdlFlags ) ); @@ -785,9 +764,7 @@ int run() usleep(1000); DEBUG_INFO("Host ready, starting session"); - while(state.running) - renderThread(NULL); - + renderThread(NULL); break; } @@ -805,6 +782,9 @@ int run() if (t_spice) SDL_WaitThread(t_spice, NULL); + if (state.lgr) + state.lgr->deinitialize(state.lgrData); + if (state.window) SDL_DestroyWindow(state.window); diff --git a/client/renderers/opengl.c b/client/renderers/opengl.c index d899ef07..1b2ed1d0 100644 --- a/client/renderers/opengl.c +++ b/client/renderers/opengl.c @@ -27,8 +27,11 @@ static PFNGLXWAITVIDEOSYNCSGIPROC glXWaitVideoSyncSGI = NULL; struct LGR_OpenGL { LG_RendererParams params; - bool initialized; + bool configured; SDL_GLContext glContext; + bool doneInfo; + + SDL_Point window; bool resizeWindow; bool frameUpdate; @@ -81,7 +84,7 @@ const char * lgr_opengl_get_name() return "OpenGL"; } -bool lgr_opengl_initialize(void ** opaque, const LG_RendererParams params, const LG_RendererFormat format) +bool lgr_opengl_initialize(void ** opaque, const LG_RendererParams params, Uint32 * sdlFlags) { // create our local storage *opaque = malloc(sizeof(struct LGR_OpenGL)); @@ -91,26 +94,10 @@ bool lgr_opengl_initialize(void ** opaque, const LG_RendererParams params, const return false; } memset(*opaque, 0, sizeof(struct LGR_OpenGL)); + struct LGR_OpenGL * this = (struct LGR_OpenGL *)*opaque; memcpy(&this->params, ¶ms, sizeof(LG_RendererParams)); - this->glContext = SDL_GL_CreateContext(params.window); - if (!this->glContext) - { - DEBUG_ERROR("Failed to create the OpenGL context"); - return false; - } - - if (SDL_GL_MakeCurrent(params.window, this->glContext) != 0) - { - DEBUG_ERROR("Failed to make the GL context current"); - return false; - } - - DEBUG_INFO("Vendor : %s", glGetString(GL_VENDOR )); - DEBUG_INFO("Renderer: %s", glGetString(GL_RENDERER)); - DEBUG_INFO("Version : %s", glGetString(GL_VERSION )); - if (!glXGetVideoSyncSGI) { glXGetVideoSyncSGI = (PFNGLXGETVIDEOSYNCSGIPROC )glXGetProcAddress((const GLubyte *)"glXGetVideoSyncSGI" ); @@ -124,6 +111,44 @@ bool lgr_opengl_initialize(void ** opaque, const LG_RendererParams params, const } } + *sdlFlags = SDL_WINDOW_OPENGL; + SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 0); + return true; +} + +bool lgr_opengl_configure(void * opaque, SDL_Window *window, const LG_RendererFormat format) +{ + struct LGR_OpenGL * this = (struct LGR_OpenGL *)opaque; + if (!this) + return false; + + if (this->configured) + { + DEBUG_ERROR("Renderer already configured, call deconfigure first"); + return false; + } + + this->glContext = SDL_GL_CreateContext(window); + if (!this->glContext) + { + DEBUG_ERROR("Failed to create the OpenGL context"); + return false; + } + + if (!this->doneInfo) + { + DEBUG_INFO("Vendor : %s", glGetString(GL_VENDOR )); + DEBUG_INFO("Renderer: %s", glGetString(GL_RENDERER)); + DEBUG_INFO("Version : %s", glGetString(GL_VERSION )); + this->doneInfo = true; + } + + if (SDL_GL_MakeCurrent(window, this->glContext) != 0) + { + DEBUG_ERROR("Failed to make the GL context current"); + return false; + } + SDL_GL_SetSwapInterval(0); // check if the GPU supports GL_ARB_buffer_storage first @@ -260,24 +285,45 @@ bool lgr_opengl_initialize(void ** opaque, const LG_RendererParams params, const // copy the format into the local storage memcpy(&this->format, &format, sizeof(LG_RendererFormat)); - this->initialized = true; + this->configured = true; return true; } +void lgr_opengl_deconfigure(void * opaque) +{ + struct LGR_OpenGL * this = (struct LGR_OpenGL *)opaque; + if (!this || !this->configured) + return; + + if (this->hasTextures) + { + glDeleteTextures(TEXTURE_COUNT, this->textures); + this->hasTextures = false; + } + + if (this->hasBuffers) + { + glDeleteBuffers(1, this->vboID); + this->hasBuffers = false; + } + + if (this->glContext) + { + SDL_GL_DeleteContext(this->glContext); + this->glContext = NULL; + } + + this->configured = false; +} + void lgr_opengl_deinitialize(void * opaque) { struct LGR_OpenGL * this = (struct LGR_OpenGL *)opaque; if (!this) return; - if (this->hasTextures) - glDeleteTextures(TEXTURE_COUNT, this->textures); - - if (this->hasBuffers) - glDeleteBuffers(1, this->vboID); - - if (this->glContext) - SDL_GL_DeleteContext(this->glContext); + if (this->configured) + lgr_opengl_deconfigure(opaque); free(this); } @@ -285,7 +331,7 @@ void lgr_opengl_deinitialize(void * opaque) bool lgr_opengl_is_compatible(void * opaque, const LG_RendererFormat format) { const struct LGR_OpenGL * this = (struct LGR_OpenGL *)opaque; - if (!this || !this->initialized) + if (!this || !this->configured) return false; return (memcmp(&this->format, &format, sizeof(LG_RendererFormat)) == 0); @@ -294,11 +340,11 @@ bool lgr_opengl_is_compatible(void * opaque, const LG_RendererFormat format) 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; - if (!this || !this->initialized) + if (!this || !this->configured) return; - this->params.width = width; - this->params.height = height; + this->window.x = width; + this->window.y = height; memcpy(&this->destRect, &destRect, sizeof(LG_RendererRect)); this->resizeWindow = true; @@ -307,7 +353,7 @@ void lgr_opengl_on_resize(void * opaque, const int width, const int height, cons bool lgr_opengl_on_mouse_shape(void * opaque, const LG_RendererCursor cursor, const int width, const int height, const int pitch, const uint8_t * data) { struct LGR_OpenGL * this = (struct LGR_OpenGL *)opaque; - if (!this || !this->initialized) + if (!this || !this->configured) return false; this->mouseType = cursor; @@ -432,7 +478,7 @@ bool lgr_opengl_on_mouse_shape(void * opaque, const LG_RendererCursor cursor, co bool lgr_opengl_on_mouse_event(void * opaque, const bool visible, const int x, const int y) { struct LGR_OpenGL * this = (struct LGR_OpenGL *)opaque; - if (!this || !this->initialized) + if (!this || !this->configured) return false; if (this->mousePos.x == x && this->mousePos.y == y && this->mouseVisible == visible) @@ -448,8 +494,17 @@ bool lgr_opengl_on_mouse_event(void * opaque, const bool visible, const int x, c bool lgr_opengl_on_frame_event(void * opaque, const uint8_t * data) { struct LGR_OpenGL * this = (struct LGR_OpenGL *)opaque; - if (!this || !this->initialized) + if (!this) + { + DEBUG_ERROR("Invalid opaque pointer"); return false; + } + + if (!this->configured) + { + DEBUG_ERROR("Not configured"); + return false; + } if (this->params.showFPS && this->renderTime > 1e9) { @@ -589,16 +644,16 @@ static inline void lgr_opengl_draw_mouse(struct LGR_OpenGL * this) bool lgr_opengl_render(void * opaque) { struct LGR_OpenGL * this = (struct LGR_OpenGL *)opaque; - if (!this || !this->initialized) + if (!this || !this->configured) return false; if (this->resizeWindow) { // setup the projection matrix - glViewport(0, 0, this->params.width, this->params.height); + glViewport(0, 0, this->window.x, this->window.y); glMatrixMode(GL_PROJECTION); glLoadIdentity(); - gluOrtho2D(0, this->params.width, this->params.height, 0); + gluOrtho2D(0, this->window.x, this->window.y, 0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); @@ -661,6 +716,8 @@ const LG_Renderer LGR_OpenGL = { .get_name = lgr_opengl_get_name, .initialize = lgr_opengl_initialize, + .configure = lgr_opengl_configure, + .deconfigure = lgr_opengl_deconfigure, .deinitialize = lgr_opengl_deinitialize, .is_compatible = lgr_opengl_is_compatible, .on_resize = lgr_opengl_on_resize,