From 60a58d4d8d800cba9198b857a9a2f8c20daab0fa Mon Sep 17 00:00:00 2001 From: Geoffrey McRae Date: Sun, 25 Jul 2021 15:29:29 +1000 Subject: [PATCH] [client] all: make it possible to signal full window invalidation Now that we are drawing with damage rects, when the window is hidden and then exposed the window may not get fully redrawn. This provides `app_invalidateWindow` for the display server backend to call when the screen needs a full redraw. --- client/include/app.h | 1 + client/include/interface/renderer.h | 2 +- client/renderers/EGL/egl.c | 4 +++- client/renderers/OpenGL/opengl.c | 3 ++- client/src/app.c | 6 ++++++ client/src/main.c | 26 ++++++++++++++------------ client/src/main.h | 3 +++ 7 files changed, 30 insertions(+), 15 deletions(-) diff --git a/client/include/app.h b/client/include/app.h index 41837523..ed6a5de5 100644 --- a/client/include/app.h +++ b/client/include/app.h @@ -46,6 +46,7 @@ bool app_isFormatValid(void); void app_updateCursorPos(double x, double y); void app_updateWindowPos(int x, int y); void app_handleResizeEvent(int w, int h, double scale, const struct Border border); +void app_invalidateWindow(void); void app_handleMouseRelative(double normx, double normy, double rawx, double rawy); diff --git a/client/include/interface/renderer.h b/client/include/interface/renderer.h index 3a0e9eaf..6b84a869 100644 --- a/client/include/interface/renderer.h +++ b/client/include/interface/renderer.h @@ -112,7 +112,7 @@ typedef bool (* LG_RendererOnMouseEvent )(void * opaque, const bool visi typedef bool (* LG_RendererOnFrameFormat)(void * opaque, const LG_RendererFormat format, bool useDMA); typedef bool (* LG_RendererOnFrame )(void * opaque, const FrameBuffer * frame, int dmaFD, const FrameDamageRect * damage, int damageCount); typedef bool (* LG_RendererRenderStartup)(void * opaque); -typedef bool (* LG_RendererRender )(void * opaque, LG_RendererRotate rotate, const bool newFrame); +typedef bool (* LG_RendererRender )(void * opaque, LG_RendererRotate rotate, const bool newFrame, const bool invalidateWindow); typedef struct LG_Renderer { diff --git a/client/renderers/EGL/egl.c b/client/renderers/EGL/egl.c index b1007181..05d9cc21 100644 --- a/client/renderers/EGL/egl.c +++ b/client/renderers/EGL/egl.c @@ -791,7 +791,8 @@ bool egl_render_startup(void * opaque) return true; } -bool egl_render(void * opaque, LG_RendererRotate rotate, const bool newFrame) +bool egl_render(void * opaque, LG_RendererRotate rotate, const bool newFrame, + const bool invalidateWindow) { struct Inst * this = (struct Inst *)opaque; @@ -856,6 +857,7 @@ bool egl_render(void * opaque, LG_RendererRotate rotate, const bool newFrame) } hasOverlay |= egl_damage_render(this->damage, newFrame ? desktopDamage : NULL); + hasOverlay |= invalidateWindow; struct Rect damage[KVMFR_MAX_DAMAGE_RECTS + MAX_OVERLAY_RECTS + 2]; int damageIdx = app_renderOverlay(damage, MAX_OVERLAY_RECTS); diff --git a/client/renderers/OpenGL/opengl.c b/client/renderers/OpenGL/opengl.c index 1261cd6b..c5acbd61 100644 --- a/client/renderers/OpenGL/opengl.c +++ b/client/renderers/OpenGL/opengl.c @@ -456,7 +456,8 @@ bool opengl_render_startup(void * opaque) return true; } -bool opengl_render(void * opaque, LG_RendererRotate rotate, const bool newFrame) +bool opengl_render(void * opaque, LG_RendererRotate rotate, const bool newFrame, + const bool invalidateWindow) { struct Inst * this = (struct Inst *)opaque; if (!this) diff --git a/client/src/app.c b/client/src/app.c index 5a21b694..ff6a801d 100644 --- a/client/src/app.c +++ b/client/src/app.c @@ -418,6 +418,12 @@ void app_handleResizeEvent(int w, int h, double scale, const struct Border borde } } +void app_invalidateWindow(void) +{ + atomic_store(&g_state.invalidateWindow, true); + lgSignalEvent(g_state.frameEvent); +} + void app_handleCloseEvent(void) { if (!g_params.ignoreQuit || !g_cursor.inView) diff --git a/client/src/main.c b/client/src/main.c index 9e7989aa..ee22ffca 100644 --- a/client/src/main.c +++ b/client/src/main.c @@ -64,7 +64,6 @@ static int cursorThread(void * unused); static int renderThread(void * unused); static LGEvent *e_startup = NULL; -static LGEvent *e_frame = NULL; static LGThread *t_spice = NULL; static LGThread *t_render = NULL; static LGThread *t_cursor = NULL; @@ -170,7 +169,7 @@ static int renderThread(void * unused) { float ups = atomic_load_explicit(&g_state.ups, memory_order_relaxed); - if (!lgWaitEventAbs(e_frame, &time) || ups > g_params.fpsMin) + if (!lgWaitEventAbs(g_state.frameEvent, &time) || ups > g_params.fpsMin) { /* only update the time if we woke up early */ clock_gettime(CLOCK_MONOTONIC, &time); @@ -208,8 +207,11 @@ static int renderThread(void * unused) const bool newFrame = frameCount != lastFrameCount; lastFrameCount = frameCount; + const bool invalidate = atomic_exchange(&g_state.invalidateWindow, false); + LG_LOCK(g_state.lgrLock); - if (!g_state.lgr->render(g_state.lgrData, g_params.winRotate, newFrame)) + if (!g_state.lgr->render(g_state.lgrData, g_params.winRotate, newFrame, + invalidate)) { LG_UNLOCK(g_state.lgrLock); break; @@ -306,7 +308,7 @@ static int cursorThread(void * unused) ); if (!g_state.stopVideo) - lgSignalEvent(e_frame); + lgSignalEvent(g_state.frameEvent); } const struct timespec req = @@ -405,7 +407,7 @@ static int cursorThread(void * unused) ); if (g_params.mouseRedraw && g_cursor.guest.visible && !g_state.stopVideo) - lgSignalEvent(e_frame); + lgSignalEvent(g_state.frameEvent); } lgmpClientUnsubscribe(&queue); @@ -678,7 +680,7 @@ int main_frameThread(void * unused) g_state.lastFrameTimeValid = true; atomic_fetch_add_explicit(&g_state.frameCount, 1, memory_order_relaxed); - lgSignalEvent(e_frame); + lgSignalEvent(g_state.frameEvent); lgmpClientMessageDone(queue); } @@ -950,7 +952,7 @@ static int lg_run(void) } // setup the new frame event - if (!(e_frame = lgCreateEvent(true, 0))) + if (!(g_state.frameEvent = lgCreateEvent(true, 0))) { DEBUG_ERROR("failed to create the frame event"); return -1; @@ -1092,7 +1094,7 @@ restart: if (g_state.state == APP_STATE_RESTART) { lgSignalEvent(e_startup); - lgSignalEvent(e_frame); + lgSignalEvent(g_state.frameEvent); core_stopFrameThread(); @@ -1116,7 +1118,7 @@ static void lg_shutdown(void) if (t_render) { lgSignalEvent(e_startup); - lgSignalEvent(e_frame); + lgSignalEvent(g_state.frameEvent); lgJoinThread(t_render, NULL); } @@ -1129,10 +1131,10 @@ static void lg_shutdown(void) g_state.overlays = NULL; } - if (e_frame) + if (g_state.frameEvent) { - lgFreeEvent(e_frame); - e_frame = NULL; + lgFreeEvent(g_state.frameEvent); + g_state.frameEvent = NULL; } if (e_startup) diff --git a/client/src/main.h b/client/src/main.h index 6d0cf3bf..8f166152 100644 --- a/client/src/main.h +++ b/client/src/main.h @@ -30,6 +30,7 @@ #include "common/ivshmem.h" #include "common/locking.h" #include "common/ringbuffer.h" +#include "common/event.h" #include "spice/spice.h" #include @@ -103,6 +104,8 @@ struct AppState PLGMPClientQueue pointerQueue; LGThread * frameThread; + LGEvent * frameEvent; + atomic_bool invalidateWindow; bool formatValid; atomic_uint_least64_t frameTime; uint64_t lastFrameTime;