[client] overlay: rework the interface to avoid possible race conditions

This commit is contained in:
Geoffrey McRae 2021-07-22 18:33:50 +10:00
parent 50f7a1a99c
commit 4acbf2e9a0
5 changed files with 73 additions and 68 deletions

View File

@ -81,7 +81,16 @@ void app_glSwapBuffers(void);
#endif #endif
void app_registerOverlay(const struct LG_OverlayOps * ops, void * params); void app_registerOverlay(const struct LG_OverlayOps * ops, void * params);
/**
* render the overlay
* returns:
* -1 for no overlay
* 0 for full output damage
* >0 number of rects written into rects
*/
int app_renderOverlay(struct Rect * rects, int maxRects); int app_renderOverlay(struct Rect * rects, int maxRects);
void app_freeOverlays(void); void app_freeOverlays(void);
struct OverlayGraph; struct OverlayGraph;

View File

@ -46,23 +46,21 @@ struct LG_OverlayOps
/* general state flags, may be changed at any time */ /* general state flags, may be changed at any time */
enum LG_OverlayFlags flags; enum LG_OverlayFlags flags;
/* get the number of windows that will be rendered when `render` is called
*
*`interactive` is true if the application is currently in overlay interaction
* mode
*/
int (*getWindowCount)(void * udata, bool interactive);
/* perform the actual drawing/rendering /* perform the actual drawing/rendering
* *
* `interactive` is true if the application is currently in overlay interaction * `interactive` is true if the application is currently in overlay interaction
* mode. * mode.
* *
* The caller provides `windowRects` to be populated by the callee and is sized * `windowRects` is an array of window rects that were rendered using screen
* according to the return value of `getWindowCount`. Note, `windowRects` may * coordinates. Will be `NULL` if the information is not required.
* be NULL if the caller does not want this information. *
* `maxRects` is the length of `windowRects`, or 0 if `windowRects` is `NULL`
*
* returns the number of rects written to `windowRects`, or -1 if there is not
* enough room left.
*/ */
void (*render)(void * udata, bool interactive, struct Rect windowRects[]); int (*render)(void * udata, bool interactive, struct Rect * windowRects,
int maxRects);
/* TODO: add load/save settings capabillity */ /* TODO: add load/save settings capabillity */
}; };
@ -71,7 +69,6 @@ struct LG_OverlayOps
assert((x)->name ); \ assert((x)->name ); \
assert((x)->init ); \ assert((x)->init ); \
assert((x)->free ); \ assert((x)->free ); \
assert((x)->getWindowCount); \
assert((x)->render ); assert((x)->render );
#endif #endif

View File

@ -628,7 +628,6 @@ struct Overlay
{ {
const struct LG_OverlayOps * ops; const struct LG_OverlayOps * ops;
void * udata; void * udata;
int windowCount;
}; };
void app_registerOverlay(const struct LG_OverlayOps * ops, void * params) void app_registerOverlay(const struct LG_OverlayOps * ops, void * params)
@ -650,43 +649,40 @@ void app_registerOverlay(const struct LG_OverlayOps * ops, void * params)
int app_renderOverlay(struct Rect * rects, int maxRects) int app_renderOverlay(struct Rect * rects, int maxRects)
{ {
int windowCount = 0; int totalRects = 0;
bool totalDamage = false;
struct Overlay * overlay; struct Overlay * overlay;
// get the total window count igNewFrame();
for (ll_reset(g_state.overlays);
ll_walk(g_state.overlays, (void **)&overlay); )
{
overlay->windowCount = overlay->ops->getWindowCount(overlay->udata, false);
windowCount += overlay->windowCount;
}
// return -1 if there are no windows to render
if (windowCount == 0)
return -1;
if (windowCount > maxRects)
{
rects = NULL;
windowCount = 0;
}
// render the overlays // render the overlays
igNewFrame();
for (ll_reset(g_state.overlays); for (ll_reset(g_state.overlays);
ll_walk(g_state.overlays, (void **)&overlay); ) ll_walk(g_state.overlays, (void **)&overlay); )
{ {
if (overlay->windowCount == 0) const int written =
overlay->ops->render(overlay->udata, false, rects, maxRects);
if (!totalDamage)
continue; continue;
overlay->ops->render(overlay->udata, false, rects); if (written == -1)
if (rects) {
rects += overlay->windowCount; // out of rects, return that the entire surface is damaged
totalDamage = true;
rects = NULL;
maxRects = 0;
totalRects = 0;
}
else
{
maxRects -= written;
rects += written;
}
} }
igRender(); igRender();
return windowCount; return totalDamage ? -1 : totalRects;
} }
void app_freeOverlays(void) void app_freeOverlays(void)

View File

@ -32,14 +32,13 @@ static void fps_free(void * udata)
{ {
} }
static int fps_getWindowCount(void * udata, bool interactive) static int fps_render(void * udata, bool interactive, struct Rect * windowRects,
int maxRects)
{ {
return g_state.showFPS ? 1 : 0; if (!g_state.showFPS)
} return 0;
static void fps_render(void * udata, bool interactive, struct Rect * windowRects) ImVec2 pos = {0.0f, 0.0f};
{
const ImVec2 pos = {0.0f, 0.0f};
igSetNextWindowBgAlpha(0.6f); igSetNextWindowBgAlpha(0.6f);
igSetNextWindowPos(pos, 0, pos); igSetNextWindowPos(pos, 0, pos);
@ -55,18 +54,21 @@ static void fps_render(void * udata, bool interactive, struct Rect * windowRects
atomic_load_explicit(&g_state.fps, memory_order_relaxed), atomic_load_explicit(&g_state.fps, memory_order_relaxed),
atomic_load_explicit(&g_state.ups, memory_order_relaxed)); atomic_load_explicit(&g_state.ups, memory_order_relaxed));
if (windowRects) if (maxRects == 0)
{ {
ImVec2 pos, size; return -1;
igGetWindowPos(&pos); igEnd();
igGetWindowSize(&size);
windowRects[0].x = pos.x;
windowRects[0].y = pos.y;
windowRects[0].w = size.x;
windowRects[0].h = size.y;
} }
ImVec2 size;
igGetWindowPos(&pos);
igGetWindowSize(&size);
windowRects[0].x = pos.x;
windowRects[0].y = pos.y;
windowRects[0].w = size.x;
windowRects[0].h = size.y;
igEnd(); igEnd();
return 1;
} }
struct LG_OverlayOps LGOverlayFPS = struct LG_OverlayOps LGOverlayFPS =
@ -74,6 +76,5 @@ struct LG_OverlayOps LGOverlayFPS =
.name = "FPS", .name = "FPS",
.init = fps_init, .init = fps_init,
.free = fps_free, .free = fps_free,
.getWindowCount = fps_getWindowCount,
.render = fps_render .render = fps_render
}; };

View File

@ -54,11 +54,6 @@ static void graphs_free(void * udata)
ll_free(gs.graphs); ll_free(gs.graphs);
} }
static int graphs_getWindowCount(void * udata, bool interactive)
{
return g_state.showTiming ? 1 : 0;
}
struct BufferMetrics struct BufferMetrics
{ {
float min; float min;
@ -91,9 +86,13 @@ static bool rbCalcMetrics(int index, void * value_, void * udata_)
return true; return true;
} }
static void graphs_render(void * udata, bool interactive, struct Rect * windowRects) static int graphs_render(void * udata, bool interactive,
struct Rect * windowRects, int maxRects)
{ {
const ImVec2 pos = {0.0f, 0.0f}; if (!g_state.showTiming)
return 0;
ImVec2 pos = {0.0f, 0.0f};
igSetNextWindowBgAlpha(0.4f); igSetNextWindowBgAlpha(0.4f);
igSetNextWindowPos(pos, 0, pos); igSetNextWindowPos(pos, 0, pos);
@ -139,18 +138,22 @@ static void graphs_render(void * udata, bool interactive, struct Rect * windowRe
sizeof(float)); sizeof(float));
}; };
if (windowRects) if (maxRects == 0)
{ {
ImVec2 pos, size; igEnd();
igGetWindowPos(&pos); return -1;
igGetWindowSize(&size);
windowRects[0].x = pos.x;
windowRects[0].y = pos.y;
windowRects[0].w = size.x;
windowRects[0].h = size.y;
} }
ImVec2 size;
igGetWindowPos(&pos);
igGetWindowSize(&size);
windowRects[0].x = pos.x;
windowRects[0].y = pos.y;
windowRects[0].w = size.x;
windowRects[0].h = size.y;
igEnd(); igEnd();
return 1;
} }
struct LG_OverlayOps LGOverlayGraphs = struct LG_OverlayOps LGOverlayGraphs =
@ -158,7 +161,6 @@ struct LG_OverlayOps LGOverlayGraphs =
.name = "Graphs", .name = "Graphs",
.init = graphs_init, .init = graphs_init,
.free = graphs_free, .free = graphs_free,
.getWindowCount = graphs_getWindowCount,
.render = graphs_render .render = graphs_render
}; };