diff --git a/include/PICA/shader.hpp b/include/PICA/shader.hpp index 8c0ca499..b8018718 100644 --- a/include/PICA/shader.hpp +++ b/include/PICA/shader.hpp @@ -128,14 +128,14 @@ class PICAShader { bool negate; if constexpr (sourceIndex == 1) { // SRC1 - negate = ((opDescriptor >> 4) & 1) != 0; - compSwizzle = (opDescriptor >> 5) & 0xff; + negate = (Helpers::getBit<4>(opDescriptor)) != 0; + compSwizzle = Helpers::getBits<5, 8>(opDescriptor); } else if constexpr (sourceIndex == 2) { // SRC2 - negate = ((opDescriptor >> 13) & 1) != 0; - compSwizzle = (opDescriptor >> 14) & 0xff; + negate = (Helpers::getBit<13>(opDescriptor)) != 0; + compSwizzle = Helpers::getBits<14, 8>(opDescriptor); } else if constexpr (sourceIndex == 3) { // SRC3 - negate = ((opDescriptor >> 22) & 1) != 0; - compSwizzle = (opDescriptor >> 23) & 0xff; + negate = (Helpers::getBit<22>(opDescriptor)) != 0; + compSwizzle = Helpers::getBits<23, 8>(opDescriptor); } // Iterate through every component of the swizzled vector in reverse order @@ -239,9 +239,9 @@ public: void uploadIntUniform(int index, u32 word) { auto& u = intUniforms[index]; u.x() = word & 0xff; - u.y() = (word >> 8) & 0xff; - u.z() = (word >> 16) & 0xff; - u.w() = (word >> 24) & 0xff; + u.y() = Helpers::getBits<8, 8>(word); + u.z() = Helpers::getBits<16, 8>(word); + u.w() = Helpers::getBits<24, 8>(word); } void run(); diff --git a/include/helpers.hpp b/include/helpers.hpp index ee1a1dac..f0a0f5ae 100644 --- a/include/helpers.hpp +++ b/include/helpers.hpp @@ -1,5 +1,6 @@ #pragma once #include +#include #include #include #include @@ -90,6 +91,30 @@ namespace Helpers { return (u16) (temp << bitsToShift >> bitsToShift); } + /// Create a mask with `count` number of one bits. + template + static constexpr T ones () { + constexpr usize bitsize = CHAR_BIT * sizeof(T); + static_assert(count <= bitsize, "count larger than bitsize of T"); + + if (count == T(0)) { + return T(0); + } + return static_cast(~static_cast(0)) >> (bitsize - count); + } + + /// Extract bits from an integer-type + template + static constexpr T getBit (T value) { + return (value >> offset) & T(1); + } + + /// Extract bits from an integer-type + template + static constexpr T getBits (T value) { + return (value >> offset) & ones(); + } + /// Check if a bit "bit" of value is set static constexpr bool isBitSet (u32 value, int bit) { return (value >> bit) & 1; diff --git a/src/core/PICA/gpu.cpp b/src/core/PICA/gpu.cpp index 7e9ddfea..9d4c06bc 100644 --- a/src/core/PICA/gpu.cpp +++ b/src/core/PICA/gpu.cpp @@ -51,7 +51,7 @@ void GPU::drawArrays() { // Configures the type of primitive and the number of vertex shader outputs const u32 primConfig = regs[PICAInternalRegs::PrimitiveConfig]; - const u32 primType = (primConfig >> 8) & 3; + const u32 primType = Helpers::getBits<8, 2>(primConfig); if (primType != 0 && primType != 1 && primType != 3) Helpers::panic("[PICA] Tried to draw unimplemented shape %d\n", primType); if (vertexCount > Renderer::vertexBufferSize) Helpers::panic("[PICA] vertexCount > vertexBufferSize"); @@ -62,7 +62,7 @@ void GPU::drawArrays() { // Get the configuration for the index buffer, used only for indexed drawing u32 indexBufferConfig = regs[PICAInternalRegs::IndexBufferConfig]; u32 indexBufferPointer = vertexBase + (indexBufferConfig & 0xfffffff); - bool shortIndex = (indexBufferConfig >> 31) & 1; // Indicates whether vert indices are 16-bit or 8-bit + bool shortIndex = Helpers::getBit<31>(indexBufferConfig); // Indicates whether vert indices are 16-bit or 8-bit // Stuff the global attribute config registers in one u64 to make attr parsing easier // TODO: Cache this when the vertex attribute format registers are written to diff --git a/src/core/PICA/regs.cpp b/src/core/PICA/regs.cpp index 33cf570a..a5e2c6b9 100644 --- a/src/core/PICA/regs.cpp +++ b/src/core/PICA/regs.cpp @@ -2,6 +2,7 @@ #include "PICA/regs.hpp" using namespace Floats; +using namespace Helpers; u32 GPU::readReg(u32 address) { if (address >= 0x1EF01000 && address < 0x1EF01C00) { // Internal registers @@ -56,7 +57,7 @@ void GPU::writeInternalReg(u32 index, u32 value, u32 mask) { case AttribFormatHigh: totalAttribCount = (value >> 28) + 1; // Total number of vertex attributes - fixedAttribMask = (value >> 16) & 0xfff; // Determines which vertex attributes are fixed for all vertices + fixedAttribMask = getBits<16, 12>(value); // Determines which vertex attributes are fixed for all vertices break; case ColourBufferLoc: { @@ -66,7 +67,7 @@ void GPU::writeInternalReg(u32 index, u32 value, u32 mask) { }; case ColourBufferFormat: { - u32 format = (value >> 16) & 7; + u32 format = getBits<16, 3>(value); renderer.setColourFormat(format); break; } @@ -85,7 +86,7 @@ void GPU::writeInternalReg(u32 index, u32 value, u32 mask) { case FramebufferSize: { const u32 width = value & 0x7ff; - const u32 height = ((value >> 12) & 0x3ff) + 1; + const u32 height = getBits<12, 10>(value) + 1; renderer.setFBSize(width, height); break; } @@ -151,7 +152,7 @@ void GPU::writeInternalReg(u32 index, u32 value, u32 mask) { // Get primitive type const u32 primConfig = regs[PICAInternalRegs::PrimitiveConfig]; - const u32 primType = (primConfig >> 8) & 3; + const u32 primType = getBits<8, 2>(primConfig); // If we've reached 3 verts, issue a draw call // Handle rendering depending on the primitive type @@ -253,7 +254,7 @@ void GPU::writeInternalReg(u32 index, u32 value, u32 mask) { break; case 2: attr.config2 = value; - attr.size = (value >> 16) & 0xff; + attr.size = getBits<16, 8>(value); attr.componentCount = value >> 28; break; } @@ -295,8 +296,8 @@ void GPU::startCommandList(u32 addr, u32 size) { u32 header = *cmdBuffCurr++; u32 id = header & 0xffff; - u32 paramMaskIndex = (header >> 16) & 0xf; - u32 paramCount = (header >> 20) & 0xff; // Number of additional parameters + u32 paramMaskIndex = getBits<16, 4>(header); + u32 paramCount = getBits<20, 8>(header); // Number of additional parameters // Bit 31 tells us whether this command is going to write to multiple sequential registers (if the bit is 1) // Or if all written values will go to the same register (If the bit is 0). It's essentially the value that // gets added to the "id" field after each register write diff --git a/src/core/PICA/shader_interpreter.cpp b/src/core/PICA/shader_interpreter.cpp index e9ef2fdf..cb6c4917 100644 --- a/src/core/PICA/shader_interpreter.cpp +++ b/src/core/PICA/shader_interpreter.cpp @@ -1,6 +1,8 @@ #include "PICA/shader.hpp" #include +using namespace Helpers; + void PICAShader::run() { pc = entrypoint; loopIndex = 0; @@ -126,9 +128,9 @@ PICAShader::vec4f& PICAShader::getDest(u32 dest) { } bool PICAShader::isCondTrue(u32 instruction) { - u32 condition = (instruction >> 22) & 3; - bool refY = ((instruction >> 24) & 1) != 0; - bool refX = ((instruction >> 25) & 1) != 0; + u32 condition = getBits<22, 2>(instruction); + bool refY = (getBit<24>(instruction)) != 0; + bool refX = (getBit<25>(instruction)) != 0; switch (condition) { case 0: // Either cmp register matches @@ -144,10 +146,10 @@ bool PICAShader::isCondTrue(u32 instruction) { void PICAShader::add(u32 instruction) { const u32 operandDescriptor = operandDescriptors[instruction & 0x7f]; - u32 src1 = (instruction >> 12) & 0x7f; - const u32 src2 = (instruction >> 7) & 0x1f; // src2 coming first because PICA moment - const u32 idx = (instruction >> 19) & 3; - const u32 dest = (instruction >> 21) & 0x1f; + u32 src1 = getBits<12, 7>(instruction); + const u32 src2 = getBits<7, 5>(instruction); // src2 coming first because PICA moment + const u32 idx = getBits<19, 2>(instruction); + const u32 dest = getBits<21, 5>(instruction); src1 = getIndexedSource(src1, idx); vec4f srcVec1 = getSourceSwizzled<1>(src1, operandDescriptor); @@ -165,10 +167,10 @@ void PICAShader::add(u32 instruction) { void PICAShader::mul(u32 instruction) { const u32 operandDescriptor = operandDescriptors[instruction & 0x7f]; - u32 src1 = (instruction >> 12) & 0x7f; - const u32 src2 = (instruction >> 7) & 0x1f; // src2 coming first because PICA moment - const u32 idx = (instruction >> 19) & 3; - const u32 dest = (instruction >> 21) & 0x1f; + u32 src1 = getBits<12, 7>(instruction); + const u32 src2 = getBits<7, 5>(instruction); // src2 coming first because PICA moment + const u32 idx = getBits<19, 2>(instruction); + const u32 dest = getBits<21, 5>(instruction); src1 = getIndexedSource(src1, idx); vec4f srcVec1 = getSourceSwizzled<1>(src1, operandDescriptor); @@ -186,9 +188,9 @@ void PICAShader::mul(u32 instruction) { void PICAShader::flr(u32 instruction) { const u32 operandDescriptor = operandDescriptors[instruction & 0x7f]; - u32 src = (instruction >> 12) & 0x7f; - const u32 idx = (instruction >> 19) & 3; - const u32 dest = (instruction >> 21) & 0x1f; + u32 src = getBits<12, 7>(instruction); + const u32 idx = getBits<19, 2>(instruction); + const u32 dest = getBits<21, 5>(instruction); src = getIndexedSource(src, idx); vec4f srcVector = getSourceSwizzled<1>(src, operandDescriptor); @@ -204,10 +206,10 @@ void PICAShader::flr(u32 instruction) { void PICAShader::max(u32 instruction) { const u32 operandDescriptor = operandDescriptors[instruction & 0x7f]; - const u32 src1 = (instruction >> 12) & 0x7f; - const u32 src2 = (instruction >> 7) & 0x1f; // src2 coming first because PICA moment - const u32 idx = (instruction >> 19) & 3; - const u32 dest = (instruction >> 21) & 0x1f; + const u32 src1 = getBits<12, 7>(instruction); + const u32 src2 = getBits<7, 5>(instruction); // src2 coming first because PICA moment + const u32 idx = getBits<19, 2>(instruction); + const u32 dest = getBits<21, 5>(instruction); if (idx) Helpers::panic("[PICA] MAX: idx != 0"); vec4f srcVec1 = getSourceSwizzled<1>(src1, operandDescriptor); @@ -226,10 +228,10 @@ void PICAShader::max(u32 instruction) { void PICAShader::min(u32 instruction) { const u32 operandDescriptor = operandDescriptors[instruction & 0x7f]; - const u32 src1 = (instruction >> 12) & 0x7f; - const u32 src2 = (instruction >> 7) & 0x1f; // src2 coming first because PICA moment - const u32 idx = (instruction >> 19) & 3; - const u32 dest = (instruction >> 21) & 0x1f; + const u32 src1 = getBits<12, 7>(instruction); + const u32 src2 = getBits<7, 5>(instruction); // src2 coming first because PICA moment + const u32 idx = getBits<19, 2>(instruction); + const u32 dest = getBits<21, 5>(instruction); if (idx) Helpers::panic("[PICA] MIN: idx != 0"); vec4f srcVec1 = getSourceSwizzled<1>(src1, operandDescriptor); @@ -248,9 +250,9 @@ void PICAShader::min(u32 instruction) { void PICAShader::mov(u32 instruction) { const u32 operandDescriptor = operandDescriptors[instruction & 0x7f]; - u32 src = (instruction >> 12) & 0x7f; - const u32 idx = (instruction >> 19) & 3; - const u32 dest = (instruction >> 21) & 0x1f; + u32 src = getBits<12, 7>(instruction); + const u32 idx = getBits<19, 2>(instruction); + const u32 dest = getBits<21, 5>(instruction); src = getIndexedSource(src, idx); vec4f srcVector = getSourceSwizzled<1>(src, operandDescriptor); @@ -266,8 +268,8 @@ void PICAShader::mov(u32 instruction) { void PICAShader::mova(u32 instruction) { const u32 operandDescriptor = operandDescriptors[instruction & 0x7f]; - const u32 src = (instruction >> 12) & 0x7f; - const u32 idx = (instruction >> 19) & 3; + const u32 src = getBits<12, 7>(instruction); + const u32 idx = getBits<19, 2>(instruction); if (idx) Helpers::panic("[PICA] MOVA: idx != 0"); vec4f srcVector = getSourceSwizzled<1>(src, operandDescriptor); @@ -281,10 +283,10 @@ void PICAShader::mova(u32 instruction) { void PICAShader::dp3(u32 instruction) { const u32 operandDescriptor = operandDescriptors[instruction & 0x7f]; - u32 src1 = (instruction >> 12) & 0x7f; - const u32 src2 = (instruction >> 7) & 0x1f; // src2 coming first because PICA moment - const u32 idx = (instruction >> 19) & 3; - const u32 dest = (instruction >> 21) & 0x1f; + u32 src1 = getBits<12, 7>(instruction); + const u32 src2 = getBits<7, 5>(instruction); // src2 coming first because PICA moment + const u32 idx = getBits<19, 2>(instruction); + const u32 dest = getBits<21, 5>(instruction); src1 = getIndexedSource(src1, idx); vec4f srcVec1 = getSourceSwizzled<1>(src1, operandDescriptor); @@ -303,10 +305,10 @@ void PICAShader::dp3(u32 instruction) { void PICAShader::dp4(u32 instruction) { const u32 operandDescriptor = operandDescriptors[instruction & 0x7f]; - u32 src1 = (instruction >> 12) & 0x7f; - const u32 src2 = (instruction >> 7) & 0x1f; // src2 coming first because PICA moment - const u32 idx = (instruction >> 19) & 3; - const u32 dest = (instruction >> 21) & 0x1f; + u32 src1 = getBits<12, 7>(instruction); + const u32 src2 = getBits<7, 5>(instruction); // src2 coming first because PICA moment + const u32 idx = getBits<19, 2>(instruction); + const u32 dest = getBits<21, 5>(instruction); src1 = getIndexedSource(src1, idx); vec4f srcVec1 = getSourceSwizzled<1>(src1, operandDescriptor); @@ -325,9 +327,9 @@ void PICAShader::dp4(u32 instruction) { void PICAShader::rcp(u32 instruction) { const u32 operandDescriptor = operandDescriptors[instruction & 0x7f]; - const u32 src1 = (instruction >> 12) & 0x7f; - const u32 idx = (instruction >> 19) & 3; - const u32 dest = (instruction >> 21) & 0x1f; + const u32 src1 = getBits<12, 7>(instruction); + const u32 idx = getBits<19, 2>(instruction); + const u32 dest = getBits<21, 5>(instruction); if (idx) Helpers::panic("[PICA] RCP: idx != 0"); vec4f srcVec1 = getSourceSwizzled<1>(src1, operandDescriptor); @@ -345,9 +347,9 @@ void PICAShader::rcp(u32 instruction) { void PICAShader::rsq(u32 instruction) { const u32 operandDescriptor = operandDescriptors[instruction & 0x7f]; - const u32 src1 = (instruction >> 12) & 0x7f; - const u32 idx = (instruction >> 19) & 3; - const u32 dest = (instruction >> 21) & 0x1f; + const u32 src1 = getBits<12, 7>(instruction); + const u32 idx = getBits<19, 2>(instruction); + const u32 dest = getBits<21, 5>(instruction); if (idx) Helpers::panic("[PICA] RSQ: idx != 0"); vec4f srcVec1 = getSourceSwizzled<1>(src1, operandDescriptor); @@ -365,11 +367,11 @@ void PICAShader::rsq(u32 instruction) { void PICAShader::mad(u32 instruction) { const u32 operandDescriptor = operandDescriptors[instruction & 0x1f]; - const u32 src1 = (instruction >> 17) & 0x1f; - u32 src2 = (instruction >> 10) & 0x7f; - const u32 src3 = (instruction >> 5) & 0x1f; - const u32 idx = (instruction >> 22) & 3; - const u32 dest = (instruction >> 24) & 0x1f; + const u32 src1 = getBits<17, 5>(instruction); + u32 src2 = getBits<10, 7>(instruction); + const u32 src3 = getBits<5, 5>(instruction); + const u32 idx = getBits<22, 2>(instruction); + const u32 dest = getBits<24, 5>(instruction); src2 = getIndexedSource(src2, idx); @@ -388,11 +390,11 @@ void PICAShader::mad(u32 instruction) { void PICAShader::madi(u32 instruction) { const u32 operandDescriptor = operandDescriptors[instruction & 0x1f]; - const u32 src1 = (instruction >> 17) & 0x1f; - const u32 src2 = (instruction >> 12) & 0x1f; - u32 src3 = (instruction >> 5) & 0x7f; - const u32 idx = (instruction >> 22) & 3; - const u32 dest = (instruction >> 24) & 0x1f; + const u32 src1 = getBits<17, 5>(instruction); + const u32 src2 = getBits<12, 5>(instruction); + u32 src3 = getBits<5, 7>(instruction); + const u32 idx = getBits<22, 2>(instruction); + const u32 dest = getBits<24, 5>(instruction); src3 = getIndexedSource(src3, idx); @@ -411,10 +413,10 @@ void PICAShader::madi(u32 instruction) { void PICAShader::slt(u32 instruction) { const u32 operandDescriptor = operandDescriptors[instruction & 0x7f]; - u32 src1 = (instruction >> 12) & 0x7f; - const u32 src2 = (instruction >> 7) & 0x1f; // src2 coming first because PICA moment - const u32 idx = (instruction >> 19) & 3; - const u32 dest = (instruction >> 21) & 0x1f; + u32 src1 = getBits<12, 7>(instruction); + const u32 src2 = getBits<7, 5>(instruction); // src2 coming first because PICA moment + const u32 idx = getBits<19, 2>(instruction); + const u32 dest = getBits<21, 5>(instruction); src1 = getIndexedSource(src1, idx); vec4f srcVec1 = getSourceSwizzled<1>(src1, operandDescriptor); @@ -431,10 +433,10 @@ void PICAShader::slt(u32 instruction) { void PICAShader::sgei(u32 instruction) { const u32 operandDescriptor = operandDescriptors[instruction & 0x7f]; - const u32 src1 = (instruction >> 14) & 0x1f; - u32 src2 = (instruction >> 7) & 0x7f; - const u32 idx = (instruction >> 19) & 3; - const u32 dest = (instruction >> 21) & 0x1f; + const u32 src1 = getBits<14, 5>(instruction); + u32 src2 = getBits<7, 7>(instruction); + const u32 idx = getBits<19, 2>(instruction); + const u32 dest = getBits<21, 5>(instruction); src2 = getIndexedSource(src2, idx); @@ -452,10 +454,10 @@ void PICAShader::sgei(u32 instruction) { void PICAShader::slti(u32 instruction) { const u32 operandDescriptor = operandDescriptors[instruction & 0x7f]; - const u32 src1 = (instruction >> 14) & 0x1f; - u32 src2 = (instruction >> 7) & 0x7f; - const u32 idx = (instruction >> 19) & 3; - const u32 dest = (instruction >> 21) & 0x1f; + const u32 src1 = getBits<14, 5>(instruction); + u32 src2 = getBits<7, 7>(instruction); + const u32 idx = getBits<19, 2>(instruction); + const u32 dest = getBits<21, 5>(instruction); src2 = getIndexedSource(src2, idx); @@ -473,11 +475,11 @@ void PICAShader::slti(u32 instruction) { void PICAShader::cmp(u32 instruction) { const u32 operandDescriptor = operandDescriptors[instruction & 0x7f]; - const u32 src1 = (instruction >> 12) & 0x7f; - const u32 src2 = (instruction >> 7) & 0x1f; // src2 coming first because PICA moment - const u32 idx = (instruction >> 19) & 3; - const u32 cmpY = (instruction >> 21) & 7; - const u32 cmpX = (instruction >> 24) & 7; + const u32 src1 = getBits<12, 7>(instruction); + const u32 src2 = getBits<7, 5>(instruction); // src2 coming first because PICA moment + const u32 idx = getBits<19, 2>(instruction); + const u32 cmpY = getBits<21, 3>(instruction); + const u32 cmpX = getBits<24, 3>(instruction); const u32 cmpOperations[2] = { cmpX, cmpY }; if (idx) Helpers::panic("[PICA] CMP: idx != 0"); @@ -518,7 +520,7 @@ void PICAShader::cmp(u32 instruction) { } void PICAShader::ifc(u32 instruction) { - const u32 dest = (instruction >> 10) & 0xfff; + const u32 dest = getBits<10, 12>(instruction); if (isCondTrue(instruction)) { if (ifIndex >= 8) [[unlikely]] @@ -535,8 +537,8 @@ 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 + const u32 dest = getBits<10, 12>(instruction); + const u32 bit = getBits<22, 4>(instruction); // Bit of the bool uniform to check if (boolUniform & (1 << bit)) { if (ifIndex >= 8) [[unlikely]] @@ -558,7 +560,7 @@ void PICAShader::call(u32 instruction) { Helpers::panic("[PICA] Overflowed CALL stack"); const u32 num = instruction & 0xff; - const u32 dest = (instruction >> 10) & 0xfff; + const u32 dest = getBits<10, 12>(instruction); auto& block = callInfo[callIndex++]; block.endingPC = dest + num; @@ -574,14 +576,14 @@ void PICAShader::callc(u32 instruction) { } void PICAShader::callu(u32 instruction) { - const u32 bit = (instruction >> 22) & 0xf; // Bit of the bool uniform to check + const u32 bit = getBits<22, 4>(instruction); // Bit of the bool uniform to check if (boolUniform & (1 << bit)) { if (callIndex >= 4) [[unlikely]] Helpers::panic("[PICA] Overflowed CALL stack"); const u32 num = instruction & 0xff; - const u32 dest = (instruction >> 10) & 0xfff; + const u32 dest = getBits<10, 12>(instruction); auto& block = callInfo[callIndex++]; block.endingPC = dest + num; @@ -595,8 +597,8 @@ void PICAShader::loop(u32 instruction) { if (loopIndex >= 4) [[unlikely]] Helpers::panic("[PICA] Overflowed loop stack"); - u32 dest = (instruction >> 10) & 0xfff; - auto& uniform = intUniforms[(instruction >> 22) & 3]; // The uniform we'll get loop info from + u32 dest = getBits<10, 12>(instruction); + auto& uniform = intUniforms[getBits<22, 2>(instruction)]; // The uniform we'll get loop info from loopCounter = uniform.y(); auto& loop = loopInfo[loopIndex++]; @@ -608,13 +610,13 @@ void PICAShader::loop(u32 instruction) { void PICAShader::jmpc(u32 instruction) { if (isCondTrue(instruction)) - pc = (instruction >> 10) & 0xfff; + pc = getBits<10, 12>(instruction); } void PICAShader::jmpu(u32 instruction) { const u32 test = (instruction & 1) ^ 1; // If the LSB is 0 we want to compare to true, otherwise compare to false - const u32 dest = (instruction >> 10) & 0xfff; - const u32 bit = (instruction >> 22) & 0xf; // Bit of the bool uniform to check + const u32 dest = getBits<10, 12>(instruction); + const u32 bit = getBits<22, 4>(instruction); // Bit of the bool uniform to check if (((boolUniform >> bit) & 1) == test) // Jump if the bool uniform is the value we want pc = dest; diff --git a/src/core/loader/lz77.cpp b/src/core/loader/lz77.cpp index 85bb96d2..d5c2178f 100644 --- a/src/core/loader/lz77.cpp +++ b/src/core/loader/lz77.cpp @@ -24,7 +24,7 @@ bool CartLZ77::decompress(std::vector& output, const std::vector& input) std::memcpy(&bufferTopAndBottom, footer, sizeof(u32)); u32 out = sizeDecompressed; // TODO: Is this meant to be u32 or s32? - u32 index = sizeCompressed - ((bufferTopAndBottom >> 24) & 0xff); + u32 index = sizeCompressed - (Helpers::getBits<24, 8>(bufferTopAndBottom)); u32 stopIndex = sizeCompressed - (bufferTopAndBottom & 0xffffff); // Set all of the decompressed buffer to 0 and copy the compressed buffer to the start of it @@ -49,7 +49,7 @@ bool CartLZ77::decompress(std::vector& output, const std::vector& input) index -= 2; u32 segmentOffset = compressed[index] | (compressed[index + 1] << 8); - u32 segment_size = ((segmentOffset >> 12) & 15) + 3; + u32 segment_size = (Helpers::getBits<12, 4>(segmentOffset)) + 3; segmentOffset &= 0x0FFF; segmentOffset += 2; diff --git a/src/core/renderer_gl/etc1.cpp b/src/core/renderer_gl/etc1.cpp index a4bc3edc..ae5abb65 100644 --- a/src/core/renderer_gl/etc1.cpp +++ b/src/core/renderer_gl/etc1.cpp @@ -3,6 +3,8 @@ #include "renderer_gl/renderer_gl.hpp" #include "renderer_gl/textures.hpp" +using namespace Helpers; + static constexpr u32 signExtend3To32(u32 val) { return (u32)(s32(val) << 29 >> 29); } @@ -58,14 +60,14 @@ u32 Texture::decodeETC(u32 alpha, u32 u, u32 v, u64 colourData) { }; // Parse colour data for 4x4 block - const u32 subindices = colourData & 0xffff; - const u32 negationFlags = (colourData >> 16) & 0xffff; - const bool flip = (colourData >> 32) & 1; - const bool diffMode = (colourData >> 33) & 1; + const u32 subindices = getBits<0, 16>(colourData); + const u32 negationFlags = getBits<16, 16>(colourData); + const bool flip = getBit<32>(colourData); + const bool diffMode = getBit<33>(colourData); // Note: index1 is indeed stored on the higher bits, with index2 in the lower bits - const u32 tableIndex1 = (colourData >> 37) & 7; - const u32 tableIndex2 = (colourData >> 34) & 7; + const u32 tableIndex1 = getBits<37, 3>(colourData); + const u32 tableIndex2 = getBits<34, 3>(colourData); const u32 texelIndex = u * 4 + v; // Index of the texel in the block if (flip) @@ -73,14 +75,14 @@ u32 Texture::decodeETC(u32 alpha, u32 u, u32 v, u64 colourData) { s32 r, g, b; if (diffMode) { - r = (colourData >> 59) & 0x1f; - g = (colourData >> 51) & 0x1f; - b = (colourData >> 43) & 0x1f; + r = getBits<59, 5>(colourData); + g = getBits<51, 5>(colourData); + b = getBits<43, 5>(colourData); if (u >= 2) { - r += signExtend3To32((colourData >> 56) & 0x7); - g += signExtend3To32((colourData >> 48) & 0x7); - b += signExtend3To32((colourData >> 40) & 0x7); + r += signExtend3To32(getBits<56, 3>(colourData)); + g += signExtend3To32(getBits<48, 3>(colourData)); + b += signExtend3To32(getBits<40, 3>(colourData)); } // Expand from 5 to 8 bits per channel @@ -89,13 +91,13 @@ u32 Texture::decodeETC(u32 alpha, u32 u, u32 v, u64 colourData) { b = Colour::convert5To8Bit(b); } else { if (u < 2) { - r = (colourData >> 60) & 0xf; - g = (colourData >> 52) & 0xf; - b = (colourData >> 44) & 0xf; + r = getBits<60, 4>(colourData); + g = getBits<52, 4>(colourData); + b = getBits<44, 4>(colourData); } else { - r = (colourData >> 56) & 0xf; - g = (colourData >> 48) & 0xf; - b = (colourData >> 40) & 0xf; + r = getBits<56, 4>(colourData); + g = getBits<48, 4>(colourData); + b = getBits<40, 4>(colourData); } // Expand from 4 to 8 bits per channel diff --git a/src/core/renderer_gl/renderer_gl.cpp b/src/core/renderer_gl/renderer_gl.cpp index f4ea3f6b..64525144 100644 --- a/src/core/renderer_gl/renderer_gl.cpp +++ b/src/core/renderer_gl/renderer_gl.cpp @@ -4,6 +4,7 @@ #include "PICA/regs.hpp" using namespace Floats; +using namespace Helpers; // This is all hacked up to display our first triangle @@ -243,19 +244,19 @@ void Renderer::setupBlending() { // Get blending equations const u32 blendControl = regs[PICAInternalRegs::BlendFunc]; const u32 rgbEquation = blendControl & 0x7; - const u32 alphaEquation = (blendControl >> 8) & 0x7; + const u32 alphaEquation = getBits<8, 3>(blendControl); // Get blending functions - const u32 rgbSourceFunc = (blendControl >> 16) & 0xf; - const u32 rgbDestFunc = (blendControl >> 20) & 0xf; - const u32 alphaSourceFunc = (blendControl >> 24) & 0xf; - const u32 alphaDestFunc = (blendControl >> 28) & 0xf; + const u32 rgbSourceFunc = getBits<16, 4>(blendControl); + const u32 rgbDestFunc = getBits<20, 4>(blendControl); + const u32 alphaSourceFunc = getBits<24, 4>(blendControl); + const u32 alphaDestFunc = getBits<28, 4>(blendControl); const u32 constantColor = regs[PICAInternalRegs::BlendColour]; const u32 r = constantColor & 0xff; - const u32 g = (constantColor >> 8) & 0xff; - const u32 b = (constantColor >> 16) & 0xff; - const u32 a = (constantColor >> 24) & 0xff; + const u32 g = getBits<8, 8>(constantColor); + const u32 b = getBits<16, 8>(constantColor); + const u32 a = getBits<24, 8>(constantColor); OpenGL::setBlendColor(float(r) / 255.f, float(g) / 255.f, float(b) / 255.f, float(a) / 255.f); // Translate equations and funcs to their GL equivalents and set them @@ -278,9 +279,9 @@ void Renderer::drawVertices(OpenGL::Primitives primType, Vertex* vertices, u32 c const u32 depthControl = regs[PICAInternalRegs::DepthAndColorMask]; const bool depthEnable = depthControl & 1; - const bool depthWriteEnable = (depthControl >> 12) & 1; - const int depthFunc = (depthControl >> 4) & 7; - const int colourMask = (depthControl >> 8) & 0xf; + const bool depthWriteEnable = getBit<12>(depthControl); + const int depthFunc = getBits<4, 3>(depthControl); + const int colourMask = getBits<8, 4>(depthControl); glColorMask(colourMask & 1, colourMask & 2, colourMask & 4, colourMask & 8); static constexpr std::array depthModes = { @@ -312,7 +313,7 @@ void Renderer::drawVertices(OpenGL::Primitives primType, Vertex* vertices, u32 c const u32 dim = regs[0x82]; const u32 config = regs[0x83]; const u32 height = dim & 0x7ff; - const u32 width = (dim >> 16) & 0x7ff; + const u32 width = getBits<16, 11>(dim); const u32 addr = (regs[0x85] & 0x0FFFFFFF) << 3; const u32 format = regs[0x8E] & 0xF; @@ -379,9 +380,9 @@ void Renderer::clearBuffer(u32 startAddress, u32 endAddress, u32 value, u32 cont return; log("GPU: Clear buffer\nStart: %08X End: %08X\nValue: %08X Control: %08X\n", startAddress, endAddress, value, control); - const float r = float((value >> 24) & 0xff) / 255.0; - const float g = float((value >> 16) & 0xff) / 255.0; - const float b = float((value >> 8) & 0xff) / 255.0; + const float r = float(getBits<24, 8>(value)) / 255.0; + const float g = float(getBits<16, 8>(value)) / 255.0; + const float b = float(getBits<8, 8>(value)) / 255.0; const float a = float(value & 0xff) / 255.0; if (startAddress == topScreenBuffer) { diff --git a/src/core/renderer_gl/textures.cpp b/src/core/renderer_gl/textures.cpp index a5affd57..f59d0779 100644 --- a/src/core/renderer_gl/textures.cpp +++ b/src/core/renderer_gl/textures.cpp @@ -2,6 +2,8 @@ #include "colour.hpp" #include +using namespace Helpers; + void Texture::allocate() { glGenTextures(1, &texture.m_handle); texture.create(size.u(), size.v(), GL_RGBA8); @@ -21,8 +23,8 @@ void Texture::setNewConfig(u32 cfg) { const auto magFilter = (cfg & 0x2) != 0 ? OpenGL::Linear : OpenGL::Nearest; const auto minFilter = (cfg & 0x4) != 0 ? OpenGL::Linear : OpenGL::Nearest; - const auto wrapT = wrappingModes[(cfg >> 8) & 0x7]; - const auto wrapS = wrappingModes[(cfg >> 12) & 0x7]; + const auto wrapT = wrappingModes[getBits<8, 3>(cfg)]; + const auto wrapS = wrappingModes[getBits<12, 3>(cfg)]; texture.setMinFilter(minFilter); texture.setMagFilter(magFilter); @@ -116,10 +118,10 @@ u32 Texture::decodeTexel(u32 u, u32 v, Texture::Formats fmt, const void* data) { auto ptr = static_cast(data); u16 texel = u16(ptr[offset]) | (u16(ptr[offset + 1]) << 8); - u8 alpha = Colour::convert4To8Bit(texel & 0xf); - u8 b = Colour::convert4To8Bit((texel >> 4) & 0xf); - u8 g = Colour::convert4To8Bit((texel >> 8) & 0xf); - u8 r = Colour::convert4To8Bit((texel >> 12) & 0xf); + u8 alpha = Colour::convert4To8Bit(getBits<0, 4>(texel)); + u8 b = Colour::convert4To8Bit(getBits<4, 4>(texel)); + u8 g = Colour::convert4To8Bit(getBits<8, 4>(texel)); + u8 r = Colour::convert4To8Bit(getBits<12, 4>(texel)); return (alpha << 24) | (b << 16) | (g << 8) | r; } @@ -129,10 +131,10 @@ u32 Texture::decodeTexel(u32 u, u32 v, Texture::Formats fmt, const void* data) { auto ptr = static_cast(data); u16 texel = u16(ptr[offset]) | (u16(ptr[offset + 1]) << 8); - u8 alpha = (texel & 1) ? 0xff : 0; - u8 b = Colour::convert5To8Bit((texel >> 1) & 0x1f); - u8 g = Colour::convert5To8Bit((texel >> 6) & 0x1f); - u8 r = Colour::convert5To8Bit((texel >> 11) & 0x1f); + u8 alpha = getBit<0>(texel) ? 0xff : 0; + u8 b = Colour::convert5To8Bit(getBits<1, 5>(texel)); + u8 g = Colour::convert5To8Bit(getBits<6, 5>(texel)); + u8 r = Colour::convert5To8Bit(getBits<11, 5>(texel)); return (alpha << 24) | (b << 16) | (g << 8) | r; } @@ -142,9 +144,9 @@ u32 Texture::decodeTexel(u32 u, u32 v, Texture::Formats fmt, const void* data) { auto ptr = static_cast(data); u16 texel = u16(ptr[offset]) | (u16(ptr[offset + 1]) << 8); - u8 b = Colour::convert5To8Bit(texel & 0x1f); - u8 g = Colour::convert6To8Bit((texel >> 5) & 0x3f); - u8 r = Colour::convert5To8Bit((texel >> 11) & 0x1f); + u8 b = Colour::convert5To8Bit(getBits<0, 5>(texel)); + u8 g = Colour::convert6To8Bit(getBits<5, 6>(texel)); + u8 r = Colour::convert5To8Bit(getBits<11, 5>(texel)); return (0xff << 24) | (b << 16) | (g << 8) | r; } @@ -201,7 +203,7 @@ u32 Texture::decodeTexel(u32 u, u32 v, Texture::Formats fmt, const void* data) { // For odd U coordinates, grab the top 4 bits, and the low 4 bits for even coordinates u8 alpha = ptr[offset] >> ((u % 2) ? 4 : 0); - alpha = Colour::convert4To8Bit(alpha & 0xf); + alpha = Colour::convert4To8Bit(getBits<0, 4>(alpha)); // A8 sets RGB to 0 return (alpha << 24) | (0 << 16) | (0 << 8) | 0; @@ -222,7 +224,7 @@ u32 Texture::decodeTexel(u32 u, u32 v, Texture::Formats fmt, const void* data) { // For odd U coordinates, grab the top 4 bits, and the low 4 bits for even coordinates u8 intensity = ptr[offset] >> ((u % 2) ? 4 : 0); - intensity = Colour::convert4To8Bit(intensity & 0xf); + intensity = Colour::convert4To8Bit(getBits<0, 4>(intensity)); // Intensity formats just copy the intensity value to every colour channel return (0xff << 24) | (intensity << 16) | (intensity << 8) | intensity;