mirror of
https://github.com/RetroPortingToolKit/psxrecomp
synced 2026-10-25 18:05:12 -04:00
Drain and reset session HUD callbacks
This commit is contained in:
@@ -1396,6 +1396,7 @@ if(BUILD_TESTING)
|
||||
|
||||
add_executable(mod_runtime_test
|
||||
src/mod_immediate.c
|
||||
src/host_overlay.c
|
||||
tests/test_mod_runtime.cpp
|
||||
src/iso_reader_c.cpp
|
||||
src/host_span_ring.c
|
||||
|
||||
@@ -49,8 +49,10 @@ void psx_host_overlay_draw(int width, int height); /* renderer side */
|
||||
/* ---- Game HUD layer ---------------------------------------------------------
|
||||
* A title's own heads-up display, drawn once per presented frame (real and
|
||||
* generated) under the in-game menu, same thread and GL rules as the overlay
|
||||
* callback above. Set once (title activation) and kept for the session; NULL
|
||||
* unregisters (no wait: the registrant keeps fn and ctx alive for the session). */
|
||||
* callback above. OpenGL only; Vulkan and the SDL renderer never invoke it.
|
||||
* Replacing or NULL unregistering drains prior calls as for the overlay above;
|
||||
* the owner may then release its old context. Registration is session-scoped:
|
||||
* activation reset and GL shutdown clear it. Register again on activation. */
|
||||
void psx_host_set_hud_draw_cb(PsxHostOverlayDrawFn fn, void *ctx);
|
||||
void psx_host_hud_draw(int width, int height); /* renderer side */
|
||||
|
||||
|
||||
@@ -6550,6 +6550,7 @@ static void pass_resources_release(void);
|
||||
static void present_image_ring_gl_forget(void);
|
||||
void gl_renderer_shutdown(void) {
|
||||
gl_renderer_render_thread_stop(); /* drains; the context comes back to this thread */
|
||||
psx_host_set_hud_draw_cb(NULL, NULL);
|
||||
/* After the worker has stopped (it presents, and captures, on its own
|
||||
* thread) and before the context dies: forget the ring's GL names. */
|
||||
present_image_ring_gl_forget();
|
||||
|
||||
@@ -104,15 +104,47 @@ void psx_host_overlay_draw(int width, int height) {
|
||||
/* ---- Game HUD layer ------------------------------------------------------- */
|
||||
static PsxHostOverlayDrawFn s_hud_fn = NULL;
|
||||
static void *s_hud_ctx = NULL;
|
||||
static atomic_flag s_hud_lock = ATOMIC_FLAG_INIT;
|
||||
static atomic_int s_hud_inflight = 0;
|
||||
#if defined(_MSC_VER)
|
||||
static __declspec(thread) int s_in_hud = 0;
|
||||
#else
|
||||
static _Thread_local int s_in_hud = 0;
|
||||
#endif
|
||||
|
||||
static void hud_lock(void) {
|
||||
while (atomic_flag_test_and_set_explicit(&s_hud_lock, memory_order_acquire))
|
||||
draw_yield();
|
||||
}
|
||||
static void hud_unlock(void) {
|
||||
atomic_flag_clear_explicit(&s_hud_lock, memory_order_release);
|
||||
}
|
||||
|
||||
void psx_host_set_hud_draw_cb(PsxHostOverlayDrawFn fn, void *ctx) {
|
||||
hud_lock();
|
||||
s_hud_ctx = ctx;
|
||||
s_hud_fn = fn;
|
||||
hud_unlock();
|
||||
/* Match the overlay lifetime contract without allocating callback records.
|
||||
* The single GL owner may unregister itself; its current call then ends
|
||||
* before another frame can consume the replacement. */
|
||||
if (!s_in_hud)
|
||||
while (atomic_load(&s_hud_inflight) > 0) draw_yield();
|
||||
}
|
||||
|
||||
void psx_host_hud_draw(int width, int height) {
|
||||
if (width <= 0 || height <= 0) return;
|
||||
hud_lock();
|
||||
PsxHostOverlayDrawFn fn = s_hud_fn;
|
||||
if (fn && width > 0 && height > 0) fn(width, height, s_hud_ctx);
|
||||
void *ctx = s_hud_ctx;
|
||||
atomic_fetch_add(&s_hud_inflight, 1);
|
||||
hud_unlock();
|
||||
if (fn) {
|
||||
s_in_hud = 1;
|
||||
fn(width, height, ctx);
|
||||
s_in_hud = 0;
|
||||
}
|
||||
atomic_fetch_sub(&s_hud_inflight, 1);
|
||||
}
|
||||
|
||||
/* ---- P3: input sink -------------------------------------------------------- */
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "mod_runtime.h"
|
||||
#include "host_launch_timing.h"
|
||||
#include "host_overlay.h"
|
||||
#include "cpu_state.h"
|
||||
|
||||
#include "disc_path.h"
|
||||
@@ -2963,6 +2964,8 @@ bool mod_runtime_read_disc_file_sectors(const std::string& path, uint32_t max_by
|
||||
extern "C" void mod_runtime_activate_plugins(void) {
|
||||
using namespace PSXRecompV4;
|
||||
HostLaunchTimingScope timing(HOST_LAUNCH_PLUGIN_ACTIVATION);
|
||||
/* Drain session-owned presentation callbacks before their contexts reset. */
|
||||
psx_host_set_hud_draw_cb(nullptr, nullptr);
|
||||
mod_reset_plugin_sessions();
|
||||
RuntimeMods& s = state();
|
||||
s.ticket_ready = false;
|
||||
|
||||
@@ -75,6 +75,29 @@ static void* life_reader(void* arg) {
|
||||
while (!atomic_load(&g_stop)) psx_host_overlay_draw(64, 64);
|
||||
return NULL;
|
||||
}
|
||||
static void* hud_life_reader(void* arg) {
|
||||
(void)arg;
|
||||
while (!atomic_load(&g_stop)) psx_host_hud_draw(64, 64);
|
||||
return NULL;
|
||||
}
|
||||
static void test_hud_lifetime(void) {
|
||||
pthread_t t;
|
||||
atomic_store(&g_stop, 0);
|
||||
pthread_create(&t, NULL, hud_life_reader, NULL);
|
||||
for (int round = 0; round < 100; ++round) {
|
||||
LifeCtx* c = (LifeCtx*)calloc(1, sizeof(*c));
|
||||
atomic_store(&c->alive, 1);
|
||||
psx_host_set_hud_draw_cb(life_draw, c);
|
||||
while (atomic_load(&c->calls) < 2) {}
|
||||
/* Also models the activation-reset / renderer-shutdown clear. */
|
||||
psx_host_set_hud_draw_cb(NULL, NULL);
|
||||
atomic_store(&c->alive, 0);
|
||||
CHECK(atomic_load(&c->used_dead) == 0);
|
||||
free(c);
|
||||
}
|
||||
atomic_store(&g_stop, 1);
|
||||
pthread_join(t, NULL);
|
||||
}
|
||||
static void test_draw_lifetime(void) {
|
||||
pthread_t t;
|
||||
atomic_store(&g_stop, 0);
|
||||
@@ -99,6 +122,7 @@ static void test_draw_lifetime(void) {
|
||||
}
|
||||
#else
|
||||
static void test_draw_lifetime(void) {}
|
||||
static void test_hud_lifetime(void) {}
|
||||
#endif
|
||||
|
||||
/* Changing the callback from inside it must not deadlock. */
|
||||
@@ -114,6 +138,18 @@ static void test_draw_reentrant(void) {
|
||||
psx_host_overlay_draw(64, 64);
|
||||
CHECK(n == 1 && !psx_host_overlay_has_draw());
|
||||
}
|
||||
static void hud_self_unregister(int w, int h, void* p) {
|
||||
(void)w; (void)h;
|
||||
++*(int*)p;
|
||||
psx_host_set_hud_draw_cb(NULL, NULL);
|
||||
}
|
||||
static void test_hud_reentrant(void) {
|
||||
int calls = 0;
|
||||
psx_host_set_hud_draw_cb(hud_self_unregister, &calls);
|
||||
psx_host_hud_draw(64, 64);
|
||||
psx_host_hud_draw(64, 64);
|
||||
CHECK(calls == 1);
|
||||
}
|
||||
|
||||
static int sunk = 0;
|
||||
static int sink(const void *ev, void *ctx) { (void)ctx; sunk++; return *(const int *)ev == 1; }
|
||||
@@ -237,6 +273,8 @@ static void test_cmdline_quote(void) {
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
test_hud_lifetime();
|
||||
test_hud_reentrant();
|
||||
test_draw_lifetime();
|
||||
test_draw_reentrant();
|
||||
test_cmdline_quote();
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "mod_runtime.h"
|
||||
#include "mod_netplay.h"
|
||||
#include "host_launch_timing.h"
|
||||
#include "host_overlay.h"
|
||||
#include "host_file_identity.h"
|
||||
#include "mod_packages.h"
|
||||
#include "mod_plugins.h"
|
||||
@@ -107,6 +108,8 @@ extern "C" uint32_t psx_mod_gpu_dma_memory_alloc(uint32_t, uint32_t) {
|
||||
}
|
||||
extern "C" void psx_ram_reset_size_request(void) {}
|
||||
static int hd_shutdown_calls, hd_configure_calls, hd_dump_value;
|
||||
static int hud_calls;
|
||||
static void old_session_hud(int, int, void*) { ++hud_calls; }
|
||||
static int hd_replacements_value, hd_reload_calls;
|
||||
static std::string hd_root;
|
||||
extern "C" void gpu_hd_textures_shutdown(void) { ++hd_shutdown_calls; hd_root.clear(); }
|
||||
@@ -724,7 +727,10 @@ int main(int argc, char** argv) {
|
||||
psx_mod_function_entry(&entry_cpu, 0x80003000u);
|
||||
check(g_psx_mod_function_entry_hooks == 0 && active_entry_hits == 0,
|
||||
"function-entry hooks must not run before plugin activation");
|
||||
psx_host_set_hud_draw_cb(old_session_hud, nullptr);
|
||||
mod_runtime_activate_plugins();
|
||||
psx_host_hud_draw(64, 64);
|
||||
check(hud_calls == 0, "activation clears the prior session HUD before resetting plugins");
|
||||
check(activation_calls == 1,
|
||||
"resolved trusted plugin must activate before runtime startup");
|
||||
entry_cpu.pc = 0x80004000u;
|
||||
|
||||
Reference in New Issue
Block a user