From ed00ddc8058aaeccd00b5cdb3f640759e13e9111 Mon Sep 17 00:00:00 2001 From: wheremyfoodat <44909372+wheremyfoodat@users.noreply.github.com> Date: Thu, 18 Jul 2024 00:55:57 +0300 Subject: [PATCH] Improve lighting register definitions --- include/PICA/pica_frag_config.hpp | 160 ++++++++++++++++++++++++++- include/PICA/regs.hpp | 12 +- include/PICA/shader_gen.hpp | 3 +- src/core/PICA/shader_gen_glsl.cpp | 2 +- src/core/renderer_gl/renderer_gl.cpp | 4 +- 5 files changed, 175 insertions(+), 6 deletions(-) diff --git a/include/PICA/pica_frag_config.hpp b/include/PICA/pica_frag_config.hpp index 9e13b3b5..cfb22e5c 100644 --- a/include/PICA/pica_frag_config.hpp +++ b/include/PICA/pica_frag_config.hpp @@ -29,20 +29,178 @@ namespace PICA { std::array tevConfigs; }; + struct Light { + union { + u16 raw; + BitField<0, 3, u16> num; + BitField<3, 1, u16> directional; + BitField<4, 1, u16> twoSidedDiffuse; + BitField<5, 1, u16> distanceAttenuationEnable; + BitField<6, 1, u16> spotAttenuationEnable; + BitField<7, 1, u16> geometricFactor0; + BitField<8, 1, u16> geometricFactor1; + BitField<9, 1, u16> shadowEnable; + }; + }; + + struct LightingLUTConfig { + union { + u32 raw; + BitField<0, 1, u32> enable; + BitField<1, 1, u32> absInput; + BitField<2, 3, u32> type; + }; + float scale; + }; + + struct LightingConfig { + union { + u32 raw{}; + BitField<0, 1, u32> enable; + BitField<1, 4, u32> lightNum; + BitField<5, 2, u32> bumpMode; + BitField<7, 2, u32> bumpSelector; + BitField<9, 1, u32> bumpRenorm; + BitField<10, 1, u32> clampHighlights; + BitField<11, 4, u32> config; + BitField<15, 1, u32> enablePrimaryAlpha; + BitField<16, 1, u32> enableSecondaryAlpha; + BitField<17, 1, u32> enableShadow; + BitField<18, 1, u32> shadowPrimary; + BitField<19, 1, u32> shadowSecondary; + BitField<20, 1, u32> shadowInvert; + BitField<21, 1, u32> shadowAlpha; + BitField<22, 2, u32> shadowSelector; + }; + + LightingLUTConfig d0{}; + LightingLUTConfig d1{}; + LightingLUTConfig sp{}; + LightingLUTConfig fr{}; + LightingLUTConfig rr{}; + LightingLUTConfig rg{}; + LightingLUTConfig rb{}; + + std::array lights{}; + + LightingConfig(const std::array& regs) { + // Ignore lighting registers if it's disabled + if ((regs[InternalRegs::LightingEnable] & 1) == 0) { + return; + } + + const u32 config0 = regs[InternalRegs::LightConfig0]; + const u32 config1 = regs[InternalRegs::LightConfig1]; + const u32 totalLightCount = Helpers::getBits<0, 3>(regs[InternalRegs::LightNumber]) + 1; + + enable = 1; + lightNum = totalLightCount; + + enableShadow = Helpers::getBit<0>(config0); + if (enableShadow) [[unlikely]] { + shadowPrimary = Helpers::getBit<16>(config0); + shadowSecondary = Helpers::getBit<17>(config0); + shadowInvert = Helpers::getBit<18>(config0); + shadowAlpha = Helpers::getBit<19>(config0); + shadowSelector = Helpers::getBits<24, 2>(config0); + } + + enablePrimaryAlpha = Helpers::getBit<2>(config0); + enableSecondaryAlpha = Helpers::getBit<3>(config0); + config = Helpers::getBits<4, 4>(config0); + + bumpSelector = Helpers::getBits<22, 2>(config0); + clampHighlights = Helpers::getBit<27>(config0); + bumpMode = Helpers::getBits<28, 2>(config0); + bumpRenorm = Helpers::getBit<30>(config0) ^ 1; // 0 = enable so flip it with xor + + for (int i = 0; i < totalLightCount; i++) { + auto& light = lights[i]; + const u32 lightConfig = 0x149 + 0x10 * i; + + light.num = (regs[InternalRegs::LightPermutation] >> (i * 4)) & 0x7; + light.directional = Helpers::getBit<0>(lightConfig); + light.twoSidedDiffuse = Helpers::getBit<1>(lightConfig); + light.geometricFactor0 = Helpers::getBit<2>(lightConfig); + light.geometricFactor1 = Helpers::getBit<3>(lightConfig); + + light.shadowEnable = ((config1 >> i) & 1) ^ 1; // This also does 0 = enabled + light.spotAttenuationEnable = ((config1 >> (8 + i)) & 1) ^ 1; // Same here + light.distanceAttenuationEnable = ((config1 >> (24 + i)) & 1) ^ 1; // Of course same here + } + + d0.enable = Helpers::getBit<16>(config1) == 0; + d1.enable = Helpers::getBit<17>(config1) == 0; + fr.enable = Helpers::getBit<19>(config1) == 0; + rb.enable = Helpers::getBit<20>(config1) == 0; + rg.enable = Helpers::getBit<21>(config1) == 0; + rr.enable = Helpers::getBit<22>(config1) == 0; + sp.enable = 1; + + const u32 lutAbs = regs[InternalRegs::LightLUTAbs]; + const u32 lutSelect = regs[InternalRegs::LightLUTSelect]; + const u32 lutScale = regs[InternalRegs::LightLUTScale]; + static constexpr float scales[] = {1.0f, 2.0f, 4.0f, 8.0f, 0.25f, 0.5f}; + + if (d0.enable) { + d0.absInput = Helpers::getBit<1>(lutAbs) == 0; + d0.type = Helpers::getBits<0, 3>(lutSelect); + d0.scale = scales[Helpers::getBits<0, 3>(lutScale)]; + } + + if (d1.enable) { + d1.absInput = Helpers::getBit<5>(lutAbs) == 0; + d1.type = Helpers::getBits<4, 3>(lutSelect); + d1.scale = scales[Helpers::getBits<4, 3>(lutScale)]; + } + + sp.absInput = Helpers::getBit<9>(lutAbs) == 0; + sp.type = Helpers::getBits<8, 3>(lutSelect); + sp.scale = scales[Helpers::getBits<8, 3>(lutScale)]; + + if (fr.enable) { + fr.absInput = Helpers::getBit<13>(lutAbs) == 0; + fr.type = Helpers::getBits<12, 3>(lutSelect); + fr.scale = scales[Helpers::getBits<12, 3>(lutScale)]; + } + + if (rb.enable) { + rb.absInput = Helpers::getBit<17>(lutAbs) == 0; + rb.type = Helpers::getBits<16, 3>(lutSelect); + rb.scale = scales[Helpers::getBits<16, 3>(lutScale)]; + } + + if (rg.enable) { + rg.absInput = Helpers::getBit<21>(lutAbs) == 0; + rg.type = Helpers::getBits<20, 3>(lutSelect); + rg.scale = scales[Helpers::getBits<20, 3>(lutScale)]; + } + + if (rr.enable) { + rr.absInput = Helpers::getBit<25>(lutAbs) == 0; + rr.type = Helpers::getBits<24, 3>(lutSelect); + rr.scale = scales[Helpers::getBits<24, 3>(lutScale)]; + } + } + }; + // Config used for identifying unique fragment pipeline configurations struct FragmentConfig { OutputConfig outConfig; TextureConfig texConfig; + LightingConfig lighting; bool operator==(const FragmentConfig& config) const { // Hash function and equality operator required by std::unordered_map return std::memcmp(this, &config, sizeof(FragmentConfig)) == 0; } + + FragmentConfig(const std::array& regs) : lighting(regs) {} }; static_assert( std::has_unique_object_representations() && std::has_unique_object_representations() && - std::has_unique_object_representations() + std::has_unique_object_representations() ); } // namespace PICA diff --git a/include/PICA/regs.hpp b/include/PICA/regs.hpp index 74f8c7d5..312ac78b 100644 --- a/include/PICA/regs.hpp +++ b/include/PICA/regs.hpp @@ -67,7 +67,17 @@ namespace PICA { ColourBufferLoc = 0x11D, FramebufferSize = 0x11E, - //LightingRegs + + // Lighting registers + LightingEnable = 0x8F, + LightNumber = 0x1C2, + LightConfig0 = 0x1C3, + LightConfig1 = 0x1C4, + LightPermutation = 0x1D9, + LightLUTAbs = 0x1D0, + LightLUTSelect = 0x1D1, + LightLUTScale = 0x1D2, + LightingLUTIndex = 0x01C5, LightingLUTData0 = 0x01C8, LightingLUTData1 = 0x01C9, diff --git a/include/PICA/shader_gen.hpp b/include/PICA/shader_gen.hpp index e8e8ca20..0a6bca8e 100644 --- a/include/PICA/shader_gen.hpp +++ b/include/PICA/shader_gen.hpp @@ -2,6 +2,7 @@ #include #include "PICA/gpu.hpp" +#include "PICA/pica_frag_config.hpp" #include "PICA/regs.hpp" #include "helpers.hpp" @@ -30,7 +31,7 @@ namespace PICA::ShaderGen { public: FragmentGenerator(API api, Language language) : api(api), language(language) {} - std::string generate(const PICARegs& regs); + std::string generate(const PICARegs& regs, const PICA::FragmentConfig& config); std::string getVertexShader(const PICARegs& regs); 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 0877e5f2..5dbc3b81 100644 --- a/src/core/PICA/shader_gen_glsl.cpp +++ b/src/core/PICA/shader_gen_glsl.cpp @@ -92,7 +92,7 @@ std::string FragmentGenerator::getVertexShader(const PICARegs& regs) { return ret; } -std::string FragmentGenerator::generate(const PICARegs& regs) { +std::string FragmentGenerator::generate(const PICARegs& regs, const FragmentConfig& config) { std::string ret = ""; switch (api) { diff --git a/src/core/renderer_gl/renderer_gl.cpp b/src/core/renderer_gl/renderer_gl.cpp index 249d8484..b85e7689 100644 --- a/src/core/renderer_gl/renderer_gl.cpp +++ b/src/core/renderer_gl/renderer_gl.cpp @@ -780,7 +780,7 @@ std::optional RendererGL::getColourBuffer(u32 addr, PICA::ColorFmt OpenGL::Program& RendererGL::getSpecializedShader() { constexpr uint uboBlockBinding = 2; - PICA::FragmentConfig fsConfig; + PICA::FragmentConfig fsConfig(regs); auto& outConfig = fsConfig.outConfig; auto& texConfig = fsConfig.texConfig; @@ -812,7 +812,7 @@ OpenGL::Program& RendererGL::getSpecializedShader() { if (!program.exists()) { std::string vs = fragShaderGen.getVertexShader(regs); - std::string fs = fragShaderGen.generate(regs); + std::string fs = fragShaderGen.generate(regs, fsConfig); OpenGL::Shader vertShader({vs.c_str(), vs.size()}, OpenGL::Vertex); OpenGL::Shader fragShader({fs.c_str(), fs.size()}, OpenGL::Fragment);