diff --git a/include/config.hpp b/include/config.hpp index 52be1af7..8cf00b61 100644 --- a/include/config.hpp +++ b/include/config.hpp @@ -13,17 +13,17 @@ 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 +// 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; + static constexpr ShaderMode defaultShaderMode = ShaderMode::Specialized; #else - static constexpr bool ubershaderDefault = true; + static constexpr ShaderMode defaultShaderMode = ShaderMode::Ubershader; #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..0503d2ab 100644 --- a/include/renderer.hpp +++ b/include/renderer.hpp @@ -20,6 +20,12 @@ enum class RendererType : s8 { Software = 3, }; +enum class ShaderMode { + Specialized, + Ubershader, + Hybrid, +}; + struct EmulatorConfig; class GPU; struct SDL_Window; @@ -56,6 +62,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 +85,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..fa972ecb 100644 --- a/include/renderer_gl/renderer_gl.hpp +++ b/include/renderer_gl/renderer_gl.hpp @@ -6,6 +6,7 @@ #include #include +#include "config.hpp" #include "PICA/float_types.hpp" #include "PICA/pica_frag_config.hpp" #include "PICA/pica_hash.hpp" @@ -30,7 +31,7 @@ class RendererGL final : public Renderer { OpenGL::VertexArray vao; OpenGL::VertexBuffer vbo; - bool enableUbershader = true; + ShaderMode shaderMode = EmulatorConfig::defaultShaderMode; // Data struct { @@ -111,7 +112,7 @@ class RendererGL final : public Renderer { 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 mode) override { shaderMode = mode; } 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..1480054d 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -60,9 +60,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 +141,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..075645a6 100644 --- a/src/core/renderer_gl/renderer_gl.cpp +++ b/src/core/renderer_gl/renderer_gl.cpp @@ -414,7 +414,7 @@ void RendererGL::drawVertices(PICA::PrimType primType, std::span v OpenGL::Triangle, }; - bool usingUbershader = enableUbershader; + bool usingUbershader = shaderMode == ShaderMode::Ubershader; if (usingUbershader) { 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 b099067f..6b14cbc3 100644 --- a/src/libretro_core.cpp +++ b/src/libretro_core.cpp @@ -150,7 +150,7 @@ static void configInit() { static const retro_variable values[] = { {"panda3ds_use_shader_jit", "Enable shader JIT; enabled|disabled"}, {"panda3ds_accurate_shader_mul", "Enable accurate shader multiplication; disabled|enabled"}, - {"panda3ds_use_ubershader", EmulatorConfig::ubershaderDefault ? "Use ubershaders (No stutter, maybe slower); enabled|disabled" + {"panda3ds_use_ubershader", defaultShaderMode == ShaderMode::Ubershader ? "Use ubershaders (No stutter, maybe slower); enabled|disabled" : "Use ubershaders (No stutter, maybe slower); disabled|enabled"}, {"panda3ds_use_vsync", "Enable VSync; enabled|disabled"}, {"panda3ds_dsp_emulation", "DSP emulation; Null|HLE|LLE"}, @@ -180,7 +180,7 @@ 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.shaderMode = FetchVariableBool("panda3ds_use_ubershader", EmulatorConfig::defaultShaderMode == ShaderMode::Ubershader) ? ShaderMode::Ubershader : ShaderMode::Specialized; config.forceShadergenForLights = FetchVariableBool("panda3ds_ubershader_lighting_override", true); config.lightShadergenThreshold = std::clamp(std::stoi(FetchVariable("panda3ds_ubershader_lighting_override_threshold", "1")), 1, 8); config.discordRpcEnabled = false; diff --git a/src/renderer.cpp b/src/renderer.cpp index 76c3e7a0..b9deb866 100644 --- a/src/renderer.cpp +++ b/src/renderer.cpp @@ -36,4 +36,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