From 7f437d48db554a739dd1cab53fb0536783c87432 Mon Sep 17 00:00:00 2001 From: Arisotura Date: Tue, 26 Dec 2023 19:04:01 +0100 Subject: [PATCH] start cleaning up: move OpenGL stuff out of EmuThread --- src/frontend/qt_sdl/Screen.cpp | 206 ++++++++++++++++++++++++++++++--- src/frontend/qt_sdl/Screen.h | 19 ++- src/frontend/qt_sdl/Window.cpp | 24 ++++ src/frontend/qt_sdl/Window.h | 3 + src/frontend/qt_sdl/main.cpp | 149 ++++-------------------- src/frontend/qt_sdl/main.h | 13 ++- 6 files changed, 263 insertions(+), 151 deletions(-) diff --git a/src/frontend/qt_sdl/Screen.cpp b/src/frontend/qt_sdl/Screen.cpp index 6de4d78e..a86147c1 100644 --- a/src/frontend/qt_sdl/Screen.cpp +++ b/src/frontend/qt_sdl/Screen.cpp @@ -34,29 +34,25 @@ #endif #endif +#include "OpenGLSupport.h" +#include "duckstation/gl/context.h" + #include "main.h" #include "NDS.h" +#include "GPU.h" +#include "GPU3D_Soft.h" +#include "GPU3D_OpenGL.h" #include "Platform.h" #include "Config.h" -//#include "main_shaders.h" +#include "main_shaders.h" #include "OSD.h" using namespace melonDS; -/*const struct { int id; float ratio; const char* label; } aspectRatios[] = -{ - { 0, 1, "4:3 (native)" }, - { 4, (5.f / 3) / (4.f / 3), "5:3 (3DS)"}, - { 1, (16.f / 9) / (4.f / 3), "16:9" }, - { 2, (21.f / 9) / (4.f / 3), "21:9" }, - { 3, 0, "window" } -}; -int AspectRatiosNum = sizeof(aspectRatios) / sizeof(aspectRatios[0]);*/ - // TEMP extern MainWindow* mainWindow; extern EmuThread* emuThread; @@ -432,6 +428,172 @@ bool ScreenPanelGL::createContext() return glContext != nullptr; } +void ScreenPanelGL::setSwapInterval(int intv) +{ + if (!glContext) return; + + glContext->SetSwapInterval(intv); +} + +void ScreenPanelGL::initOpenGL() +{ + if (!glContext) return; + + glContext->MakeCurrent(); + + OpenGL::BuildShaderProgram(kScreenVS, kScreenFS, screenShaderProgram, "ScreenShader"); + GLuint pid = screenShaderProgram[2]; + glBindAttribLocation(pid, 0, "vPosition"); + glBindAttribLocation(pid, 1, "vTexcoord"); + glBindFragDataLocation(pid, 0, "oColor"); + + OpenGL::LinkShaderProgram(screenShaderProgram); + + glUseProgram(pid); + glUniform1i(glGetUniformLocation(pid, "ScreenTex"), 0); + + screenShaderScreenSizeULoc = glGetUniformLocation(pid, "uScreenSize"); + screenShaderTransformULoc = glGetUniformLocation(pid, "uTransform"); + + // to prevent bleeding between both parts of the screen + // with bilinear filtering enabled + const int paddedHeight = 192*2+2; + const float padPixels = 1.f / paddedHeight; + + const float vertices[] = + { + 0.f, 0.f, 0.f, 0.f, + 0.f, 192.f, 0.f, 0.5f - padPixels, + 256.f, 192.f, 1.f, 0.5f - padPixels, + 0.f, 0.f, 0.f, 0.f, + 256.f, 192.f, 1.f, 0.5f - padPixels, + 256.f, 0.f, 1.f, 0.f, + + 0.f, 0.f, 0.f, 0.5f + padPixels, + 0.f, 192.f, 0.f, 1.f, + 256.f, 192.f, 1.f, 1.f, + 0.f, 0.f, 0.f, 0.5f + padPixels, + 256.f, 192.f, 1.f, 1.f, + 256.f, 0.f, 1.f, 0.5f + padPixels + }; + + glGenBuffers(1, &screenVertexBuffer); + glBindBuffer(GL_ARRAY_BUFFER, screenVertexBuffer); + glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); + + glGenVertexArrays(1, &screenVertexArray); + glBindVertexArray(screenVertexArray); + glEnableVertexAttribArray(0); // position + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4*4, (void*)(0)); + glEnableVertexAttribArray(1); // texcoord + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4*4, (void*)(2*4)); + + glGenTextures(1, &screenTexture); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, screenTexture); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, paddedHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + // fill the padding + u8 zeroData[256*4*4]; + memset(zeroData, 0, sizeof(zeroData)); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 192, 256, 2, GL_RGBA, GL_UNSIGNED_BYTE, zeroData); + + OSD::Init(true); + + glContext->SetSwapInterval(Config::ScreenVSync ? Config::ScreenVSyncInterval : 0); + transferLayout(); +} + +void ScreenPanelGL::deinitOpenGL() +{ + if (!glContext) return; + + glDeleteTextures(1, &screenTexture); + + glDeleteVertexArrays(1, &screenVertexArray); + glDeleteBuffers(1, &screenVertexBuffer); + + OpenGL::DeleteShaderProgram(screenShaderProgram); + + OSD::DeInit(); + + glContext->DoneCurrent(); + + lastScreenWidth = lastScreenHeight = -1; +} + +void ScreenPanelGL::drawScreenGL() +{ + if (!glContext) return; + if (!emuThread->NDS) return; + + int w = windowInfo.surface_width; + int h = windowInfo.surface_height; + float factor = windowInfo.surface_scale; + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glDisable(GL_DEPTH_TEST); + glDepthMask(false); + glDisable(GL_BLEND); + glDisable(GL_SCISSOR_TEST); + glDisable(GL_STENCIL_TEST); + glClear(GL_COLOR_BUFFER_BIT); + + glViewport(0, 0, w, h); + + glUseProgram(screenShaderProgram[2]); + glUniform2f(screenShaderScreenSizeULoc, w / factor, h / factor); + + int frontbuf = emuThread->FrontBuffer; + glActiveTexture(GL_TEXTURE0); + +#ifdef OGLRENDERER_ENABLED + if (emuThread->NDS->GPU.GetRenderer3D().Accelerated) + { + // hardware-accelerated render + static_cast(emuThread->NDS->GPU.GetRenderer3D()).GetCompositor().BindOutputTexture(frontbuf); + } + else +#endif + { + // regular render + glBindTexture(GL_TEXTURE_2D, screenTexture); + + if (emuThread->NDS->GPU.Framebuffer[frontbuf][0] && emuThread->NDS->GPU.Framebuffer[frontbuf][1]) + { + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 256, 192, GL_RGBA, + GL_UNSIGNED_BYTE, emuThread->NDS->GPU.Framebuffer[frontbuf][0].get()); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 192+2, 256, 192, GL_RGBA, + GL_UNSIGNED_BYTE, emuThread->NDS->GPU.Framebuffer[frontbuf][1].get()); + } + } + + screenSettingsLock.lock(); + + GLint filter = this->filter ? GL_LINEAR : GL_NEAREST; + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter); + + glBindBuffer(GL_ARRAY_BUFFER, screenVertexBuffer); + glBindVertexArray(screenVertexArray); + + for (int i = 0; i < numScreens; i++) + { + glUniformMatrix2x3fv(screenShaderTransformULoc, 1, GL_TRUE, screenMatrix[i]); + glDrawArrays(GL_TRIANGLES, screenKind[i] == 0 ? 0 : 2*3, 2*3); + } + + screenSettingsLock.unlock(); + + OSD::Update(); + OSD::DrawGL(w, h); + + glContext->SwapBuffers(); +} + qreal ScreenPanelGL::devicePixelRatioFromScreen() const { const QScreen* screen_for_ratio = window()->windowHandle()->screen(); @@ -507,8 +669,7 @@ void ScreenPanelGL::setupScreenLayout() int h = height(); screenSetupLayout(w, h); - if (emuThread) - transferLayout(emuThread); + transferLayout(); } void ScreenPanelGL::resizeEvent(QResizeEvent* event) @@ -550,11 +711,26 @@ bool ScreenPanelGL::event(QEvent* event) return QWidget::event(event); } -void ScreenPanelGL::transferLayout(EmuThread* thread) +void ScreenPanelGL::transferLayout() { std::optional windowInfo = getWindowInfo(); if (windowInfo.has_value()) - thread->updateScreenSettings(Config::ScreenFilter, *windowInfo, numScreens, screenKind, &screenMatrix[0][0]); + { + screenSettingsLock.lock(); + + if (lastScreenWidth != windowInfo->surface_width || lastScreenHeight != windowInfo->surface_height) + { + if (glContext) + glContext->ResizeSurface(windowInfo->surface_width, windowInfo->surface_height); + lastScreenWidth = windowInfo->surface_width; + lastScreenHeight = windowInfo->surface_height; + } + + this->filter = Config::ScreenFilter; + this->windowInfo = *windowInfo; + + screenSettingsLock.unlock(); + } } void ScreenPanelGL::onScreenLayoutChanged() diff --git a/src/frontend/qt_sdl/Screen.h b/src/frontend/qt_sdl/Screen.h index 955eb2e6..b11df29b 100644 --- a/src/frontend/qt_sdl/Screen.h +++ b/src/frontend/qt_sdl/Screen.h @@ -122,9 +122,15 @@ public: bool createContext(); + void setSwapInterval(int intv); + + void initOpenGL(); + void deinitOpenGL(); + void drawScreenGL(); + GL::Context* getContext() { return glContext.get(); } - void transferLayout(EmuThread* thread); + void transferLayout(); protected: qreal devicePixelRatioFromScreen() const; @@ -149,6 +155,17 @@ private: void setupScreenLayout(); std::unique_ptr glContext; + + GLuint screenVertexBuffer, screenVertexArray; + GLuint screenTexture; + GLuint screenShaderProgram[3]; + GLuint screenShaderTransformULoc, screenShaderScreenSizeULoc; + + QMutex screenSettingsLock; + WindowInfo windowInfo; + bool filter; + + int lastScreenWidth = -1, lastScreenHeight = -1; }; #endif // SCREEN_H diff --git a/src/frontend/qt_sdl/Window.cpp b/src/frontend/qt_sdl/Window.cpp index f373450b..7e86354e 100644 --- a/src/frontend/qt_sdl/Window.cpp +++ b/src/frontend/qt_sdl/Window.cpp @@ -749,6 +749,30 @@ GL::Context* MainWindow::getOGLContext() return glpanel->getContext(); } +/*void MainWindow::initOpenGL() +{ + if (!hasOGL) return; + + ScreenPanelGL* glpanel = static_cast(panel); + return glpanel->initOpenGL(); +} + +void MainWindow::deinitOpenGL() +{ + if (!hasOGL) return; + + ScreenPanelGL* glpanel = static_cast(panel); + return glpanel->deinitOpenGL(); +} + +void MainWindow::drawScreenGL() +{ + if (!hasOGL) return; + + ScreenPanelGL* glpanel = static_cast(panel); + return glpanel->drawScreenGL(); +}*/ + void MainWindow::resizeEvent(QResizeEvent* event) { int w = event->size().width(); diff --git a/src/frontend/qt_sdl/Window.h b/src/frontend/qt_sdl/Window.h index 445d5e28..f0f66c26 100644 --- a/src/frontend/qt_sdl/Window.h +++ b/src/frontend/qt_sdl/Window.h @@ -106,6 +106,9 @@ public: bool hasOGL; GL::Context* getOGLContext(); + /*void initOpenGL(); + void deinitOpenGL(); + void drawScreenGL();*/ bool preloadROMs(QStringList file, QStringList gbafile, bool boot); QStringList splitArchivePath(const QString& filename, bool useMemberSyntax); diff --git a/src/frontend/qt_sdl/main.cpp b/src/frontend/qt_sdl/main.cpp index 3f53f3cc..22cb0344 100644 --- a/src/frontend/qt_sdl/main.cpp +++ b/src/frontend/qt_sdl/main.cpp @@ -99,7 +99,7 @@ #include "Savestate.h" -#include "main_shaders.h" +//#include "main_shaders.h" #include "ROMManager.h" #include "ArchiveUtil.h" @@ -194,9 +194,6 @@ EmuThread::EmuThread(QObject* parent) : QThread(parent) connect(this, SIGNAL(windowFullscreenToggle()), mainWindow, SLOT(onFullscreenToggled())); connect(this, SIGNAL(swapScreensToggle()), mainWindow->actScreenSwap, SLOT(trigger())); connect(this, SIGNAL(screenEmphasisToggle()), mainWindow, SLOT(onScreenEmphasisToggled())); - - auto glPanel = dynamic_cast(mainWindow->panel); - if (glPanel) glPanel->transferLayout(this); } std::unique_ptr EmuThread::CreateConsole( @@ -402,116 +399,6 @@ bool EmuThread::UpdateConsole(UpdateConsoleNDSArgs&& ndsargs, UpdateConsoleGBAAr return true; } -void EmuThread::updateScreenSettings(bool filter, const WindowInfo& windowInfo, int numScreens, int* screenKind, float* screenMatrix) -{ - screenSettingsLock.lock(); - - if (lastScreenWidth != windowInfo.surface_width || lastScreenHeight != windowInfo.surface_height) - { - if (oglContext) - oglContext->ResizeSurface(windowInfo.surface_width, windowInfo.surface_height); - lastScreenWidth = windowInfo.surface_width; - lastScreenHeight = windowInfo.surface_height; - } - - this->filter = filter; - this->windowInfo = windowInfo; - this->numScreens = numScreens; - memcpy(this->screenKind, screenKind, sizeof(int)*numScreens); - memcpy(this->screenMatrix, screenMatrix, sizeof(float)*numScreens*6); - - screenSettingsLock.unlock(); -} - -void EmuThread::initOpenGL() -{ - GL::Context* windowctx = mainWindow->getOGLContext(); - - oglContext = windowctx; - oglContext->MakeCurrent(); - - OpenGL::BuildShaderProgram(kScreenVS, kScreenFS, screenShaderProgram, "ScreenShader"); - GLuint pid = screenShaderProgram[2]; - glBindAttribLocation(pid, 0, "vPosition"); - glBindAttribLocation(pid, 1, "vTexcoord"); - glBindFragDataLocation(pid, 0, "oColor"); - - OpenGL::LinkShaderProgram(screenShaderProgram); - - glUseProgram(pid); - glUniform1i(glGetUniformLocation(pid, "ScreenTex"), 0); - - screenShaderScreenSizeULoc = glGetUniformLocation(pid, "uScreenSize"); - screenShaderTransformULoc = glGetUniformLocation(pid, "uTransform"); - - // to prevent bleeding between both parts of the screen - // with bilinear filtering enabled - const int paddedHeight = 192*2+2; - const float padPixels = 1.f / paddedHeight; - - const float vertices[] = - { - 0.f, 0.f, 0.f, 0.f, - 0.f, 192.f, 0.f, 0.5f - padPixels, - 256.f, 192.f, 1.f, 0.5f - padPixels, - 0.f, 0.f, 0.f, 0.f, - 256.f, 192.f, 1.f, 0.5f - padPixels, - 256.f, 0.f, 1.f, 0.f, - - 0.f, 0.f, 0.f, 0.5f + padPixels, - 0.f, 192.f, 0.f, 1.f, - 256.f, 192.f, 1.f, 1.f, - 0.f, 0.f, 0.f, 0.5f + padPixels, - 256.f, 192.f, 1.f, 1.f, - 256.f, 0.f, 1.f, 0.5f + padPixels - }; - - glGenBuffers(1, &screenVertexBuffer); - glBindBuffer(GL_ARRAY_BUFFER, screenVertexBuffer); - glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); - - glGenVertexArrays(1, &screenVertexArray); - glBindVertexArray(screenVertexArray); - glEnableVertexAttribArray(0); // position - glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4*4, (void*)(0)); - glEnableVertexAttribArray(1); // texcoord - glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4*4, (void*)(2*4)); - - glGenTextures(1, &screenTexture); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, screenTexture); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, paddedHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); - // fill the padding - u8 zeroData[256*4*4]; - memset(zeroData, 0, sizeof(zeroData)); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 192, 256, 2, GL_RGBA, GL_UNSIGNED_BYTE, zeroData); - - OSD::Init(true); - - oglContext->SetSwapInterval(Config::ScreenVSync ? Config::ScreenVSyncInterval : 0); -} - -void EmuThread::deinitOpenGL() -{ - glDeleteTextures(1, &screenTexture); - - glDeleteVertexArrays(1, &screenVertexArray); - glDeleteBuffers(1, &screenVertexBuffer); - - OpenGL::DeleteShaderProgram(screenShaderProgram); - - OSD::DeInit(); - - oglContext->DoneCurrent(); - oglContext = nullptr; - - lastScreenWidth = lastScreenHeight = -1; -} - void EmuThread::run() { u32 mainScreenPos[3]; @@ -529,11 +416,13 @@ void EmuThread::run() if (mainWindow->hasOGL) { - initOpenGL(); + screenGL = static_cast(mainWindow->panel); + screenGL->initOpenGL(); videoRenderer = Config::_3DRenderer; } else { + screenGL = nullptr; videoRenderer = 0; } @@ -654,9 +543,9 @@ void EmuThread::run() // to the old setting again if (videoSettingsDirty || Input::HotkeyReleased(HK_FastForward)) { - if (oglContext) + if (screenGL) { - oglContext->SetSwapInterval(Config::ScreenVSync ? Config::ScreenVSyncInterval : 0); + screenGL->setSwapInterval(Config::ScreenVSync ? Config::ScreenVSyncInterval : 0); videoRenderer = Config::_3DRenderer; } #ifdef OGLRENDERER_ENABLED @@ -666,7 +555,7 @@ void EmuThread::run() videoRenderer = 0; } - videoRenderer = oglContext ? Config::_3DRenderer : 0; + videoRenderer = screenGL ? Config::_3DRenderer : 0; videoSettingsDirty = false; @@ -738,7 +627,7 @@ void EmuThread::run() if (ROMManager::FirmwareSave) ROMManager::FirmwareSave->CheckFlush(); - if (!oglContext) + if (!screenGL) { FrontBufferLock.lock(); FrontBuffer = NDS->GPU.FrontBuffer; @@ -747,7 +636,7 @@ void EmuThread::run() else { FrontBuffer = NDS->GPU.FrontBuffer; - drawScreenGL(); + screenGL->drawScreenGL(); } #ifdef MELONCAP @@ -757,7 +646,7 @@ void EmuThread::run() if (EmuRunning == emuStatus_Exit) break; winUpdateCount++; - if (winUpdateCount >= winUpdateFreq && !oglContext) + if (winUpdateCount >= winUpdateFreq && !screenGL) { emit windowUpdate(); winUpdateCount = 0; @@ -765,9 +654,9 @@ void EmuThread::run() bool fastforward = Input::HotkeyDown(HK_FastForward); - if (fastforward && oglContext && Config::ScreenVSync) + if (fastforward && screenGL && Config::ScreenVSync) { - oglContext->SetSwapInterval(0); + screenGL->setSwapInterval(0); } if (Config::DSiVolumeSync && NDS->ConsoleType == 1) @@ -856,18 +745,20 @@ void EmuThread::run() SDL_Delay(75); - if (oglContext) - drawScreenGL(); + if (screenGL) + screenGL->drawScreenGL(); ContextRequestKind contextRequest = ContextRequest; if (contextRequest == contextRequest_InitGL) { - initOpenGL(); + screenGL = static_cast(mainWindow->panel); + screenGL->initOpenGL(); ContextRequest = contextRequest_None; } else if (contextRequest == contextRequest_DeInitGL) { - deinitOpenGL(); + screenGL->deinitOpenGL(); + screenGL = nullptr; ContextRequest = contextRequest_None; } } @@ -964,7 +855,7 @@ bool EmuThread::emuIsActive() return (RunningSomething == 1); } -void EmuThread::drawScreenGL() +/*void EmuThread::drawScreenGL() { if (!NDS) return; int w = windowInfo.surface_width; @@ -1029,7 +920,7 @@ void EmuThread::drawScreenGL() OSD::DrawGL(w, h); oglContext->SwapBuffers(); -} +}*/ diff --git a/src/frontend/qt_sdl/main.h b/src/frontend/qt_sdl/main.h index 9703c178..4034ba34 100644 --- a/src/frontend/qt_sdl/main.h +++ b/src/frontend/qt_sdl/main.h @@ -78,7 +78,7 @@ public: int FrontBuffer = 0; QMutex FrontBufferLock; - void updateScreenSettings(bool filter, const WindowInfo& windowInfo, int numScreens, int* screenKind, float* screenMatrix); + //void updateScreenSettings(bool filter, const WindowInfo& windowInfo, int numScreens, int* screenKind, float* screenMatrix); /// Applies the config in args. /// Creates a new NDS console if needed, @@ -113,9 +113,9 @@ private: std::unique_ptr&& ndscart, std::unique_ptr&& gbacart ) noexcept; - void drawScreenGL(); - void initOpenGL(); - void deinitOpenGL(); + //void drawScreenGL(); + //void initOpenGL(); + //void deinitOpenGL(); enum EmuStatusKind { @@ -141,7 +141,7 @@ private: }; std::atomic ContextRequest = contextRequest_None; - GL::Context* oglContext = nullptr; + /*GL::Context* oglContext = nullptr; GLuint screenVertexBuffer, screenVertexArray; GLuint screenTexture; GLuint screenShaderProgram[3]; @@ -154,7 +154,8 @@ private: int numScreens; bool filter; - int lastScreenWidth = -1, lastScreenHeight = -1; + int lastScreenWidth = -1, lastScreenHeight = -1;*/ + ScreenPanelGL* screenGL; }; class MelonApplication : public QApplication