From 6eb145d960839bd99d7d2ae1a0220ee3ebef59f1 Mon Sep 17 00:00:00 2001 From: wheremyfoodat <44909372+wheremyfoodat@users.noreply.github.com> Date: Fri, 8 Mar 2024 00:41:11 +0200 Subject: [PATCH] Implement texture filters --- include/config.hpp | 5 +++++ include/renderer.hpp | 9 ++++++++ src/config.cpp | 33 ++++++++++++++++++++++++++++ src/core/PICA/gpu.cpp | 1 + src/core/renderer_gl/renderer_gl.cpp | 10 ++++++++- 5 files changed, 57 insertions(+), 1 deletion(-) diff --git a/include/config.hpp b/include/config.hpp index 8c0d2e12..3256805a 100644 --- a/include/config.hpp +++ b/include/config.hpp @@ -16,6 +16,8 @@ struct EmulatorConfig { bool shaderJitEnabled = shaderJitDefault; bool discordRpcEnabled = false; RendererType rendererType = RendererType::OpenGL; + TextureFilter textureFilter = TextureFilter::Auto; + Audio::DSPCore::Type dspType = Audio::DSPCore::Type::Null; bool sdCardInserted = true; @@ -34,4 +36,7 @@ struct EmulatorConfig { EmulatorConfig(const std::filesystem::path& path); void load(); void save(); + + static TextureFilter textureFilterFromString(std::string str); + static std::string textureFilterToString(TextureFilter filter); }; \ No newline at end of file diff --git a/include/renderer.hpp b/include/renderer.hpp index 8888b41e..1a7e8b3f 100644 --- a/include/renderer.hpp +++ b/include/renderer.hpp @@ -19,6 +19,12 @@ enum class RendererType : s8 { Software = 3, }; +enum class TextureFilter { + Auto = 0, + ForceNearest, + ForceBilinear, +}; + class GPU; struct SDL_Window; @@ -44,6 +50,7 @@ class Renderer { // We initialize it to the 3DS resolution by default and the frontend can notify us if it changes via the setOutputSize function u32 outputWindowWidth = 400; u32 outputWindowHeight = 240 * 2; + TextureFilter filterSetting = TextureFilter::Auto; public: Renderer(GPU& gpu, const std::array& internalRegs, const std::array& externalRegs); @@ -91,4 +98,6 @@ class Renderer { outputWindowWidth = width; outputWindowHeight = height; } + + void setFiltering(TextureFilter value) { filterSetting = value; } }; diff --git a/src/config.cpp b/src/config.cpp index 299ef594..ed39ff40 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -1,5 +1,7 @@ #include "config.hpp" +#include +#include #include #include #include @@ -61,6 +63,9 @@ void EmulatorConfig::load() { shaderJitEnabled = toml::find_or(gpu, "EnableShaderJIT", shaderJitDefault); vsyncEnabled = toml::find_or(gpu, "EnableVSync", true); + + auto textureFilterName = toml::find_or(gpu, "TextureFilter", "Auto"); + textureFilter = textureFilterFromString(textureFilterName); } } @@ -122,6 +127,7 @@ void EmulatorConfig::save() { data["General"]["UsePortableBuild"] = usePortableBuild; data["GPU"]["EnableShaderJIT"] = shaderJitEnabled; data["GPU"]["Renderer"] = std::string(Renderer::typeToString(rendererType)); + data["GPU"]["TextureFilter"] = textureFilterToString(textureFilter); data["GPU"]["EnableVSync"] = vsyncEnabled; data["Audio"]["DSPEmulation"] = std::string(Audio::DSPCore::typeToString(dspType)); data["Audio"]["EnableAudio"] = audioEnabled; @@ -136,3 +142,30 @@ void EmulatorConfig::save() { file << data; file.close(); } + +std::string EmulatorConfig::textureFilterToString(TextureFilter filter) { + switch (filter) { + case TextureFilter::Auto: return "auto"; + case TextureFilter::ForceNearest: return "nearest"; + case TextureFilter::ForceBilinear: return "bilinear"; + default: Helpers::warn("Invalid texture filter type"); return "unknown"; + } +} + +TextureFilter EmulatorConfig::textureFilterFromString(std::string str) { + // Transform to lower-case to make the setting case-insensitive + std::transform(str.begin(), str.end(), str.begin(), [](unsigned char c) { return std::tolower(c); }); + + static const std::unordered_map map = { + {"auto", TextureFilter::Auto}, + {"nearest", TextureFilter::ForceNearest}, + {"bilinear", TextureFilter::ForceBilinear}, + }; + + if (auto search = map.find(str); search != map.end()) { + return search->second; + } + + printf("Invalid texture filtering type. Defaulting to auto\n"); + return TextureFilter::Auto; +} diff --git a/src/core/PICA/gpu.cpp b/src/core/PICA/gpu.cpp index c0499382..9a4fa32e 100644 --- a/src/core/PICA/gpu.cpp +++ b/src/core/PICA/gpu.cpp @@ -106,6 +106,7 @@ void GPU::reset() { externalRegs[Framebuffer1Select] = 0; renderer->reset(); + renderer->setFiltering(config.textureFilter); } // Call the correct version of drawArrays based on whether this is an indexed draw (first template parameter) diff --git a/src/core/renderer_gl/renderer_gl.cpp b/src/core/renderer_gl/renderer_gl.cpp index a11a6ffa..4d3b6ea5 100644 --- a/src/core/renderer_gl/renderer_gl.cpp +++ b/src/core/renderer_gl/renderer_gl.cpp @@ -616,7 +616,15 @@ OpenGL::Texture RendererGL::getTexture(Texture& tex) { if (buffer.has_value()) { return buffer.value().get().texture; } else { - const auto textureData = std::span{gpu.getPointerPhys(tex.location), tex.sizeInBytes()}; // Get pointer to the texture data in 3DS memory + // Get pointer to the texture data in 3DS memory + const auto textureData = std::span{gpu.getPointerPhys(tex.location), tex.sizeInBytes()}; + // Override texture filtering if necessary by adjust the texunit config before uploading the texture + if (filterSetting == TextureFilter::ForceNearest) { + tex.config &= ~(0b110); // Force nearest filtering + } else if (filterSetting == TextureFilter::ForceBilinear) { + tex.config |= 0b110; // Force bilinear + } + Texture& newTex = textureCache.add(tex); newTex.decodeTexture(textureData);