From ff81fb04b40649febff6ed986c33d79a856868dc Mon Sep 17 00:00:00 2001
From: pawelniegowski <pniegowski@rs-game.net>
Date: Fri, 29 Jul 2022 12:26:18 +0200
Subject: [PATCH] Fix MakeCurrent and shader issues with AMD 22.7 driver

---
 src/citra/emu_window/emu_window_sdl2.cpp             | 10 +++++++++-
 src/citra/emu_window/emu_window_sdl2.h               |  8 ++++++++
 src/citra_qt/bootmanager.cpp                         |  2 ++
 src/core/frontend/emu_window.h                       | 10 ++++++++++
 src/video_core/renderer_opengl/gl_shader_manager.cpp |  5 +++++
 src/video_core/renderer_opengl/gl_shader_util.cpp    |  2 +-
 6 files changed, 35 insertions(+), 2 deletions(-)

diff --git a/src/citra/emu_window/emu_window_sdl2.cpp b/src/citra/emu_window/emu_window_sdl2.cpp
index 98045c3c6..e5a0594c4 100644
--- a/src/citra/emu_window/emu_window_sdl2.cpp
+++ b/src/citra/emu_window/emu_window_sdl2.cpp
@@ -30,7 +30,6 @@ SharedContext_SDL2::SharedContext_SDL2() {
 }
 
 SharedContext_SDL2::~SharedContext_SDL2() {
-    DoneCurrent();
     SDL_GL_DeleteContext(context);
     SDL_DestroyWindow(window);
 }
@@ -185,6 +184,7 @@ EmuWindow_SDL2::EmuWindow_SDL2(bool fullscreen) {
 
     window_context = SDL_GL_CreateContext(render_window);
     core_context = CreateSharedContext();
+    last_saved_context = nullptr;
 
     if (window_context == nullptr) {
         LOG_CRITICAL(Frontend, "Failed to create SDL2 GL context: {}", SDL_GetError());
@@ -222,6 +222,14 @@ std::unique_ptr<Frontend::GraphicsContext> EmuWindow_SDL2::CreateSharedContext()
     return std::make_unique<SharedContext_SDL2>();
 }
 
+void EmuWindow_SDL2::SaveContext() {
+    last_saved_context = SDL_GL_GetCurrentContext();
+}
+
+void EmuWindow_SDL2::RestoreContext() {
+    SDL_GL_MakeCurrent(render_window, last_saved_context);
+}
+
 void EmuWindow_SDL2::Present() {
     SDL_GL_MakeCurrent(render_window, window_context);
     SDL_GL_SetSwapInterval(1);
diff --git a/src/citra/emu_window/emu_window_sdl2.h b/src/citra/emu_window/emu_window_sdl2.h
index b0834fd06..64dec5381 100644
--- a/src/citra/emu_window/emu_window_sdl2.h
+++ b/src/citra/emu_window/emu_window_sdl2.h
@@ -49,6 +49,11 @@ public:
     /// Creates a new context that is shared with the current context
     std::unique_ptr<GraphicsContext> CreateSharedContext() const override;
 
+    /// Saves the current context, for the purpose of e.g. creating new shared contexts
+    void SaveContext() override;
+    /// Restores the context previously saved
+    void RestoreContext() override;
+
 private:
     /// Called by PollEvents when a key is pressed or released.
     void OnKeyEvent(int key, u8 state);
@@ -94,6 +99,9 @@ private:
     /// The OpenGL context associated with the window
     SDL_GLContext window_context;
 
+    /// Used by SaveContext and RestoreContext
+    SDL_GLContext last_saved_context;
+
     /// The OpenGL context associated with the core
     std::unique_ptr<Frontend::GraphicsContext> core_context;
 
diff --git a/src/citra_qt/bootmanager.cpp b/src/citra_qt/bootmanager.cpp
index 8b4c145bf..3a3eeb322 100644
--- a/src/citra_qt/bootmanager.cpp
+++ b/src/citra_qt/bootmanager.cpp
@@ -53,6 +53,8 @@ void EmuThread::run() {
 
     emit LoadProgress(VideoCore::LoadCallbackStage::Complete, 0, 0);
 
+    core_context.MakeCurrent();
+
     if (Core::System::GetInstance().frame_limiter.IsFrameAdvancing()) {
         // Usually the loading screen is hidden after the first frame is drawn. In this case
         // we hide it immediately as we need to wait for user input to start the emulation.
diff --git a/src/core/frontend/emu_window.h b/src/core/frontend/emu_window.h
index 326563655..0bf3b5115 100644
--- a/src/core/frontend/emu_window.h
+++ b/src/core/frontend/emu_window.h
@@ -111,6 +111,16 @@ public:
         return nullptr;
     }
 
+    /**
+     * Save current GraphicsContext.
+     */
+    virtual void SaveContext() {};
+
+    /**
+     * Restore saved GraphicsContext.
+     */
+    virtual void RestoreContext() {};
+
     /**
      * Signal that a touch pressed event has occurred (e.g. mouse click pressed)
      * @param framebuffer_x Framebuffer x-coordinate that was pressed
diff --git a/src/video_core/renderer_opengl/gl_shader_manager.cpp b/src/video_core/renderer_opengl/gl_shader_manager.cpp
index 7f49e9b73..f019bc80e 100644
--- a/src/video_core/renderer_opengl/gl_shader_manager.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_manager.cpp
@@ -706,6 +706,8 @@ void ShaderProgramManager::LoadDiskCache(const std::atomic_bool& stop_loading,
     const std::size_t bucket_size{load_raws_size / num_workers};
     std::vector<std::unique_ptr<Frontend::GraphicsContext>> contexts(num_workers);
     std::vector<std::thread> threads(num_workers);
+
+    emu_window.SaveContext();
     for (std::size_t i = 0; i < num_workers; ++i) {
         const bool is_last_worker = i + 1 == num_workers;
         const std::size_t start{bucket_size * i};
@@ -713,11 +715,14 @@ void ShaderProgramManager::LoadDiskCache(const std::atomic_bool& stop_loading,
 
         // On some platforms the shared context has to be created from the GUI thread
         contexts[i] = emu_window.CreateSharedContext();
+        // Release the context, so it can be immediately used by the spawned thread
+        contexts[i]->DoneCurrent();
         threads[i] = std::thread(LoadRawSepareble, contexts[i].get(), start, end);
     }
     for (auto& thread : threads) {
         thread.join();
     }
+    emu_window.RestoreContext();
 
     if (compilation_failed) {
         disk_cache.InvalidateAll();
diff --git a/src/video_core/renderer_opengl/gl_shader_util.cpp b/src/video_core/renderer_opengl/gl_shader_util.cpp
index 036cd49a3..ff75e1eab 100644
--- a/src/video_core/renderer_opengl/gl_shader_util.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_util.cpp
@@ -26,7 +26,7 @@ GLuint LoadShader(const char* source, GLenum type) {
 #extension GL_EXT_clip_cull_distance : enable
 #endif // defined(GL_EXT_clip_cull_distance)
 )"
-                                     : "#version 330\n";
+                                     : "#version 430\n";
 
     const char* debug_type;
     switch (type) {