diff --git a/SDL/SDLMain.cpp b/SDL/SDLMain.cpp index acc5cc0e10..7770682204 100644 --- a/SDL/SDLMain.cpp +++ b/SDL/SDLMain.cpp @@ -14,9 +14,11 @@ SDLJoystick *joystick = NULL; #include #endif +#include #include #include #include +#include #include "base/display.h" #include "base/logging.h" @@ -32,6 +34,7 @@ SDLJoystick *joystick = NULL; #include "util/text/utf8.h" #include "util/text/parsers.h" #include "math/math_util.h" +#include "thin3d/GLRenderManager.h" #include "Common/Vulkan/VulkanContext.h" #include "Common/Vulkan/VulkanDebug.h" #include "math.h" @@ -198,6 +201,8 @@ void EGL_Close() { } #endif +class GLRenderManager; + class SDLGLGraphicsContext : public DummyGraphicsContext { public: SDLGLGraphicsContext() { @@ -218,21 +223,30 @@ public: } void SwapBuffers() override { -#ifdef USING_EGL - eglSwapBuffers(g_eglDisplay, g_eglSurface); -#else - SDL_GL_SwapWindow(window_); -#endif + renderManager_->Swap(); } Draw::DrawContext *GetDrawContext() override { return draw_; } + void ThreadStart() override { + renderManager_->ThreadStart(); + } + + bool ThreadFrame() override { + return renderManager_->ThreadFrame(); + } + + void ThreadEnd() override { + renderManager_->ThreadEnd(); + } + private: Draw::DrawContext *draw_ = nullptr; SDL_Window *window_; SDL_GLContext glContext = nullptr; + GLRenderManager *renderManager_ = nullptr; }; // Returns 0 on success. @@ -340,9 +354,17 @@ int SDLGLGraphicsContext::Init(SDL_Window *&window, int x, int y, int mode, std: // Finally we can do the regular initialization. CheckGLExtensions(); draw_ = Draw::T3DCreateGLContext(); + renderManager_ = (GLRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER); SetGPUBackend(GPUBackend::OPENGL); bool success = draw_->CreatePresets(); assert(success); + renderManager_->SetSwapFunction([&]() { +#ifdef USING_EGL + eglSwapBuffers(g_eglDisplay, g_eglSurface); +#else + SDL_GL_SwapWindow(window_); +#endif + }); window_ = window; return 0; } @@ -691,6 +713,38 @@ void ToggleFullScreenIfFlagSet(SDL_Window *window) { } } +enum class EmuThreadState { + DISABLED, + START_REQUESTED, + RUNNING, + QUIT_REQUESTED, + STOPPED, +}; + +static std::thread emuThread; +static std::atomic emuThreadState((int)EmuThreadState::DISABLED); + +static void EmuThreadFunc() { + // There's no real requirement that NativeInit happen on this thread. + // We just call the update/render loop here. + emuThreadState = (int)EmuThreadState::RUNNING; + while (emuThreadState != (int)EmuThreadState::QUIT_REQUESTED) { + UpdateRunLoop(); + } + emuThreadState = (int)EmuThreadState::STOPPED; +} + +static void EmuThreadStart() { + emuThreadState = (int)EmuThreadState::START_REQUESTED; + emuThread = std::thread(&EmuThreadFunc); +} + +static void EmuThreadStop() { + emuThreadState = (int)EmuThreadState::QUIT_REQUESTED; + emuThread.join(); + emuThread = std::thread(); +} + #ifdef _WIN32 #undef main #endif @@ -888,6 +942,11 @@ int main(int argc, char *argv[]) { } } + // Since we render from the main thread, there's nothing done here, but we call it to avoid confusion. + if (!graphicsContext->InitFromRenderThread(&error_message)) { + printf("Init from thread error: '%s'\n", error_message.c_str()); + } + SDL_SetWindowTitle(window, (app_name_nice + " " + PPSSPP_GIT_VERSION).c_str()); #ifdef MOBILE_DEVICE @@ -934,6 +993,9 @@ int main(int argc, char *argv[]) { int framecount = 0; bool mouseDown = false; + EmuThreadStart(); + graphicsContext->ThreadStart(); + while (true) { SDL_Event event; while (SDL_PollEvent(&event)) { @@ -1101,7 +1163,9 @@ int main(int argc, char *argv[]) { if (g_QuitRequested) break; const uint8_t *keys = SDL_GetKeyboardState(NULL); - UpdateRunLoop(); + if (emuThreadState == (int)EmuThreadState::DISABLED) { + UpdateRunLoop(); + } if (g_QuitRequested) break; #if !defined(MOBILE_DEVICE) @@ -1118,12 +1182,22 @@ int main(int argc, char *argv[]) { // glsl_refresh(); // auto-reloads modified GLSL shaders once per second. } + if (emuThreadState != (int)EmuThreadState::DISABLED) { + if (!graphicsContext->ThreadFrame()) + break; + } graphicsContext->SwapBuffers(); ToggleFullScreenIfFlagSet(window); time_update(); framecount++; } + + graphicsContext->ThreadEnd(); + graphicsContext->ShutdownFromRenderThread(); + + EmuThreadStop(); + delete joystick; NativeShutdownGraphics(); graphicsContext->Shutdown();