[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) \
((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;

View File

@ -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);

View File

@ -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, &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)
{
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,