Files
psxrecomp/runtime/include/host_overlay.h
T
Shokunin facdf01ac6 Overlay draw callback: unregister waits for in-flight draws (lifetime contract)
Review (#599): who keeps the callback context alive until render-thread
calls are quiescent. Draw calls now run inside an in-flight count, and
set_draw_cb (replace or NULL) swaps the record and waits until no call
that read the old one is running, then frees it. When it returns, the
registrant may free ctx and its GL objects; it must unregister before
destroying them or the context. A change from inside the callback does
not wait. Documented in host_overlay.h. Tests: a reader thread drawing
while the owner unregisters and frees (300 rounds; fails without the
wait), and self-unregister from the callback.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 14:33:29 -07:00

51 lines
2.4 KiB
C

/* host_overlay.h -- hooks for an optional in-game menu ("overlay provider").
*
* Every hook is inert until something registers with it: a title with no
* overlay provider runs exactly as before. Sections are added by the
* docs/IN_GAME_OVERLAY.md PR stack (P1 pause, P2 draw, P3 input, ...).
*/
#ifndef PSX_HOST_OVERLAY_H
#define PSX_HOST_OVERLAY_H
#ifdef __cplusplus
extern "C" {
#endif
/* ---- P1: host pause --------------------------------------------------------
* A nesting pause owned by the host (not the guest): while depth > 0 the
* runtime holds the guest at the vblank present, keeps presenting the last
* frame and pauses audio. Push refuses (returns 0) while the refusal probe
* says so -- the runtime installs psx_netplay_active() there, because pausing
* one peer would stall the session. Main thread only. */
typedef int (*PsxHostPauseRefuseFn)(void);
int psx_host_pause_push(const char *reason);
void psx_host_pause_pop(void);
int psx_host_pause_depth(void);
const char *psx_host_pause_reason(void);
void psx_host_pause_set_refuse_probe(PsxHostPauseRefuseFn fn);
/* ---- P2: overlay draw callback ---------------------------------------------
* Called once per presented frame by the OpenGL backend after the game image
* and the host OSD layers are composed, before present_shot capture and the
* swap, with the drawable size in pixels. It runs on the thread that owns the
* GL context (the render thread when it is on, else the main thread), with the
* window framebuffer bound. The callback must leave GL state as it found it.
* Vulkan and the SDL renderer never call it. NULL unregisters.
*
* Lifetime contract: the registrant owns ctx. psx_host_overlay_set_draw_cb
* (replace or NULL) returns only after any draw call that may still be using
* the previous fn/ctx has finished, so the registrant may free ctx and the GL
* objects it draws with right after it returns, and must keep them alive
* until then. Unregister before destroying those objects or the GL context
* (e.g. on renderer shutdown). Called from inside the callback it does not
* wait; the current call is then the last one with the old ctx. */
typedef void (*PsxHostOverlayDrawFn)(int width, int height, void *ctx);
void psx_host_overlay_set_draw_cb(PsxHostOverlayDrawFn fn, void *ctx);
int psx_host_overlay_has_draw(void);
void psx_host_overlay_draw(int width, int height); /* renderer side */
#ifdef __cplusplus
}
#endif
#endif