From 1b779cafa1b14f5688859fb9567c26eef8f596e2 Mon Sep 17 00:00:00 2001 From: offtkp Date: Wed, 31 Jul 2024 01:44:55 +0300 Subject: [PATCH] Add shaderMode option and remove useUbershader option --- include/config.hpp | 10 +--------- include/renderer.hpp | 18 +++++++++++++++++- include/renderer_gl/renderer_gl.hpp | 6 +++--- src/config.cpp | 14 ++++++++++++-- src/core/PICA/gpu.cpp | 2 +- src/core/renderer_gl/renderer_gl.cpp | 6 ++++-- src/libretro_core.cpp | 4 +++- src/renderer.cpp | 27 +++++++++++++++++++++++++++ 8 files changed, 68 insertions(+), 19 deletions(-) diff --git a/include/config.hpp b/include/config.hpp index 52be1af7..4769055f 100644 --- a/include/config.hpp +++ b/include/config.hpp @@ -13,17 +13,9 @@ struct EmulatorConfig { static constexpr bool shaderJitDefault = false; #endif - // For now, use specialized shaders by default on MacOS as M1 drivers are buggy when using the ubershader, and on Android since mobile GPUs are - // horrible. On other platforms we default to ubershader + shadergen fallback for lights -#if defined(__ANDROID__) || defined(__APPLE__) - static constexpr bool ubershaderDefault = false; -#else - static constexpr bool ubershaderDefault = true; -#endif - bool shaderJitEnabled = shaderJitDefault; bool discordRpcEnabled = false; - bool useUbershaders = ubershaderDefault; + ShaderMode shaderMode = defaultShaderMode; bool accurateShaderMul = false; // Toggles whether to force shadergen when there's more than N lights active and we're using the ubershader, for better performance diff --git a/include/renderer.hpp b/include/renderer.hpp index 569a730b..d7131cde 100644 --- a/include/renderer.hpp +++ b/include/renderer.hpp @@ -21,6 +21,20 @@ enum class RendererType : s8 { }; struct EmulatorConfig; +enum class ShaderMode { + Specialized = 1, + Ubershader = 2, + Hybrid = 3, +}; + +// For now, use specialized shaders by default on MacOS as M1 drivers are buggy when using the ubershader, and on Android since mobile GPUs are +// horrible. On other platforms we default to ubershader + shadergen fallback for lights +#if defined(__ANDROID__) || defined(__APPLE__) + static constexpr ShaderMode defaultShaderMode = ShaderMode::Specialized; +#else + static constexpr ShaderMode defaultShaderMode = ShaderMode::Ubershader; +#endif + class GPU; struct SDL_Window; @@ -56,6 +70,8 @@ class Renderer { static constexpr u32 vertexBufferSize = 0x10000; static std::optional typeFromString(std::string inString); static const char* typeToString(RendererType rendererType); + static std::optional shaderModeFromString(std::string inString); + static const char* shaderModeToString(ShaderMode shaderMode); virtual void reset() = 0; virtual void display() = 0; // Display the 3DS screen contents to the window @@ -77,7 +93,7 @@ class Renderer { virtual std::string getUbershader() { return ""; } virtual void setUbershader(const std::string& shader) {} - virtual void setUbershaderSetting(bool value) {} + virtual void setShaderMode(ShaderMode shaderMode) {} // Functions for initializing the graphics context for the Qt frontend, where we don't have the convenience of SDL_Window #ifdef PANDA3DS_FRONTEND_QT diff --git a/include/renderer_gl/renderer_gl.hpp b/include/renderer_gl/renderer_gl.hpp index 42b8bba1..c10cb896 100644 --- a/include/renderer_gl/renderer_gl.hpp +++ b/include/renderer_gl/renderer_gl.hpp @@ -30,7 +30,7 @@ class RendererGL final : public Renderer { OpenGL::VertexArray vao; OpenGL::VertexBuffer vbo; - bool enableUbershader = true; + ShaderMode shaderMode = defaultShaderMode; // Data struct { @@ -110,8 +110,8 @@ class RendererGL final : public Renderer { virtual bool supportsShaderReload() override { return true; } virtual std::string getUbershader() override; virtual void setUbershader(const std::string& shader) override; - - virtual void setUbershaderSetting(bool value) override { enableUbershader = value; } + + virtual void setShaderMode(ShaderMode value) override { shaderMode = value; } std::optional getColourBuffer(u32 addr, PICA::ColorFmt format, u32 width, u32 height, bool createIfnotFound = true); diff --git a/src/config.cpp b/src/config.cpp index dae5a0ab..a4a052c8 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -6,6 +6,7 @@ #include #include "helpers.hpp" +#include "renderer.hpp" #include "toml.hpp" // Largely based on https://github.com/nba-emu/NanoBoyAdvance/blob/master/src/platform/core/src/config.cpp @@ -60,9 +61,18 @@ void EmulatorConfig::load() { rendererType = RendererType::OpenGL; } + auto shaderModeName = toml::find_or(gpu, "ShaderMode", Renderer::shaderModeToString(defaultShaderMode)); + auto configShaderMode = Renderer::shaderModeFromString(shaderModeName); + + if (configShaderMode.has_value()) { + shaderMode = configShaderMode.value(); + } else { + Helpers::warn("Invalid shader mode specified: %s\n", shaderModeName.c_str()); + shaderMode = defaultShaderMode; + } + shaderJitEnabled = toml::find_or(gpu, "EnableShaderJIT", shaderJitDefault); vsyncEnabled = toml::find_or(gpu, "EnableVSync", true); - useUbershaders = toml::find_or(gpu, "UseUbershaders", ubershaderDefault); accurateShaderMul = toml::find_or(gpu, "AccurateShaderMultiplication", false); forceShadergenForLights = toml::find_or(gpu, "ForceShadergenForLighting", true); @@ -132,7 +142,7 @@ void EmulatorConfig::save() { data["GPU"]["Renderer"] = std::string(Renderer::typeToString(rendererType)); data["GPU"]["EnableVSync"] = vsyncEnabled; data["GPU"]["AccurateShaderMultiplication"] = accurateShaderMul; - data["GPU"]["UseUbershaders"] = useUbershaders; + data["GPU"]["ShaderMode"] = std::string(Renderer::shaderModeToString(shaderMode)); data["GPU"]["ForceShadergenForLighting"] = forceShadergenForLights; data["GPU"]["ShadergenLightThreshold"] = lightShadergenThreshold; diff --git a/src/core/PICA/gpu.cpp b/src/core/PICA/gpu.cpp index fe336edc..ce97d8fa 100644 --- a/src/core/PICA/gpu.cpp +++ b/src/core/PICA/gpu.cpp @@ -117,7 +117,7 @@ void GPU::reset() { externalRegs[Framebuffer1Config] = static_cast(PICA::ColorFmt::RGB8); externalRegs[Framebuffer1Select] = 0; - renderer->setUbershaderSetting(config.useUbershaders); + renderer->setShaderMode(config.shaderMode); renderer->reset(); } diff --git a/src/core/renderer_gl/renderer_gl.cpp b/src/core/renderer_gl/renderer_gl.cpp index f8fc31e7..4913ce0c 100644 --- a/src/core/renderer_gl/renderer_gl.cpp +++ b/src/core/renderer_gl/renderer_gl.cpp @@ -414,8 +414,10 @@ void RendererGL::drawVertices(PICA::PrimType primType, std::span v OpenGL::Triangle, }; - bool usingUbershader = enableUbershader; - if (usingUbershader) { + bool usingUbershader = false; + if (shaderMode == ShaderMode::Ubershader) { + usingUbershader = true; + const bool lightsEnabled = (regs[InternalRegs::LightingEnable] & 1) != 0; const uint lightCount = (regs[InternalRegs::LightNumber] & 0x7) + 1; diff --git a/src/libretro_core.cpp b/src/libretro_core.cpp index 3e0436b8..2b22422d 100644 --- a/src/libretro_core.cpp +++ b/src/libretro_core.cpp @@ -5,6 +5,7 @@ #include #include +#include "renderer.hpp" static retro_environment_t envCallbacks; static retro_video_refresh_t videoCallbacks; @@ -179,9 +180,10 @@ static void configUpdate() { config.sdCardInserted = FetchVariableBool("panda3ds_use_virtual_sd", true); config.sdWriteProtected = FetchVariableBool("panda3ds_write_protect_virtual_sd", false); config.accurateShaderMul = FetchVariableBool("panda3ds_accurate_shader_mul", false); - config.useUbershaders = FetchVariableBool("panda3ds_use_ubershader", true); config.forceShadergenForLights = FetchVariableBool("panda3ds_ubershader_lighting_override", true); config.lightShadergenThreshold = std::clamp(std::stoi(FetchVariable("panda3ds_ubershader_lighting_override_threshold", "1")), 1, 8); + // TODO: be able to use hybrid mode + config.shaderMode = FetchVariableBool("panda3ds_use_ubershader", defaultShaderMode == ShaderMode::Ubershader) ? ShaderMode::Ubershader : ShaderMode::Specialized; config.discordRpcEnabled = false; config.save(); diff --git a/src/renderer.cpp b/src/renderer.cpp index 76c3e7a0..1542f44a 100644 --- a/src/renderer.cpp +++ b/src/renderer.cpp @@ -1,6 +1,7 @@ #include "renderer.hpp" #include +#include #include Renderer::Renderer(GPU& gpu, const std::array& internalRegs, const std::array& externalRegs) @@ -36,4 +37,30 @@ const char* Renderer::typeToString(RendererType rendererType) { case RendererType::Software: return "software"; default: return "Invalid"; } +} + +std::optional Renderer::shaderModeFromString(std::string inString) { + // Transform to lower-case to make the setting case-insensitive + std::transform(inString.begin(), inString.end(), inString.begin(), [](unsigned char c) { return std::tolower(c); }); + + static const std::unordered_map map = { + {"specialized", ShaderMode::Specialized}, {"special", ShaderMode::Specialized}, + {"ubershader", ShaderMode::Ubershader}, {"uber", ShaderMode::Ubershader}, + {"hybrid", ShaderMode::Hybrid}, {"threaded", ShaderMode::Hybrid}, {"i hate opengl context creation", ShaderMode::Hybrid}, + }; + + if (auto search = map.find(inString); search != map.end()) { + return search->second; + } + + return std::nullopt; +} + +const char* Renderer::shaderModeToString(ShaderMode shaderMode) { + switch (shaderMode) { + case ShaderMode::Specialized: return "specialized"; + case ShaderMode::Ubershader: return "ubershader"; + case ShaderMode::Hybrid: return "hybrid"; + default: return "Invalid"; + } } \ No newline at end of file