diff --git a/include/PICA/shader.hpp b/include/PICA/shader.hpp index 78de1adc..50f5d8e3 100644 --- a/include/PICA/shader.hpp +++ b/include/PICA/shader.hpp @@ -34,7 +34,8 @@ class PICAShader { std::array floatUniformBuffer; // Buffer for temporarily caching float uniform data std::array operandDescriptors; std::array tempRegisters; // General purpose registers the shader can use for temp values - OpenGL::Vector addrRegister; // Address register + OpenGL::Vector addrRegister; // Address register + u32 loopCounter; ShaderType type; vec4f getSource(u32 source); @@ -94,6 +95,8 @@ class PICAShader { return srcVector; } + u8 getIndexedSource(u32 source, u32 index); + public: std::array loadedShader; // Currently loaded & active shader std::array bufferedShader; // Shader to be transferred when the SH_CODETRANSFER_END reg gets written to diff --git a/src/core/PICA/shader_interpreter.cpp b/src/core/PICA/shader_interpreter.cpp index afdf9a07..8e9113da 100644 --- a/src/core/PICA/shader_interpreter.cpp +++ b/src/core/PICA/shader_interpreter.cpp @@ -19,6 +19,21 @@ void PICAShader::run() { } } +// Calculate the actual source value using an instruction's source field and it's respective index value +// The index value is used to apply relative addressing when index != 0 by adding one of the 3 addr registers to the +// source field, but only with the original source field is pointing at a vector uniform register +u8 PICAShader::getIndexedSource(u32 source, u32 index) { + if (source < 0x20) // No offset is applied if the source isn't pointing to a vector uniform reg + return source; + + switch (index) { + case 0: return u8(source); // No offset applied + case 1: return u8(source + addrRegister.x()); + case 2: return u8(source + addrRegister.y()); + case 3: return u8(source + loopCounter); + } +} + PICAShader::vec4f PICAShader::getSource(u32 source) { if (source < 0x10) return attributes[source]; @@ -83,11 +98,11 @@ void PICAShader::mul(u32 instruction) { void PICAShader::mov(u32 instruction) { const u32 operandDescriptor = operandDescriptors[instruction & 0x7f]; - const u32 src = (instruction >> 12) & 0x7f; + u32 src = (instruction >> 12) & 0x7f; const u32 idx = (instruction >> 19) & 3; const u32 dest = (instruction >> 21) & 0x1f; - if (idx) Helpers::panic("[PICA] MOV: idx != 0"); + src = getIndexedSource(src, idx); vec4f srcVector = getSourceSwizzled<1>(src, operandDescriptor); vec4f& destVector = getDest(dest); @@ -110,9 +125,9 @@ void PICAShader::mova(u32 instruction) { u32 componentMask = operandDescriptor & 0xf; if (componentMask & 0b1000) // x component - addrRegister.x() = static_cast(srcVector.x().toFloat32()); + addrRegister.x() = static_cast(srcVector.x().toFloat32()); if (componentMask & 0b0100) // y component - addrRegister.y() = static_cast(srcVector.y().toFloat32()); + addrRegister.y() = static_cast(srcVector.y().toFloat32()); } void PICAShader::dp4(u32 instruction) { diff --git a/src/core/PICA/shader_unit.cpp b/src/core/PICA/shader_unit.cpp index 1e8377e9..e6f6bce7 100644 --- a/src/core/PICA/shader_unit.cpp +++ b/src/core/PICA/shader_unit.cpp @@ -23,4 +23,8 @@ void PICAShader::reset() { floatUniforms.fill(zero); outputs.fill(zero); tempRegisters.fill(zero); + + addrRegister.x() = 0; + addrRegister.y() = 0; + loopCounter = 0; } \ No newline at end of file