[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.
This commit is contained in:
Geoffrey McRae 2021-07-25 15:29:29 +10:00
parent 8c2a77e84e
commit 60a58d4d8d
7 changed files with 30 additions and 15 deletions

View file

@ -46,6 +46,7 @@ bool app_isFormatValid(void);
void app_updateCursorPos(double x, double y); void app_updateCursorPos(double x, double y);
void app_updateWindowPos(int x, int y); void app_updateWindowPos(int x, int y);
void app_handleResizeEvent(int w, int h, double scale, const struct Border border); void app_handleResizeEvent(int w, int h, double scale, const struct Border border);
void app_invalidateWindow(void);
void app_handleMouseRelative(double normx, double normy, void app_handleMouseRelative(double normx, double normy,
double rawx, double rawy); double rawx, double rawy);

View file

@ -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_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_RendererOnFrame )(void * opaque, const FrameBuffer * frame, int dmaFD, const FrameDamageRect * damage, int damageCount);
typedef bool (* LG_RendererRenderStartup)(void * opaque); 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 typedef struct LG_Renderer
{ {

View file

@ -791,7 +791,8 @@ bool egl_render_startup(void * opaque)
return true; 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; 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 |= egl_damage_render(this->damage, newFrame ? desktopDamage : NULL);
hasOverlay |= invalidateWindow;
struct Rect damage[KVMFR_MAX_DAMAGE_RECTS + MAX_OVERLAY_RECTS + 2]; struct Rect damage[KVMFR_MAX_DAMAGE_RECTS + MAX_OVERLAY_RECTS + 2];
int damageIdx = app_renderOverlay(damage, MAX_OVERLAY_RECTS); int damageIdx = app_renderOverlay(damage, MAX_OVERLAY_RECTS);

View file

@ -456,7 +456,8 @@ bool opengl_render_startup(void * opaque)
return true; 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; struct Inst * this = (struct Inst *)opaque;
if (!this) if (!this)

View file

@ -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) void app_handleCloseEvent(void)
{ {
if (!g_params.ignoreQuit || !g_cursor.inView) if (!g_params.ignoreQuit || !g_cursor.inView)

View file

@ -64,7 +64,6 @@ static int cursorThread(void * unused);
static int renderThread(void * unused); static int renderThread(void * unused);
static LGEvent *e_startup = NULL; static LGEvent *e_startup = NULL;
static LGEvent *e_frame = NULL;
static LGThread *t_spice = NULL; static LGThread *t_spice = NULL;
static LGThread *t_render = NULL; static LGThread *t_render = NULL;
static LGThread *t_cursor = 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); 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 */ /* only update the time if we woke up early */
clock_gettime(CLOCK_MONOTONIC, &time); clock_gettime(CLOCK_MONOTONIC, &time);
@ -208,8 +207,11 @@ static int renderThread(void * unused)
const bool newFrame = frameCount != lastFrameCount; const bool newFrame = frameCount != lastFrameCount;
lastFrameCount = frameCount; lastFrameCount = frameCount;
const bool invalidate = atomic_exchange(&g_state.invalidateWindow, false);
LG_LOCK(g_state.lgrLock); 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); LG_UNLOCK(g_state.lgrLock);
break; break;
@ -306,7 +308,7 @@ static int cursorThread(void * unused)
); );
if (!g_state.stopVideo) if (!g_state.stopVideo)
lgSignalEvent(e_frame); lgSignalEvent(g_state.frameEvent);
} }
const struct timespec req = const struct timespec req =
@ -405,7 +407,7 @@ static int cursorThread(void * unused)
); );
if (g_params.mouseRedraw && g_cursor.guest.visible && !g_state.stopVideo) if (g_params.mouseRedraw && g_cursor.guest.visible && !g_state.stopVideo)
lgSignalEvent(e_frame); lgSignalEvent(g_state.frameEvent);
} }
lgmpClientUnsubscribe(&queue); lgmpClientUnsubscribe(&queue);
@ -678,7 +680,7 @@ int main_frameThread(void * unused)
g_state.lastFrameTimeValid = true; g_state.lastFrameTimeValid = true;
atomic_fetch_add_explicit(&g_state.frameCount, 1, memory_order_relaxed); atomic_fetch_add_explicit(&g_state.frameCount, 1, memory_order_relaxed);
lgSignalEvent(e_frame); lgSignalEvent(g_state.frameEvent);
lgmpClientMessageDone(queue); lgmpClientMessageDone(queue);
} }
@ -950,7 +952,7 @@ static int lg_run(void)
} }
// setup the new frame event // 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"); DEBUG_ERROR("failed to create the frame event");
return -1; return -1;
@ -1092,7 +1094,7 @@ restart:
if (g_state.state == APP_STATE_RESTART) if (g_state.state == APP_STATE_RESTART)
{ {
lgSignalEvent(e_startup); lgSignalEvent(e_startup);
lgSignalEvent(e_frame); lgSignalEvent(g_state.frameEvent);
core_stopFrameThread(); core_stopFrameThread();
@ -1116,7 +1118,7 @@ static void lg_shutdown(void)
if (t_render) if (t_render)
{ {
lgSignalEvent(e_startup); lgSignalEvent(e_startup);
lgSignalEvent(e_frame); lgSignalEvent(g_state.frameEvent);
lgJoinThread(t_render, NULL); lgJoinThread(t_render, NULL);
} }
@ -1129,10 +1131,10 @@ static void lg_shutdown(void)
g_state.overlays = NULL; g_state.overlays = NULL;
} }
if (e_frame) if (g_state.frameEvent)
{ {
lgFreeEvent(e_frame); lgFreeEvent(g_state.frameEvent);
e_frame = NULL; g_state.frameEvent = NULL;
} }
if (e_startup) if (e_startup)

View file

@ -30,6 +30,7 @@
#include "common/ivshmem.h" #include "common/ivshmem.h"
#include "common/locking.h" #include "common/locking.h"
#include "common/ringbuffer.h" #include "common/ringbuffer.h"
#include "common/event.h"
#include "spice/spice.h" #include "spice/spice.h"
#include <lgmp/client.h> #include <lgmp/client.h>
@ -103,6 +104,8 @@ struct AppState
PLGMPClientQueue pointerQueue; PLGMPClientQueue pointerQueue;
LGThread * frameThread; LGThread * frameThread;
LGEvent * frameEvent;
atomic_bool invalidateWindow;
bool formatValid; bool formatValid;
atomic_uint_least64_t frameTime; atomic_uint_least64_t frameTime;
uint64_t lastFrameTime; uint64_t lastFrameTime;