diff --git a/client/include/interface/renderer.h b/client/include/interface/renderer.h index b89eb770..4cf7679e 100644 --- a/client/include/interface/renderer.h +++ b/client/include/interface/renderer.h @@ -86,34 +86,36 @@ typedef const char * (* LG_RendererGetName)(); // called pre-creation to allow the renderer to register any options it might have typedef void (* LG_RendererSetup)(); -typedef bool (* LG_RendererCreate )(void ** opaque, const LG_RendererParams params); -typedef bool (* LG_RendererInitialize )(void * opaque, Uint32 * sdlFlags); -typedef void (* LG_RendererDeInitialize)(void * opaque); -typedef void (* LG_RendererOnRestart )(void * opaque); -typedef void (* LG_RendererOnResize )(void * opaque, const int width, const int height, const LG_RendererRect destRect); -typedef bool (* LG_RendererOnMouseShape)(void * opaque, const LG_RendererCursor cursor, const int width, const int height, const int pitch, const uint8_t * data); -typedef bool (* LG_RendererOnMouseEvent)(void * opaque, const bool visible , const int x, const int y); -typedef bool (* LG_RendererOnFrameEvent)(void * opaque, const LG_RendererFormat format, const FrameBuffer * frame); -typedef void (* LG_RendererOnAlert )(void * opaque, const LG_MsgAlert alert, const char * message, bool ** closeFlag); -typedef bool (* LG_RendererRender )(void * opaque, SDL_Window *window); -typedef void (* LG_RendererUpdateFPS )(void * opaque, const float avgUPS, const float avgFPS); +typedef bool (* LG_RendererCreate )(void ** opaque, const LG_RendererParams params); +typedef bool (* LG_RendererInitialize )(void * opaque, Uint32 * sdlFlags); +typedef void (* LG_RendererDeInitialize )(void * opaque); +typedef void (* LG_RendererOnRestart )(void * opaque); +typedef void (* LG_RendererOnResize )(void * opaque, const int width, const int height, const LG_RendererRect destRect); +typedef bool (* LG_RendererOnMouseShape )(void * opaque, const LG_RendererCursor cursor, const int width, const int height, const int pitch, const uint8_t * data); +typedef bool (* LG_RendererOnMouseEvent )(void * opaque, const bool visible , const int x, const int y); +typedef bool (* LG_RendererOnFrameFormat)(void * opaque, const LG_RendererFormat format); +typedef bool (* LG_RendererOnFrame )(void * opaque, const FrameBuffer * frame); +typedef void (* LG_RendererOnAlert )(void * opaque, const LG_MsgAlert alert, const char * message, bool ** closeFlag); +typedef bool (* LG_RendererRender )(void * opaque, SDL_Window *window); +typedef void (* LG_RendererUpdateFPS )(void * opaque, const float avgUPS, const float avgFPS); typedef struct LG_Renderer { LG_RendererGetName get_name; LG_RendererSetup setup; - LG_RendererCreate create; - LG_RendererInitialize initialize; - LG_RendererDeInitialize deinitialize; - LG_RendererOnRestart on_restart; - LG_RendererOnResize on_resize; - LG_RendererOnMouseShape on_mouse_shape; - LG_RendererOnMouseEvent on_mouse_event; - LG_RendererOnFrameEvent on_frame_event; - LG_RendererOnAlert on_alert; - LG_RendererRender render_startup; - LG_RendererRender render; - LG_RendererUpdateFPS update_fps; + LG_RendererCreate create; + LG_RendererInitialize initialize; + LG_RendererDeInitialize deinitialize; + LG_RendererOnRestart on_restart; + LG_RendererOnResize on_resize; + LG_RendererOnMouseShape on_mouse_shape; + LG_RendererOnMouseEvent on_mouse_event; + LG_RendererOnFrameFormat on_frame_format; + LG_RendererOnFrame on_frame; + LG_RendererOnAlert on_alert; + LG_RendererRender render_startup; + LG_RendererRender render; + LG_RendererUpdateFPS update_fps; } LG_Renderer; diff --git a/client/renderers/EGL/desktop.c b/client/renderers/EGL/desktop.c index 78de4776..a266aba7 100644 --- a/client/renderers/EGL/desktop.c +++ b/client/renderers/EGL/desktop.c @@ -175,60 +175,62 @@ void egl_desktop_free(EGL_Desktop ** desktop) *desktop = NULL; } -bool egl_desktop_update(EGL_Desktop * desktop, const bool sourceChanged, const LG_RendererFormat format, const FrameBuffer * frame) +bool egl_desktop_setup(EGL_Desktop * desktop, const LG_RendererFormat format) { - if (sourceChanged) + enum EGL_PixelFormat pixFmt; + switch(format.type) { - enum EGL_PixelFormat pixFmt; - switch(format.type) - { - case FRAME_TYPE_BGRA: - pixFmt = EGL_PF_BGRA; - desktop->shader = &desktop->shader_generic; - break; + case FRAME_TYPE_BGRA: + pixFmt = EGL_PF_BGRA; + desktop->shader = &desktop->shader_generic; + break; - case FRAME_TYPE_RGBA: - pixFmt = EGL_PF_RGBA; - desktop->shader = &desktop->shader_generic; - break; + case FRAME_TYPE_RGBA: + pixFmt = EGL_PF_RGBA; + desktop->shader = &desktop->shader_generic; + break; - case FRAME_TYPE_RGBA10: - pixFmt = EGL_PF_RGBA10; - desktop->shader = &desktop->shader_generic; - break; + case FRAME_TYPE_RGBA10: + pixFmt = EGL_PF_RGBA10; + desktop->shader = &desktop->shader_generic; + break; - case FRAME_TYPE_RGBA16F: - pixFmt = EGL_PF_RGBA16F; - desktop->shader = &desktop->shader_generic; - break; + case FRAME_TYPE_RGBA16F: + pixFmt = EGL_PF_RGBA16F; + desktop->shader = &desktop->shader_generic; + break; - case FRAME_TYPE_YUV420: - pixFmt = EGL_PF_YUV420; - desktop->shader = &desktop->shader_yuv; - break; + case FRAME_TYPE_YUV420: + pixFmt = EGL_PF_YUV420; + desktop->shader = &desktop->shader_yuv; + break; - default: - DEBUG_ERROR("Unsupported frame format"); - return false; - } - - desktop->width = format.width; - desktop->height = format.height; - - if (!egl_texture_setup( - desktop->texture, - pixFmt, - format.width, - format.height, - format.pitch, - true // streaming texture - )) - { - DEBUG_ERROR("Failed to setup the desktop texture"); + default: + DEBUG_ERROR("Unsupported frame format"); return false; - } } + desktop->width = format.width; + desktop->height = format.height; + + if (!egl_texture_setup( + desktop->texture, + pixFmt, + format.width, + format.height, + format.pitch, + true // streaming texture + )) + { + DEBUG_ERROR("Failed to setup the desktop texture"); + return false; + } + + return true; +} + +bool egl_desktop_update(EGL_Desktop * desktop, const FrameBuffer * frame) +{ if (!egl_texture_update_from_frame(desktop->texture, frame)) return false; diff --git a/client/renderers/EGL/desktop.h b/client/renderers/EGL/desktop.h index e66ed06c..b7ce3396 100644 --- a/client/renderers/EGL/desktop.h +++ b/client/renderers/EGL/desktop.h @@ -28,5 +28,6 @@ typedef struct EGL_Desktop EGL_Desktop; bool egl_desktop_init(void * egl, EGL_Desktop ** desktop); void egl_desktop_free(EGL_Desktop ** desktop); -bool egl_desktop_update(EGL_Desktop * desktop, const bool sourceChanged, const LG_RendererFormat format, const FrameBuffer * frame); +bool egl_desktop_setup (EGL_Desktop * desktop, const LG_RendererFormat format); +bool egl_desktop_update(EGL_Desktop * desktop, const FrameBuffer * frame); bool egl_desktop_render(EGL_Desktop * desktop, const float x, const float y, const float scaleX, const float scaleY, const bool nearest); diff --git a/client/renderers/EGL/egl.c b/client/renderers/EGL/egl.c index efb60bf3..b2507236 100644 --- a/client/renderers/EGL/egl.c +++ b/client/renderers/EGL/egl.c @@ -308,20 +308,10 @@ bool egl_on_mouse_event(void * opaque, const bool visible, const int x, const in return true; } -bool egl_on_frame_event(void * opaque, const LG_RendererFormat format, const FrameBuffer * frame) +bool egl_on_frame_format(void * opaque, const LG_RendererFormat format) { struct Inst * this = (struct Inst *)opaque; - const bool sourceChanged = ( - this->format.type != format.type || - this->format.width != format.width || - this->format.height != format.height || - this->format.pitch != format.pitch - ); - - if (sourceChanged) - memcpy(&this->format, &format, sizeof(LG_RendererFormat)); - - this->useNearest = this->width < format.width || this->height < format.height; + memcpy(&this->format, &format, sizeof(LG_RendererFormat)); /* this event runs in a second thread so we need to init it here */ if (!this->frameContext) @@ -344,7 +334,15 @@ bool egl_on_frame_event(void * opaque, const LG_RendererFormat format, const Fra } } - if (!egl_desktop_update(this->desktop, sourceChanged, format, frame)) + this->useNearest = this->width < format.width || this->height < format.height; + return egl_desktop_setup(this->desktop, format); +} + +bool egl_on_frame(void * opaque, const FrameBuffer * frame) +{ + struct Inst * this = (struct Inst *)opaque; + + if (!egl_desktop_update(this->desktop, frame)) { DEBUG_INFO("Failed to to update the desktop"); return false; @@ -614,18 +612,19 @@ void egl_update_fps(void * opaque, const float avgUPS, const float avgFPS) struct LG_Renderer LGR_EGL = { - .get_name = egl_get_name, - .setup = egl_setup, - .create = egl_create, - .initialize = egl_initialize, - .deinitialize = egl_deinitialize, - .on_restart = egl_on_restart, - .on_resize = egl_on_resize, - .on_mouse_shape = egl_on_mouse_shape, - .on_mouse_event = egl_on_mouse_event, - .on_frame_event = egl_on_frame_event, - .on_alert = egl_on_alert, - .render_startup = egl_render_startup, - .render = egl_render, - .update_fps = egl_update_fps + .get_name = egl_get_name, + .setup = egl_setup, + .create = egl_create, + .initialize = egl_initialize, + .deinitialize = egl_deinitialize, + .on_restart = egl_on_restart, + .on_resize = egl_on_resize, + .on_mouse_shape = egl_on_mouse_shape, + .on_mouse_event = egl_on_mouse_event, + .on_frame_format = egl_on_frame_format, + .on_frame = egl_on_frame, + .on_alert = egl_on_alert, + .render_startup = egl_render_startup, + .render = egl_render, + .update_fps = egl_update_fps }; diff --git a/client/renderers/OpenGL/opengl.c b/client/renderers/OpenGL/opengl.c index eadc4f47..155baa76 100644 --- a/client/renderers/OpenGL/opengl.c +++ b/client/renderers/OpenGL/opengl.c @@ -375,36 +375,20 @@ bool opengl_on_mouse_event(void * opaque, const bool visible, const int x, const return false; } -bool opengl_on_frame_event(void * opaque, const LG_RendererFormat format, const FrameBuffer * frame) +bool opengl_on_frame_format(void * opaque, const LG_RendererFormat format) { struct Inst * this = (struct Inst *)opaque; - if (!this) - { - DEBUG_ERROR("Invalid opaque pointer"); - return false; - } LG_LOCK(this->formatLock); - if (this->reconfigure) - { - LG_UNLOCK(this->formatLock); - return true; - } - - if (!this->configured || - this->format.type != format.type || - this->format.width != format.width || - this->format.height != format.height || - this->format.stride != format.stride || - this->format.bpp != format.bpp - ) - { - memcpy(&this->format, &format, sizeof(LG_RendererFormat)); - this->reconfigure = true; - LG_UNLOCK(this->formatLock); - return true; - } + memcpy(&this->format, &format, sizeof(LG_RendererFormat)); + this->reconfigure = true; LG_UNLOCK(this->formatLock); + return true; +} + +bool opengl_on_frame(void * opaque, const FrameBuffer * frame) +{ + struct Inst * this = (struct Inst *)opaque; LG_LOCK(this->syncLock); this->frame = frame; @@ -829,21 +813,22 @@ static void render_wait(struct Inst * this) const LG_Renderer LGR_OpenGL = { - .get_name = opengl_get_name, - .setup = opengl_setup, + .get_name = opengl_get_name, + .setup = opengl_setup, - .create = opengl_create, - .initialize = opengl_initialize, - .deinitialize = opengl_deinitialize, - .on_restart = opengl_on_restart, - .on_resize = opengl_on_resize, - .on_mouse_shape = opengl_on_mouse_shape, - .on_mouse_event = opengl_on_mouse_event, - .on_frame_event = opengl_on_frame_event, - .on_alert = opengl_on_alert, - .render_startup = opengl_render_startup, - .render = opengl_render, - .update_fps = opengl_update_fps + .create = opengl_create, + .initialize = opengl_initialize, + .deinitialize = opengl_deinitialize, + .on_restart = opengl_on_restart, + .on_resize = opengl_on_resize, + .on_mouse_shape = opengl_on_mouse_shape, + .on_mouse_event = opengl_on_mouse_event, + .on_frame_format = opengl_on_frame_format, + .on_frame = opengl_on_frame, + .on_alert = opengl_on_alert, + .render_startup = opengl_render_startup, + .render = opengl_render, + .update_fps = opengl_update_fps }; static bool _check_gl_error(unsigned int line, const char * name) diff --git a/client/src/main.c b/client/src/main.c index 914cf6ad..b44f9c73 100644 --- a/client/src/main.c +++ b/client/src/main.c @@ -471,6 +471,18 @@ static int frameThread(void * unused) formatValid = true; formatVer = frame->formatVer; + + DEBUG_INFO("Format: %s %ux%u %u %u", + FrameTypeStr[frame->type], + frame->width, frame->height, + frame->stride, frame->pitch); + + if (!state.lgr->on_frame_format(state.lgrData, lgrFormat)) + { + DEBUG_ERROR("renderer failed to configure format"); + state.state = APP_STATE_SHUTDOWN; + break; + } } if (lgrFormat.width != state.srcSize.x || lgrFormat.height != state.srcSize.y) @@ -485,9 +497,10 @@ static int frameThread(void * unused) } FrameBuffer * fb = (FrameBuffer *)(((uint8_t*)frame) + frame->offset); - if (!state.lgr->on_frame_event(state.lgrData, lgrFormat, fb)) + if (!state.lgr->on_frame(state.lgrData, fb)) { - DEBUG_ERROR("renderer on frame event returned failure"); + lgmpClientMessageDone(queue); + DEBUG_ERROR("renderer on frame returned failure"); state.state = APP_STATE_SHUTDOWN; break; } diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index e78196cc..ff152a83 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -18,6 +18,7 @@ set(COMMON_SOURCES src/stringlist.c src/option.c src/framebuffer.c + src/KVMFR.c ) add_library(lg_common STATIC ${COMMON_SOURCES}) diff --git a/common/include/common/KVMFR.h b/common/include/common/KVMFR.h index 10dab83c..ddb650c4 100644 --- a/common/include/common/KVMFR.h +++ b/common/include/common/KVMFR.h @@ -35,6 +35,8 @@ typedef enum FrameType } FrameType; +extern const char * FrameTypeStr[FRAME_TYPE_MAX]; + enum { CURSOR_FLAG_POSITION = 0x1, diff --git a/common/src/KVMFR.c b/common/src/KVMFR.c new file mode 100644 index 00000000..988740c3 --- /dev/null +++ b/common/src/KVMFR.c @@ -0,0 +1,30 @@ +/* +KVMGFX Client - A KVM Client for VGA Passthrough +Copyright (C) 2017-2020 Geoffrey McRae +https://looking-glass.hostfission.com + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation; either version 2 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A +PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program; if not, write to the Free Software Foundation, Inc., 59 Temple +Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "common/KVMFR.h" + +const char * FrameTypeStr[FRAME_TYPE_MAX] = +{ + "FRAME_TYPE_INVALID", + "FRAME_TYPE_BGRA", + "FRAME_TYPE_RGBA", + "FRAME_TYPE_RGBA10", + "FRAME_TYPE_RGBA16F", + "FRAME_TYPE_YUV420" +};