From 78a3f9fa232467aff74e7561a65b8b78a18b24bd Mon Sep 17 00:00:00 2001 From: Wunkolo <Wunkolo@gmail.com> Date: Sat, 17 Jun 2023 11:59:45 -0700 Subject: [PATCH] Add PICA texel-format and topology types Slowly stepping the codebase towards having renderer-agnostic types and keeping the translation of PICA-types to OpenGL/VK/DX/Software/etc to the renderer-backend. --- include/PICA/regs.hpp | 49 ++++++++++++++++++++++++- include/renderer_gl/renderer_gl.hpp | 19 +++++----- include/renderer_gl/surfaces.hpp | 53 +++++----------------------- src/core/PICA/gpu.cpp | 14 +++----- src/core/PICA/regs.cpp | 8 ++--- src/core/renderer_gl/renderer_gl.cpp | 18 ++++++---- 6 files changed, 85 insertions(+), 76 deletions(-) diff --git a/include/PICA/regs.hpp b/include/PICA/regs.hpp index 0b3246db..607e72e6 100644 --- a/include/PICA/regs.hpp +++ b/include/PICA/regs.hpp @@ -127,4 +127,51 @@ namespace PICAInternalRegs { VertexShaderOpDescriptorData6 = 0x2DC, VertexShaderOpDescriptorData7 = 0x2DD, }; -} \ No newline at end of file +} + +enum class PICAColorFmt : u32 { + RGBA8 = 0, + BGR8 = 1, + RGB5A1 = 2, + RGB565 = 3, + RGBA4 = 4, + + // Technically selectable, but their function is unknown + Unknown5 = 5, + Unknown6 = 6, + Unknown7 = 7, +}; + +enum class PICADepthFmt : u32 { + Depth16 = 0, + Unknown1 = 1, // Technically selectable, but function is unknown + Depth24 = 2, + Depth24Stencil8 = 3, +}; + +// Size occupied by each pixel in bytes + +// All formats are 16BPP except for RGBA8 (32BPP) and BGR8 (24BPP) +inline constexpr usize sizePerPixel(PICAColorFmt format) { + switch (format) { + case PICAColorFmt::BGR8: return 3; + case PICAColorFmt::RGBA8: return 4; + default: return 2; + } +} + +inline constexpr usize sizePerPixel(PICADepthFmt format) { + switch (format) { + case PICADepthFmt::Depth16: return 2; + case PICADepthFmt::Depth24: return 3; + case PICADepthFmt::Depth24Stencil8: return 4; + default: return 1; // Invalid format + } +} + +enum class PICAPrimType : u32 { + TriangleList = 0, + TriangleStrip = 1, + TriangleFan = 2, + GeometryPrimitive = 3, +}; \ No newline at end of file diff --git a/include/renderer_gl/renderer_gl.hpp b/include/renderer_gl/renderer_gl.hpp index f387cb69..86ebcfe2 100644 --- a/include/renderer_gl/renderer_gl.hpp +++ b/include/renderer_gl/renderer_gl.hpp @@ -7,6 +7,7 @@ #include "opengl.hpp" #include "surface_cache.hpp" #include "textures.hpp" +#include "PICA/regs.hpp" // More circular dependencies! class GPU; @@ -46,11 +47,11 @@ class Renderer { OpenGL::uvec2 fbSize; // The size of the framebuffer (ie both the colour and depth buffer)' u32 colourBufferLoc; // Location in 3DS VRAM for the colour buffer - ColourBuffer::Formats colourBufferFormat; // Format of the colours stored in the colour buffer + PICAColorFmt colourBufferFormat; // Format of the colours stored in the colour buffer // Same for the depth/stencil buffer u32 depthBufferLoc; - DepthBuffer::Formats depthBufferFormat; + PICADepthFmt depthBufferFormat; // Dummy VAO/VBO for blitting the final output OpenGL::VertexArray dummyVAO; @@ -75,23 +76,19 @@ class Renderer { 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 displayTransfer(u32 inputAddr, u32 outputAddr, u32 inputSize, u32 outputSize, u32 flags); // Perform display transfer - void drawVertices(OpenGL::Primitives primType, std::span<const Vertex> vertices); // Draw the given vertices + void drawVertices(PICAPrimType primType, std::span<const Vertex> vertices); // Draw the given vertices void setFBSize(u32 width, u32 height) { fbSize.x() = width; fbSize.y() = height; } - void setColourFormat(ColourBuffer::Formats format) { colourBufferFormat = format; } - void setColourFormat(u32 format) { colourBufferFormat = static_cast<ColourBuffer::Formats>(format); } - - void setDepthFormat(DepthBuffer::Formats format) { depthBufferFormat = format; } - void setDepthFormat(u32 format) { - if (format == 1) { + void setColourFormat(PICAColorFmt format) { colourBufferFormat = format; } + void setDepthFormat(PICADepthFmt format) { + if (format == PICADepthFmt::Unknown1) { Helpers::panic("[PICA] Undocumented depth-stencil mode!"); } - - depthBufferFormat = static_cast<DepthBuffer::Formats>(format); + depthBufferFormat = format; } void setColourBufferLoc(u32 loc) { colourBufferLoc = loc; } diff --git a/include/renderer_gl/surfaces.hpp b/include/renderer_gl/surfaces.hpp index 680a1454..7685a765 100644 --- a/include/renderer_gl/surfaces.hpp +++ b/include/renderer_gl/surfaces.hpp @@ -1,4 +1,5 @@ #pragma once +#include "PICA/regs.hpp" #include "boost/icl/interval.hpp" #include "helpers.hpp" #include "opengl.hpp" @@ -7,18 +8,8 @@ template <typename T> using Interval = boost::icl::right_open_interval<T>; struct ColourBuffer { - enum class Formats : u32 { - RGBA8 = 0, - BGR8 = 1, - RGB5A1 = 2, - RGB565 = 3, - RGBA4 = 4, - - Trash1 = 5, Trash2 = 6, Trash3 = 7 // Technically selectable, but their function is unknown - }; - u32 location; - Formats format; + PICAColorFmt format; OpenGL::uvec2 size; bool valid; @@ -30,7 +21,7 @@ struct ColourBuffer { ColourBuffer() : valid(false) {} - ColourBuffer(u32 loc, Formats format, u32 x, u32 y, bool valid = true) + ColourBuffer(u32 loc, PICAColorFmt format, u32 x, u32 y, bool valid = true) : location(loc), format(format), size({x, y}), valid(valid) { u64 endLoc = (u64)loc + sizeInBytes(); @@ -78,31 +69,14 @@ struct ColourBuffer { size.x() == other.size.x() && size.y() == other.size.y(); } - // Size occupied by each pixel in bytes - // All formats are 16BPP except for RGBA8 (32BPP) and BGR8 (24BPP) - size_t sizePerPixel() { - switch (format) { - case Formats::BGR8: return 3; - case Formats::RGBA8: return 4; - default: return 2; - } - } - size_t sizeInBytes() { - return (size_t)size.x() * (size_t)size.y() * sizePerPixel(); + return (size_t)size.x() * (size_t)size.y() * sizePerPixel(format); } }; struct DepthBuffer { - enum class Formats : u32 { - Depth16 = 0, - Garbage = 1, - Depth24 = 2, - Depth24Stencil8 = 3 - }; - u32 location; - Formats format; + PICADepthFmt format; OpenGL::uvec2 size; // Implicitly set to the size of the framebuffer bool valid; @@ -113,7 +87,7 @@ struct DepthBuffer { DepthBuffer() : valid(false) {} - DepthBuffer(u32 loc, Formats format, u32 x, u32 y, bool valid = true) : + DepthBuffer(u32 loc, PICADepthFmt format, u32 x, u32 y, bool valid = true) : location(loc), format(format), size({x, y}), valid(valid) { u64 endLoc = (u64)loc + sizeInBytes(); @@ -122,7 +96,7 @@ struct DepthBuffer { } bool hasStencil() { - return format == Formats::Depth24Stencil8; + return format == PICADepthFmt::Depth24Stencil8; } void allocate() { @@ -167,18 +141,7 @@ struct DepthBuffer { size.x() == other.size.x() && size.y() == other.size.y(); } - // Size occupied by each pixel in bytes - size_t sizePerPixel() { - switch (format) { - case Formats::Depth16: return 2; - case Formats::Depth24: return 3; - case Formats::Depth24Stencil8: return 4; - - default: return 1; // Invalid format - } - } - size_t sizeInBytes() { - return (size_t)size.x() * (size_t)size.y() * sizePerPixel(); + return (size_t)size.x() * (size_t)size.y() * sizePerPixel(format); } }; \ No newline at end of file diff --git a/src/core/PICA/gpu.cpp b/src/core/PICA/gpu.cpp index f0e832a2..a8e79417 100644 --- a/src/core/PICA/gpu.cpp +++ b/src/core/PICA/gpu.cpp @@ -55,11 +55,12 @@ void GPU::drawArrays() { // Configures the type of primitive and the number of vertex shader outputs const u32 primConfig = regs[PICAInternalRegs::PrimitiveConfig]; - const u32 primType = Helpers::getBits<8, 2>(primConfig); - if (primType != 0 && primType != 1 && primType != 3) Helpers::panic("[PICA] Tried to draw unimplemented shape %d\n", primType); + const PICAPrimType primType = static_cast<PICAPrimType>(Helpers::getBits<8, 2>(primConfig)); + if (primType == PICAPrimType::TriangleFan) Helpers::panic("[PICA] Tried to draw unimplemented shape %d\n", primType); if (vertexCount > Renderer::vertexBufferSize) Helpers::panic("[PICA] vertexCount > vertexBufferSize"); - if ((primType == 0 && vertexCount % 3) || (primType == 1 && vertexCount < 3)) { + if ((primType == PICAPrimType::TriangleList && vertexCount % 3) || + (primType == PICAPrimType::TriangleStrip && vertexCount < 3)) { Helpers::panic("Invalid vertex count for primitive. Type: %d, vert count: %d\n", primType, vertexCount); } @@ -203,12 +204,7 @@ void GPU::drawArrays() { //printf("(u, v ) = (%f, %f)\n", vertices[i].UVs.u(), vertices[i].UVs.v()); } - // The fourth type is meant to be "Geometry primitive". TODO: Find out what that is - static constexpr std::array<OpenGL::Primitives, 4> primTypes = { - OpenGL::Triangle, OpenGL::TriangleStrip, OpenGL::TriangleFan, OpenGL::Triangle - }; - const auto shape = primTypes[primType]; - renderer.drawVertices(shape, std::span(vertices).first(vertexCount)); + renderer.drawVertices(primType, std::span(vertices).first(vertexCount)); } Vertex GPU::getImmediateModeVertex() { diff --git a/src/core/PICA/regs.cpp b/src/core/PICA/regs.cpp index 26feaf9d..9dbd584b 100644 --- a/src/core/PICA/regs.cpp +++ b/src/core/PICA/regs.cpp @@ -68,7 +68,7 @@ void GPU::writeInternalReg(u32 index, u32 value, u32 mask) { case ColourBufferFormat: { u32 format = getBits<16, 3>(value); - renderer.setColourFormat(format); + renderer.setColourFormat(static_cast<PICAColorFmt>(format)); break; } @@ -79,8 +79,8 @@ void GPU::writeInternalReg(u32 index, u32 value, u32 mask) { } case DepthBufferFormat: { - u32 fmt = value & 0x3; - renderer.setDepthFormat(fmt); + u32 format = value & 0x3; + renderer.setDepthFormat(static_cast<PICADepthFmt>(format)); break; } @@ -157,7 +157,7 @@ void GPU::writeInternalReg(u32 index, u32 value, u32 mask) { // If we've reached 3 verts, issue a draw call // Handle rendering depending on the primitive type if (immediateModeVertIndex == 3) { - renderer.drawVertices(OpenGL::Triangle, immediateModeVertices); + renderer.drawVertices(PICAPrimType::TriangleList, immediateModeVertices); switch (primType) { // Triangle or geometry primitive. Draw a triangle and discard all vertices diff --git a/src/core/renderer_gl/renderer_gl.cpp b/src/core/renderer_gl/renderer_gl.cpp index 9265e2f4..1a8f1f5b 100644 --- a/src/core/renderer_gl/renderer_gl.cpp +++ b/src/core/renderer_gl/renderer_gl.cpp @@ -144,10 +144,10 @@ void Renderer::reset() { // Init the colour/depth buffer settings to some random defaults on reset colourBufferLoc = 0; - colourBufferFormat = ColourBuffer::Formats::RGBA8; + colourBufferFormat = PICAColorFmt::RGBA8; depthBufferLoc = 0; - depthBufferFormat = DepthBuffer::Formats::Depth16; + depthBufferFormat = PICADepthFmt::Depth16; if (triangleProgram.exists()) { const auto oldProgram = OpenGL::getProgram(); @@ -264,7 +264,13 @@ void Renderer::setupBlending() { } } -void Renderer::drawVertices(OpenGL::Primitives primType, std::span<const Vertex> vertices) { +void Renderer::drawVertices(PICAPrimType primType, std::span<const Vertex> vertices) { + // The fourth type is meant to be "Geometry primitive". TODO: Find out what that is + static constexpr std::array<OpenGL::Primitives, 4> primTypes = { + OpenGL::Triangle, OpenGL::TriangleStrip, OpenGL::TriangleFan, OpenGL::Triangle + }; + const auto primitiveTopology = primTypes[static_cast<usize>(primType)]; + // Adjust alpha test if necessary const u32 alphaControl = regs[PICAInternalRegs::AlphaTestConfig]; if (alphaControl != oldAlphaControl) { @@ -352,7 +358,7 @@ void Renderer::drawVertices(OpenGL::Primitives primType, std::span<const Vertex> } vbo.bufferVertsSub(vertices); - OpenGL::draw(primType, vertices.size()); + OpenGL::draw(primitiveTopology, vertices.size()); } constexpr u32 topScreenBuffer = 0x1f000000; @@ -423,8 +429,8 @@ void Renderer::bindDepthBuffer() { tex = depthBufferCache.add(sampleBuffer).texture.m_handle; } - if (DepthBuffer::Formats::Depth24Stencil8 != depthBufferFormat) Helpers::panic("TODO: Should we remove stencil attachment?"); - auto attachment = depthBufferFormat == DepthBuffer::Formats::Depth24Stencil8 ? GL_DEPTH_STENCIL_ATTACHMENT : GL_DEPTH_ATTACHMENT; + if (PICADepthFmt::Depth24Stencil8 != depthBufferFormat) Helpers::panic("TODO: Should we remove stencil attachment?"); + auto attachment = depthBufferFormat == PICADepthFmt::Depth24Stencil8 ? GL_DEPTH_STENCIL_ATTACHMENT : GL_DEPTH_ATTACHMENT; glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, GL_TEXTURE_2D, tex, 0); }