diff --git a/include/PICA/pica_frag_config.hpp b/include/PICA/pica_frag_config.hpp index 5338f719..3e736deb 100644 --- a/include/PICA/pica_frag_config.hpp +++ b/include/PICA/pica_frag_config.hpp @@ -81,6 +81,11 @@ namespace PICA { LightingLUTConfig rg{}; LightingLUTConfig rb{}; + u32 config1; + u32 lutAbs; + u32 lutScale; + u32 lutSelect; + std::array lights{}; LightingConfig(const std::array& regs) { @@ -90,9 +95,13 @@ namespace PICA { } const u32 config0 = regs[InternalRegs::LightConfig0]; - const u32 config1 = regs[InternalRegs::LightConfig1]; const u32 totalLightCount = Helpers::getBits<0, 3>(regs[InternalRegs::LightNumber]) + 1; + config1 = regs[InternalRegs::LightConfig1]; + lutAbs = regs[InternalRegs::LightLUTAbs]; + lutScale = regs[InternalRegs::LightLUTScale]; + lutSelect = regs[InternalRegs::LightLUTSelect]; + enable = 1; lightNum = totalLightCount; @@ -195,7 +204,31 @@ namespace PICA { return std::memcmp(this, &config, sizeof(FragmentConfig)) == 0; } - FragmentConfig(const std::array& regs) : lighting(regs) {} + FragmentConfig(const std::array& regs) : lighting(regs) + { + auto alphaTestConfig = regs[InternalRegs::AlphaTestConfig]; + auto alphaTestFunction = Helpers::getBits<4, 3>(alphaTestConfig); + + outConfig.alphaTestFunction = (alphaTestConfig & 1) ? static_cast(alphaTestFunction) : PICA::CompareFunction::Always; + outConfig.depthMapEnable = regs[InternalRegs::DepthmapEnable] & 1; + + texConfig.texUnitConfig = regs[InternalRegs::TexUnitCfg]; + texConfig.texEnvUpdateBuffer = regs[InternalRegs::TexEnvUpdateBuffer]; + + // Set up TEV stages. Annoyingly we can't just memcpy as the TEV registers are arranged like + // {Source, Operand, Combiner, Color, Scale} and we want to skip the color register since it's uploaded via UBO + #define setupTevStage(stage) \ + std::memcpy(&texConfig.tevConfigs[stage * 4], ®s[InternalRegs::TexEnv##stage##Source], 3 * sizeof(u32)); \ + texConfig.tevConfigs[stage * 4 + 3] = regs[InternalRegs::TexEnv##stage##Source + 5]; + + setupTevStage(0); + setupTevStage(1); + setupTevStage(2); + setupTevStage(3); + setupTevStage(4); + setupTevStage(5); + #undef setupTevStage + } }; static_assert( diff --git a/include/PICA/shader_gen.hpp b/include/PICA/shader_gen.hpp index 8cdaadfc..6cf810a0 100644 --- a/include/PICA/shader_gen.hpp +++ b/include/PICA/shader_gen.hpp @@ -14,27 +14,24 @@ namespace PICA::ShaderGen { enum class Language { GLSL }; class FragmentGenerator { - using PICARegs = std::array; API api; Language language; - void compileTEV(std::string& shader, int stage, const PICARegs& regs); - void getSource(std::string& shader, PICA::TexEnvConfig::Source source, int index); - void getColorOperand(std::string& shader, PICA::TexEnvConfig::Source source, PICA::TexEnvConfig::ColorOperand color, int index); - void getAlphaOperand(std::string& shader, PICA::TexEnvConfig::Source source, PICA::TexEnvConfig::AlphaOperand alpha, int index); + void compileTEV(std::string& shader, int stage, const PICA::FragmentConfig& config); + void getSource(std::string& shader, PICA::TexEnvConfig::Source source, int index, const PICA::FragmentConfig& config); + void getColorOperand(std::string& shader, PICA::TexEnvConfig::Source source, PICA::TexEnvConfig::ColorOperand color, int index, const PICA::FragmentConfig& config); + void getAlphaOperand(std::string& shader, PICA::TexEnvConfig::Source source, PICA::TexEnvConfig::AlphaOperand alpha, int index, const PICA::FragmentConfig& config); void getColorOperation(std::string& shader, PICA::TexEnvConfig::Operation op); void getAlphaOperation(std::string& shader, PICA::TexEnvConfig::Operation op); - void applyAlphaTest(std::string& shader, const PICARegs& regs); - void compileLights(std::string& shader, const PICA::FragmentConfig& config, const PICARegs& regs); - void compileLUTLookup(std::string& shader, const PICA::FragmentConfig& config, const PICARegs& regs, u32 lightIndex, u32 lutID); + void applyAlphaTest(std::string& shader, const PICA::FragmentConfig& config); + void compileLights(std::string& shader, const PICA::FragmentConfig& config); + void compileLUTLookup(std::string& shader, const PICA::FragmentConfig& config, u32 lightIndex, u32 lutID); bool isSamplerEnabled(u32 environmentID, u32 lutID); - u32 textureConfig = 0; - public: FragmentGenerator(API api, Language language) : api(api), language(language) {} - std::string generate(const PICARegs& regs, const PICA::FragmentConfig& config); + std::string generate(const PICA::FragmentConfig& config); std::string getDefaultVertexShader(); void setTarget(API api, Language language) { diff --git a/src/core/PICA/shader_gen_glsl.cpp b/src/core/PICA/shader_gen_glsl.cpp index e19c459e..5fff34ae 100644 --- a/src/core/PICA/shader_gen_glsl.cpp +++ b/src/core/PICA/shader_gen_glsl.cpp @@ -1,3 +1,4 @@ +#include "PICA/regs.hpp" #include "PICA/shader_gen.hpp" using namespace PICA; using namespace PICA::ShaderGen; @@ -101,7 +102,7 @@ std::string FragmentGenerator::getDefaultVertexShader() { return ret; } -std::string FragmentGenerator::generate(const PICARegs& regs, const FragmentConfig& config) { +std::string FragmentGenerator::generate(const FragmentConfig& config) { std::string ret = ""; switch (api) { @@ -168,7 +169,7 @@ std::string FragmentGenerator::generate(const PICARegs& regs, const FragmentConf vec4 secondaryColor = vec4(0.0); )"; - compileLights(ret, config, regs); + compileLights(ret, config); ret += R"( vec3 colorOp1 = vec3(0.0); @@ -187,44 +188,39 @@ std::string FragmentGenerator::generate(const PICARegs& regs, const FragmentConf float depth = z_over_w * depthScale + depthOffset; )"; - if ((regs[InternalRegs::DepthmapEnable] & 1) == 0) { + if (!config.outConfig.depthMapEnable) { ret += "depth /= gl_FragCoord.w;\n"; } ret += "gl_FragDepth = depth;\n"; - textureConfig = regs[InternalRegs::TexUnitCfg]; for (int i = 0; i < 6; i++) { - compileTEV(ret, i, regs); + compileTEV(ret, i, config); } - applyAlphaTest(ret, regs); + applyAlphaTest(ret, config); ret += "fragColor = combinerOutput;\n}"; // End of main function return ret; } -void FragmentGenerator::compileTEV(std::string& shader, int stage, const PICARegs& regs) { - // Base address for each TEV stage's configuration - static constexpr std::array ioBases = { - InternalRegs::TexEnv0Source, InternalRegs::TexEnv1Source, InternalRegs::TexEnv2Source, - InternalRegs::TexEnv3Source, InternalRegs::TexEnv4Source, InternalRegs::TexEnv5Source, - }; +void FragmentGenerator::compileTEV(std::string& shader, int stage, const PICA::FragmentConfig& config) { + const u32* tevValues = config.texConfig.tevConfigs.data() + stage * 4; - const u32 ioBase = ioBases[stage]; - TexEnvConfig tev(regs[ioBase], regs[ioBase + 1], regs[ioBase + 2], regs[ioBase + 3], regs[ioBase + 4]); + // Pass a 0 to constColor here, as it doesn't matter for compilation + TexEnvConfig tev(tevValues[0], tevValues[1], tevValues[2], 0, tevValues[3]); if (!tev.isPassthroughStage()) { // Get color operands shader += "colorOp1 = "; - getColorOperand(shader, tev.colorSource1, tev.colorOperand1, stage); + getColorOperand(shader, tev.colorSource1, tev.colorOperand1, stage, config); shader += ";\ncolorOp2 = "; - getColorOperand(shader, tev.colorSource2, tev.colorOperand2, stage); + getColorOperand(shader, tev.colorSource2, tev.colorOperand2, stage, config); shader += ";\ncolorOp3 = "; - getColorOperand(shader, tev.colorSource3, tev.colorOperand3, stage); + getColorOperand(shader, tev.colorSource3, tev.colorOperand3, stage, config); shader += ";\nvec3 outputColor" + std::to_string(stage) + " = clamp("; getColorOperation(shader, tev.colorOp); @@ -236,13 +232,13 @@ void FragmentGenerator::compileTEV(std::string& shader, int stage, const PICAReg } else { // Get alpha operands shader += "alphaOp1 = "; - getAlphaOperand(shader, tev.alphaSource1, tev.alphaOperand1, stage); + getAlphaOperand(shader, tev.alphaSource1, tev.alphaOperand1, stage, config); shader += ";\nalphaOp2 = "; - getAlphaOperand(shader, tev.alphaSource2, tev.alphaOperand2, stage); + getAlphaOperand(shader, tev.alphaSource2, tev.alphaOperand2, stage, config); shader += ";\nalphaOp3 = "; - getAlphaOperand(shader, tev.alphaSource3, tev.alphaOperand3, stage); + getAlphaOperand(shader, tev.alphaSource3, tev.alphaOperand3, stage, config); shader += ";\nfloat outputAlpha" + std::to_string(stage) + " = clamp("; getAlphaOperation(shader, tev.alphaOp); @@ -258,7 +254,7 @@ void FragmentGenerator::compileTEV(std::string& shader, int stage, const PICAReg shader += "previousBuffer = tevNextPreviousBuffer;\n\n"; // Update the "next previous buffer" if necessary - const u32 textureEnvUpdateBuffer = regs[InternalRegs::TexEnvUpdateBuffer]; + const u32 textureEnvUpdateBuffer = config.texConfig.texEnvUpdateBuffer; if (stage < 4) { // Check whether to update rgb if ((textureEnvUpdateBuffer & (0x100 << stage))) { @@ -272,7 +268,7 @@ void FragmentGenerator::compileTEV(std::string& shader, int stage, const PICAReg } } -void FragmentGenerator::getColorOperand(std::string& shader, TexEnvConfig::Source source, TexEnvConfig::ColorOperand color, int index) { +void FragmentGenerator::getColorOperand(std::string& shader, TexEnvConfig::Source source, TexEnvConfig::ColorOperand color, int index, const PICA::FragmentConfig& config) { using OperandType = TexEnvConfig::ColorOperand; // For inverting operands, add the 1.0 - x subtraction @@ -284,31 +280,31 @@ void FragmentGenerator::getColorOperand(std::string& shader, TexEnvConfig::Sourc switch (color) { case OperandType::SourceColor: case OperandType::OneMinusSourceColor: - getSource(shader, source, index); + getSource(shader, source, index, config); shader += ".rgb"; break; case OperandType::SourceRed: case OperandType::OneMinusSourceRed: - getSource(shader, source, index); + getSource(shader, source, index, config); shader += ".rrr"; break; case OperandType::SourceGreen: case OperandType::OneMinusSourceGreen: - getSource(shader, source, index); + getSource(shader, source, index, config); shader += ".ggg"; break; case OperandType::SourceBlue: case OperandType::OneMinusSourceBlue: - getSource(shader, source, index); + getSource(shader, source, index, config); shader += ".bbb"; break; case OperandType::SourceAlpha: case OperandType::OneMinusSourceAlpha: - getSource(shader, source, index); + getSource(shader, source, index, config); shader += ".aaa"; break; @@ -319,7 +315,7 @@ void FragmentGenerator::getColorOperand(std::string& shader, TexEnvConfig::Sourc } } -void FragmentGenerator::getAlphaOperand(std::string& shader, TexEnvConfig::Source source, TexEnvConfig::AlphaOperand color, int index) { +void FragmentGenerator::getAlphaOperand(std::string& shader, TexEnvConfig::Source source, TexEnvConfig::AlphaOperand color, int index, const PICA::FragmentConfig& config) { using OperandType = TexEnvConfig::AlphaOperand; // For inverting operands, add the 1.0 - x subtraction @@ -331,25 +327,25 @@ void FragmentGenerator::getAlphaOperand(std::string& shader, TexEnvConfig::Sourc switch (color) { case OperandType::SourceRed: case OperandType::OneMinusSourceRed: - getSource(shader, source, index); + getSource(shader, source, index, config); shader += ".r"; break; case OperandType::SourceGreen: case OperandType::OneMinusSourceGreen: - getSource(shader, source, index); + getSource(shader, source, index, config); shader += ".g"; break; case OperandType::SourceBlue: case OperandType::OneMinusSourceBlue: - getSource(shader, source, index); + getSource(shader, source, index, config); shader += ".b"; break; case OperandType::SourceAlpha: case OperandType::OneMinusSourceAlpha: - getSource(shader, source, index); + getSource(shader, source, index, config); shader += ".a"; break; @@ -360,14 +356,14 @@ void FragmentGenerator::getAlphaOperand(std::string& shader, TexEnvConfig::Sourc } } -void FragmentGenerator::getSource(std::string& shader, TexEnvConfig::Source source, int index) { +void FragmentGenerator::getSource(std::string& shader, TexEnvConfig::Source source, int index, const PICA::FragmentConfig& config) { switch (source) { case TexEnvConfig::Source::PrimaryColor: shader += "v_colour"; break; case TexEnvConfig::Source::Texture0: shader += "texture(u_tex0, v_texcoord0.xy)"; break; case TexEnvConfig::Source::Texture1: shader += "texture(u_tex1, v_texcoord1)"; break; case TexEnvConfig::Source::Texture2: { // If bit 13 in texture config is set then we use the texcoords for texture 1, otherwise for texture 2 - if (Helpers::getBit<13>(textureConfig)) { + if (Helpers::getBit<13>(config.texConfig.texUnitConfig)) { shader += "texture(u_tex2, v_texcoord1)"; } else { shader += "texture(u_tex2, v_texcoord2)"; @@ -428,12 +424,11 @@ void FragmentGenerator::getAlphaOperation(std::string& shader, TexEnvConfig::Ope } } -void FragmentGenerator::applyAlphaTest(std::string& shader, const PICARegs& regs) { - const u32 alphaConfig = regs[InternalRegs::AlphaTestConfig]; - const auto function = static_cast(Helpers::getBits<4, 3>(alphaConfig)); +void FragmentGenerator::applyAlphaTest(std::string& shader, const PICA::FragmentConfig& config) { + const CompareFunction function = config.outConfig.alphaTestFunction; // Alpha test disabled - if (Helpers::getBit<0>(alphaConfig) == 0 || function == CompareFunction::Always) { + if (function == CompareFunction::Always) { return; } @@ -458,7 +453,7 @@ void FragmentGenerator::applyAlphaTest(std::string& shader, const PICARegs& regs shader += ") { discard; }\n"; } -void FragmentGenerator::compileLights(std::string& shader, const PICA::FragmentConfig& config, const PICARegs& regs) { +void FragmentGenerator::compileLights(std::string& shader, const PICA::FragmentConfig& config) { if (!config.lighting.enable) { return; } @@ -516,27 +511,27 @@ void FragmentGenerator::compileLights(std::string& shader, const PICA::FragmentC ", int(clamp(floor(distance_att_delta * 256.0), 0.0, 255.0)));\n"; } - compileLUTLookup(shader, config, regs, lightID, spotlightLutIndex); + compileLUTLookup(shader, config, lightID, spotlightLutIndex); shader += "spotlight_attenuation = lut_lookup_result;\n"; - compileLUTLookup(shader, config, regs, lightID, PICA::Lights::LUT_D0); + compileLUTLookup(shader, config, lightID, PICA::Lights::LUT_D0); shader += "specular0_dist = lut_lookup_result;\n"; - compileLUTLookup(shader, config, regs, lightID, PICA::Lights::LUT_D1); + compileLUTLookup(shader, config, lightID, PICA::Lights::LUT_D1); shader += "specular1_dist = lut_lookup_result;\n"; - compileLUTLookup(shader, config, regs, lightID, PICA::Lights::LUT_RR); + compileLUTLookup(shader, config, lightID, PICA::Lights::LUT_RR); shader += "reflected_color.r = lut_lookup_result;\n"; if (isSamplerEnabled(config.lighting.config, PICA::Lights::LUT_RG)) { - compileLUTLookup(shader, config, regs, lightID, PICA::Lights::LUT_RG); + compileLUTLookup(shader, config, lightID, PICA::Lights::LUT_RG); shader += "reflected_color.g = lut_lookup_result;\n"; } else { shader += "reflected_color.g = reflected_color.r;\n"; } if (isSamplerEnabled(config.lighting.config, PICA::Lights::LUT_RB)) { - compileLUTLookup(shader, config, regs, lightID, PICA::Lights::LUT_RB); + compileLUTLookup(shader, config, lightID, PICA::Lights::LUT_RB); shader += "reflected_color.b = lut_lookup_result;\n"; } else { shader += "reflected_color.b = reflected_color.r;\n"; @@ -565,7 +560,7 @@ void FragmentGenerator::compileLights(std::string& shader, const PICA::FragmentC } if (config.lighting.enablePrimaryAlpha || config.lighting.enableSecondaryAlpha) { - compileLUTLookup(shader, config, regs, lightID, PICA::Lights::LUT_FR); + compileLUTLookup(shader, config, lightID, PICA::Lights::LUT_FR); shader += "float fresnel_factor = lut_lookup_result;\n"; } @@ -602,7 +597,7 @@ bool FragmentGenerator::isSamplerEnabled(u32 environmentID, u32 lutID) { return samplerEnabled[environmentID * 7 + lutID]; } -void FragmentGenerator::compileLUTLookup(std::string& shader, const PICA::FragmentConfig& config, const PICARegs& regs, u32 lightIndex, u32 lutID) { +void FragmentGenerator::compileLUTLookup(std::string& shader, const PICA::FragmentConfig& config, u32 lightIndex, u32 lutID) { uint lutIndex = 0; int bitInConfig1 = 0; @@ -618,7 +613,7 @@ void FragmentGenerator::compileLUTLookup(std::string& shader, const PICA::Fragme } const bool samplerEnabled = isSamplerEnabled(config.lighting.config, lutID); - const u32 config1 = regs[InternalRegs::LightConfig1]; + const u32 config1 = config.lighting.config1; if (!samplerEnabled || ((config1 >> bitInConfig1) & 1)) { shader += "lut_lookup_result = 1.0;\n"; @@ -626,9 +621,9 @@ void FragmentGenerator::compileLUTLookup(std::string& shader, const PICA::Fragme } static constexpr float scales[] = {1.0f, 2.0f, 4.0f, 8.0f, 0.0f, 0.0f, 0.25f, 0.5f}; - const u32 lutAbs = regs[InternalRegs::LightLUTAbs]; - const u32 lutSelect = regs[InternalRegs::LightLUTSelect]; - const u32 lutScale = regs[InternalRegs::LightLUTScale]; + const u32 lutAbs = config.lighting.lutAbs; + const u32 lutSelect = config.lighting.lutSelect; + const u32 lutScale = config.lighting.lutScale; // The way these bitfields are encoded is so cursed float scale = scales[(lutScale >> (4 * lutID)) & 0x7]; diff --git a/src/core/renderer_gl/renderer_gl.cpp b/src/core/renderer_gl/renderer_gl.cpp index 7fca385d..2d39f65f 100644 --- a/src/core/renderer_gl/renderer_gl.cpp +++ b/src/core/renderer_gl/renderer_gl.cpp @@ -784,37 +784,12 @@ OpenGL::Program& RendererGL::getSpecializedShader() { constexpr uint uboBlockBinding = 2; PICA::FragmentConfig fsConfig(regs); - auto& outConfig = fsConfig.outConfig; - auto& texConfig = fsConfig.texConfig; - - auto alphaTestConfig = regs[InternalRegs::AlphaTestConfig]; - auto alphaTestFunction = Helpers::getBits<4, 3>(alphaTestConfig); - - outConfig.alphaTestFunction = (alphaTestConfig & 1) ? static_cast(alphaTestFunction) : PICA::CompareFunction::Always; - outConfig.depthMapEnable = regs[InternalRegs::DepthmapEnable] & 1; - - texConfig.texUnitConfig = regs[InternalRegs::TexUnitCfg]; - texConfig.texEnvUpdateBuffer = regs[InternalRegs::TexEnvUpdateBuffer]; - - // Set up TEV stages. Annoyingly we can't just memcpy as the TEV registers are arranged like - // {Source, Operand, Combiner, Color, Scale} and we want to skip the color register since it's uploaded via UBO -#define setupTevStage(stage) \ - std::memcpy(&texConfig.tevConfigs[stage * 4], ®s[InternalRegs::TexEnv##stage##Source], 3 * sizeof(u32)); \ - texConfig.tevConfigs[stage * 4 + 3] = regs[InternalRegs::TexEnv##stage##Source + 5]; - - setupTevStage(0); - setupTevStage(1); - setupTevStage(2); - setupTevStage(3); - setupTevStage(4); - setupTevStage(5); -#undef setupTevStage CachedProgram& programEntry = shaderCache[fsConfig]; OpenGL::Program& program = programEntry.program; if (!program.exists()) { - std::string fs = fragShaderGen.generate(regs, fsConfig); + std::string fs = fragShaderGen.generate(fsConfig); OpenGL::Shader fragShader({fs.c_str(), fs.size()}, OpenGL::Fragment); program.create({defaultShadergenVs, fragShader});