[client] adjusted renderer interface to allow for APIs such as Vulkan

This commit is contained in:
Geoffrey McRae 2017-12-14 17:42:16 +11:00
parent 7280f305e0
commit 8ec4abc544
3 changed files with 151 additions and 111 deletions

View File

@ -27,6 +27,8 @@ Place, Suite 330, Boston, MA 02111-1307 USA
#define IS_LG_RENDERER_VALID(x) \ #define IS_LG_RENDERER_VALID(x) \
((x)->get_name && \ ((x)->get_name && \
(x)->initialize && \ (x)->initialize && \
(x)->configure && \
(x)->deconfigure && \
(x)->deinitialize && \ (x)->deinitialize && \
(x)->is_compatible && \ (x)->is_compatible && \
(x)->on_resize && \ (x)->on_resize && \
@ -36,12 +38,9 @@ Place, Suite 330, Boston, MA 02111-1307 USA
typedef struct LG_RendererParams typedef struct LG_RendererParams
{ {
SDL_Window * window; TTF_Font * font;
TTF_Font * font; bool showFPS;
bool showFPS; bool resample;
bool resample;
int width;
int height;
} }
LG_RendererParams; LG_RendererParams;
@ -73,7 +72,9 @@ typedef enum LG_RendererCursor
LG_RendererCursor; LG_RendererCursor;
typedef const char * (* LG_RendererGetName )(); 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 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, const LG_RendererRect destRect); 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_RendererGetName get_name;
LG_RendererInitialize initialize; LG_RendererInitialize initialize;
LG_RendererConfigure configure;
LG_RendererDeConfigure deconfigure;
LG_RendererDeInitialize deinitialize; LG_RendererDeInitialize deinitialize;
LG_RendererIsCompatible is_compatible; LG_RendererIsCompatible is_compatible;
LG_RendererOnResize on_resize; LG_RendererOnResize on_resize;

View File

@ -228,67 +228,17 @@ int renderThread(void * unused)
break; break;
} }
// check if we have a compatible renderer // check if the renderer needs reconfiguration
if (!state.lgr || !state.lgr->is_compatible(state.lgrData, lgrFormat)) 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", DEBUG_INFO("Data Format: w=%u, h=%u, s=%u, p=%u, bpp=%u",
lgrFormat.width, lgrFormat.height, lgrFormat.stride, lgrFormat.pitch, lgrFormat.bpp); lgrFormat.width, lgrFormat.height, lgrFormat.stride, lgrFormat.pitch, lgrFormat.bpp);
// first try to reinitialize any existing renderer state.lgr->deconfigure(state.lgrData);
if (state.lgr) if (!state.lgr->configure(state.lgrData, state.window, lgrFormat))
{ {
state.lgr->deinitialize(state.lgrData); DEBUG_ERROR("Failed to reconfigure %s", state.lgr->get_name());
if (state.lgr->initialize(&state.lgrData, lgrParams, lgrFormat)) break;
{
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;
}
} }
state.srcSize.x = header.frame.width; state.srcSize.x = header.frame.width;
@ -361,9 +311,6 @@ int renderThread(void * unused)
state.lgr->render(state.lgrData); state.lgr->render(state.lgrData);
} }
if (state.lgr)
state.lgr->deinitialize(state.lgrData);
return 0; return 0;
} }
@ -661,7 +608,39 @@ int run()
FcPatternDestroy(pat); 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( state.window = SDL_CreateWindow(
"Looking Glass (Client)", "Looking Glass (Client)",
@ -670,10 +649,10 @@ int run()
params.w, params.w,
params.h, params.h,
( (
SDL_WINDOW_SHOWN | SDL_WINDOW_SHOWN |
SDL_WINDOW_OPENGL |
(params.allowResize ? SDL_WINDOW_RESIZABLE : 0) | (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); usleep(1000);
DEBUG_INFO("Host ready, starting session"); DEBUG_INFO("Host ready, starting session");
while(state.running) renderThread(NULL);
renderThread(NULL);
break; break;
} }
@ -805,6 +782,9 @@ int run()
if (t_spice) if (t_spice)
SDL_WaitThread(t_spice, NULL); SDL_WaitThread(t_spice, NULL);
if (state.lgr)
state.lgr->deinitialize(state.lgrData);
if (state.window) if (state.window)
SDL_DestroyWindow(state.window); SDL_DestroyWindow(state.window);

View File

@ -27,8 +27,11 @@ static PFNGLXWAITVIDEOSYNCSGIPROC glXWaitVideoSyncSGI = NULL;
struct LGR_OpenGL struct LGR_OpenGL
{ {
LG_RendererParams params; LG_RendererParams params;
bool initialized; bool configured;
SDL_GLContext glContext; SDL_GLContext glContext;
bool doneInfo;
SDL_Point window;
bool resizeWindow; bool resizeWindow;
bool frameUpdate; bool frameUpdate;
@ -81,7 +84,7 @@ const char * lgr_opengl_get_name()
return "OpenGL"; 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 // create our local storage
*opaque = malloc(sizeof(struct LGR_OpenGL)); *opaque = malloc(sizeof(struct LGR_OpenGL));
@ -91,26 +94,10 @@ bool lgr_opengl_initialize(void ** opaque, const LG_RendererParams params, const
return false; return false;
} }
memset(*opaque, 0, sizeof(struct LGR_OpenGL)); memset(*opaque, 0, sizeof(struct LGR_OpenGL));
struct LGR_OpenGL * this = (struct LGR_OpenGL *)*opaque; struct LGR_OpenGL * this = (struct LGR_OpenGL *)*opaque;
memcpy(&this->params, &params, sizeof(LG_RendererParams)); memcpy(&this->params, &params, 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) if (!glXGetVideoSyncSGI)
{ {
glXGetVideoSyncSGI = (PFNGLXGETVIDEOSYNCSGIPROC )glXGetProcAddress((const GLubyte *)"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); SDL_GL_SetSwapInterval(0);
// check if the GPU supports GL_ARB_buffer_storage first // 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 // copy the format into the local storage
memcpy(&this->format, &format, sizeof(LG_RendererFormat)); memcpy(&this->format, &format, sizeof(LG_RendererFormat));
this->initialized = true; this->configured = true;
return 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) void lgr_opengl_deinitialize(void * opaque)
{ {
struct LGR_OpenGL * this = (struct LGR_OpenGL *)opaque; struct LGR_OpenGL * this = (struct LGR_OpenGL *)opaque;
if (!this) if (!this)
return; return;
if (this->hasTextures) if (this->configured)
glDeleteTextures(TEXTURE_COUNT, this->textures); lgr_opengl_deconfigure(opaque);
if (this->hasBuffers)
glDeleteBuffers(1, this->vboID);
if (this->glContext)
SDL_GL_DeleteContext(this->glContext);
free(this); free(this);
} }
@ -285,7 +331,7 @@ void lgr_opengl_deinitialize(void * opaque)
bool lgr_opengl_is_compatible(void * opaque, const LG_RendererFormat format) bool lgr_opengl_is_compatible(void * opaque, const LG_RendererFormat format)
{ {
const struct LGR_OpenGL * this = (struct LGR_OpenGL *)opaque; const struct LGR_OpenGL * this = (struct LGR_OpenGL *)opaque;
if (!this || !this->initialized) if (!this || !this->configured)
return false; return false;
return (memcmp(&this->format, &format, sizeof(LG_RendererFormat)) == 0); 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) 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->configured)
return; return;
this->params.width = width; this->window.x = width;
this->params.height = height; this->window.y = height;
memcpy(&this->destRect, &destRect, sizeof(LG_RendererRect)); memcpy(&this->destRect, &destRect, sizeof(LG_RendererRect));
this->resizeWindow = true; 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) 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; struct LGR_OpenGL * this = (struct LGR_OpenGL *)opaque;
if (!this || !this->initialized) if (!this || !this->configured)
return false; return false;
this->mouseType = cursor; 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) 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; struct LGR_OpenGL * this = (struct LGR_OpenGL *)opaque;
if (!this || !this->initialized) if (!this || !this->configured)
return false; return false;
if (this->mousePos.x == x && this->mousePos.y == y && this->mouseVisible == visible) 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) bool lgr_opengl_on_frame_event(void * opaque, const uint8_t * data)
{ {
struct LGR_OpenGL * this = (struct LGR_OpenGL *)opaque; struct LGR_OpenGL * this = (struct LGR_OpenGL *)opaque;
if (!this || !this->initialized) if (!this)
{
DEBUG_ERROR("Invalid opaque pointer");
return false; return false;
}
if (!this->configured)
{
DEBUG_ERROR("Not configured");
return false;
}
if (this->params.showFPS && this->renderTime > 1e9) 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) bool lgr_opengl_render(void * opaque)
{ {
struct LGR_OpenGL * this = (struct LGR_OpenGL *)opaque; struct LGR_OpenGL * this = (struct LGR_OpenGL *)opaque;
if (!this || !this->initialized) if (!this || !this->configured)
return false; return false;
if (this->resizeWindow) if (this->resizeWindow)
{ {
// setup the projection matrix // 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); glMatrixMode(GL_PROJECTION);
glLoadIdentity(); glLoadIdentity();
gluOrtho2D(0, this->params.width, this->params.height, 0); gluOrtho2D(0, this->window.x, this->window.y, 0);
glMatrixMode(GL_MODELVIEW); glMatrixMode(GL_MODELVIEW);
glLoadIdentity(); glLoadIdentity();
@ -661,6 +716,8 @@ const LG_Renderer LGR_OpenGL =
{ {
.get_name = lgr_opengl_get_name, .get_name = lgr_opengl_get_name,
.initialize = lgr_opengl_initialize, .initialize = lgr_opengl_initialize,
.configure = lgr_opengl_configure,
.deconfigure = lgr_opengl_deconfigure,
.deinitialize = lgr_opengl_deinitialize, .deinitialize = lgr_opengl_deinitialize,
.is_compatible = lgr_opengl_is_compatible, .is_compatible = lgr_opengl_is_compatible,
.on_resize = lgr_opengl_on_resize, .on_resize = lgr_opengl_on_resize,