From ca89909c00026430a2e63acc570b9f7d900987ce Mon Sep 17 00:00:00 2001 From: Sky Date: Sat, 1 Jul 2023 11:22:39 -0700 Subject: [PATCH] Refactored Vertex Pipeline to always use Pica Formatted Vertex --- include/PICA/gpu.hpp | 5 ++- include/PICA/pica_vertex.hpp | 42 +++++++++++++++++ include/renderer_gl/renderer_gl.hpp | 13 +----- src/core/PICA/gpu.cpp | 67 +++++----------------------- src/core/PICA/regs.cpp | 2 +- src/core/renderer_gl/renderer_gl.cpp | 25 ++++++----- 6 files changed, 72 insertions(+), 82 deletions(-) create mode 100644 include/PICA/pica_vertex.hpp diff --git a/include/PICA/gpu.hpp b/include/PICA/gpu.hpp index 21102bc5..2b000320 100644 --- a/include/PICA/gpu.hpp +++ b/include/PICA/gpu.hpp @@ -8,6 +8,7 @@ #include "PICA/shader_unit.hpp" #include "PICA/dynapica/shader_rec.hpp" #include "renderer_gl/renderer_gl.hpp" +#include "PICA/pica_vertex.hpp" class GPU { static constexpr u32 regNum = 0x300; @@ -27,7 +28,7 @@ class GPU { std::array currentAttributes; // Vertex attributes before being passed to the shader std::array immediateModeAttributes; // Vertex attributes uploaded via immediate mode submission - std::array immediateModeVertices; + std::array immediateModeVertices; uint immediateModeVertIndex; uint immediateModeAttrIndex; // Index of the immediate mode attribute we're uploading @@ -67,7 +68,7 @@ class GPU { u32* cmdBuffCurr = nullptr; Renderer renderer; - Vertex getImmediateModeVertex(); + PicaVertex getImmediateModeVertex(); public: GPU(Memory& mem); void initGraphicsContext() { renderer.initGraphicsContext(); } diff --git a/include/PICA/pica_vertex.hpp b/include/PICA/pica_vertex.hpp new file mode 100644 index 00000000..23fc8393 --- /dev/null +++ b/include/PICA/pica_vertex.hpp @@ -0,0 +1,42 @@ +#pragma once +#include "PICA/float_types.hpp" +#include + +// A representation of the output vertex as it comes out of the vertex shader, with padding and all +struct PicaVertex { + using vec2f = std::array; + using vec3f = std::array; + using vec4f = std::array; + + union { + struct { + vec4f positions; // Vertex position + vec4f quaternion; // Quaternion specifying the normal/tangent frame (for fragment lighting) + vec4f colour; // Vertex color + vec2f texcoord0; // Texcoords for texture unit 0 (Only U and V, W is stored separately for 3D textures!) + vec2f texcoord1; // Texcoords for TU 1 + Floats::f24 texcoord0_w; // W component for texcoord 0 if using a 3D texture + u32 padding; // Unused + + vec3f view; // View vector (for fragment lighting) + u32 padding2; // Unused + vec2f texcoord2; // Texcoords for TU 2 + } s; + + // The software, non-accelerated vertex loader writes here and then reads specific components from the above struct + Floats::f24 raw[0x20]; + }; + PicaVertex() {} +}; +//Float is used here instead of Floats::f24 to ensure that Floats::f24 is properly sized for direct interpretations as a float by the render backend +#define ASSERT_POS(member, pos) static_assert(offsetof(PicaVertex, s.member) == pos * sizeof(float), "PicaVertex struct is broken!"); + +ASSERT_POS(positions, 0) +ASSERT_POS(quaternion, 4) +ASSERT_POS(colour, 8) +ASSERT_POS(texcoord0, 12) +ASSERT_POS(texcoord1, 14) +ASSERT_POS(texcoord0_w, 16) +ASSERT_POS(view, 18) +ASSERT_POS(texcoord2, 22) +#undef ASSERT_POS \ No newline at end of file diff --git a/include/renderer_gl/renderer_gl.hpp b/include/renderer_gl/renderer_gl.hpp index 90f1fd2f..636c4c65 100644 --- a/include/renderer_gl/renderer_gl.hpp +++ b/include/renderer_gl/renderer_gl.hpp @@ -9,20 +9,11 @@ #include "surface_cache.hpp" #include "textures.hpp" #include "PICA/regs.hpp" +#include "PICA/pica_vertex.hpp" // More circular dependencies! class GPU; -struct Vertex { - OpenGL::vec4 position; - OpenGL::vec4 colour; - OpenGL::vec2 texcoord0; - OpenGL::vec2 texcoord1; - Floats::f24 texcoord0_w; - u32 padding; // pad so that texcoord2 is 64-bit aligned - OpenGL::vec2 texcoord2; -}; - class Renderer { GPU& gpu; OpenGL::Program triangleProgram; @@ -95,7 +86,7 @@ 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(PICA::PrimType primType, std::span vertices); // Draw the given vertices + void drawVertices(PICA::PrimType primType, std::span vertices); // Draw the given vertices void setFBSize(u32 width, u32 height) { fbSize.x() = width; diff --git a/src/core/PICA/gpu.cpp b/src/core/PICA/gpu.cpp index 9ee574a8..e90e814e 100644 --- a/src/core/PICA/gpu.cpp +++ b/src/core/PICA/gpu.cpp @@ -10,42 +10,6 @@ using namespace Floats; -// A representation of the output vertex as it comes out of the vertex shader, with padding and all -struct OutputVertex { - using vec2f = OpenGL::Vector; - using vec3f = OpenGL::Vector; - using vec4f = OpenGL::Vector; - - union { - struct { - vec4f positions; // Vertex position - vec4f quaternion; // Quaternion specifying the normal/tangent frame (for fragment lighting) - vec4f colour; // Vertex color - vec2f texcoord0; // Texcoords for texture unit 0 (Only U and V, W is stored separately for 3D textures!) - vec2f texcoord1; // Texcoords for TU 1 - f24 texcoord0_w; // W component for texcoord 0 if using a 3D texture - u32 padding; // Unused - - vec3f view; // View vector (for fragment lighting) - u32 padding2; // Unused - vec2f texcoord2; // Texcoords for TU 2 - } s; - - // The software, non-accelerated vertex loader writes here and then reads specific components from the above struct - f24 raw[0x20]; - }; - OutputVertex() {} -}; -#define ASSERT_POS(member, pos) static_assert(offsetof(OutputVertex, s.member) == pos * sizeof(f24), "OutputVertex struct is broken!"); - -ASSERT_POS(positions, 0) -ASSERT_POS(quaternion, 4) -ASSERT_POS(colour, 8) -ASSERT_POS(texcoord0, 12) -ASSERT_POS(texcoord1, 14) -ASSERT_POS(texcoord0_w, 16) -ASSERT_POS(view, 18) -ASSERT_POS(texcoord2, 22) GPU::GPU(Memory& mem) : mem(mem), renderer(*this, regs) { vram = new u8[vramSize]; @@ -95,7 +59,7 @@ void GPU::drawArrays(bool indexed) { } } -static std::array vertices; +static std::array vertices; template void GPU::drawArrays() { @@ -283,7 +247,7 @@ void GPU::drawArrays() { shaderUnit.vs.run(); } - OutputVertex out; + PicaVertex &out=vertices[i]; // Map shader outputs to fixed function properties const u32 totalShaderOutputs = regs[PICA::InternalRegs::ShaderOutputCount] & 7; for (int i = 0; i < totalShaderOutputs; i++) { @@ -294,24 +258,13 @@ void GPU::drawArrays() { out.raw[mapping] = shaderUnit.vs.outputs[i][j]; } } - - std::memcpy(&vertices[i].position, &out.s.positions, sizeof(vec4f)); - std::memcpy(&vertices[i].colour, &out.s.colour, sizeof(vec4f)); - std::memcpy(&vertices[i].texcoord0, &out.s.texcoord0, 2 * sizeof(f24)); - std::memcpy(&vertices[i].texcoord1, &out.s.texcoord1, 2 * sizeof(f24)); - std::memcpy(&vertices[i].texcoord0_w, &out.s.texcoord0_w, sizeof(f24)); - std::memcpy(&vertices[i].texcoord2, &out.s.texcoord2, 2 * sizeof(f24)); - - //printf("(x, y, z, w) = (%f, %f, %f, %f)\n", (double)vertices[i].position.x(), (double)vertices[i].position.y(), (double)vertices[i].position.z(), (double)vertices[i].position.w()); - //printf("(r, g, b, a) = (%f, %f, %f, %f)\n", (double)vertices[i].colour.r(), (double)vertices[i].colour.g(), (double)vertices[i].colour.b(), (double)vertices[i].colour.a()); - //printf("(u, v ) = (%f, %f)\n", vertices[i].UVs.u(), vertices[i].UVs.v()); } renderer.drawVertices(primType, std::span(vertices).first(vertexCount)); } -Vertex GPU::getImmediateModeVertex() { - Vertex v; +PicaVertex GPU::getImmediateModeVertex() { + PicaVertex v; const int totalAttrCount = (regs[PICA::InternalRegs::VertexShaderAttrNum] & 0xf) + 1; // Copy immediate mode attributes to vertex shader unit @@ -321,13 +274,13 @@ Vertex GPU::getImmediateModeVertex() { // Run VS and return vertex data. TODO: Don't hardcode offsets for each attribute shaderUnit.vs.run(); - std::memcpy(&v.position, &shaderUnit.vs.outputs[0], sizeof(vec4f)); - std::memcpy(&v.colour, &shaderUnit.vs.outputs[1], sizeof(vec4f)); - std::memcpy(&v.texcoord0, &shaderUnit.vs.outputs[2], 2 * sizeof(f24)); + std::memcpy(&v.s.positions, &shaderUnit.vs.outputs[0], sizeof(vec4f)); + std::memcpy(&v.s.colour, &shaderUnit.vs.outputs[1], sizeof(vec4f)); + std::memcpy(&v.s.texcoord0, &shaderUnit.vs.outputs[2], 2 * sizeof(f24)); - printf("(x, y, z, w) = (%f, %f, %f, %f)\n", (double)v.position.x(), (double)v.position.y(), (double)v.position.z(), (double)v.position.w()); - printf("(r, g, b, a) = (%f, %f, %f, %f)\n", (double)v.colour.r(), (double)v.colour.g(), (double)v.colour.b(), (double)v.colour.a()); - printf("(u, v ) = (%f, %f)\n", v.texcoord0.u(), v.texcoord0.v()); + printf("(x, y, z, w) = (%f, %f, %f, %f)\n", (double)v.s.positions[0], (double)v.s.positions[1], (double)v.s.positions[2], (double)v.s.positions[3]); + printf("(r, g, b, a) = (%f, %f, %f, %f)\n", (double)v.s.colour[0], (double)v.s.colour[1], (double)v.s.colour[2], (double)v.s.colour[3]); + printf("(u, v ) = (%f, %f)\n", (double)v.s.texcoord0[0], (double)v.s.texcoord0[1]); return v; } diff --git a/src/core/PICA/regs.cpp b/src/core/PICA/regs.cpp index 14f61ef7..610cfe16 100644 --- a/src/core/PICA/regs.cpp +++ b/src/core/PICA/regs.cpp @@ -146,7 +146,7 @@ void GPU::writeInternalReg(u32 index, u32 value, u32 mask) { immediateModeAttributes[immediateModeAttrIndex++] = attr; if (immediateModeAttrIndex == totalAttrCount) { - Vertex v = getImmediateModeVertex(); + PicaVertex v = getImmediateModeVertex(); immediateModeAttrIndex = 0; immediateModeVertices[immediateModeVertIndex++] = v; diff --git a/src/core/renderer_gl/renderer_gl.cpp b/src/core/renderer_gl/renderer_gl.cpp index 0cbc9cbc..863ec676 100644 --- a/src/core/renderer_gl/renderer_gl.cpp +++ b/src/core/renderer_gl/renderer_gl.cpp @@ -189,15 +189,18 @@ const char* fragmentShader = R"( return result; } - + void calcLighting(out vec4 primary_color, out vec4 secondary_color){ + primary_color = vec4(vec3(0.0),1.0); + secondary_color = vec4(vec3(0.0),1.0); + } void main() { vec2 tex2UV = (u_textureConfig & (1u << 13)) != 0u ? v_texcoord1 : v_texcoord2; // TODO: what do invalid sources and disabled textures read as? // And what does the "previous combiner" source read initially? tevSources[0] = v_colour; // Primary/vertex color - tevSources[1] = vec4(vec3(0.5), 1.0); // Fragment primary color - tevSources[2] = vec4(vec3(0.5), 1.0); // Fragment secondary color + calcLighting(tevSources[1],tevSources[2]); + if ((u_textureConfig & 1u) != 0u) tevSources[3] = texture(u_tex0, v_texcoord0.xy); if ((u_textureConfig & 2u) != 0u) tevSources[4] = texture(u_tex1, v_texcoord1); if ((u_textureConfig & 4u) != 0u) tevSources[5] = texture(u_tex2, tex2UV); @@ -379,28 +382,28 @@ void Renderer::initGraphicsContext() { displayProgram.use(); glUniform1i(OpenGL::uniformLocation(displayProgram, "u_texture"), 0); // Init sampler object - vbo.createFixedSize(sizeof(Vertex) * vertexBufferSize, GL_STREAM_DRAW); + vbo.createFixedSize(sizeof(PicaVertex) * vertexBufferSize, GL_STREAM_DRAW); vbo.bind(); vao.create(); vao.bind(); // Position (x, y, z, w) attributes - vao.setAttributeFloat(0, 4, sizeof(Vertex), offsetof(Vertex, position)); + vao.setAttributeFloat(0, 4, sizeof(PicaVertex), offsetof(PicaVertex, s.positions)); vao.enableAttribute(0); // Colour attribute - vao.setAttributeFloat(1, 4, sizeof(Vertex), offsetof(Vertex, colour)); + vao.setAttributeFloat(1, 4, sizeof(PicaVertex), offsetof(PicaVertex, s.colour)); vao.enableAttribute(1); // UV 0 attribute - vao.setAttributeFloat(2, 2, sizeof(Vertex), offsetof(Vertex, texcoord0)); + vao.setAttributeFloat(2, 2, sizeof(PicaVertex), offsetof(PicaVertex, s.texcoord0)); vao.enableAttribute(2); // UV 1 attribute - vao.setAttributeFloat(3, 2, sizeof(Vertex), offsetof(Vertex, texcoord1)); + vao.setAttributeFloat(3, 2, sizeof(PicaVertex), offsetof(PicaVertex, s.texcoord1)); vao.enableAttribute(3); // UV 0 W-component attribute - vao.setAttributeFloat(4, 1, sizeof(Vertex), offsetof(Vertex, texcoord0_w)); + vao.setAttributeFloat(4, 1, sizeof(PicaVertex), offsetof(PicaVertex, s.texcoord0_w)); vao.enableAttribute(4); // UV 2 attribute - vao.setAttributeFloat(5, 2, sizeof(Vertex), offsetof(Vertex, texcoord2)); + vao.setAttributeFloat(5, 2, sizeof(PicaVertex), offsetof(PicaVertex, s.texcoord2)); vao.enableAttribute(5); dummyVBO.create(); @@ -548,7 +551,7 @@ void Renderer::bindTexturesToSlots() { } } -void Renderer::drawVertices(PICA::PrimType primType, std::span vertices) { +void Renderer::drawVertices(PICA::PrimType primType, std::span vertices) { // The fourth type is meant to be "Geometry primitive". TODO: Find out what that is static constexpr std::array primTypes = { OpenGL::Triangle, OpenGL::TriangleStrip, OpenGL::TriangleFan, OpenGL::Triangle