diff --git a/src/frontend/EmuThread.cpp b/src/frontend/EmuThread.cpp index 0a83ce7..7d54327 100644 --- a/src/frontend/EmuThread.cpp +++ b/src/frontend/EmuThread.cpp @@ -1,52 +1,55 @@ #include #include #include +#include +#include + +using namespace std::chrono_literals; EmuThread::EmuThread(double &fps, SettingsWindow &settings) noexcept : settings(settings), fps(fps) {} -void EmuThread::run() const noexcept { +void EmuThread::run() noexcept { n64::Core& core = n64::Core::GetInstance(); - if(!core.romLoaded) return; - - auto lastSample = std::chrono::high_resolution_clock::now(); - auto avgFps = 16.667; - auto sampledFps = 0; - static bool oneSecondPassed = false; + rdramCopy = core.GetMem().GetRDRAM(); - fps = 1000.0 / avgFps; - - const auto startFrameTime = std::chrono::high_resolution_clock::now(); - if (!core.pause) { - core.Run(settings.getVolumeL(), settings.getVolumeR()); - } - - const auto endFrameTime = std::chrono::high_resolution_clock::now(); - using namespace std::chrono_literals; - const auto frameTimeMs = std::chrono::duration(endFrameTime - startFrameTime) / 1ms; - avgFps += frameTimeMs; - - sampledFps++; - - if (const auto elapsedSinceLastSample = std::chrono::duration(endFrameTime - lastSample) / 1s; - elapsedSinceLastSample >= 1.0) { - if (!oneSecondPassed) { - oneSecondPassed = true; - return; + while(!shouldExit) { + if(!core.romLoaded) { + std::this_thread::sleep_for(1ms); + continue; } - avgFps /= sampledFps; - fps = 1000.0 / avgFps; + + if(core.pause) { + std::this_thread::sleep_for(1ms); + continue; + } + + core.Run(settings.getVolumeL(), settings.getVolumeR()); + { + std::lock_guard lk(presentMutex); + memcpy(rdramCopy.data(), core.GetMem().GetRDRAMPtr(), RDRAM_SIZE); + } + readyForPresentation.notify_all(); } } +void EmuThread::create() noexcept { + shouldExit.store(false, std::memory_order_release); + std::thread worker(&EmuThread::run, this); + worker.detach(); +} + void EmuThread::TogglePause() const noexcept { n64::Core::GetInstance().TogglePause(); } -void EmuThread::Reset() const noexcept { - n64::Core::GetInstance().Reset(); +void EmuThread::Reset() noexcept { + n64::Core& core = n64::Core::GetInstance(); + core.Reset(); + rdramCopy = core.GetMem().GetRDRAM(); } -void EmuThread::Stop() const noexcept { +void EmuThread::Stop() noexcept { + shouldExit.store(true, std::memory_order_release); n64::Core& core = n64::Core::GetInstance(); core.Stop(); core.rom = {}; diff --git a/src/frontend/EmuThread.hpp b/src/frontend/EmuThread.hpp index 6172867..23478f5 100644 --- a/src/frontend/EmuThread.hpp +++ b/src/frontend/EmuThread.hpp @@ -2,6 +2,7 @@ #include #include #include +#include namespace n64 { struct Core; @@ -12,12 +13,17 @@ class EmuThread final { public: explicit EmuThread(double &, SettingsWindow &) noexcept; ~EmuThread() = default; - void run() const noexcept; + void create() noexcept; + void run() noexcept; void TogglePause() const noexcept; - void Reset() const noexcept; - void Stop() const noexcept; + void Reset() noexcept; + void Stop() noexcept; bool interruptionRequested = false, parallelRDPInitialized = false; SettingsWindow &settings; double& fps; + std::atomic_bool shouldExit = false; + std::mutex presentMutex; + std::condition_variable readyForPresentation; + std::vector rdramCopy; }; diff --git a/src/frontend/KaizenGui.cpp b/src/frontend/KaizenGui.cpp index dd4f4d8..fc0dd20 100644 --- a/src/frontend/KaizenGui.cpp +++ b/src/frontend/KaizenGui.cpp @@ -4,8 +4,11 @@ #include #include #include +#include -KaizenGui::KaizenGui() noexcept : window("Kaizen " KAIZEN_VERSION_STR, 1280, 720), settingsWindow(window), vulkanWidget(window.getHandle()), emuThread(fpsCounter, settingsWindow) { +using namespace std::chrono_literals; + +KaizenGui::KaizenGui() noexcept : window("Kaizen " KAIZEN_VERSION_STR, 1280, 720), settingsWindow(window), emuThread(fpsCounter, settingsWindow), vulkanWidget(window.getHandle(), emuThread.rdramCopy.data()) { gui::Initialize(n64::Core::GetInstance().parallel.wsi, window.getHandle()); SDL_InitSubSystem(SDL_INIT_GAMEPAD); @@ -412,16 +415,21 @@ void KaizenGui::RenderUI() { return; if(core.romLoaded) { - core.parallel.UpdateScreen(); + std::unique_lock lk(emuThread.presentMutex); + if(emuThread.readyForPresentation.wait_for(lk, 16.6667ms) == std::cv_status::no_timeout) + core.parallel.UpdateScreen(); + else + core.parallel.UpdateScreen(); return; } - + core.parallel.UpdateScreen(); } void KaizenGui::LoadROM(const std::string &path) noexcept { n64::Core& core = n64::Core::GetInstance(); core.LoadROM(path); + emuThread.create(); const auto gameNameDB = n64::Core::GetMem().rom.gameNameDB; SDL_SetWindowTitle(window.getHandle(), ("Kaizen " KAIZEN_VERSION_STR " - " + gameNameDB).c_str()); } @@ -449,8 +457,6 @@ void KaizenGui::run() { } SDL_GetWindowSize(window.getHandle(), &width, &height); - - emuThread.run(); RenderUI(); } } diff --git a/src/frontend/KaizenGui.hpp b/src/frontend/KaizenGui.hpp index d55a78d..88b1354 100644 --- a/src/frontend/KaizenGui.hpp +++ b/src/frontend/KaizenGui.hpp @@ -17,8 +17,8 @@ public: bool minimized = false; SettingsWindow settingsWindow; - RenderWidget vulkanWidget; EmuThread emuThread; + RenderWidget vulkanWidget; Debugger debugger; SDL_Gamepad* gamepad = nullptr; diff --git a/src/frontend/RenderWidget.cpp b/src/frontend/RenderWidget.cpp index c3a88df..585a2f6 100644 --- a/src/frontend/RenderWidget.cpp +++ b/src/frontend/RenderWidget.cpp @@ -4,9 +4,9 @@ #include #include -RenderWidget::RenderWidget(SDL_Window* window) { +RenderWidget::RenderWidget(SDL_Window* window, u8* rdram) { wsiPlatform = std::make_shared(window); windowInfo = std::make_shared(window); n64::Core& core = n64::Core::GetInstance(); - core.parallel.Init(wsiPlatform, windowInfo, core.GetMem().GetRDRAMPtr()); + core.parallel.Init(wsiPlatform, windowInfo, rdram); } \ No newline at end of file diff --git a/src/frontend/RenderWidget.hpp b/src/frontend/RenderWidget.hpp index af3ff6a..e4ba0be 100644 --- a/src/frontend/RenderWidget.hpp +++ b/src/frontend/RenderWidget.hpp @@ -72,7 +72,7 @@ private: class RenderWidget final { public: - explicit RenderWidget(SDL_Window*); + explicit RenderWidget(SDL_Window*, u8* rdram); std::shared_ptr windowInfo; std::shared_ptr wsiPlatform;