Files
psxrecomp/runtime/src/host_overlay.c
T
Shokunin 8b003a591d Overlay draw callback: publish fn+ctx atomically; link it in GL fixtures
Review (#599): fn and ctx were two separate stores read on the render
thread, so an unregister could pair a live fn with a NULL ctx. They are now
one immutable record behind an acquire/release atomic pointer. The GL
fixture runners compile a fixed source list; gpu_gl_renderer.c now calls
psx_host_overlay_draw, so every run_gl_*.py links host_overlay.c.

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

66 lines
2.3 KiB
C

/* host_overlay.c -- see host_overlay.h. */
#include "host_overlay.h"
#include <stdatomic.h>
#include <stddef.h>
#include <stdlib.h>
/* ---- P1: host pause ------------------------------------------------------ */
#define PSX_HOST_PAUSE_MAX 8
static int s_pause_depth = 0;
static const char *s_pause_reason[PSX_HOST_PAUSE_MAX];
static PsxHostPauseRefuseFn s_pause_refuse = NULL;
int psx_host_pause_push(const char *reason) {
if (s_pause_refuse && s_pause_refuse()) return 0;
if (s_pause_depth >= PSX_HOST_PAUSE_MAX) return 0;
s_pause_reason[s_pause_depth++] = reason ? reason : "host";
return 1;
}
void psx_host_pause_pop(void) {
if (s_pause_depth > 0) s_pause_reason[--s_pause_depth] = NULL;
}
int psx_host_pause_depth(void) { return s_pause_depth; }
const char *psx_host_pause_reason(void) {
return s_pause_depth > 0 ? s_pause_reason[s_pause_depth - 1] : NULL;
}
void psx_host_pause_set_refuse_probe(PsxHostPauseRefuseFn fn) { s_pause_refuse = fn; }
/* ---- P2: overlay draw callback -------------------------------------------- */
/* Registered on the main thread, read on the render / present thread. The
* function and its context are published together as one immutable record
* behind an atomic pointer (release on store, acquire on load), so a reader
* can never pair a live function with a stale or NULL context. Records are
* never freed: registration happens a handful of times per process, and a
* reader may still hold the previous record when it is replaced. */
typedef struct {
PsxHostOverlayDrawFn fn;
void *ctx;
} PsxHostOverlayDraw;
static _Atomic(PsxHostOverlayDraw *) s_draw = NULL;
void psx_host_overlay_set_draw_cb(PsxHostOverlayDrawFn fn, void *ctx) {
PsxHostOverlayDraw *rec = NULL;
if (fn) {
rec = (PsxHostOverlayDraw *)malloc(sizeof(*rec));
if (!rec) return;
rec->fn = fn;
rec->ctx = ctx;
}
atomic_store_explicit(&s_draw, rec, memory_order_release);
}
int psx_host_overlay_has_draw(void) {
return atomic_load_explicit(&s_draw, memory_order_acquire) != NULL;
}
void psx_host_overlay_draw(int width, int height) {
const PsxHostOverlayDraw *rec = atomic_load_explicit(&s_draw, memory_order_acquire);
if (rec && rec->fn && width > 0 && height > 0) rec->fn(width, height, rec->ctx);
}