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(); mainWindow->makeCurrentGL();
} }
void EmuInstance::releaseGL()
{
for (int i = 0; i < kMaxWindows; i++)
{
if (windowList[i])
windowList[i]->releaseGL();
}
}
void EmuInstance::drawScreenGL() void EmuInstance::drawScreenGL()
{ {
for (int i = 0; i < kMaxWindows; i++) 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 deinitOpenGL(int win);
void setVSyncGL(bool vsync); void setVSyncGL(bool vsync);
void makeCurrentGL(); void makeCurrentGL();
void releaseGL();
void drawScreenGL(); void drawScreenGL();
// return: empty string = setup OK, non-empty = error message // 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() void EmuThread::handleMessages()
{ {
bool glborrow = false;
msgMutex.lock(); msgMutex.lock();
while (!msgQueue.empty()) while (!msgQueue.empty())
{ {
@ -576,6 +578,11 @@ void EmuThread::handleMessages()
useOpenGL = false; useOpenGL = false;
break; break;
case msg_BorrowGL:
emuInstance->releaseGL();
glborrow = true;
break;
case msg_BootROM: case msg_BootROM:
msgResult = 0; msgResult = 0;
if (!emuInstance->loadROM(msg.param.value<QStringList>(), true, msgError)) if (!emuInstance->loadROM(msg.param.value<QStringList>(), true, msgError))
@ -667,6 +674,13 @@ void EmuThread::handleMessages()
msgSemaphore.release(); msgSemaphore.release();
} }
msgMutex.unlock(); msgMutex.unlock();
if (glborrow)
{
glBorrowMutex.lock();
glBorrowCond.wait(&glBorrowMutex);
glBorrowMutex.unlock();
}
} }
void EmuThread::changeWindowTitle(char* title) void EmuThread::changeWindowTitle(char* title)
@ -686,6 +700,19 @@ void EmuThread::deinitContext(int win)
waitMessage(); waitMessage();
} }
void EmuThread::borrowGL()
{
sendMessage(msg_BorrowGL);
waitMessage();
}
void EmuThread::returnGL()
{
glBorrowMutex.lock();
glBorrowCond.wakeAll();
glBorrowMutex.unlock();
}
void EmuThread::emuRun() void EmuThread::emuRun()
{ {
sendMessage(msg_EmuRun); sendMessage(msg_EmuRun);

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

@ -22,6 +22,7 @@
#include <QThread> #include <QThread>
#include <QMutex> #include <QMutex>
#include <QSemaphore> #include <QSemaphore>
#include <QWaitCondition>
#include <QQueue> #include <QQueue>
#include <QVariant> #include <QVariant>
@ -66,6 +67,7 @@ public:
msg_InitGL, msg_InitGL,
msg_DeInitGL, msg_DeInitGL,
msg_BorrowGL,
msg_BootROM, msg_BootROM,
msg_BootFirmware, msg_BootFirmware,
@ -130,12 +132,17 @@ public:
void initContext(int win); void initContext(int win);
void deinitContext(int win); void deinitContext(int win);
void borrowGL();
void returnGL();
void updateVideoSettings() { videoSettingsDirty = true; } void updateVideoSettings() { videoSettingsDirty = true; }
void updateVideoRenderer() { videoSettingsDirty = true; lastVideoRenderer = -1; } void updateVideoRenderer() { videoSettingsDirty = true; lastVideoRenderer = -1; }
int frontBuffer = 0; int frontBuffer = 0;
QMutex frontBufferLock; QMutex frontBufferLock;
QWaitCondition glBorrowCond;
QMutex glBorrowMutex;
signals: signals:
void windowUpdate(); void windowUpdate();
void windowTitleChange(QString title); 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(); glContext->MakeCurrent();
} }
void ScreenPanelGL::releaseGL()
{
if (!glContext) return;
glContext->DoneCurrent();
}
void ScreenPanelGL::osdRenderItem(OSDItem* item) void ScreenPanelGL::osdRenderItem(OSDItem* item)
{ {
ScreenPanel::osdRenderItem(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 initOpenGL();
void deinitOpenGL(); void deinitOpenGL();
void makeCurrentGL(); void makeCurrentGL();
void releaseGL();
void drawScreenGL(); void drawScreenGL();
GL::Context* getContext() { return glContext.get(); } GL::Context* getContext() { return glContext.get(); }

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

@ -864,7 +864,10 @@ void MainWindow::createScreenPanel()
ScreenPanelGL* panelGL = new ScreenPanelGL(this); ScreenPanelGL* panelGL = new ScreenPanelGL(this);
panelGL->show(); 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 // Check that creating the context hasn't failed
if (panelGL->createContext() == false) if (panelGL->createContext() == false)
@ -874,7 +877,15 @@ void MainWindow::createScreenPanel()
globalCfg.SetBool("Screen.UseGL", false); globalCfg.SetBool("Screen.UseGL", false);
globalCfg.SetInt("3D.Renderer", renderer3D_Software); globalCfg.SetInt("3D.Renderer", renderer3D_Software);
delete panelGL;
panelGL = nullptr;
} }
if (windowID != 0)
emuThread->returnGL();
panel = panelGL;
} }
if (!hasOGL) if (!hasOGL)
@ -924,6 +935,7 @@ void MainWindow::setGLSwapInterval(int intv)
if (!hasOGL) return; if (!hasOGL) return;
ScreenPanelGL* glpanel = static_cast<ScreenPanelGL*>(panel); ScreenPanelGL* glpanel = static_cast<ScreenPanelGL*>(panel);
if (!glpanel) return;
return glpanel->setSwapInterval(intv); return glpanel->setSwapInterval(intv);
} }
@ -932,14 +944,25 @@ void MainWindow::makeCurrentGL()
if (!hasOGL) return; if (!hasOGL) return;
ScreenPanelGL* glpanel = static_cast<ScreenPanelGL*>(panel); ScreenPanelGL* glpanel = static_cast<ScreenPanelGL*>(panel);
if (!glpanel) return;
return glpanel->makeCurrentGL(); return glpanel->makeCurrentGL();
} }
void MainWindow::releaseGL()
{
if (!hasOGL) return;
ScreenPanelGL* glpanel = static_cast<ScreenPanelGL*>(panel);
if (!glpanel) return;
return glpanel->releaseGL();
}
void MainWindow::drawScreenGL() void MainWindow::drawScreenGL()
{ {
if (!hasOGL) return; if (!hasOGL) return;
ScreenPanelGL* glpanel = static_cast<ScreenPanelGL*>(panel); ScreenPanelGL* glpanel = static_cast<ScreenPanelGL*>(panel);
if (!glpanel) return;
return glpanel->drawScreenGL(); return glpanel->drawScreenGL();
} }
@ -2263,42 +2286,49 @@ void MainWindow::onUpdateVideoSettings(bool glchange)
if (parentwin) if (parentwin)
return parentwin->onUpdateVideoSettings(glchange); return parentwin->onUpdateVideoSettings(glchange);
auto childwins = findChildren<MainWindow *>(nullptr, Qt::FindDirectChildrenOnly);
bool hadOGL = hasOGL; bool hadOGL = hasOGL;
if (glchange) if (glchange)
{ {
emuThread->emuPause(); 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(); createScreenPanel();
for (auto child: childwins)
{
child->createScreenPanel();
}
} }
emuThread->updateVideoSettings(); 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) for (auto child: childwins)
{ {
// child windows may belong to a different instance // child windows may belong to a different instance
// in that case we need to signal their thread appropriately // in that case we need to signal their thread appropriately
auto thread = child->getEmuInstance()->getEmuThread(); auto thread = child->getEmuInstance()->getEmuThread();
if (glchange)
{
if (hadOGL) thread->deinitContext(child->windowID);
child->createScreenPanel();
}
if (child->getWindowID() == 0) if (child->getWindowID() == 0)
thread->updateVideoSettings(); thread->updateVideoSettings();
}
if (glchange) if (glchange)
{ {
if (hasOGL) thread->initContext(child->windowID); if (hasOGL)
{
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 deinitOpenGL();
void setGLSwapInterval(int intv); void setGLSwapInterval(int intv);
void makeCurrentGL(); void makeCurrentGL();
void releaseGL();
void drawScreenGL(); void drawScreenGL();
bool preloadROMs(QStringList file, QStringList gbafile, bool boot); bool preloadROMs(QStringList file, QStringList gbafile, bool boot);