From ec2f7ee838e2b0b7f7968ac01b4b683fc6ab7711 Mon Sep 17 00:00:00 2001 From: Arisotura Date: Sat, 28 Jun 2025 03:02:00 +0200 Subject: [PATCH] fix issues with multi-window and OpenGL on Windows --- src/frontend/qt_sdl/EmuInstance.cpp | 9 ++++ src/frontend/qt_sdl/EmuInstance.h | 1 + src/frontend/qt_sdl/EmuThread.cpp | 27 ++++++++++++ src/frontend/qt_sdl/EmuThread.h | 7 +++ src/frontend/qt_sdl/Screen.cpp | 7 +++ src/frontend/qt_sdl/Screen.h | 1 + src/frontend/qt_sdl/Window.cpp | 68 +++++++++++++++++++++-------- src/frontend/qt_sdl/Window.h | 1 + 8 files changed, 102 insertions(+), 19 deletions(-) mode change 100644 => 100755 src/frontend/qt_sdl/EmuInstance.cpp mode change 100644 => 100755 src/frontend/qt_sdl/EmuInstance.h mode change 100644 => 100755 src/frontend/qt_sdl/EmuThread.cpp mode change 100644 => 100755 src/frontend/qt_sdl/EmuThread.h mode change 100644 => 100755 src/frontend/qt_sdl/Screen.cpp mode change 100644 => 100755 src/frontend/qt_sdl/Screen.h mode change 100644 => 100755 src/frontend/qt_sdl/Window.cpp mode change 100644 => 100755 src/frontend/qt_sdl/Window.h diff --git a/src/frontend/qt_sdl/EmuInstance.cpp b/src/frontend/qt_sdl/EmuInstance.cpp old mode 100644 new mode 100755 index 499987c4..d619fd3e --- a/src/frontend/qt_sdl/EmuInstance.cpp +++ b/src/frontend/qt_sdl/EmuInstance.cpp @@ -408,6 +408,15 @@ void EmuInstance::makeCurrentGL() mainWindow->makeCurrentGL(); } +void EmuInstance::releaseGL() +{ + for (int i = 0; i < kMaxWindows; i++) + { + if (windowList[i]) + windowList[i]->releaseGL(); + } +} + void EmuInstance::drawScreenGL() { for (int i = 0; i < kMaxWindows; i++) diff --git a/src/frontend/qt_sdl/EmuInstance.h b/src/frontend/qt_sdl/EmuInstance.h old mode 100644 new mode 100755 index c83f30a8..295e9bf6 --- a/src/frontend/qt_sdl/EmuInstance.h +++ b/src/frontend/qt_sdl/EmuInstance.h @@ -120,6 +120,7 @@ public: void deinitOpenGL(int win); void setVSyncGL(bool vsync); void makeCurrentGL(); + void releaseGL(); void drawScreenGL(); // return: empty string = setup OK, non-empty = error message diff --git a/src/frontend/qt_sdl/EmuThread.cpp b/src/frontend/qt_sdl/EmuThread.cpp old mode 100644 new mode 100755 index 9b54ed6e..7737038a --- a/src/frontend/qt_sdl/EmuThread.cpp +++ b/src/frontend/qt_sdl/EmuThread.cpp @@ -485,6 +485,8 @@ void EmuThread::waitAllMessages() void EmuThread::handleMessages() { + bool glborrow = false; + msgMutex.lock(); while (!msgQueue.empty()) { @@ -576,6 +578,11 @@ void EmuThread::handleMessages() useOpenGL = false; break; + case msg_BorrowGL: + emuInstance->releaseGL(); + glborrow = true; + break; + case msg_BootROM: msgResult = 0; if (!emuInstance->loadROM(msg.param.value(), true, msgError)) @@ -667,6 +674,13 @@ void EmuThread::handleMessages() msgSemaphore.release(); } msgMutex.unlock(); + + if (glborrow) + { + glBorrowMutex.lock(); + glBorrowCond.wait(&glBorrowMutex); + glBorrowMutex.unlock(); + } } void EmuThread::changeWindowTitle(char* title) @@ -686,6 +700,19 @@ void EmuThread::deinitContext(int win) waitMessage(); } +void EmuThread::borrowGL() +{ + sendMessage(msg_BorrowGL); + waitMessage(); +} + +void EmuThread::returnGL() +{ + glBorrowMutex.lock(); + glBorrowCond.wakeAll(); + glBorrowMutex.unlock(); +} + void EmuThread::emuRun() { sendMessage(msg_EmuRun); diff --git a/src/frontend/qt_sdl/EmuThread.h b/src/frontend/qt_sdl/EmuThread.h old mode 100644 new mode 100755 index 4ca90097..7a7f0600 --- a/src/frontend/qt_sdl/EmuThread.h +++ b/src/frontend/qt_sdl/EmuThread.h @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -66,6 +67,7 @@ public: msg_InitGL, msg_DeInitGL, + msg_BorrowGL, msg_BootROM, msg_BootFirmware, @@ -130,12 +132,17 @@ public: void initContext(int win); void deinitContext(int win); + void borrowGL(); + void returnGL(); void updateVideoSettings() { videoSettingsDirty = true; } void updateVideoRenderer() { videoSettingsDirty = true; lastVideoRenderer = -1; } int frontBuffer = 0; QMutex frontBufferLock; + QWaitCondition glBorrowCond; + QMutex glBorrowMutex; + signals: void windowUpdate(); void windowTitleChange(QString title); diff --git a/src/frontend/qt_sdl/Screen.cpp b/src/frontend/qt_sdl/Screen.cpp old mode 100644 new mode 100755 index 8024c9b4..2515b155 --- a/src/frontend/qt_sdl/Screen.cpp +++ b/src/frontend/qt_sdl/Screen.cpp @@ -1055,6 +1055,13 @@ void ScreenPanelGL::makeCurrentGL() glContext->MakeCurrent(); } +void ScreenPanelGL::releaseGL() +{ + if (!glContext) return; + + glContext->DoneCurrent(); +} + void ScreenPanelGL::osdRenderItem(OSDItem* item) { ScreenPanel::osdRenderItem(item); diff --git a/src/frontend/qt_sdl/Screen.h b/src/frontend/qt_sdl/Screen.h old mode 100644 new mode 100755 index a0e1fea7..d7f54797 --- a/src/frontend/qt_sdl/Screen.h +++ b/src/frontend/qt_sdl/Screen.h @@ -189,6 +189,7 @@ public: void initOpenGL(); void deinitOpenGL(); void makeCurrentGL(); + void releaseGL(); void drawScreenGL(); GL::Context* getContext() { return glContext.get(); } diff --git a/src/frontend/qt_sdl/Window.cpp b/src/frontend/qt_sdl/Window.cpp old mode 100644 new mode 100755 index 9a14dea3..cf1a27f1 --- a/src/frontend/qt_sdl/Window.cpp +++ b/src/frontend/qt_sdl/Window.cpp @@ -864,7 +864,10 @@ void MainWindow::createScreenPanel() ScreenPanelGL* panelGL = new ScreenPanelGL(this); panelGL->show(); - panel = panelGL; + // make sure no GL context is in use by the emu thread + // otherwise we may fail to create a shared context + if (windowID != 0) + emuThread->borrowGL(); // Check that creating the context hasn't failed if (panelGL->createContext() == false) @@ -874,7 +877,15 @@ void MainWindow::createScreenPanel() globalCfg.SetBool("Screen.UseGL", false); globalCfg.SetInt("3D.Renderer", renderer3D_Software); + + delete panelGL; + panelGL = nullptr; } + + if (windowID != 0) + emuThread->returnGL(); + + panel = panelGL; } if (!hasOGL) @@ -924,6 +935,7 @@ void MainWindow::setGLSwapInterval(int intv) if (!hasOGL) return; ScreenPanelGL* glpanel = static_cast(panel); + if (!glpanel) return; return glpanel->setSwapInterval(intv); } @@ -932,14 +944,25 @@ void MainWindow::makeCurrentGL() if (!hasOGL) return; ScreenPanelGL* glpanel = static_cast(panel); + if (!glpanel) return; return glpanel->makeCurrentGL(); } +void MainWindow::releaseGL() +{ + if (!hasOGL) return; + + ScreenPanelGL* glpanel = static_cast(panel); + if (!glpanel) return; + return glpanel->releaseGL(); +} + void MainWindow::drawScreenGL() { if (!hasOGL) return; ScreenPanelGL* glpanel = static_cast(panel); + if (!glpanel) return; return glpanel->drawScreenGL(); } @@ -2263,42 +2286,49 @@ void MainWindow::onUpdateVideoSettings(bool glchange) if (parentwin) return parentwin->onUpdateVideoSettings(glchange); + auto childwins = findChildren(nullptr, Qt::FindDirectChildrenOnly); + bool hadOGL = hasOGL; if (glchange) { emuThread->emuPause(); - if (hadOGL) emuThread->deinitContext(windowID); + if (hadOGL) + { + emuThread->deinitContext(windowID); + for (auto child: childwins) + { + auto thread = child->getEmuInstance()->getEmuThread(); + thread->deinitContext(child->windowID); + } + } createScreenPanel(); + for (auto child: childwins) + { + child->createScreenPanel(); + } } emuThread->updateVideoSettings(); - - if (glchange) - { - if (hasOGL) emuThread->initContext(windowID); - } - - // update any child windows we have - auto childwins = findChildren(nullptr, Qt::FindDirectChildrenOnly); for (auto child: childwins) { // child windows may belong to a different instance // in that case we need to signal their thread appropriately auto thread = child->getEmuInstance()->getEmuThread(); - - if (glchange) - { - if (hadOGL) thread->deinitContext(child->windowID); - child->createScreenPanel(); - } - if (child->getWindowID() == 0) thread->updateVideoSettings(); + } - if (glchange) + if (glchange) + { + if (hasOGL) { - if (hasOGL) thread->initContext(child->windowID); + emuThread->initContext(windowID); + for (auto child: childwins) + { + auto thread = child->getEmuInstance()->getEmuThread(); + thread->initContext(child->windowID); + } } } diff --git a/src/frontend/qt_sdl/Window.h b/src/frontend/qt_sdl/Window.h old mode 100644 new mode 100755 index 21c65d9e..678be7c9 --- a/src/frontend/qt_sdl/Window.h +++ b/src/frontend/qt_sdl/Window.h @@ -124,6 +124,7 @@ public: void deinitOpenGL(); void setGLSwapInterval(int intv); void makeCurrentGL(); + void releaseGL(); void drawScreenGL(); bool preloadROMs(QStringList file, QStringList gbafile, bool boot);