diff --git a/src/citra/citra.cpp b/src/citra/citra.cpp index 294ba7b88..debc54b1c 100644 --- a/src/citra/citra.cpp +++ b/src/citra/citra.cpp @@ -35,6 +35,7 @@ #include "core/file_sys/cia_container.h" #include "core/frontend/applets/default_applets.h" #include "core/frontend/framebuffer_layout.h" +#include "core/frontend/scope_acquire_context.h" #include "core/gdbstub/gdbstub.h" #include "core/hle/service/am/am.h" #include "core/hle/service/cfg/cfg.h" @@ -347,7 +348,7 @@ int main(int argc, char** argv) { Core::System::GetInstance().RegisterImageInterface(std::make_shared()); std::unique_ptr emu_window{std::make_unique(fullscreen)}; - + Frontend::ScopeAcquireContext scope(*emu_window); Core::System& system{Core::System::GetInstance()}; const Core::System::ResultStatus load_result{system.Load(*emu_window, filepath)}; @@ -411,9 +412,11 @@ int main(int argc, char** argv) { system.VideoDumper().StartDumping(dump_video, "webm", layout); } + std::thread render_thread([&emu_window] { emu_window->Present(); }); while (emu_window->IsOpen()) { system.RunLoop(); } + render_thread.join(); Core::Movie::GetInstance().Shutdown(); if (system.VideoDumper().IsDumping()) { diff --git a/src/citra/emu_window/emu_window_sdl2.cpp b/src/citra/emu_window/emu_window_sdl2.cpp index 34d3d2fdb..851303987 100644 --- a/src/citra/emu_window/emu_window_sdl2.cpp +++ b/src/citra/emu_window/emu_window_sdl2.cpp @@ -20,6 +20,28 @@ #include "input_common/motion_emu.h" #include "input_common/sdl/sdl.h" #include "network/network.h" +#include "video_core/renderer_base.h" +#include "video_core/video_core.h" + +SharedContext_SDL2::SharedContext_SDL2() { + window = SDL_CreateWindow(NULL, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 0, 0, + SDL_WINDOW_HIDDEN | SDL_WINDOW_OPENGL); + context = SDL_GL_CreateContext(window); +} + +SharedContext_SDL2::~SharedContext_SDL2() { + DoneCurrent(); + SDL_GL_DeleteContext(context); + SDL_DestroyWindow(window); +} + +void SharedContext_SDL2::MakeCurrent() { + SDL_GL_MakeCurrent(window, context); +} + +void SharedContext_SDL2::DoneCurrent() { + SDL_GL_MakeCurrent(window, nullptr); +} void EmuWindow_SDL2::OnMouseMotion(s32 x, s32 y) { TouchMoved((unsigned)std::max(x, 0), (unsigned)std::max(y, 0)); @@ -135,6 +157,10 @@ EmuWindow_SDL2::EmuWindow_SDL2(bool fullscreen) { SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 0); + // Enable context sharing for the shared context + SDL_GL_SetAttribute(SDL_GL_SHARE_WITH_CURRENT_CONTEXT, 1); + // Enable vsync + SDL_GL_SetSwapInterval(1); std::string window_title = fmt::format("Citra {} | {}-{}", Common::g_build_fullname, Common::g_scm_branch, Common::g_scm_desc); @@ -150,16 +176,24 @@ EmuWindow_SDL2::EmuWindow_SDL2(bool fullscreen) { exit(1); } + dummy_window = SDL_CreateWindow(NULL, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 0, 0, + SDL_WINDOW_HIDDEN | SDL_WINDOW_OPENGL); + if (fullscreen) { Fullscreen(); } - gl_context = SDL_GL_CreateContext(render_window); + window_context = SDL_GL_CreateContext(render_window); + core_context = CreateSharedContext(); - if (gl_context == nullptr) { + if (window_context == nullptr) { LOG_CRITICAL(Frontend, "Failed to create SDL2 GL context: {}", SDL_GetError()); exit(1); } + if (core_context == nullptr) { + LOG_CRITICAL(Frontend, "Failed to create shared SDL2 GL context: {}", SDL_GetError()); + exit(1); + } auto gl_load_func = Settings::values.use_gles ? gladLoadGLES2Loader : gladLoadGLLoader; @@ -171,23 +205,30 @@ EmuWindow_SDL2::EmuWindow_SDL2(bool fullscreen) { OnResize(); OnMinimalClientAreaChangeRequest(GetActiveConfig().min_client_area_size); SDL_PumpEvents(); - SDL_GL_SetSwapInterval(Settings::values.vsync_enabled); LOG_INFO(Frontend, "Citra Version: {} | {}-{}", Common::g_build_fullname, Common::g_scm_branch, Common::g_scm_desc); Settings::LogSettings(); - - DoneCurrent(); } EmuWindow_SDL2::~EmuWindow_SDL2() { Network::Shutdown(); InputCommon::Shutdown(); - SDL_GL_DeleteContext(gl_context); + SDL_GL_DeleteContext(window_context); SDL_Quit(); } -void EmuWindow_SDL2::SwapBuffers() { - SDL_GL_SwapWindow(render_window); +std::unique_ptr EmuWindow_SDL2::CreateSharedContext() const { + return std::make_unique(); +} + +void EmuWindow_SDL2::Present() { + SDL_GL_MakeCurrent(render_window, window_context); + SDL_GL_SetSwapInterval(1); + while (IsOpen()) { + VideoCore::g_renderer->Present(); + SDL_GL_SwapWindow(render_window); + } + SDL_GL_MakeCurrent(render_window, nullptr); } void EmuWindow_SDL2::PollEvents() { @@ -256,11 +297,11 @@ void EmuWindow_SDL2::PollEvents() { } void EmuWindow_SDL2::MakeCurrent() { - SDL_GL_MakeCurrent(render_window, gl_context); + core_context->MakeCurrent(); } void EmuWindow_SDL2::DoneCurrent() { - SDL_GL_MakeCurrent(render_window, nullptr); + core_context->DoneCurrent(); } void EmuWindow_SDL2::OnMinimalClientAreaChangeRequest(std::pair minimal_size) { diff --git a/src/citra/emu_window/emu_window_sdl2.h b/src/citra/emu_window/emu_window_sdl2.h index 3462c5bd9..b0834fd06 100644 --- a/src/citra/emu_window/emu_window_sdl2.h +++ b/src/citra/emu_window/emu_window_sdl2.h @@ -10,13 +10,29 @@ struct SDL_Window; +class SharedContext_SDL2 : public Frontend::GraphicsContext { +public: + using SDL_GLContext = void*; + + SharedContext_SDL2(); + + ~SharedContext_SDL2() override; + + void MakeCurrent() override; + + void DoneCurrent() override; + +private: + SDL_GLContext context; + SDL_Window* window; +}; + class EmuWindow_SDL2 : public Frontend::EmuWindow { public: explicit EmuWindow_SDL2(bool fullscreen); ~EmuWindow_SDL2(); - /// Swap buffers to display the next frame - void SwapBuffers() override; + void Present(); /// Polls window events void PollEvents() override; @@ -30,6 +46,9 @@ public: /// Whether the window is still open, and a close request hasn't yet been sent bool IsOpen() const; + /// Creates a new context that is shared with the current context + std::unique_ptr CreateSharedContext() const override; + private: /// Called by PollEvents when a key is pressed or released. void OnKeyEvent(int key, u8 state); @@ -67,9 +86,16 @@ private: /// Internal SDL2 render window SDL_Window* render_window; + /// Fake hidden window for the core context + SDL_Window* dummy_window; + using SDL_GLContext = void*; + /// The OpenGL context associated with the window - SDL_GLContext gl_context; + SDL_GLContext window_context; + + /// The OpenGL context associated with the core + std::unique_ptr core_context; /// Keeps track of how often to update the title bar during gameplay u32 last_time = 0;