From b403e9a66ec97fbc2c99c3bcfae35fd299e56f0c Mon Sep 17 00:00:00 2001 From: wheremyfoodat <44909372+wheremyfoodat@users.noreply.github.com> Date: Tue, 4 Jul 2023 23:26:18 +0300 Subject: [PATCH] Start work on GL state manager object --- CMakeLists.txt | 6 +-- include/PICA/gpu.hpp | 2 +- include/emulator.hpp | 5 ++- include/gl_state.hpp | 58 +++++++++++++++++++++++++++++ include/renderer_gl/renderer_gl.hpp | 6 ++- src/core/PICA/gpu.cpp | 5 ++- src/emulator.cpp | 8 +++- src/gl_state.cpp | 16 ++++++++ 8 files changed, 95 insertions(+), 11 deletions(-) create mode 100644 include/gl_state.hpp create mode 100644 src/gl_state.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index f5edc420..7ce91389 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -83,8 +83,8 @@ else() message(FATAL_ERROR "Currently unsupported CPU architecture") endif() -set(SOURCE_FILES src/main.cpp src/emulator.cpp src/io_file.cpp src/core/CPU/cpu_dynarmic.cpp src/core/CPU/dynarmic_cycles.cpp - src/core/memory.cpp +set(SOURCE_FILES src/main.cpp src/emulator.cpp src/io_file.cpp src/gl_state.cpp src/core/CPU/cpu_dynarmic.cpp + src/core/CPU/dynarmic_cycles.cpp src/core/memory.cpp ) 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 @@ -138,7 +138,7 @@ set(HEADER_FILES include/emulator.hpp include/helpers.hpp include/opengl.hpp inc include/PICA/dynapica/shader_rec_emitter_x64.hpp include/PICA/pica_hash.hpp include/result/result.hpp include/result/result_common.hpp include/result/result_fs.hpp include/result/result_fnd.hpp include/result/result_gsp.hpp include/result/result_kernel.hpp include/result/result_os.hpp - include/crypto/aes_engine.hpp include/metaprogramming.hpp include/PICA/pica_vertex.hpp + include/crypto/aes_engine.hpp include/metaprogramming.hpp include/PICA/pica_vertex.hpp include/gl_state.hpp ) set(THIRD_PARTY_SOURCE_FILES third_party/imgui/imgui.cpp diff --git a/include/PICA/gpu.hpp b/include/PICA/gpu.hpp index ced2c557..c2fbc1c6 100644 --- a/include/PICA/gpu.hpp +++ b/include/PICA/gpu.hpp @@ -81,7 +81,7 @@ class GPU { // Set to false by the renderer when the lighting_lut is uploaded ot the GPU bool lightingLUTDirty = false; - GPU(Memory& mem); + GPU(Memory& mem, GLStateManager& gl); void initGraphicsContext() { renderer.initGraphicsContext(); } void getGraphicsContext() { renderer.getGraphicsContext(); } void display() { renderer.display(); } diff --git a/include/emulator.hpp b/include/emulator.hpp index 10279443..7cbc27b7 100644 --- a/include/emulator.hpp +++ b/include/emulator.hpp @@ -11,7 +11,7 @@ #include "crypto/aes_engine.hpp" #include "io_file.hpp" #include "memory.hpp" -#include "opengl.hpp" +#include "gl_state.hpp" enum class ROMType { None, ELF, NCSD }; @@ -22,6 +22,7 @@ class Emulator { Kernel kernel; Crypto::AESEngine aesEngine; + GLStateManager gl; SDL_Window* window; SDL_GLContext glContext; SDL_GameController* gameController; @@ -56,5 +57,5 @@ class Emulator { bool loadNCSD(const std::filesystem::path& path); bool loadELF(const std::filesystem::path& path); bool loadELF(std::ifstream& file); - void initGraphicsContext() { gpu.initGraphicsContext(); } + void initGraphicsContext(); }; diff --git a/include/gl_state.hpp b/include/gl_state.hpp new file mode 100644 index 00000000..3c9458d5 --- /dev/null +++ b/include/gl_state.hpp @@ -0,0 +1,58 @@ +#pragma once +#include + +#include "opengl.hpp" + +// GL state manager object for use in the OpenGL GPU renderer and potentially other things in the future (such as a potential ImGui GUI) +// This object is meant to help us avoid duplicate OpenGL calls (such as binding the same program twice, enabling/disabling a setting twice, etc) +// by checking if we actually *need* a state change. This is meant to avoid expensive driver calls and minimize unneeded state changes +// A lot of code is in the header file instead of the relevant source file to make sure stuff gets inlined even without LTO, and +// because this header should ideally not be getting included in too many places +// Code that does not need inlining however, like the reset() function should be in gl_state.cpp +// This state manager may not handle every aspect of OpenGL, in which case anything not handled here should just be manipulated with raw +// OpenGL/opengl.hpp calls However, anything that can be handled through the state manager should, or at least there should be an attempt to keep it +// consistent with the current GL state to avoid bugs/suboptimal code. + +// The state manager must *also* be a trivially constructible/destructible type, to ensure that no OpenGL functions get called sneakily without us +// knowing. This is important for when we want to eg add a Vulkan or misc backend. Would definitely not want to refactor all this. So we try to be as +// backend-agnostic as possible + +struct GLStateManager { + bool blendEnabled; + bool depthEnabled; + + void reset(); + void resetBlend(); + void resetDepth(); + + void enableDepth() { + if (!depthEnabled) { + depthEnabled = true; + OpenGL::enableDepth(); + } + } + + void disableDepth() { + if (depthEnabled) { + depthEnabled = false; + OpenGL::disableDepth(); + } + } + + void enableBlend() { + if (!blendEnabled) { + blendEnabled = true; + OpenGL::enableBlend(); + } + } + + void disableBlend() { + if (blendEnabled) { + blendEnabled = false; + OpenGL::disableBlend(); + } + } +}; + +static_assert(std::is_trivially_constructible(), "OpenGL State Manager class is not trivially constructible!"); +static_assert(std::is_trivially_destructible(), "OpenGL State Manager class is not trivially destructible!"); \ No newline at end of file diff --git a/include/renderer_gl/renderer_gl.hpp b/include/renderer_gl/renderer_gl.hpp index bf85904b..0bf9b0a3 100644 --- a/include/renderer_gl/renderer_gl.hpp +++ b/include/renderer_gl/renderer_gl.hpp @@ -3,9 +3,9 @@ #include #include "PICA/float_types.hpp" +#include "gl_state.hpp" #include "helpers.hpp" #include "logger.hpp" -#include "opengl.hpp" #include "surface_cache.hpp" #include "textures.hpp" #include "PICA/regs.hpp" @@ -16,6 +16,8 @@ class GPU; class Renderer { GPU& gpu; + GLStateManager& gl; + OpenGL::Program triangleProgram; OpenGL::Program displayProgram; @@ -81,7 +83,7 @@ class Renderer { void updateLightingLUT(); public: - Renderer(GPU& gpu, const std::array& internalRegs) : gpu(gpu), regs(internalRegs) {} + Renderer(GPU& gpu, GLStateManager& gl, const std::array& internalRegs) : gpu(gpu), gl(gl), regs(internalRegs) {} void reset(); void display(); // Display the 3DS screen contents to the window diff --git a/src/core/PICA/gpu.cpp b/src/core/PICA/gpu.cpp index 2efc4195..43bcf674 100644 --- a/src/core/PICA/gpu.cpp +++ b/src/core/PICA/gpu.cpp @@ -10,8 +10,9 @@ using namespace Floats; - -GPU::GPU(Memory& mem) : mem(mem), renderer(*this, regs) { +// Note: For when we have multiple backends, the GL state manager can stay here and have the constructor for the Vulkan-or-whatever renderer ignore it +// Thus, our GLStateManager being here does not negatively impact renderer-agnosticness +GPU::GPU(Memory& mem, GLStateManager& gl) : mem(mem), renderer(*this, gl, regs) { vram = new u8[vramSize]; mem.setVRAM(vram); // Give the bus a pointer to our VRAM } diff --git a/src/emulator.cpp b/src/emulator.cpp index bb96cadc..76a10698 100644 --- a/src/emulator.cpp +++ b/src/emulator.cpp @@ -1,6 +1,6 @@ #include "emulator.hpp" -Emulator::Emulator() : kernel(cpu, memory, gpu), cpu(memory, kernel), gpu(memory), memory(cpu.getTicksRef()) { +Emulator::Emulator() : kernel(cpu, memory, gpu), cpu(memory, kernel), gpu(memory, gl), memory(cpu.getTicksRef()) { if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS) < 0) { Helpers::panic("Failed to initialize SDL2"); } @@ -326,3 +326,9 @@ bool Emulator::loadELF(std::ifstream& file) { } return true; } + +// Reset our graphics context and initialize the GPU's graphics context +void Emulator::initGraphicsContext() { + gl.reset(); // TODO (For when we have multiple backends): Only do this if we are using OpenGL + gpu.initGraphicsContext(); +} \ No newline at end of file diff --git a/src/gl_state.cpp b/src/gl_state.cpp new file mode 100644 index 00000000..902971ab --- /dev/null +++ b/src/gl_state.cpp @@ -0,0 +1,16 @@ +#include "gl_state.hpp" + +void GLStateManager::resetBlend() { + blendEnabled = false; + OpenGL::disableBlend(); +} + +void GLStateManager::resetDepth() { + depthEnabled = false; + OpenGL::disableDepth(); +} + +void GLStateManager::reset() { + resetBlend(); + resetDepth(); +} \ No newline at end of file