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.
This commit is contained in:
Wunkolo 2023-07-17 10:12:38 -07:00
parent 1becbef811
commit ceff20f57f
7 changed files with 48 additions and 24 deletions

View file

@ -1,9 +1,12 @@
#pragma once #pragma once
#include <filesystem> #include <filesystem>
#include "renderer.hpp"
// Remember to initialize every field here to its default value otherwise bad things will happen // Remember to initialize every field here to its default value otherwise bad things will happen
struct EmulatorConfig { struct EmulatorConfig {
bool shaderJitEnabled = false; bool shaderJitEnabled = false;
RendererType rendererType = RendererType::OpenGL;
void load(const std::filesystem::path& path); void load(const std::filesystem::path& path);
void save(const std::filesystem::path& path); void save(const std::filesystem::path& path);

View file

@ -70,8 +70,8 @@ class Emulator {
public: public:
// Decides whether to reload or not reload the ROM when resetting. We use enum class over a plain bool for clarity. // 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 // 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 // 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
// and just resets the emu // ROM and just resets the emu
enum class ReloadOption { NoReload, Reload }; enum class ReloadOption { NoReload, Reload };
Emulator(); Emulator();

View file

@ -6,6 +6,12 @@
#include "PICA/regs.hpp" #include "PICA/regs.hpp"
#include "helpers.hpp" #include "helpers.hpp"
enum class RendererType : s8 {
// Todo: Auto = -1,
Null = 0,
OpenGL = 1,
};
class GPU; class GPU;
class Renderer { class Renderer {

View file

@ -31,6 +31,7 @@ void EmulatorConfig::load(const std::filesystem::path& path) {
if (gpuResult.is_ok()) { if (gpuResult.is_ok()) {
auto gpu = gpuResult.unwrap(); auto gpu = gpuResult.unwrap();
rendererType = RendererType(toml::find_or<toml::integer>(gpu, "Renderer", int64_t(rendererType)));
shaderJitEnabled = toml::find_or<toml::boolean>(gpu, "EnableShaderJIT", false); shaderJitEnabled = toml::find_or<toml::boolean>(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()); printf("Saving new configuration file %s\n", path.string().c_str());
} }
data["GPU"]["Renderer"] = static_cast<s8>(rendererType);
data["GPU"]["EnableShaderJIT"] = shaderJitEnabled; data["GPU"]["EnableShaderJIT"] = shaderJitEnabled;
std::ofstream file(path, std::ios::out); std::ofstream file(path, std::ios::out);

View file

@ -7,7 +7,7 @@
#include "PICA/float_types.hpp" #include "PICA/float_types.hpp"
#include "PICA/regs.hpp" #include "PICA/regs.hpp"
#include "renderer_null/renderer_null.hpp"
#ifdef PANDA3DS_ENABLE_OPENGL #ifdef PANDA3DS_ENABLE_OPENGL
#include "renderer_gl/renderer_gl.hpp" #include "renderer_gl/renderer_gl.hpp"
#endif #endif
@ -20,10 +20,22 @@ GPU::GPU(Memory& mem, EmulatorConfig& config) : mem(mem), config(config) {
vram = new u8[vramSize]; vram = new u8[vramSize];
mem.setVRAM(vram); // Give the bus a pointer to our VRAM 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 #ifdef PANDA3DS_ENABLE_OPENGL
renderer.reset(new RendererGL(*this, regs)); case RendererType::OpenGL: {
renderer.reset(new RendererGL(*this, regs));
break;
}
#endif #endif
default: {
Helpers::panic("Invalid rendering backend index: %d", static_cast<s8>(config.rendererType));
break;
}
}
} }
void GPU::reset() { void GPU::reset() {

View file

@ -26,24 +26,26 @@ Emulator::Emulator() : kernel(cpu, memory, gpu), cpu(memory, kernel), gpu(memory
} }
#ifdef PANDA3DS_ENABLE_OPENGL #ifdef PANDA3DS_ENABLE_OPENGL
// Request OpenGL 4.1 Core (Max available on MacOS) if (config.rendererType == RendererType::OpenGL) {
// MacOS gets mad if we don't explicitly demand a core profile // Request OpenGL 4.1 Core (Max available on MacOS)
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); // MacOS gets mad if we don't explicitly demand a core profile
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4); SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
window = SDL_CreateWindow("Alber", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, SDL_WINDOW_OPENGL); 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) { if (window == nullptr) {
Helpers::panic("Window creation failed: %s", SDL_GetError()); Helpers::panic("Window creation failed: %s", SDL_GetError());
} }
glContext = SDL_GL_CreateContext(window); glContext = SDL_GL_CreateContext(window);
if (glContext == nullptr) { if (glContext == nullptr) {
Helpers::panic("OpenGL context creation failed: %s", SDL_GetError()); Helpers::panic("OpenGL context creation failed: %s", SDL_GetError());
} }
if (!gladLoadGL(reinterpret_cast<GLADloadfunc>(SDL_GL_GetProcAddress))) { if (!gladLoadGL(reinterpret_cast<GLADloadfunc>(SDL_GL_GetProcAddress))) {
Helpers::panic("OpenGL init failed: %s", SDL_GetError()); Helpers::panic("OpenGL init failed: %s", SDL_GetError());
}
} }
#endif #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); reset(ReloadOption::NoReload);
} }

View file

@ -1,9 +1,9 @@
#include "emulator.hpp" #include "emulator.hpp"
int main (int argc, char *argv[]) { int main(int argc, char *argv[]) {
Emulator emu; Emulator emu;
emu.initGraphicsContext(); emu.initGraphicsContext();
if (argc > 1) { if (argc > 1) {
auto romPath = std::filesystem::current_path() / argv[1]; auto romPath = std::filesystem::current_path() / argv[1];