Remove dependency of PICA regs in fragment config

This commit is contained in:
offtkp 2024-07-19 23:44:26 +03:00
parent eb7e02fbc2
commit ce4146f9ba
4 changed files with 90 additions and 90 deletions

View file

@ -81,6 +81,11 @@ namespace PICA {
LightingLUTConfig rg{};
LightingLUTConfig rb{};
u32 config1;
u32 lutAbs;
u32 lutScale;
u32 lutSelect;
std::array<Light, 8> lights{};
LightingConfig(const std::array<u32, 0x300>& 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<u32, 0x300>& regs) : lighting(regs) {}
FragmentConfig(const std::array<u32, 0x300>& regs) : lighting(regs)
{
auto alphaTestConfig = regs[InternalRegs::AlphaTestConfig];
auto alphaTestFunction = Helpers::getBits<4, 3>(alphaTestConfig);
outConfig.alphaTestFunction = (alphaTestConfig & 1) ? static_cast<PICA::CompareFunction>(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], &regs[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(

View file

@ -14,27 +14,24 @@ namespace PICA::ShaderGen {
enum class Language { GLSL };
class FragmentGenerator {
using PICARegs = std::array<u32, 0x300>;
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) {

View file

@ -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<u32, 6> 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<CompareFunction>(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];

View file

@ -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<PICA::CompareFunction>(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], &regs[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});