From b10e69de0e44d89d9e416b834ef1c35ab452862b Mon Sep 17 00:00:00 2001 From: Wunkolo Date: Mon, 17 Jul 2023 09:30:12 -0700 Subject: [PATCH 01/11] Add virtual deconstructor override Virtual classes need to override the base-type deconstructor so that they are proper called when referred to by their base-type. --- include/renderer_gl/renderer_gl.hpp | 1 + src/core/renderer_gl/renderer_gl.cpp | 2 ++ 2 files changed, 3 insertions(+) diff --git a/include/renderer_gl/renderer_gl.hpp b/include/renderer_gl/renderer_gl.hpp index 0e7f7bcb4..15d12ade8 100644 --- a/include/renderer_gl/renderer_gl.hpp +++ b/include/renderer_gl/renderer_gl.hpp @@ -68,6 +68,7 @@ class RendererGL final : public Renderer { public: RendererGL(GPU& gpu, const std::array& internalRegs) : Renderer(gpu, internalRegs) {} + ~RendererGL() override; void reset() override; void display() override; // Display the 3DS screen contents to the window diff --git a/src/core/renderer_gl/renderer_gl.cpp b/src/core/renderer_gl/renderer_gl.cpp index 94639f517..4d9484449 100644 --- a/src/core/renderer_gl/renderer_gl.cpp +++ b/src/core/renderer_gl/renderer_gl.cpp @@ -14,6 +14,8 @@ using namespace Floats; using namespace Helpers; using namespace PICA; +RendererGL::~RendererGL() {} + void RendererGL::reset() { depthBufferCache.reset(); colourBufferCache.reset(); From 1becbef81194306ecf0638c5cedcf72759721c37 Mon Sep 17 00:00:00 2001 From: Wunkolo Date: Mon, 17 Jul 2023 09:34:07 -0700 Subject: [PATCH 02/11] Add Null rendering backend Doesn't implement any functions, currently not selectable or configurable --- CMakeLists.txt | 5 +++-- include/renderer_null/renderer_null.hpp | 17 +++++++++++++++++ src/core/renderer_null/renderer_null.cpp | 12 ++++++++++++ 3 files changed, 32 insertions(+), 2 deletions(-) create mode 100644 include/renderer_null/renderer_null.hpp create mode 100644 src/core/renderer_null/renderer_null.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index ef98e1af6..620a1c27a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -95,7 +95,8 @@ endif() set(SOURCE_FILES src/main.cpp src/emulator.cpp src/io_file.cpp src/config.cpp src/core/CPU/cpu_dynarmic.cpp src/core/CPU/dynarmic_cycles.cpp - src/core/memory.cpp src/renderer.cpp src/httpserver.cpp src/stb_image_write.c + src/core/memory.cpp src/renderer.cpp src/core/renderer_null/renderer_null.cpp + src/httpserver.cpp src/stb_image_write.c ) set(CRYPTO_SOURCE_FILES src/core/crypto/aes_engine.cpp) set(KERNEL_SOURCE_FILES src/core/kernel/kernel.cpp src/core/kernel/resource_limits.cpp @@ -130,7 +131,7 @@ set(HEADER_FILES include/emulator.hpp include/helpers.hpp include/termcolor.hpp include/dynarmic_cp15.hpp include/kernel/resource_limits.hpp include/kernel/kernel_types.hpp include/kernel/config_mem.hpp include/services/service_manager.hpp include/services/apt.hpp include/kernel/handles.hpp include/services/hid.hpp include/services/fs.hpp - include/services/gsp_gpu.hpp include/services/gsp_lcd.hpp include/arm_defs.hpp + include/services/gsp_gpu.hpp include/services/gsp_lcd.hpp include/arm_defs.hpp include/renderer_null/renderer_null.hpp include/PICA/gpu.hpp include/PICA/regs.hpp include/services/ndm.hpp include/PICA/shader.hpp include/PICA/shader_unit.hpp include/PICA/float_types.hpp include/logger.hpp include/loader/ncch.hpp include/loader/ncsd.hpp include/io_file.hpp diff --git a/include/renderer_null/renderer_null.hpp b/include/renderer_null/renderer_null.hpp new file mode 100644 index 000000000..290807863 --- /dev/null +++ b/include/renderer_null/renderer_null.hpp @@ -0,0 +1,17 @@ +#include "renderer.hpp" + +class GPU; + +class RendererNull final : public Renderer { + public: + RendererNull(GPU& gpu, const std::array& internalRegs); + ~RendererNull() override; + + void reset() override; + void display() override; + void initGraphicsContext() override; + void clearBuffer(u32 startAddress, u32 endAddress, u32 value, u32 control) override; + void displayTransfer(u32 inputAddr, u32 outputAddr, u32 inputSize, u32 outputSize, u32 flags) override; + void drawVertices(PICA::PrimType primType, std::span vertices) override; + void screenshot(const std::string& name) override; +}; \ No newline at end of file diff --git a/src/core/renderer_null/renderer_null.cpp b/src/core/renderer_null/renderer_null.cpp new file mode 100644 index 000000000..9df2ddebf --- /dev/null +++ b/src/core/renderer_null/renderer_null.cpp @@ -0,0 +1,12 @@ +#include "renderer_null/renderer_null.hpp" + +RendererNull::RendererNull(GPU& gpu, const std::array& internalRegs) : Renderer(gpu, internalRegs) {} +RendererNull::~RendererNull() {} + +void RendererNull::reset() {} +void RendererNull::display() {} +void RendererNull::initGraphicsContext() {} +void RendererNull::clearBuffer(u32 startAddress, u32 endAddress, u32 value, u32 control) {} +void RendererNull::displayTransfer(u32 inputAddr, u32 outputAddr, u32 inputSize, u32 outputSize, u32 flags) {} +void RendererNull::drawVertices(PICA::PrimType primType, std::span vertices) {} +void RendererNull::screenshot(const std::string& name) {} \ No newline at end of file From ceff20f57fe09644b3074d1cf2b4bf68d2b6eddd Mon Sep 17 00:00:00 2001 From: Wunkolo Date: Mon, 17 Jul 2023 10:12:38 -0700 Subject: [PATCH 03/11] Add configurable Renderer backend There are still some initialization errors to work through, such as config not being initialized properly by the time GPU tries to utilize it too. Also some life-time issues. But manually forcing it to use the Null backnd successfully works and allows games to be "played" headlessly. --- include/config.hpp | 3 +++ include/emulator.hpp | 4 ++-- include/renderer.hpp | 6 ++++++ src/config.cpp | 2 ++ src/core/PICA/gpu.cpp | 18 +++++++++++++++--- src/emulator.cpp | 35 ++++++++++++++++++----------------- src/main.cpp | 6 +++--- 7 files changed, 49 insertions(+), 25 deletions(-) diff --git a/include/config.hpp b/include/config.hpp index bdb697bff..adbddd321 100644 --- a/include/config.hpp +++ b/include/config.hpp @@ -1,9 +1,12 @@ #pragma once #include +#include "renderer.hpp" + // Remember to initialize every field here to its default value otherwise bad things will happen struct EmulatorConfig { bool shaderJitEnabled = false; + RendererType rendererType = RendererType::OpenGL; void load(const std::filesystem::path& path); void save(const std::filesystem::path& path); diff --git a/include/emulator.hpp b/include/emulator.hpp index f27cd990a..5df986dc9 100644 --- a/include/emulator.hpp +++ b/include/emulator.hpp @@ -70,8 +70,8 @@ class Emulator { public: // Decides whether to reload or not reload the ROM when resetting. We use enum class over a plain bool for clarity. // If NoReload is selected, the emulator will not reload its selected ROM. This is useful for things like booting up the emulator, or resetting to - // change ROMs. If Reload is selected, the emulator will reload its selected ROM. This is useful for eg a "reset" button that keeps the current ROM - // and just resets the emu + // change ROMs. If Reload is selected, the emulator will reload its selected ROM. This is useful for eg a "reset" button that keeps the current + // ROM and just resets the emu enum class ReloadOption { NoReload, Reload }; Emulator(); diff --git a/include/renderer.hpp b/include/renderer.hpp index 5a2b40b4d..50ed1a32d 100644 --- a/include/renderer.hpp +++ b/include/renderer.hpp @@ -6,6 +6,12 @@ #include "PICA/regs.hpp" #include "helpers.hpp" +enum class RendererType : s8 { + // Todo: Auto = -1, + Null = 0, + OpenGL = 1, +}; + class GPU; class Renderer { diff --git a/src/config.cpp b/src/config.cpp index 6c9a8450f..7df73dbd3 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -31,6 +31,7 @@ void EmulatorConfig::load(const std::filesystem::path& path) { if (gpuResult.is_ok()) { auto gpu = gpuResult.unwrap(); + rendererType = RendererType(toml::find_or(gpu, "Renderer", int64_t(rendererType))); shaderJitEnabled = toml::find_or(gpu, "EnableShaderJIT", false); } } @@ -54,6 +55,7 @@ void EmulatorConfig::save(const std::filesystem::path& path) { printf("Saving new configuration file %s\n", path.string().c_str()); } + data["GPU"]["Renderer"] = static_cast(rendererType); data["GPU"]["EnableShaderJIT"] = shaderJitEnabled; std::ofstream file(path, std::ios::out); diff --git a/src/core/PICA/gpu.cpp b/src/core/PICA/gpu.cpp index 15c99c42a..487a87439 100644 --- a/src/core/PICA/gpu.cpp +++ b/src/core/PICA/gpu.cpp @@ -7,7 +7,7 @@ #include "PICA/float_types.hpp" #include "PICA/regs.hpp" - +#include "renderer_null/renderer_null.hpp" #ifdef PANDA3DS_ENABLE_OPENGL #include "renderer_gl/renderer_gl.hpp" #endif @@ -20,10 +20,22 @@ GPU::GPU(Memory& mem, EmulatorConfig& config) : mem(mem), config(config) { vram = new u8[vramSize]; mem.setVRAM(vram); // Give the bus a pointer to our VRAM - // TODO: Configurable backend + switch (config.rendererType) { + case RendererType::Null: { + renderer.reset(new RendererNull(*this, regs)); + break; + } #ifdef PANDA3DS_ENABLE_OPENGL - renderer.reset(new RendererGL(*this, regs)); + case RendererType::OpenGL: { + renderer.reset(new RendererGL(*this, regs)); + break; + } #endif + default: { + Helpers::panic("Invalid rendering backend index: %d", static_cast(config.rendererType)); + break; + } + } } void GPU::reset() { diff --git a/src/emulator.cpp b/src/emulator.cpp index 23baa258b..07ce61b53 100644 --- a/src/emulator.cpp +++ b/src/emulator.cpp @@ -26,24 +26,26 @@ Emulator::Emulator() : kernel(cpu, memory, gpu), cpu(memory, kernel), gpu(memory } #ifdef PANDA3DS_ENABLE_OPENGL - // Request OpenGL 4.1 Core (Max available on MacOS) - // MacOS gets mad if we don't explicitly demand a core profile - SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1); - window = SDL_CreateWindow("Alber", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, SDL_WINDOW_OPENGL); - - if (window == nullptr) { - Helpers::panic("Window creation failed: %s", SDL_GetError()); - } + if (config.rendererType == RendererType::OpenGL) { + // Request OpenGL 4.1 Core (Max available on MacOS) + // MacOS gets mad if we don't explicitly demand a core profile + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1); + window = SDL_CreateWindow("Alber", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, SDL_WINDOW_OPENGL); + + if (window == nullptr) { + Helpers::panic("Window creation failed: %s", SDL_GetError()); + } - glContext = SDL_GL_CreateContext(window); - if (glContext == nullptr) { - Helpers::panic("OpenGL context creation failed: %s", SDL_GetError()); - } + glContext = SDL_GL_CreateContext(window); + if (glContext == nullptr) { + Helpers::panic("OpenGL context creation failed: %s", SDL_GetError()); + } - if (!gladLoadGL(reinterpret_cast(SDL_GL_GetProcAddress))) { - Helpers::panic("OpenGL init failed: %s", SDL_GetError()); + if (!gladLoadGL(reinterpret_cast(SDL_GL_GetProcAddress))) { + Helpers::panic("OpenGL init failed: %s", SDL_GetError()); + } } #endif @@ -56,7 +58,6 @@ Emulator::Emulator() : kernel(cpu, memory, gpu), cpu(memory, kernel), gpu(memory } } - config.load(std::filesystem::current_path() / "config.toml"); reset(ReloadOption::NoReload); } diff --git a/src/main.cpp b/src/main.cpp index 1559565a8..66a04b9e5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,9 +1,9 @@ #include "emulator.hpp" -int main (int argc, char *argv[]) { - Emulator emu; +int main(int argc, char *argv[]) { + Emulator emu; - emu.initGraphicsContext(); + emu.initGraphicsContext(); if (argc > 1) { auto romPath = std::filesystem::current_path() / argv[1]; From 2c57936c500403bc3d71f1f6f1d36cc6589b9ec8 Mon Sep 17 00:00:00 2001 From: Wunkolo Date: Mon, 17 Jul 2023 10:23:10 -0700 Subject: [PATCH 04/11] Fix `EmulatorConfig` initialization order `config` was being consumed much too early before it has a chance to call `load`. This caused GPU to read weird uninitialized data, and then `load` called, and then further initialization to occur based on default data and the data inside of `config.toml`. `EmulatorConfig` needs to be loaded in first before any sort of initialization happens, by adding a new constructor so that it can be initialized sooner. --- include/config.hpp | 1 + include/emulator.hpp | 2 +- src/config.cpp | 2 ++ src/emulator.cpp | 4 +++- 4 files changed, 7 insertions(+), 2 deletions(-) diff --git a/include/config.hpp b/include/config.hpp index adbddd321..6bccdad6d 100644 --- a/include/config.hpp +++ b/include/config.hpp @@ -8,6 +8,7 @@ struct EmulatorConfig { bool shaderJitEnabled = false; RendererType rendererType = RendererType::OpenGL; + EmulatorConfig(const std::filesystem::path& path); void load(const std::filesystem::path& path); void save(const std::filesystem::path& path); }; \ No newline at end of file diff --git a/include/emulator.hpp b/include/emulator.hpp index 5df986dc9..d99eff1df 100644 --- a/include/emulator.hpp +++ b/include/emulator.hpp @@ -25,13 +25,13 @@ enum class ROMType { }; class Emulator { + EmulatorConfig config; CPU cpu; GPU gpu; Memory memory; Kernel kernel; Crypto::AESEngine aesEngine; - EmulatorConfig config; SDL_Window* window; #ifdef PANDA3DS_ENABLE_OPENGL diff --git a/src/config.cpp b/src/config.cpp index 7df73dbd3..6923204de 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -9,6 +9,8 @@ // We are legally allowed, as per the author's wish, to use the above code without any licensing restrictions // However we still want to follow the license as closely as possible and offer the proper attributions. +EmulatorConfig::EmulatorConfig(const std::filesystem::path& path) { load(path); } + void EmulatorConfig::load(const std::filesystem::path& path) { // If the configuration file does not exist, create it and return std::error_code error; diff --git a/src/emulator.cpp b/src/emulator.cpp index 07ce61b53..8ab6e06e0 100644 --- a/src/emulator.cpp +++ b/src/emulator.cpp @@ -14,7 +14,9 @@ __declspec(dllexport) DWORD AmdPowerXpressRequestHighPerformance = 1; } #endif -Emulator::Emulator() : kernel(cpu, memory, gpu), cpu(memory, kernel), gpu(memory, config), memory(cpu.getTicksRef()) { +Emulator::Emulator() + : config(std::filesystem::current_path() / "config.toml"), kernel(cpu, memory, gpu), cpu(memory, kernel), gpu(memory, config), + memory(cpu.getTicksRef()) { if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS) < 0) { Helpers::panic("Failed to initialize SDL2"); } From 528ed510c2af8905c906d92ab4d02e55d3f658cb Mon Sep 17 00:00:00 2001 From: Wunkolo Date: Mon, 17 Jul 2023 17:27:15 -0700 Subject: [PATCH 05/11] Add string-based renderer backend configuration Rather than using integer-indices, just use plaintext case-insensitive names and leave the actual enum indexes as an implementation detail. --- include/renderer.hpp | 3 +++ src/config.cpp | 16 ++++++++++++++-- src/core/PICA/gpu.cpp | 2 +- src/renderer.cpp | 20 ++++++++++++++++++++ 4 files changed, 38 insertions(+), 3 deletions(-) diff --git a/include/renderer.hpp b/include/renderer.hpp index 50ed1a32d..8381c2796 100644 --- a/include/renderer.hpp +++ b/include/renderer.hpp @@ -12,6 +12,9 @@ enum class RendererType : s8 { OpenGL = 1, }; +std::optional fromString(std::string inString); +const char* toString(RendererType rendererType); + class GPU; class Renderer { diff --git a/src/config.cpp b/src/config.cpp index 6923204de..412a96f64 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -33,7 +33,19 @@ void EmulatorConfig::load(const std::filesystem::path& path) { if (gpuResult.is_ok()) { auto gpu = gpuResult.unwrap(); - rendererType = RendererType(toml::find_or(gpu, "Renderer", int64_t(rendererType))); + // Get renderer + auto rendererResult = toml::expect(gpu, "Renderer"); + if (rendererResult.is_ok()) { + auto rendererName = rendererResult.unwrap(); + if (auto configRendererType = fromString(rendererName); configRendererType.has_value()) { + rendererType = configRendererType.value(); + } else { + Helpers::warn("Invalid renderer specified: %s\n", rendererName.c_str()); + } + } else { + Helpers::warn("Renderer not specified: %s\n", rendererResult.unwrap_err()); + } + shaderJitEnabled = toml::find_or(gpu, "EnableShaderJIT", false); } } @@ -57,7 +69,7 @@ void EmulatorConfig::save(const std::filesystem::path& path) { printf("Saving new configuration file %s\n", path.string().c_str()); } - data["GPU"]["Renderer"] = static_cast(rendererType); + data["GPU"]["Renderer"] = toString(rendererType); data["GPU"]["EnableShaderJIT"] = shaderJitEnabled; std::ofstream file(path, std::ios::out); diff --git a/src/core/PICA/gpu.cpp b/src/core/PICA/gpu.cpp index 487a87439..92ac60d9b 100644 --- a/src/core/PICA/gpu.cpp +++ b/src/core/PICA/gpu.cpp @@ -32,7 +32,7 @@ GPU::GPU(Memory& mem, EmulatorConfig& config) : mem(mem), config(config) { } #endif default: { - Helpers::panic("Invalid rendering backend index: %d", static_cast(config.rendererType)); + Helpers::panic("Rendering backend not supported: %s", toString(config.rendererType)); break; } } diff --git a/src/renderer.cpp b/src/renderer.cpp index b3da05014..a000bb856 100644 --- a/src/renderer.cpp +++ b/src/renderer.cpp @@ -1,4 +1,24 @@ #include "renderer.hpp" +std::optional fromString(std::string inString) { + // case-insensitive + std::transform(inString.begin(), inString.end(), inString.begin(), [](unsigned char c) { return std::tolower(c); }); + + if (inString == "null") + return RendererType::Null; + else if (inString == "opengl") + return RendererType::OpenGL; + + return std::nullopt; +} + +const char* toString(RendererType rendererType) { + switch (rendererType) { + case RendererType::Null: return "null"; + case RendererType::OpenGL: return "opengl"; + default: return "Invalid"; + } +} + Renderer::Renderer(GPU& gpu, const std::array& internalRegs) : gpu(gpu), regs(internalRegs) {} Renderer::~Renderer() {} \ No newline at end of file From 0b60cf690134802475bb7e5b4537137abadaf0f8 Mon Sep 17 00:00:00 2001 From: Wunkolo Date: Tue, 18 Jul 2023 10:02:07 -0700 Subject: [PATCH 06/11] Migrate RenderType string functions to static Renderer functions Also fix some IWYU build errors --- include/renderer.hpp | 6 +++--- src/config.cpp | 6 +++--- src/core/PICA/gpu.cpp | 2 +- src/renderer.cpp | 12 ++++++------ 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/include/renderer.hpp b/include/renderer.hpp index 8381c2796..6cb211033 100644 --- a/include/renderer.hpp +++ b/include/renderer.hpp @@ -1,6 +1,7 @@ #pragma once #include #include +#include #include "PICA/pica_vertex.hpp" #include "PICA/regs.hpp" @@ -12,9 +13,6 @@ enum class RendererType : s8 { OpenGL = 1, }; -std::optional fromString(std::string inString); -const char* toString(RendererType rendererType); - class GPU; class Renderer { @@ -37,6 +35,8 @@ class Renderer { virtual ~Renderer(); static constexpr u32 vertexBufferSize = 0x10000; + static std::optional typeFromString(std::string inString); + static const char* typeToString(RendererType rendererType); virtual void reset() = 0; virtual void display() = 0; // Display the 3DS screen contents to the window diff --git a/src/config.cpp b/src/config.cpp index 412a96f64..06995252d 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -37,13 +37,13 @@ void EmulatorConfig::load(const std::filesystem::path& path) { auto rendererResult = toml::expect(gpu, "Renderer"); if (rendererResult.is_ok()) { auto rendererName = rendererResult.unwrap(); - if (auto configRendererType = fromString(rendererName); configRendererType.has_value()) { + if (auto configRendererType = Renderer::typeFromString(rendererName); configRendererType.has_value()) { rendererType = configRendererType.value(); } else { Helpers::warn("Invalid renderer specified: %s\n", rendererName.c_str()); } } else { - Helpers::warn("Renderer not specified: %s\n", rendererResult.unwrap_err()); + Helpers::warn("Renderer not specified: %s\n", rendererResult.unwrap_err().c_str()); } shaderJitEnabled = toml::find_or(gpu, "EnableShaderJIT", false); @@ -69,7 +69,7 @@ void EmulatorConfig::save(const std::filesystem::path& path) { printf("Saving new configuration file %s\n", path.string().c_str()); } - data["GPU"]["Renderer"] = toString(rendererType); + data["GPU"]["Renderer"] = Renderer::typeToString(rendererType); data["GPU"]["EnableShaderJIT"] = shaderJitEnabled; std::ofstream file(path, std::ios::out); diff --git a/src/core/PICA/gpu.cpp b/src/core/PICA/gpu.cpp index 92ac60d9b..afc2601e9 100644 --- a/src/core/PICA/gpu.cpp +++ b/src/core/PICA/gpu.cpp @@ -32,7 +32,7 @@ GPU::GPU(Memory& mem, EmulatorConfig& config) : mem(mem), config(config) { } #endif default: { - Helpers::panic("Rendering backend not supported: %s", toString(config.rendererType)); + Helpers::panic("Rendering backend not supported: %s", Renderer::typeToString(config.rendererType)); break; } } diff --git a/src/renderer.cpp b/src/renderer.cpp index a000bb856..c76806fd8 100644 --- a/src/renderer.cpp +++ b/src/renderer.cpp @@ -1,6 +1,9 @@ #include "renderer.hpp" -std::optional fromString(std::string inString) { +Renderer::Renderer(GPU& gpu, const std::array& internalRegs) : gpu(gpu), regs(internalRegs) {} +Renderer::~Renderer() {} + +std::optional Renderer::typeFromString(std::string inString) { // case-insensitive std::transform(inString.begin(), inString.end(), inString.begin(), [](unsigned char c) { return std::tolower(c); }); @@ -12,13 +15,10 @@ std::optional fromString(std::string inString) { return std::nullopt; } -const char* toString(RendererType rendererType) { +const char* Renderer::typeToString(RendererType rendererType) { switch (rendererType) { case RendererType::Null: return "null"; case RendererType::OpenGL: return "opengl"; default: return "Invalid"; } -} - -Renderer::Renderer(GPU& gpu, const std::array& internalRegs) : gpu(gpu), regs(internalRegs) {} -Renderer::~Renderer() {} \ No newline at end of file +} \ No newline at end of file From 19a77c2a859cc36956b233010addb3c6d3171203 Mon Sep 17 00:00:00 2001 From: Wunkolo Date: Tue, 18 Jul 2023 10:23:55 -0700 Subject: [PATCH 07/11] Add missing `algorithm` header --- src/renderer.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/renderer.cpp b/src/renderer.cpp index c76806fd8..b1f68acf0 100644 --- a/src/renderer.cpp +++ b/src/renderer.cpp @@ -1,5 +1,7 @@ #include "renderer.hpp" +#include + Renderer::Renderer(GPU& gpu, const std::array& internalRegs) : gpu(gpu), regs(internalRegs) {} Renderer::~Renderer() {} From 77b0382d0cd7a8d05b0b5929d9d6ba2174f85386 Mon Sep 17 00:00:00 2001 From: wheremyfoodat <44909372+wheremyfoodat@users.noreply.github.com> Date: Tue, 18 Jul 2023 22:23:28 +0300 Subject: [PATCH 08/11] Cleanup, C string -> std::string --- include/renderer.hpp | 4 +++- src/config.cpp | 20 +++++++++----------- src/renderer.cpp | 3 ++- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/include/renderer.hpp b/include/renderer.hpp index 6cb211033..05f418db6 100644 --- a/include/renderer.hpp +++ b/include/renderer.hpp @@ -1,6 +1,7 @@ #pragma once #include #include +#include #include #include "PICA/pica_vertex.hpp" @@ -11,6 +12,7 @@ enum class RendererType : s8 { // Todo: Auto = -1, Null = 0, OpenGL = 1, + Vulkan = 2, }; class GPU; @@ -36,7 +38,7 @@ class Renderer { static constexpr u32 vertexBufferSize = 0x10000; static std::optional typeFromString(std::string inString); - static const char* typeToString(RendererType rendererType); + static std::string typeToString(RendererType rendererType); virtual void reset() = 0; virtual void display() = 0; // Display the 3DS screen contents to the window diff --git a/src/config.cpp b/src/config.cpp index 06995252d..9fdbe17fb 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -34,16 +34,14 @@ void EmulatorConfig::load(const std::filesystem::path& path) { auto gpu = gpuResult.unwrap(); // Get renderer - auto rendererResult = toml::expect(gpu, "Renderer"); - if (rendererResult.is_ok()) { - auto rendererName = rendererResult.unwrap(); - if (auto configRendererType = Renderer::typeFromString(rendererName); configRendererType.has_value()) { - rendererType = configRendererType.value(); - } else { - Helpers::warn("Invalid renderer specified: %s\n", rendererName.c_str()); - } + auto rendererName = toml::find_or(gpu, "Renderer", "OpenGL"); + auto configRendererType = Renderer::typeFromString(rendererName); + + if (configRendererType.has_value()) { + rendererType = configRendererType.value(); } else { - Helpers::warn("Renderer not specified: %s\n", rendererResult.unwrap_err().c_str()); + Helpers::warn("Invalid renderer specified: %s\n", rendererName.c_str()); + rendererType = RendererType::OpenGL; } shaderJitEnabled = toml::find_or(gpu, "EnableShaderJIT", false); @@ -58,7 +56,7 @@ void EmulatorConfig::save(const std::filesystem::path& path) { if (std::filesystem::exists(path, error)) { try { data = toml::parse(path); - } catch (std::exception& ex) { + } catch (const std::exception& ex) { Helpers::warn("Exception trying to parse config file. Exception: %s\n", ex.what()); return; } @@ -69,8 +67,8 @@ void EmulatorConfig::save(const std::filesystem::path& path) { printf("Saving new configuration file %s\n", path.string().c_str()); } - data["GPU"]["Renderer"] = Renderer::typeToString(rendererType); data["GPU"]["EnableShaderJIT"] = shaderJitEnabled; + data["GPU"]["Renderer"] = Renderer::typeToString(rendererType); std::ofstream file(path, std::ios::out); file << data; diff --git a/src/renderer.cpp b/src/renderer.cpp index b1f68acf0..a2970a3d8 100644 --- a/src/renderer.cpp +++ b/src/renderer.cpp @@ -17,10 +17,11 @@ std::optional Renderer::typeFromString(std::string inString) { return std::nullopt; } -const char* Renderer::typeToString(RendererType rendererType) { +std::string Renderer::typeToString(RendererType rendererType) { switch (rendererType) { case RendererType::Null: return "null"; case RendererType::OpenGL: return "opengl"; + case RendererType::Vulkan: return "vk"; default: return "Invalid"; } } \ No newline at end of file From 6860ccc396837ef0ba1f7de7754b26ab1c4a69b4 Mon Sep 17 00:00:00 2001 From: wheremyfoodat <44909372+wheremyfoodat@users.noreply.github.com> Date: Tue, 18 Jul 2023 22:30:58 +0300 Subject: [PATCH 09/11] Dummy-proof renderer config --- src/renderer.cpp | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/renderer.cpp b/src/renderer.cpp index a2970a3d8..b69875382 100644 --- a/src/renderer.cpp +++ b/src/renderer.cpp @@ -1,18 +1,26 @@ #include "renderer.hpp" #include +#include Renderer::Renderer(GPU& gpu, const std::array& internalRegs) : gpu(gpu), regs(internalRegs) {} Renderer::~Renderer() {} std::optional Renderer::typeFromString(std::string inString) { - // case-insensitive + // 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); }); - if (inString == "null") - return RendererType::Null; - else if (inString == "opengl") - return RendererType::OpenGL; + // Huge table of possible names and misspellings + // Please stop misspelling Vulkan as Vulcan + static const std::unordered_map map = { + {"null", RendererType::Null}, {"nil", RendererType::Null}, {"none", RendererType::Null}, + {"gl", RendererType::OpenGL}, {"ogl", RendererType::OpenGL}, {"opengl", RendererType::OpenGL}, + {"vk", RendererType::Vulkan}, {"vulkan", RendererType::Vulkan}, {"vulcan", RendererType::Vulkan}, + }; + + if (auto search = map.find(inString); search != map.end()) { + return search->second; + } return std::nullopt; } From 31d1c6ff3f272540692db48464b31b72bd67665d Mon Sep 17 00:00:00 2001 From: wheremyfoodat <44909372+wheremyfoodat@users.noreply.github.com> Date: Tue, 18 Jul 2023 22:33:59 +0300 Subject: [PATCH 10/11] Bonk people who select Vulkan as the renderer --- src/core/PICA/gpu.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/core/PICA/gpu.cpp b/src/core/PICA/gpu.cpp index afc2601e9..d75b0ae58 100644 --- a/src/core/PICA/gpu.cpp +++ b/src/core/PICA/gpu.cpp @@ -31,6 +31,11 @@ GPU::GPU(Memory& mem, EmulatorConfig& config) : mem(mem), config(config) { break; } #endif + + case RendererType::Vulkan: { + Helpers::panic("Vulkan is not supported yet, please pick another renderer"); + } + default: { Helpers::panic("Rendering backend not supported: %s", Renderer::typeToString(config.rendererType)); break; From c339c7d1c511a96e6a5e57e50d36f1318b5f0da2 Mon Sep 17 00:00:00 2001 From: wheremyfoodat <44909372+wheremyfoodat@users.noreply.github.com> Date: Tue, 18 Jul 2023 22:45:55 +0300 Subject: [PATCH 11/11] Bonk --- include/renderer.hpp | 3 +-- src/config.cpp | 3 ++- src/renderer.cpp | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/renderer.hpp b/include/renderer.hpp index 05f418db6..e14afcea1 100644 --- a/include/renderer.hpp +++ b/include/renderer.hpp @@ -1,7 +1,6 @@ #pragma once #include #include -#include #include #include "PICA/pica_vertex.hpp" @@ -38,7 +37,7 @@ class Renderer { static constexpr u32 vertexBufferSize = 0x10000; static std::optional typeFromString(std::string inString); - static std::string typeToString(RendererType rendererType); + static const char* typeToString(RendererType rendererType); virtual void reset() = 0; virtual void display() = 0; // Display the 3DS screen contents to the window diff --git a/src/config.cpp b/src/config.cpp index 9fdbe17fb..a5e9330c7 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -1,6 +1,7 @@ #include "config.hpp" #include +#include #include "helpers.hpp" #include "toml.hpp" @@ -68,7 +69,7 @@ void EmulatorConfig::save(const std::filesystem::path& path) { } data["GPU"]["EnableShaderJIT"] = shaderJitEnabled; - data["GPU"]["Renderer"] = Renderer::typeToString(rendererType); + data["GPU"]["Renderer"] = std::string(Renderer::typeToString(rendererType)); std::ofstream file(path, std::ios::out); file << data; diff --git a/src/renderer.cpp b/src/renderer.cpp index b69875382..3ba29aeaf 100644 --- a/src/renderer.cpp +++ b/src/renderer.cpp @@ -25,11 +25,11 @@ std::optional Renderer::typeFromString(std::string inString) { return std::nullopt; } -std::string Renderer::typeToString(RendererType rendererType) { +const char* Renderer::typeToString(RendererType rendererType) { switch (rendererType) { case RendererType::Null: return "null"; case RendererType::OpenGL: return "opengl"; - case RendererType::Vulkan: return "vk"; + case RendererType::Vulkan: return "vulkan"; default: return "Invalid"; } } \ No newline at end of file