[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
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);
void app_freeOverlays(void);
struct OverlayGraph;

View File

@ -46,23 +46,21 @@ struct LG_OverlayOps
/* general state flags, may be changed at any time */
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
*
* `interactive` is true if the application is currently in overlay interaction
* mode.
*
* The caller provides `windowRects` to be populated by the callee and is sized
* according to the return value of `getWindowCount`. Note, `windowRects` may
* be NULL if the caller does not want this information.
* `windowRects` is an array of window rects that were rendered using screen
* coordinates. Will be `NULL` if the information is not required.
*
* `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 */
};
@ -71,7 +69,6 @@ struct LG_OverlayOps
assert((x)->name ); \
assert((x)->init ); \
assert((x)->free ); \
assert((x)->getWindowCount); \
assert((x)->render );
#endif

View File

@ -628,7 +628,6 @@ struct Overlay
{
const struct LG_OverlayOps * ops;
void * udata;
int windowCount;
};
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 windowCount = 0;
int totalRects = 0;
bool totalDamage = false;
struct Overlay * overlay;
// get the total window count
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;
}
igNewFrame();
// render the overlays
igNewFrame();
for (ll_reset(g_state.overlays);
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;
overlay->ops->render(overlay->udata, false, rects);
if (rects)
rects += overlay->windowCount;
if (written == -1)
{
// out of rects, return that the entire surface is damaged
totalDamage = true;
rects = NULL;
maxRects = 0;
totalRects = 0;
}
else
{
maxRects -= written;
rects += written;
}
}
igRender();
return windowCount;
return totalDamage ? -1 : totalRects;
}
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)
{
const ImVec2 pos = {0.0f, 0.0f};
ImVec2 pos = {0.0f, 0.0f};
igSetNextWindowBgAlpha(0.6f);
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.ups, memory_order_relaxed));
if (windowRects)
if (maxRects == 0)
{
ImVec2 pos, size;
return -1;
igEnd();
}
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();
return 1;
}
struct LG_OverlayOps LGOverlayFPS =
@ -74,6 +76,5 @@ struct LG_OverlayOps LGOverlayFPS =
.name = "FPS",
.init = fps_init,
.free = fps_free,
.getWindowCount = fps_getWindowCount,
.render = fps_render
};

View File

@ -54,11 +54,6 @@ static void graphs_free(void * udata)
ll_free(gs.graphs);
}
static int graphs_getWindowCount(void * udata, bool interactive)
{
return g_state.showTiming ? 1 : 0;
}
struct BufferMetrics
{
float min;
@ -91,9 +86,13 @@ static bool rbCalcMetrics(int index, void * value_, void * udata_)
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);
igSetNextWindowPos(pos, 0, pos);
@ -139,18 +138,22 @@ static void graphs_render(void * udata, bool interactive, struct Rect * windowRe
sizeof(float));
};
if (windowRects)
if (maxRects == 0)
{
ImVec2 pos, size;
igEnd();
return -1;
}
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();
return 1;
}
struct LG_OverlayOps LGOverlayGraphs =
@ -158,7 +161,6 @@ struct LG_OverlayOps LGOverlayGraphs =
.name = "Graphs",
.init = graphs_init,
.free = graphs_free,
.getWindowCount = graphs_getWindowCount,
.render = graphs_render
};