diff --git a/src/frontend/qt_sdl/Config.cpp b/src/frontend/qt_sdl/Config.cpp index 302e3d3f..8109a69b 100644 --- a/src/frontend/qt_sdl/Config.cpp +++ b/src/frontend/qt_sdl/Config.cpp @@ -68,6 +68,7 @@ bool Threaded3D; int GL_ScaleFactor; bool GL_BetterPolygons; +bool GL_HiresCoordinates; bool LimitFPS; int MaxFPS; diff --git a/src/frontend/qt_sdl/EmuThread.cpp b/src/frontend/qt_sdl/EmuThread.cpp index 2ebc5408..36c17a98 100644 --- a/src/frontend/qt_sdl/EmuThread.cpp +++ b/src/frontend/qt_sdl/EmuThread.cpp @@ -51,6 +51,7 @@ #include "DSi_I2C.h" #include "GPU3D_Soft.h" #include "GPU3D_OpenGL.h" +#include "GPU3D_Compute.h" #include "Savestate.h" @@ -169,18 +170,7 @@ void EmuThread::run() //screenGL = nullptr; //videoRenderer = 0; - if (videoRenderer == 0) - { // If we're using the software renderer... - emuInstance->nds->GPU.SetRenderer3D(std::make_unique(Config::Threaded3D != 0)); - } - else - { - mainWindow->makeCurrentGL(); - - auto glrenderer = melonDS::GLRenderer::New(); - glrenderer->SetRenderSettings(Config::GL_BetterPolygons, Config::GL_ScaleFactor); - emuInstance->nds->GPU.SetRenderer3D(std::move(glrenderer)); - } + updateRenderer(); Input::Init(); @@ -301,20 +291,9 @@ void EmuThread::run() videoRenderer = 0; } - videoRenderer = useOpenGL ? Config::_3DRenderer : 0; + updateRenderer(); videoSettingsDirty = false; - - if (videoRenderer == 0) - { // If we're using the software renderer... - emuInstance->nds->GPU.SetRenderer3D(std::make_unique(Config::Threaded3D != 0)); - } - else - { - auto glrenderer = melonDS::GLRenderer::New(); - glrenderer->SetRenderSettings(Config::GL_BetterPolygons, Config::GL_ScaleFactor); - emuInstance->nds->GPU.SetRenderer3D(std::move(glrenderer)); - } } // process input and hotkeys @@ -362,7 +341,16 @@ void EmuThread::run() // emulate - u32 nlines = emuInstance->nds->RunFrame(); + u32 nlines; + if (emuInstance->nds->GPU.GetRenderer3D().NeedsShaderCompile()) + { + compileShaders(); + nlines = 1; + } + else + { + nlines = emuInstance->nds->RunFrame(); + } if (emuInstance->ndsSave) emuInstance->ndsSave->CheckFlush(); @@ -615,3 +603,53 @@ bool EmuThread::emuIsActive() { return (RunningSomething == 1); } + +void EmuThread::updateRenderer() +{ + if (videoRenderer != lastVideoRenderer) + { + printf("creating renderer %d\n", videoRenderer); + switch (videoRenderer) + { + case renderer3D_Software: + emuInstance->nds->GPU.SetRenderer3D(std::make_unique()); + break; + case renderer3D_OpenGL: + emuInstance->nds->GPU.SetRenderer3D(GLRenderer::New()); + break; + case renderer3D_OpenGLCompute: + emuInstance->nds->GPU.SetRenderer3D(ComputeRenderer::New()); + break; + default: __builtin_unreachable(); + } + } + lastVideoRenderer = videoRenderer; + + switch (videoRenderer) + { + case renderer3D_Software: + static_cast(emuInstance->nds->GPU.GetRenderer3D()).SetThreaded(Config::Threaded3D, emuInstance->nds->GPU); + break; + case renderer3D_OpenGL: + static_cast(emuInstance->nds->GPU.GetRenderer3D()).SetRenderSettings(Config::GL_BetterPolygons, Config::GL_ScaleFactor); + break; + case renderer3D_OpenGLCompute: + static_cast(emuInstance->nds->GPU.GetRenderer3D()).SetRenderSettings(Config::GL_ScaleFactor, Config::GL_HiresCoordinates); + break; + default: __builtin_unreachable(); + } +} + +void EmuThread::compileShaders() +{ + int currentShader, shadersCount; + u64 startTime = SDL_GetPerformanceCounter(); + // kind of hacky to look at the wallclock, though it is easier than + // than disabling vsync + do + { + emuInstance->nds->GPU.GetRenderer3D().ShaderCompileStep(currentShader, shadersCount); + } while (emuInstance->nds->GPU.GetRenderer3D().NeedsShaderCompile() && + (SDL_GetPerformanceCounter() - startTime) * perfCountsSec < 1.0 / 6.0); + mainWindow->osdAddMessage(0, "Compiling shader %d/%d", currentShader+1, shadersCount); +} diff --git a/src/frontend/qt_sdl/EmuThread.h b/src/frontend/qt_sdl/EmuThread.h index ff005f22..6f38b600 100644 --- a/src/frontend/qt_sdl/EmuThread.h +++ b/src/frontend/qt_sdl/EmuThread.h @@ -93,6 +93,9 @@ signals: void syncVolumeLevel(); private: + void updateRenderer(); + void compileShaders(); + enum EmuStatusKind { emuStatus_Exit, @@ -125,6 +128,10 @@ private: int autoScreenSizing; + int lastVideoRenderer = -1; + + double perfCountsSec; + bool useOpenGL; int videoRenderer; bool videoSettingsDirty; diff --git a/src/frontend/qt_sdl/Screen.cpp b/src/frontend/qt_sdl/Screen.cpp index a7c08949..bb1fffe4 100644 --- a/src/frontend/qt_sdl/Screen.cpp +++ b/src/frontend/qt_sdl/Screen.cpp @@ -739,19 +739,17 @@ void ScreenPanelGL::initOpenGL() 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::CompileVertexFragmentProgram(screenShaderProgram, + kScreenVS, kScreenFS, + "ScreenShader", + {{"vPosition", 0}, {"vTexcoord", 1}}, + {{"oColor", 0}}); - OpenGL::LinkShaderProgram(screenShaderProgram); + glUseProgram(screenShaderProgram); + glUniform1i(glGetUniformLocation(screenShaderProgram, "ScreenTex"), 0); - glUseProgram(pid); - glUniform1i(glGetUniformLocation(pid, "ScreenTex"), 0); - - screenShaderScreenSizeULoc = glGetUniformLocation(pid, "uScreenSize"); - screenShaderTransformULoc = glGetUniformLocation(pid, "uTransform"); + screenShaderScreenSizeULoc = glGetUniformLocation(screenShaderProgram, "uScreenSize"); + screenShaderTransformULoc = glGetUniformLocation(screenShaderProgram, "uTransform"); // to prevent bleeding between both parts of the screen // with bilinear filtering enabled @@ -800,20 +798,19 @@ void ScreenPanelGL::initOpenGL() glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 192, 256, 2, GL_RGBA, GL_UNSIGNED_BYTE, zeroData); - OpenGL::BuildShaderProgram(kScreenVS_OSD, kScreenFS_OSD, osdShader, "OSDShader"); + OpenGL::CompileVertexFragmentProgram(osdShader, + kScreenVS_OSD, kScreenFS_OSD, + "OSDShader", + {{"vPosition", 0}}, + {{"oColor", 0}}); - pid = osdShader[2]; - glBindAttribLocation(pid, 0, "vPosition"); - glBindFragDataLocation(pid, 0, "oColor"); + glUseProgram(osdShader); + glUniform1i(glGetUniformLocation(osdShader, "OSDTex"), 0); - OpenGL::LinkShaderProgram(osdShader); - glUseProgram(pid); - glUniform1i(glGetUniformLocation(pid, "OSDTex"), 0); - - osdScreenSizeULoc = glGetUniformLocation(pid, "uScreenSize"); - osdPosULoc = glGetUniformLocation(pid, "uOSDPos"); - osdSizeULoc = glGetUniformLocation(pid, "uOSDSize"); - osdScaleFactorULoc = glGetUniformLocation(pid, "uScaleFactor"); + osdScreenSizeULoc = glGetUniformLocation(osdShader, "uScreenSize"); + osdPosULoc = glGetUniformLocation(osdShader, "uOSDPos"); + osdSizeULoc = glGetUniformLocation(osdShader, "uOSDSize"); + osdScaleFactorULoc = glGetUniformLocation(osdShader, "uScaleFactor"); const float osdvertices[6*2] = { @@ -848,7 +845,7 @@ void ScreenPanelGL::deinitOpenGL() glDeleteVertexArrays(1, &screenVertexArray); glDeleteBuffers(1, &screenVertexBuffer); - OpenGL::DeleteShaderProgram(screenShaderProgram); + glDeleteProgram(screenShaderProgram); for (const auto& [key, tex] : osdTextures) @@ -860,7 +857,7 @@ void ScreenPanelGL::deinitOpenGL() glDeleteVertexArrays(1, &osdVertexArray); glDeleteBuffers(1, &osdVertexBuffer); - OpenGL::DeleteShaderProgram(osdShader); + glDeleteProgram(osdShader); glContext->DoneCurrent(); @@ -928,7 +925,7 @@ void ScreenPanelGL::drawScreenGL() glViewport(0, 0, w, h); - glUseProgram(screenShaderProgram[2]); + glUseProgram(screenShaderProgram); glUniform2f(screenShaderScreenSizeULoc, w / factor, h / factor); int frontbuf = emuThread->FrontBuffer; @@ -938,7 +935,7 @@ void ScreenPanelGL::drawScreenGL() if (nds->GPU.GetRenderer3D().Accelerated) { // hardware-accelerated render - static_cast(nds->GPU.GetRenderer3D()).GetCompositor().BindOutputTexture(frontbuf); + nds->GPU.GetRenderer3D().BindOutputTexture(frontbuf); } else #endif @@ -979,7 +976,7 @@ void ScreenPanelGL::drawScreenGL() u32 y = kOSDMargin; - glUseProgram(osdShader[2]); + glUseProgram(osdShader); glUniform2f(osdScreenSizeULoc, w, h); glUniform1f(osdScaleFactorULoc, factor);