diff --git a/include/PICA/draw_acceleration.hpp b/include/PICA/draw_acceleration.hpp index eec76b87..f940fc7c 100644 --- a/include/PICA/draw_acceleration.hpp +++ b/include/PICA/draw_acceleration.hpp @@ -6,13 +6,28 @@ namespace PICA { struct DrawAcceleration { + static constexpr u32 maxAttribCount = 12; + + struct AttributeInfo { + u32 offset; + + u8 type; + u8 componentCount; + bool fixed; + + std::array fixedValue; // For fixed attributes + }; + u8* vertexBuffer; u8* indexBuffer; // Minimum and maximum index in the index buffer for a draw call u16 minimumIndex, maximumIndex; + u32 totalAttribCount; u32 vertexDataSize; + std::array attributeInfo; + bool canBeAccelerated; bool indexed; }; diff --git a/src/core/PICA/draw_acceleration.cpp b/src/core/PICA/draw_acceleration.cpp index 4f3e5bdd..b96f6db4 100644 --- a/src/core/PICA/draw_acceleration.cpp +++ b/src/core/PICA/draw_acceleration.cpp @@ -7,6 +7,8 @@ void GPU::getAcceleratedDrawInfo(PICA::DrawAcceleration& accel, bool indexed) { accel.indexed = indexed; + accel.totalAttribCount = totalAttribCount; + const u32 vertexBase = ((regs[PICA::InternalRegs::VertexAttribLoc] >> 1) & 0xfffffff) * 16; const u32 vertexCount = regs[PICA::InternalRegs::VertexCountReg]; // Total # of vertices to transfer @@ -47,23 +49,60 @@ void GPU::getAcceleratedDrawInfo(PICA::DrawAcceleration& accel, bool indexed) { accel.maximumIndex = accel.minimumIndex + vertexCount - 1; } + const u64 vertexCfg = u64(regs[PICA::InternalRegs::AttribFormatLow]) | (u64(regs[PICA::InternalRegs::AttribFormatHigh]) << 32); int buffer = 0; accel.vertexDataSize = 0; for (int attrCount = 0; attrCount < totalAttribCount; attrCount++) { - bool fixedAttribute = (fixedAttribMask & (1 << attrCount)) != 0; + auto& attr = accel.attributeInfo[attrCount]; + attr.fixed = (fixedAttribMask & (1 << attrCount)) != 0; - if (!fixedAttribute) { - auto& attr = attributeInfo[buffer]; // Get information for this attribute - - if (attr.componentCount != 0) { + // Variable attribute attribute + if (!attr.fixed) { + auto& attrData = attributeInfo[buffer]; // Get information for this attribute + u64 attrCfg = attrData.getConfigFull(); // Get config1 | (config2 << 32) + u32 attributeOffset = attrData.offset; + + if (attrData.componentCount != 0) { // Size of the attribute in bytes multiplied by the total number of vertices - const u32 bytes = attr.size * vertexCount; + const u32 bytes = attrData.size * vertexCount; // Add it to the total vertex data size, aligned to 4 bytes. accel.vertexDataSize += (bytes + 3) & ~3; } + for (int i = 0; i < attrData.componentCount; i++) { + uint index = (attrCfg >> (i * 4)) & 0xf; // Get index of attribute in vertexCfg + + // Vertex attributes used as padding + // 12, 13, 14 and 15 are equivalent to 4, 8, 12 and 16 bytes of padding respectively + if (index >= 12) [[unlikely]] { + Helpers::panic("Padding attribute"); + // Align attribute address up to a 4 byte boundary + attributeOffset = (attributeOffset + 3) & -4; + attributeOffset += (index - 11) << 2; + continue; + } + + u32 attribInfo = (vertexCfg >> (index * 4)) & 0xf; + u32 attribType = attribInfo & 0x3; // Type of attribute(sbyte/ubyte/short/float) + u32 size = (attribInfo >> 2) + 1; // Total number of components + + attr.componentCount = size; + attr.offset = attributeOffset; + attr.type = attribType; + + // Size of each component based on the attribute type + static constexpr u32 sizePerComponent[4] = {1, 1, 2, 4}; + attributeOffset += size * sizePerComponent[attribType]; + } + buffer++; + } else { + vec4f& fixedAttr = shaderUnit.vs.fixedAttributes[attrCount]; + + for (int i = 0; i < 4; i++) { + attr.fixedValue[i] = fixedAttr[i].toFloat32(); + } } } diff --git a/src/core/renderer_gl/renderer_gl.cpp b/src/core/renderer_gl/renderer_gl.cpp index d0ecf443..71346f9b 100644 --- a/src/core/renderer_gl/renderer_gl.cpp +++ b/src/core/renderer_gl/renderer_gl.cpp @@ -1115,5 +1115,15 @@ void RendererGL::initUbershader(OpenGL::Program& program) { } void RendererGL::accelerateVertexUpload(ShaderUnit& shaderUnit, PICA::DrawAcceleration* accel) { + u32 buffer = 0; // Vertex buffer index for non-fixed attributes + u32 attrCount = 0; + const u32 totalAttribCount = accel->totalAttribCount; + + static constexpr GLenum attributeFormats[4] = { + GL_BYTE, // 0: Signed byte + GL_UNSIGNED_BYTE, // 1: Unsigned byte + GL_SHORT, // 2: Short + GL_FLOAT, // 3: Float + }; } \ No newline at end of file