From 2acc5250f8365a7a4171e00247b7252dbaf7c1d8 Mon Sep 17 00:00:00 2001 From: Ziemas Date: Sun, 14 Aug 2022 23:21:02 +0200 Subject: [PATCH] Run IOP Vblank handler on the IOP thread (#1752) --- game/graphics/gfx.cpp | 13 +++++++++++++ game/graphics/gfx.h | 2 ++ game/graphics/sceGraphicsInterface.cpp | 2 -- game/overlord/overlord.cpp | 2 +- game/overlord/srpc.cpp | 2 +- game/overlord/srpc.h | 2 +- game/runtime.cpp | 3 +++ game/sce/iop.cpp | 7 +++++++ game/sce/iop.h | 2 ++ game/system/IOP_Kernel.cpp | 8 ++++++++ game/system/IOP_Kernel.h | 10 ++++++++++ 11 files changed, 48 insertions(+), 5 deletions(-) diff --git a/game/graphics/gfx.cpp b/game/graphics/gfx.cpp index 597c570e6..b98beec43 100644 --- a/game/graphics/gfx.cpp +++ b/game/graphics/gfx.cpp @@ -7,6 +7,7 @@ #include #include +#include #include "display.h" @@ -49,6 +50,7 @@ void InitSettings(GfxSettings& settings) { namespace Gfx { +std::function vsync_callback; GfxGlobalSettings g_global_settings; GfxSettings g_settings; // const std::vector renderers = {&moduleOpenGL}; @@ -149,8 +151,19 @@ u32 Exit() { return 0; } +void register_vsync_callback(std::function f) { + vsync_callback = std::move(f); +} + +void clear_vsync_callback() { + vsync_callback = nullptr; +} + u32 vsync() { if (GetCurrentRenderer()) { + // Inform the IOP kernel that we're vsyncing so it can run the vblank handler + if (vsync_callback != nullptr) + vsync_callback(); return GetCurrentRenderer()->vsync(); } return 0; diff --git a/game/graphics/gfx.h b/game/graphics/gfx.h index aaf0945b0..941ac790f 100644 --- a/game/graphics/gfx.h +++ b/game/graphics/gfx.h @@ -125,6 +125,8 @@ void Loop(std::function f); u32 Exit(); u32 vsync(); +void register_vsync_callback(std::function f); +void clear_vsync_callback(); u32 sync_path(); void send_chain(const void* data, u32 offset); void texture_upload_now(const u8* tpage, int mode, u32 s7_ptr); diff --git a/game/graphics/sceGraphicsInterface.cpp b/game/graphics/sceGraphicsInterface.cpp index 641b76d23..a3cf8e325 100644 --- a/game/graphics/sceGraphicsInterface.cpp +++ b/game/graphics/sceGraphicsInterface.cpp @@ -5,7 +5,6 @@ #include "common/util/Assert.h" #include "game/graphics/gfx.h" -#include "game/overlord/srpc.h" /*! * Wait for rendering to complete. @@ -32,6 +31,5 @@ u32 sceGsSyncPath(u32 mode, u32 timeout) { */ u32 sceGsSyncV(u32 mode) { ASSERT(mode == 0); - VBlank_Handler(); return Gfx::vsync(); } diff --git a/game/overlord/overlord.cpp b/game/overlord/overlord.cpp index 7e22ae818..03ec3811e 100644 --- a/game/overlord/overlord.cpp +++ b/game/overlord/overlord.cpp @@ -39,7 +39,7 @@ int start_overlord(int argc, const char* const* argv) { InitSound_Overlord(); } InitRamdisk(); - // RegisterVblankHandler(0, 0x20, VBlank_Handler, nullptr); + RegisterVblankHandler(0, 0x20, VBlank_Handler, nullptr); ThreadParam thread_param; thread_param.attr = TH_C; diff --git a/game/overlord/srpc.cpp b/game/overlord/srpc.cpp index 99979b8a8..a07737d67 100644 --- a/game/overlord/srpc.cpp +++ b/game/overlord/srpc.cpp @@ -440,7 +440,7 @@ void* RPC_Loader(unsigned int /*fno*/, void* data, int size) { static s32 dmaid = 0; -s32 VBlank_Handler() { +s32 VBlank_Handler(void*) { if (!gSoundEnable) return 1; diff --git a/game/overlord/srpc.h b/game/overlord/srpc.h index f8fb8aac4..005b9f2c7 100644 --- a/game/overlord/srpc.h +++ b/game/overlord/srpc.h @@ -170,7 +170,7 @@ extern s32 gMusicTweak; u32 Thread_Loader(); u32 Thread_Player(); -s32 VBlank_Handler(); +s32 VBlank_Handler(void*); // added for PC port extern u32 gMusicFadeHack; diff --git a/game/runtime.cpp b/game/runtime.cpp index 9b51461b5..96061b522 100644 --- a/game/runtime.cpp +++ b/game/runtime.cpp @@ -209,6 +209,7 @@ void iop_runner(SystemThreadInterface& iface) { iop.reset_allocator(); ee::LIBRARY_sceSif_register(&iop); iop::LIBRARY_register(&iop); + Gfx::register_vsync_callback([&iop]() { iop.kernel.signal_vblank(); }); // todo! dma_init_globals(); @@ -256,6 +257,8 @@ void iop_runner(SystemThreadInterface& iface) { // So we can wait for that long or until something else needs it to wake up. iop.wait_run_iop(iop.kernel.dispatch()); } + + Gfx::clear_vsync_callback(); } } // namespace diff --git a/game/sce/iop.cpp b/game/sce/iop.cpp index d4bfe558f..3b9d9fe46 100644 --- a/game/sce/iop.cpp +++ b/game/sce/iop.cpp @@ -225,4 +225,11 @@ s32 WakeupThread(s32 thid) { iop->kernel.WakeupThread(thid); return 0; } + +s32 RegisterVblankHandler(int edge, int priority, int (*handler)(void*), void* userdata) { + (void)edge; + (void)priority; + return iop->kernel.RegisterVblankHandler(handler); +} + } // namespace iop diff --git a/game/sce/iop.h b/game/sce/iop.h index a3cda1823..708920c9b 100644 --- a/game/sce/iop.h +++ b/game/sce/iop.h @@ -138,6 +138,8 @@ s32 WaitSema(s32 sema); s32 SignalSema(s32 sema); s32 PollSema(s32 sema); +s32 RegisterVblankHandler(int edge, int priority, int (*handler)(void*), void* userdata); + void FlushDcache(); u32 sceSifCheckInit(); diff --git a/game/system/IOP_Kernel.cpp b/game/system/IOP_Kernel.cpp index db638dc21..dff282645 100644 --- a/game/system/IOP_Kernel.cpp +++ b/game/system/IOP_Kernel.cpp @@ -243,9 +243,17 @@ void IOP_Kernel::processWakeups() { * Run the next IOP thread. */ time_stamp IOP_Kernel::dispatch() { + // Check vblank interrupt + if (vblank_handler != nullptr && vblank_recieved) { + vblank_handler(nullptr); + vblank_recieved = false; + } + + // Update thread states updateDelay(); processWakeups(); + // Run until all threads are idle IopThread* next = schedNext(); while (next != nullptr) { // printf("[IOP Kernel] Dispatch %s (%d)\n", next->name.c_str(), next->thID); diff --git a/game/system/IOP_Kernel.h b/game/system/IOP_Kernel.h index f53b76edd..7d9db6864 100644 --- a/game/system/IOP_Kernel.h +++ b/game/system/IOP_Kernel.h @@ -173,6 +173,13 @@ class IOP_Kernel { s32 SignalSema(s32 id); s32 PollSema(s32 id); + s32 RegisterVblankHandler(int (*handler)(void*)) { + vblank_handler = handler; + return 0; + } + + void signal_vblank() { vblank_recieved = true; }; + void read_disc_sectors(u32 sector, u32 sectors, void* buffer); bool sif_busy(u32 id); @@ -193,6 +200,9 @@ class IOP_Kernel { IopThread* schedNext(); time_stamp nextWakeup(); + s32 (*vblank_handler)(void*); + std::atomic_bool vblank_recieved = false; + cothread_t kernel_thread; s32 _nextThID = 0; IopThread* _currentThread = nullptr;