diff --git a/CMakeLists.txt b/CMakeLists.txt index 87f8a9ed..4a6a5648 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -78,7 +78,7 @@ set(HEADER_FILES include/emulator.hpp include/helpers.hpp include/opengl.hpp inc include/loader/lz77.hpp include/fs/archive_base.hpp include/fs/archive_ncch.hpp include/services/dsp.hpp include/services/cfg.hpp include/services/region_codes.hpp include/fs/archive_save_data.hpp include/fs/archive_sdmc.hpp include/services/ptm.hpp - include/services/mic.hpp include/services/cecd.hpp + include/services/mic.hpp include/services/cecd.hpp include/renderer_gl/renderer_gl.hpp ) set(THIRD_PARTY_SOURCE_FILES third_party/imgui/imgui.cpp diff --git a/include/PICA/gpu.hpp b/include/PICA/gpu.hpp index 7a80c633..32655035 100644 --- a/include/PICA/gpu.hpp +++ b/include/PICA/gpu.hpp @@ -3,9 +3,9 @@ #include "helpers.hpp" #include "logger.hpp" #include "memory.hpp" -#include "opengl.hpp" #include "PICA/float_types.hpp" #include "PICA/shader_unit.hpp" +#include "renderer_gl/renderer_gl.hpp" class GPU { using vec4f = OpenGL::Vector; @@ -20,11 +20,6 @@ class GPU { static constexpr u32 vramSize = 6_MB; std::array regs; // GPU internal registers - struct Vertex { - OpenGL::vec4 position; - OpenGL::vec4 colour; - }; - // Read a value of type T from physical address paddr // This is necessary because vertex attribute fetching uses physical addresses template @@ -80,32 +75,15 @@ class GPU { u32 fixedAttribCount = 0; // How many attribute components have we written? When we get to 4 the attr will actually get submitted std::array fixedAttrBuff; // Buffer to hold fixed attributes in until they get submitted - // OpenGL renderer state - OpenGL::Framebuffer fbo; - OpenGL::Texture fboTexture; - OpenGL::Program triangleProgram; - OpenGL::Program displayProgram; - - OpenGL::VertexArray vao; - OpenGL::VertexBuffer vbo; - GLint alphaControlLoc = -1; - u32 oldAlphaControl = 0; - - // Dummy VAO/VBO for blitting the final output - OpenGL::VertexArray dummyVAO; - OpenGL::VertexBuffer dummyVBO; - - static constexpr u32 vertexBufferSize = 0x1000; - void drawVertices(OpenGL::Primitives primType, Vertex* vertices, u32 count); + Renderer renderer; public: GPU(Memory& mem); - void initGraphicsContext(); // Initialize graphics context - void getGraphicsContext(); // Set up the graphics context for rendering - void display(); // Display the screen contents onto our window + void initGraphicsContext() { renderer.initGraphicsContext(); } + void getGraphicsContext() { renderer.getGraphicsContext(); } + void display() { renderer.display(); } void fireDMA(u32 dest, u32 source, u32 size); - void clearBuffer(u32 startAddress, u32 endAddress, u32 value, u32 control); void reset(); // Used by the GSP GPU service for readHwRegs/writeHwRegs/writeHwRegsMasked @@ -115,4 +93,8 @@ public: // Used when processing GPU command lists u32 readInternalReg(u32 index); void writeInternalReg(u32 index, u32 value, u32 mask); + + void clearBuffer(u32 startAddress, u32 endAddress, u32 value, u32 control) { + renderer.clearBuffer(startAddress, endAddress, value, control); + } }; \ No newline at end of file diff --git a/include/logger.hpp b/include/logger.hpp index 5025bc44..cdcf2f2c 100644 --- a/include/logger.hpp +++ b/include/logger.hpp @@ -25,6 +25,7 @@ namespace Log { static Logger svcLogger; static Logger threadLogger; static Logger gpuLogger; + static Logger rendererLogger; // Service loggers static Logger aptLogger; diff --git a/include/renderer_gl/renderer_gl.hpp b/include/renderer_gl/renderer_gl.hpp new file mode 100644 index 00000000..999272e3 --- /dev/null +++ b/include/renderer_gl/renderer_gl.hpp @@ -0,0 +1,44 @@ +#pragma once +#include +#include "helpers.hpp" +#include "logger.hpp" +#include "opengl.hpp" + +struct Vertex { + OpenGL::vec4 position; + OpenGL::vec4 colour; +}; + +class Renderer { + // OpenGL renderer state + OpenGL::Framebuffer fbo; + OpenGL::Texture fboTexture; + OpenGL::Program triangleProgram; + OpenGL::Program displayProgram; + + OpenGL::VertexArray vao; + OpenGL::VertexBuffer vbo; + GLint alphaControlLoc = -1; + u32 oldAlphaControl = 0; + + // Dummy VAO/VBO for blitting the final output + OpenGL::VertexArray dummyVAO; + OpenGL::VertexBuffer dummyVBO; + + static constexpr u32 regNum = 0x300; // Number of internal PICA registers + const std::array& regs; + + MAKE_LOG_FUNCTION(log, rendererLogger) + +public: + Renderer(const std::array& internalRegs) : regs(internalRegs) {} + + void reset(); + void display(); // Display the 3DS screen contents to the window + void initGraphicsContext(); // Initialize graphics context + void getGraphicsContext(); // Set up graphics context for rendering + void clearBuffer(u32 startAddress, u32 endAddress, u32 value, u32 control); // Clear a GPU buffer in VRAM + void drawVertices(OpenGL::Primitives primType, Vertex* vertices, u32 count); // Draw the given vertices + + static constexpr u32 vertexBufferSize = 0x1500; +}; \ No newline at end of file diff --git a/src/core/PICA/gpu.cpp b/src/core/PICA/gpu.cpp index 3e02280f..0b7ad3d3 100644 --- a/src/core/PICA/gpu.cpp +++ b/src/core/PICA/gpu.cpp @@ -6,6 +6,7 @@ using namespace Floats; GPU::GPU(Memory& mem) : mem(mem) { +GPU::GPU(Memory& mem) : mem(mem), renderer(regs) { vram = new u8[vramSize]; } @@ -49,12 +50,13 @@ void GPU::drawArrays() { const u32 primType = (primConfig >> 8) & 3; if (primType != 0 && primType != 1) Helpers::panic("[PICA] Tried to draw unimplemented shape %d\n", primType); if (vertexCount > vertexBufferSize) Helpers::panic("[PICA] vertexCount > vertexBufferSize"); + if (vertexCount > Renderer::vertexBufferSize) Helpers::panic("[PICA] vertexCount > vertexBufferSize"); if ((primType == 0 && vertexCount % 3) || (primType == 1 && vertexCount < 3)) { Helpers::panic("Invalid vertex count for primitive. Type: %d, vert count: %d\n", primType, vertexCount); } - Vertex vertices[vertexBufferSize]; + Vertex vertices[Renderer::vertexBufferSize]; // Get the configuration for the index buffer, used only for indexed drawing u32 indexBufferConfig = regs[PICAInternalRegs::IndexBufferConfig]; @@ -157,7 +159,7 @@ void GPU::drawArrays() { OpenGL::Triangle, OpenGL::TriangleStrip, OpenGL::TriangleFan, OpenGL::LineStrip }; const auto shape = primTypes[primType]; - drawVertices(shape, vertices, vertexCount); + renderer.drawVertices(shape, vertices, vertexCount); } void GPU::fireDMA(u32 dest, u32 source, u32 size) { diff --git a/src/core/renderer_gl/renderer_gl.cpp b/src/core/renderer_gl/renderer_gl.cpp index 5cd63dd1..a5c18d75 100644 --- a/src/core/renderer_gl/renderer_gl.cpp +++ b/src/core/renderer_gl/renderer_gl.cpp @@ -1,7 +1,6 @@ +#include "renderer_gl/renderer_gl.hpp" #include "PICA/float_types.hpp" -#include "PICA/gpu.hpp" #include "PICA/regs.hpp" -#include "opengl.hpp" using namespace Floats; @@ -106,7 +105,7 @@ const char* displayFragmentShader = R"( } )"; -void GPU::initGraphicsContext() { +void Renderer::initGraphicsContext() { // Set up texture for top screen fboTexture.create(400, 240, GL_RGBA8); fboTexture.bind(); @@ -159,7 +158,7 @@ void GPU::initGraphicsContext() { dummyVAO.create(); } -void GPU::getGraphicsContext() { +void Renderer::getGraphicsContext() { OpenGL::disableScissor(); OpenGL::setViewport(400, 240); fbo.bind(OpenGL::DrawAndReadFramebuffer); @@ -169,7 +168,7 @@ void GPU::getGraphicsContext() { triangleProgram.use(); } -void GPU::drawVertices(OpenGL::Primitives primType, Vertex* vertices, u32 count) { +void Renderer::drawVertices(OpenGL::Primitives primType, Vertex* vertices, u32 count) { // Adjust alpha test if necessary const u32 alphaControl = regs[PICAInternalRegs::AlphaTestConfig]; if (alphaControl != oldAlphaControl) { @@ -220,7 +219,7 @@ constexpr u32 topScreenBuffer = 0x1f000000; constexpr u32 bottomScreenBuffer = 0x1f05dc00; // Quick hack to display top screen for now -void GPU::display() { +void Renderer::display() { OpenGL::disableDepth(); OpenGL::disableScissor(); OpenGL::bindScreenFramebuffer(); @@ -234,7 +233,7 @@ void GPU::display() { OpenGL::draw(OpenGL::TriangleStrip, 4); } -void GPU::clearBuffer(u32 startAddress, u32 endAddress, u32 value, u32 control) { +void Renderer::clearBuffer(u32 startAddress, u32 endAddress, u32 value, u32 control) { log("GPU: Clear buffer\nStart: %08X End: %08X\nValue: %08X Control: %08X\n", startAddress, endAddress, value, control); const float r = float((value >> 24) & 0xff) / 255.0;