diff --git a/include/PICA/gpu.hpp b/include/PICA/gpu.hpp index 9605a177..21ad6b27 100644 --- a/include/PICA/gpu.hpp +++ b/include/PICA/gpu.hpp @@ -22,6 +22,11 @@ class GPU { std::array regs; // GPU internal registers std::array currentAttributes; // Vertex attributes before being passed to the shader + std::array immediateModeAttributes; // Vertex attributes uploaded via immediate mode submission + std::array immediateModeVertices; + uint immediateModeVertIndex; + uint immediateModeAttrIndex; // Index of the immediate mode attribute we're uploading + template void drawArrays(); @@ -53,7 +58,7 @@ class GPU { std::array fixedAttrBuff; // Buffer to hold fixed attributes in until they get submitted Renderer renderer; - + Vertex getImmediateModeVertex(); public: GPU(Memory& mem); void initGraphicsContext() { renderer.initGraphicsContext(); } diff --git a/src/core/PICA/gpu.cpp b/src/core/PICA/gpu.cpp index 0eecd21d..adec82da 100644 --- a/src/core/PICA/gpu.cpp +++ b/src/core/PICA/gpu.cpp @@ -18,6 +18,9 @@ void GPU::reset() { fixedAttribMask = 0; fixedAttribIndex = 0; fixedAttribCount = 0; + immediateModeAttrIndex = 0; + immediateModeVertIndex = 0; + fixedAttrBuff.fill(0); for (auto& e : attributeInfo) { @@ -193,7 +196,6 @@ void GPU::drawArrays() { //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()); } // The fourth type is meant to be "Geometry primitive". TODO: Find out what that is @@ -204,8 +206,24 @@ void GPU::drawArrays() { renderer.drawVertices(shape, vertices, vertexCount); } +Vertex GPU::getImmediateModeVertex() { + Vertex v; + const int totalAttrCount = (regs[PICAInternalRegs::VertexShaderAttrNum] & 0xf) + 1; + + // Copy immediate mode attributes to vertex shader unit + for (int i = 0; i < totalAttrCount; i++) { + shaderUnit.vs.inputs[i] = immediateModeAttributes[i]; + } + + // 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.UVs, &shaderUnit.vs.outputs[2], 2 * sizeof(f24)); + + return v; +} void GPU::fireDMA(u32 dest, u32 source, u32 size) { - printf("[GPU] DMA of %08X bytes from %08X to %08X\n", size, source, dest); constexpr u32 vramStart = VirtualAddrs::VramStart; constexpr u32 vramSize = VirtualAddrs::VramSize; diff --git a/src/core/PICA/regs.cpp b/src/core/PICA/regs.cpp index 214ae4cb..4310205b 100644 --- a/src/core/PICA/regs.cpp +++ b/src/core/PICA/regs.cpp @@ -104,24 +104,52 @@ void GPU::writeInternalReg(u32 index, u32 value, u32 mask) { fixedAttribCount = 0; fixedAttribIndex = value & 0xf; - if (fixedAttribIndex == 0xf) Helpers::panic("[PICA] Immediate mode vertex submission"); + if (fixedAttribIndex == 0xf) { + log("[PICA] Immediate mode vertex submission enabled"); + immediateModeAttrIndex = 0; + immediateModeVertIndex = 0; + } break; case FixedAttribData0: case FixedAttribData1: case FixedAttribData2: - if (fixedAttribIndex >= 12) Helpers::panic("[PICA] Tried to write to fixed attribute %d", fixedAttribIndex); - fixedAttrBuff[fixedAttribCount++] = value; + if (fixedAttribCount == 3) { fixedAttribCount = 0; - vec4f& attr = shaderUnit.vs.fixedAttributes[fixedAttribIndex]; + vec4f attr; // These are stored in the reverse order anyone would expect them to be in attr.x() = f24::fromRaw(fixedAttrBuff[2] & 0xffffff); attr.y() = f24::fromRaw(((fixedAttrBuff[1] & 0xffff) << 8) | (fixedAttrBuff[2] >> 24)); attr.z() = f24::fromRaw(((fixedAttrBuff[0] & 0xff) << 16) | (fixedAttrBuff[1] >> 16)); attr.w() = f24::fromRaw(fixedAttrBuff[0] >> 8); - fixedAttribIndex++; + // If the fixed attribute index is < 12, we're just writing to one of the fixed attributes + if (fixedAttribIndex < 12) [[likely]] { + shaderUnit.vs.fixedAttributes[fixedAttribIndex++] = attr; + } else if (fixedAttribIndex == 15) { // Otherwise if it's 15, we're submitting an immediate mode vertex + const uint totalAttrCount = (regs[PICAInternalRegs::VertexShaderAttrNum] & 0xf) + 1; + if (totalAttrCount <= immediateModeAttrIndex) { + printf("Broken state in the immediate mode vertex submission pipeline. Failing silently\n"); + immediateModeAttrIndex = 0; + immediateModeVertIndex = 0; + } + + immediateModeAttributes[immediateModeAttrIndex++] = attr; + if (immediateModeAttrIndex == totalAttrCount) { + Vertex v = getImmediateModeVertex(); + immediateModeAttrIndex = 0; + immediateModeVertices[immediateModeVertIndex++] = v; + + // If we've reached 3 verts, issue a draw call + if (immediateModeVertIndex == 3) { + renderer.drawVertices(OpenGL::Triangle, &immediateModeVertices[0], 3); + immediateModeVertIndex = 0; + } + } + } else { // Writing to fixed attributes 13 and 14 probably does nothing, but we'll see + log("Wrote to invalid fixed vertex attribute %d\n", fixedAttribIndex); + } } break; diff --git a/src/core/renderer_gl/renderer_gl.cpp b/src/core/renderer_gl/renderer_gl.cpp index f8858d22..90b696f7 100644 --- a/src/core/renderer_gl/renderer_gl.cpp +++ b/src/core/renderer_gl/renderer_gl.cpp @@ -51,9 +51,9 @@ const char* fragmentShader = R"( fragColour = colour; } - // Get original depth value pre-perspective by converting from [near, far] = [0, 1] to [-1, 1] + // Get original depth value by converting from [near, far] = [0, 1] to [-1, 1] // We do this by converting to [0, 2] first and subtracting 1 to go to [-1, 1] - float z_over_w = gl_FragCoord.z * 2.0f - 1.0; + float z_over_w = gl_FragCoord.z * 2.0f - 1.0f; float depth = z_over_w * u_depthScale + u_depthOffset; if (!u_depthmapEnable) // Divide z by w if depthmap enable == 0 (ie using W-buffering)