diff --git a/include/PICA/gpu.hpp b/include/PICA/gpu.hpp index 330f5f27..db61a0f9 100644 --- a/include/PICA/gpu.hpp +++ b/include/PICA/gpu.hpp @@ -78,6 +78,7 @@ 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; @@ -85,6 +86,8 @@ class GPU { OpenGL::VertexArray vao; OpenGL::VertexBuffer vbo; + GLint alphaControlLoc = -1; + u32 oldAlphaControl = 0; // Dummy VAO/VBO for blitting the final output OpenGL::VertexArray dummyVAO; diff --git a/include/PICA/regs.hpp b/include/PICA/regs.hpp index be807e0d..76112d4c 100644 --- a/include/PICA/regs.hpp +++ b/include/PICA/regs.hpp @@ -2,7 +2,17 @@ namespace PICAInternalRegs { enum : u32 { + // Rasterizer registers + ViewportWidth = 0x41, + ViewportInvw = 0x42, + ViewportHeight = 0x43, + ViewportInvh = 0x44, + + DepthScale = 0x4D, + DepthOffset = 0x4E, + // Framebuffer registers + AlphaTestConfig = 0x104, DepthAndColorMask = 0x107, // Geometry pipeline registers diff --git a/include/PICA/shader.hpp b/include/PICA/shader.hpp index df30d117..cf43044a 100644 --- a/include/PICA/shader.hpp +++ b/include/PICA/shader.hpp @@ -74,7 +74,7 @@ class PICAShader { std::array loopInfo; std::array conditionalInfo; - std::array callInfo; + std::array callInfo; ShaderType type; @@ -157,7 +157,7 @@ public: std::array floatUniforms; std::array fixedAttributes; // Fixed vertex attributes - std::array attributes; // Attributes past to the shader + std::array attributes; // Attributes passed to the shader std::array outputs; PICAShader(ShaderType type) : type(type) {} @@ -177,6 +177,7 @@ public: } void uploadWord(u32 word) { + if (bufferIndex >= 511) Helpers::panic("o no"); bufferedShader[bufferIndex++] = word; bufferIndex &= 0x1ff; } diff --git a/src/core/PICA/gpu.cpp b/src/core/PICA/gpu.cpp index 6e46282a..2ed5f50c 100644 --- a/src/core/PICA/gpu.cpp +++ b/src/core/PICA/gpu.cpp @@ -131,7 +131,8 @@ void GPU::drawArrays() { std::memcpy(&vertices[i].position, &shaderUnit.vs.outputs[0], sizeof(vec4f)); std::memcpy(&vertices[i].colour, &shaderUnit.vs.outputs[1], sizeof(vec4f)); - printf("(x, y, z) = (%f, %f, %f)\n", (double)vertices[i].position.x(), (double)vertices[i].position.y(), (double)vertices[i].position.z()); + //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()); } drawVertices(OpenGL::Triangle, vertices, vertexCount); diff --git a/src/core/PICA/renderer_opengl.cpp b/src/core/PICA/renderer_opengl.cpp index 398366d5..fabf09a1 100644 --- a/src/core/PICA/renderer_opengl.cpp +++ b/src/core/PICA/renderer_opengl.cpp @@ -1,7 +1,10 @@ +#include "PICA/float_types.hpp" #include "PICA/gpu.hpp" #include "PICA/regs.hpp" #include "opengl.hpp" +using namespace Floats; + // This is all hacked up to display our first triangle const char* vertexShader = R"( @@ -24,8 +27,46 @@ const char* fragmentShader = R"( in vec4 colour; out vec4 fragColour; + uniform uint u_alphaControl; + void main() { fragColour = colour; + gl_FragDepth *= -1.0; + + if ((u_alphaControl & 1u) != 0u) { // Check if alpha test is on + uint func = (u_alphaControl >> 4u) & 7u; + float reference = float((u_alphaControl >> 8u) & 0xffu) / 255.0; + float alpha = fragColour.a; + + switch (func) { + case 0: discard; break; // Never pass alpha test + case 1: break; // Always pass alpha test + case 2: // Pass if equal + if (alpha != reference) + discard; + break; + case 3: // Pass if not equal + if (alpha == reference) + discard; + break; + case 4: // Pass if less than + if (alpha >= reference) + discard; + break; + case 5: // Pass if less than or equal + if (alpha > reference) + discard; + break; + case 6: // Pass if greater than + if (alpha <= reference) + discard; + break; + case 7: // Pass if greater than or equal + if (alpha < reference) + discard; + break; + } + } } )"; @@ -94,6 +135,10 @@ void GPU::initGraphicsContext() { OpenGL::Shader vert(vertexShader, OpenGL::Vertex); OpenGL::Shader frag(fragmentShader, OpenGL::Fragment); triangleProgram.create({ vert, frag }); + triangleProgram.use(); + + alphaControlLoc = OpenGL::uniformLocation(triangleProgram, "u_alphaControl"); + glUniform1ui(alphaControlLoc, 0); // Default alpha control to 0 OpenGL::Shader vertDisplay(displayVertexShader, OpenGL::Vertex); OpenGL::Shader fragDisplay(displayFragmentShader, OpenGL::Fragment); @@ -126,7 +171,13 @@ void GPU::getGraphicsContext() { } void GPU::drawVertices(OpenGL::Primitives primType, Vertex* vertices, u32 count) { - // Adjust depth buffer + // Adjust alpha test if necessary + const u32 alphaControl = regs[PICAInternalRegs::AlphaTestConfig]; + if (alphaControl != oldAlphaControl) { + oldAlphaControl = alphaControl; + glUniform1ui(alphaControlLoc, alphaControl); + } + const u32 depthControl = regs[PICAInternalRegs::DepthAndColorMask]; bool depthEnable = depthControl & 1; bool depthWriteEnable = (depthControl >> 12) & 1; @@ -137,8 +188,17 @@ void GPU::drawVertices(OpenGL::Primitives primType, Vertex* vertices, u32 count) GL_NEVER, GL_ALWAYS, GL_EQUAL, GL_NOTEQUAL, GL_LESS, GL_LEQUAL, GL_GREATER, GL_GEQUAL }; + f24 depthScale = f24::fromRaw(regs[PICAInternalRegs::DepthScale] & 0xffffff); + f24 depthOffset = f24::fromRaw(regs[PICAInternalRegs::DepthOffset] & 0xffffff); printf("Depth enable: %d, func: %d, writeEnable: %d\n", depthEnable, depthFunc, depthWriteEnable); + if (depthScale.toFloat32() != -1.0 || depthOffset.toFloat32() != 0.0) + Helpers::panic("TODO: Implement depth scale/offset. Remove the depth *= -1.0 from fragment shader"); + + // TODO: Actually use this + float viewportWidth = f24::fromRaw(regs[PICAInternalRegs::ViewportWidth] & 0xffffff).toFloat32() * 2.0; + float viewportHeight = f24::fromRaw(regs[PICAInternalRegs::ViewportHeight] & 0xffffff).toFloat32() * 2.0; + if (depthEnable) { OpenGL::enableDepth(); glDepthFunc(depthModes[depthFunc]); @@ -153,7 +213,6 @@ void GPU::drawVertices(OpenGL::Primitives primType, Vertex* vertices, u32 count) } if (colourMask != 0xf) Helpers::panic("[PICA] Colour mask = %X != 0xf", colourMask); - vbo.bufferVertsSub(vertices, count); OpenGL::draw(primType, count); } diff --git a/src/core/PICA/shader_interpreter.cpp b/src/core/PICA/shader_interpreter.cpp index f8071a4a..58be21d5 100644 --- a/src/core/PICA/shader_interpreter.cpp +++ b/src/core/PICA/shader_interpreter.cpp @@ -101,9 +101,9 @@ PICAShader::vec4f PICAShader::getSource(u32 source) { } PICAShader::vec4f& PICAShader::getDest(u32 dest) { - if (dest <= 0x6) { + if (dest < 0x10) { return outputs[dest]; - } else if (dest >= 0x10 && dest <= 0x1f) { // Temporary registers + } else if (dest < 0x20) { return tempRegisters[dest - 0x10]; } Helpers::panic("[PICA] Unimplemented dest: %X", dest); @@ -298,15 +298,15 @@ void PICAShader::mad(u32 instruction) { src2 = getIndexedSource(src2, idx); - auto src1Vec = getSourceSwizzled<1>(src1, operandDescriptor); - auto src2Vec = getSourceSwizzled<2>(src2, operandDescriptor); - auto src3Vec = getSourceSwizzled<3>(src3, operandDescriptor); + auto srcVec1 = getSourceSwizzled<1>(src1, operandDescriptor); + auto srcVec2 = getSourceSwizzled<2>(src2, operandDescriptor); + auto srcVec3 = getSourceSwizzled<3>(src3, operandDescriptor); auto& destVector = getDest(dest); u32 componentMask = operandDescriptor & 0xf; for (int i = 0; i < 4; i++) { if (componentMask & (1 << i)) { - destVector[3 - i] = src1Vec[3 - i] * src2Vec[3 - i] + src3Vec[3 - i]; + destVector[3 - i] = srcVec1[3 - i] * srcVec2[3 - i] + srcVec3[3 - i]; } } } @@ -374,6 +374,25 @@ void PICAShader::ifc(u32 instruction) { } } +void PICAShader::ifu(u32 instruction) { + const u32 dest = (instruction >> 10) & 0xfff; + const u32 bit = (instruction >> 22) & 0xf; // Bit of the bool uniform to check + + if (boolUniform & (1 << bit)) { + if (ifIndex >= 8) [[unlikely]] + Helpers::panic("[PICA] Overflowed IF stack"); + + const u32 num = instruction & 0xff; + + auto& block = conditionalInfo[ifIndex++]; + block.endingPC = dest; + block.newPC = dest + num; + } + else { + pc = dest; + } +} + void PICAShader::callu(u32 instruction) { const u32 bit = (instruction >> 22) & 0xf; // Bit of the bool uniform to check @@ -392,24 +411,6 @@ void PICAShader::callu(u32 instruction) { } } -void PICAShader::ifu(u32 instruction) { - const u32 dest = (instruction >> 10) & 0xfff; - const u32 bit = (instruction >> 22) & 0xf; // Bit of the bool uniform to check - - if (boolUniform & (1 << bit)) { - if (ifIndex >= 8) [[unlikely]] - Helpers::panic("[PICA] Overflowed IF stack"); - - const u32 num = instruction & 0xff; - - auto& block = conditionalInfo[ifIndex++]; - block.endingPC = dest; - block.newPC = dest + num; - } else { - pc = dest; - } -} - void PICAShader::loop(u32 instruction) { if (loopIndex >= 4) [[unlikely]] Helpers::panic("[PICA] Overflowed loop stack");