fix issues with multi-window and OpenGL on Windows

This commit is contained in:
Arisotura
2025-06-28 03:02:00 +02:00
parent 005ef9c9fc
commit ec2f7ee838
8 changed files with 102 additions and 19 deletions

9
src/frontend/qt_sdl/EmuInstance.cpp Normal file → Executable file
View File

@ -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++)

1
src/frontend/qt_sdl/EmuInstance.h Normal file → Executable file
View File

@ -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

27
src/frontend/qt_sdl/EmuThread.cpp Normal file → Executable file
View File

@ -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<QStringList>(), 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);

7
src/frontend/qt_sdl/EmuThread.h Normal file → Executable file
View File

@ -22,6 +22,7 @@
#include <QThread>
#include <QMutex>
#include <QSemaphore>
#include <QWaitCondition>
#include <QQueue>
#include <QVariant>
@ -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);

7
src/frontend/qt_sdl/Screen.cpp Normal file → Executable file
View File

@ -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);

1
src/frontend/qt_sdl/Screen.h Normal file → Executable file
View File

@ -189,6 +189,7 @@ public:
void initOpenGL();
void deinitOpenGL();
void makeCurrentGL();
void releaseGL();
void drawScreenGL();
GL::Context* getContext() { return glContext.get(); }

68
src/frontend/qt_sdl/Window.cpp Normal file → Executable file
View File

@ -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<ScreenPanelGL*>(panel);
if (!glpanel) return;
return glpanel->setSwapInterval(intv);
}
@ -932,14 +944,25 @@ void MainWindow::makeCurrentGL()
if (!hasOGL) return;
ScreenPanelGL* glpanel = static_cast<ScreenPanelGL*>(panel);
if (!glpanel) return;
return glpanel->makeCurrentGL();
}
void MainWindow::releaseGL()
{
if (!hasOGL) return;
ScreenPanelGL* glpanel = static_cast<ScreenPanelGL*>(panel);
if (!glpanel) return;
return glpanel->releaseGL();
}
void MainWindow::drawScreenGL()
{
if (!hasOGL) return;
ScreenPanelGL* glpanel = static_cast<ScreenPanelGL*>(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<MainWindow *>(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<MainWindow *>(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);
}
}
}

1
src/frontend/qt_sdl/Window.h Normal file → Executable file
View File

@ -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);