From 881a740cabbbc5b3e877572de474df03d9dc4dd5 Mon Sep 17 00:00:00 2001 From: Arisotura Date: Sun, 27 Oct 2024 01:14:29 +0200 Subject: [PATCH] start actually implementing multi-window feature, still rough around the edges fix crash when closing main window if sub windows are involved fix OpenGL context handling, still need to fix when changing display type --- src/frontend/qt_sdl/EmuInstance.cpp | 35 +++++++++++++---------------- src/frontend/qt_sdl/EmuInstance.h | 4 ++-- src/frontend/qt_sdl/EmuThread.cpp | 14 ++++++------ src/frontend/qt_sdl/EmuThread.h | 4 ++-- src/frontend/qt_sdl/Screen.cpp | 6 +++++ src/frontend/qt_sdl/Screen.h | 1 + src/frontend/qt_sdl/Window.cpp | 16 +++++++++++-- src/frontend/qt_sdl/Window.h | 2 ++ 8 files changed, 49 insertions(+), 33 deletions(-) diff --git a/src/frontend/qt_sdl/EmuInstance.cpp b/src/frontend/qt_sdl/EmuInstance.cpp index 402af56b..09f6a2bc 100644 --- a/src/frontend/qt_sdl/EmuInstance.cpp +++ b/src/frontend/qt_sdl/EmuInstance.cpp @@ -199,6 +199,10 @@ void EmuInstance::createWindow() numWindows++; emuThread->attachWindow(win); + + // if creating a secondary window, we may need to initialize its OpenGL context here + if (win->hasOpenGL() && (win != topWindow)) + emuThread->initContext(id); } void EmuInstance::deleteWindow(int id, bool close) @@ -208,12 +212,8 @@ void EmuInstance::deleteWindow(int id, bool close) MainWindow* win = windowList[id]; if (!win) return; - if (win->hasOpenGL() && win == mainWindow) - { - // we intentionally don't unpause here - emuThread->emuPause(); - emuThread->deinitContext(); - } + if (win->hasOpenGL()) + emuThread->deinitContext(id); emuThread->detachWindow(win); @@ -226,9 +226,10 @@ void EmuInstance::deleteWindow(int id, bool close) if (close) win->close(); - if ((!mainWindow) && (!deleting)) + if (numWindows == 0) { - // if we closed this instance's main window, delete the instance + // if we closed the last window, delete the instance + // if the main window is closed, Qt will take care of closing any secondary windows deleteEmuInstance(instanceID); } } @@ -292,24 +293,18 @@ bool EmuInstance::usesOpenGL() (globalCfg.GetInt("3D.Renderer") != renderer3D_Software); } -void EmuInstance::initOpenGL() +void EmuInstance::initOpenGL(int win) { - for (int i = 0; i < kMaxWindows; i++) - { - if (windowList[i]) - windowList[i]->initOpenGL(); - } + if (windowList[win]) + windowList[win]->initOpenGL(); setVSyncGL(true); } -void EmuInstance::deinitOpenGL() +void EmuInstance::deinitOpenGL(int win) { - for (int i = 0; i < kMaxWindows; i++) - { - if (windowList[i]) - windowList[i]->deinitOpenGL(); - } + if (windowList[win]) + windowList[win]->deinitOpenGL(); } void EmuInstance::setVSyncGL(bool vsync) diff --git a/src/frontend/qt_sdl/EmuInstance.h b/src/frontend/qt_sdl/EmuInstance.h index 742bebba..8022867a 100644 --- a/src/frontend/qt_sdl/EmuInstance.h +++ b/src/frontend/qt_sdl/EmuInstance.h @@ -103,8 +103,8 @@ public: void emuStop(melonDS::Platform::StopReason reason); bool usesOpenGL(); - void initOpenGL(); - void deinitOpenGL(); + void initOpenGL(int win); + void deinitOpenGL(int win); void setVSyncGL(bool vsync); void makeCurrentGL(); void drawScreenGL(); diff --git a/src/frontend/qt_sdl/EmuThread.cpp b/src/frontend/qt_sdl/EmuThread.cpp index 589f11e2..da28365c 100644 --- a/src/frontend/qt_sdl/EmuThread.cpp +++ b/src/frontend/qt_sdl/EmuThread.cpp @@ -115,7 +115,7 @@ void EmuThread::run() if (emuInstance->usesOpenGL()) { - emuInstance->initOpenGL(); + emuInstance->initOpenGL(0); useOpenGL = true; videoRenderer = globalCfg.GetInt("3D.Renderer"); @@ -547,12 +547,12 @@ void EmuThread::handleMessages() break; case msg_InitGL: - emuInstance->initOpenGL(); + emuInstance->initOpenGL(msg.param.value()); useOpenGL = true; break; case msg_DeInitGL: - emuInstance->deinitOpenGL(); + emuInstance->deinitOpenGL(msg.param.value()); useOpenGL = false; break; @@ -650,15 +650,15 @@ void EmuThread::changeWindowTitle(char* title) emit windowTitleChange(QString(title)); } -void EmuThread::initContext() +void EmuThread::initContext(int win) { - sendMessage(msg_InitGL); + sendMessage({.type = msg_InitGL, .param = win}); waitMessage(); } -void EmuThread::deinitContext() +void EmuThread::deinitContext(int win) { - sendMessage(msg_DeInitGL); + sendMessage({.type = msg_DeInitGL, .param = win}); waitMessage(); } diff --git a/src/frontend/qt_sdl/EmuThread.h b/src/frontend/qt_sdl/EmuThread.h index c53740c8..57f389af 100644 --- a/src/frontend/qt_sdl/EmuThread.h +++ b/src/frontend/qt_sdl/EmuThread.h @@ -127,8 +127,8 @@ public: bool emuIsRunning(); bool emuIsActive(); - void initContext(); - void deinitContext(); + void initContext(int win); + void deinitContext(int win); void updateVideoSettings() { videoSettingsDirty = true; } void updateVideoRenderer() { videoSettingsDirty = true; lastVideoRenderer = -1; } diff --git a/src/frontend/qt_sdl/Screen.cpp b/src/frontend/qt_sdl/Screen.cpp index 3780de55..11a6150a 100644 --- a/src/frontend/qt_sdl/Screen.cpp +++ b/src/frontend/qt_sdl/Screen.cpp @@ -736,6 +736,8 @@ ScreenPanelGL::ScreenPanelGL(QWidget* parent) : ScreenPanel(parent) setAttribute(Qt::WA_KeyCompression, false); setFocusPolicy(Qt::StrongFocus); setMinimumSize(screenGetMinSize()); + + glInited = false; } ScreenPanelGL::~ScreenPanelGL() @@ -781,6 +783,7 @@ void ScreenPanelGL::setSwapInterval(int intv) void ScreenPanelGL::initOpenGL() { if (!glContext) return; + if (glInited) return; glContext->MakeCurrent(); @@ -877,11 +880,13 @@ void ScreenPanelGL::initOpenGL() glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, (void*)(0)); transferLayout(); + glInited = true; } void ScreenPanelGL::deinitOpenGL() { if (!glContext) return; + if (!glInited) return; glDeleteTextures(1, &screenTexture); @@ -906,6 +911,7 @@ void ScreenPanelGL::deinitOpenGL() glContext->DoneCurrent(); lastScreenWidth = lastScreenHeight = -1; + glInited = false; } void ScreenPanelGL::makeCurrentGL() diff --git a/src/frontend/qt_sdl/Screen.h b/src/frontend/qt_sdl/Screen.h index f3662d8d..c17626bd 100644 --- a/src/frontend/qt_sdl/Screen.h +++ b/src/frontend/qt_sdl/Screen.h @@ -197,6 +197,7 @@ private: void setupScreenLayout() override; std::unique_ptr glContext; + bool glInited; GLuint screenVertexBuffer, screenVertexArray; GLuint screenTexture; diff --git a/src/frontend/qt_sdl/Window.cpp b/src/frontend/qt_sdl/Window.cpp index 7c6c0c4c..19c59673 100644 --- a/src/frontend/qt_sdl/Window.cpp +++ b/src/frontend/qt_sdl/Window.cpp @@ -588,6 +588,13 @@ MainWindow::MainWindow(int id, EmuInstance* inst, QWidget* parent) : } } + menu->addSeparator(); + + actNewWindow = menu->addAction("Open new window"); + connect(actNewWindow, &QAction::triggered, this, &MainWindow::onOpenNewWindow); + + menu->addSeparator(); + actScreenFiltering = menu->addAction("Screen filtering"); actScreenFiltering->setCheckable(true); connect(actScreenFiltering, &QAction::triggered, this, &MainWindow::onChangeScreenFiltering); @@ -1950,6 +1957,11 @@ void MainWindow::onChangeIntegerScaling(bool checked) emit screenLayoutChange(); } +void MainWindow::onOpenNewWindow() +{ + emuInstance->createWindow(); +} + void MainWindow::onChangeScreenFiltering(bool checked) { windowCfg.SetBool("ScreenFilter", checked); @@ -2077,7 +2089,7 @@ void MainWindow::onUpdateVideoSettings(bool glchange) if (glchange) { emuThread->emuPause(); - if (hasOGL) emuThread->deinitContext(); + if (hasOGL) emuThread->deinitContext(windowID); delete panel; createScreenPanel(); @@ -2088,7 +2100,7 @@ void MainWindow::onUpdateVideoSettings(bool glchange) if (glchange) { - if (hasOGL) emuThread->initContext(); + if (hasOGL) emuThread->initContext(windowID); emuThread->emuUnpause(); } } diff --git a/src/frontend/qt_sdl/Window.h b/src/frontend/qt_sdl/Window.h index 98298c0b..b1391911 100644 --- a/src/frontend/qt_sdl/Window.h +++ b/src/frontend/qt_sdl/Window.h @@ -208,6 +208,7 @@ private slots: void onChangeScreenSizing(QAction* act); void onChangeScreenAspect(QAction* act); void onChangeIntegerScaling(bool checked); + void onOpenNewWindow(); void onChangeScreenFiltering(bool checked); void onChangeShowOSD(bool checked); void onChangeLimitFramerate(bool checked); @@ -325,6 +326,7 @@ public: QAction** actScreenAspectTop; QActionGroup* grpScreenAspectBot; QAction** actScreenAspectBot; + QAction* actNewWindow; QAction* actScreenFiltering; QAction* actShowOSD; QAction* actLimitFramerate;