Initial support for proper GXSetAlphaCompare logic, needs more testing to verify it works properly

This commit is contained in:
Phillip Stephens 2022-03-19 14:06:27 -07:00
parent 9e546931f4
commit a84bc64358
Signed by: Antidote
GPG Key ID: F8BEE4C83DACA60D
3 changed files with 71 additions and 16 deletions

View File

@ -108,14 +108,7 @@ void GXSetChanCtrl(GX::ChannelID id, bool lightingEnabled, GX::ColorSrc ambSrc,
g_gxState.colorChannelState[idx].lightState = lightState; g_gxState.colorChannelState[idx].lightState = lightState;
} }
void GXSetAlphaCompare(GX::Compare comp0, float ref0, GX::AlphaOp op, GX::Compare comp1, float ref1) noexcept { void GXSetAlphaCompare(GX::Compare comp0, float ref0, GX::AlphaOp op, GX::Compare comp1, float ref1) noexcept {
if (comp0 == GX::ALWAYS && comp1 == GX::ALWAYS) { g_gxState.alphaCompare = {comp0, ref0, op, comp1, ref1};
g_gxState.alphaDiscard.reset();
} else if (comp0 == GX::GEQUAL && comp1 == GX::NEVER) {
g_gxState.alphaDiscard = ref0;
} else {
Log.report(logvisor::Fatal, FMT_STRING("GXSetAlphaCompare: unknown operands"));
unreachable();
}
} }
void GXSetTexCoordGen2(GX::TexCoordID dst, GX::TexGenType type, GX::TexGenSrc src, GX::TexMtx mtx, GXBool normalize, void GXSetTexCoordGen2(GX::TexCoordID dst, GX::TexGenType type, GX::TexGenSrc src, GX::TexMtx mtx, GXBool normalize,
GX::PTTexMtx postMtx) noexcept { GX::PTTexMtx postMtx) noexcept {
@ -422,7 +415,7 @@ ShaderInfo populate_pipeline_config(PipelineConfig& config, GX::Primitive primit
for (u8 i = 0; i < g_gxState.numTexGens; ++i) { for (u8 i = 0; i < g_gxState.numTexGens; ++i) {
config.shaderConfig.tcgs[i] = g_gxState.tcgs[i]; config.shaderConfig.tcgs[i] = g_gxState.tcgs[i];
} }
config.shaderConfig.alphaDiscard = g_gxState.alphaDiscard; config.shaderConfig.alphaCompare = g_gxState.alphaCompare;
if (std::any_of(config.shaderConfig.vtxAttrs.begin(), config.shaderConfig.vtxAttrs.end(), if (std::any_of(config.shaderConfig.vtxAttrs.begin(), config.shaderConfig.vtxAttrs.end(),
[](const auto type) { return type == GX::INDEX8 || type == GX::INDEX16; })) { [](const auto type) { return type == GX::INDEX8 || type == GX::INDEX16; })) {
config.shaderConfig.hasIndexedAttributes = true; config.shaderConfig.hasIndexedAttributes = true;

View File

@ -99,6 +99,15 @@ struct TevSwap {
operator bool() const { return *this != TevSwap{}; } operator bool() const { return *this != TevSwap{}; }
}; };
struct AlphaCompare {
GX::Compare comp0 = GX::ALWAYS;
float ref0 = 0.f;
GX::AlphaOp op = GX::AOP_AND;
GX::Compare comp1 = GX::ALWAYS;
float ref1 = 0.f;
bool operator==(const AlphaCompare& other) const = default;
operator bool() const { return *this != AlphaCompare{}; }
};
struct GXState { struct GXState {
zeus::CMatrix4f mv; zeus::CMatrix4f mv;
zeus::CMatrix4f mvInv; zeus::CMatrix4f mvInv;
@ -112,7 +121,7 @@ struct GXState {
GX::Compare depthFunc = GX::LEQUAL; GX::Compare depthFunc = GX::LEQUAL;
zeus::CColor clearColor = zeus::skBlack; zeus::CColor clearColor = zeus::skBlack;
std::optional<float> dstAlpha; std::optional<float> dstAlpha;
std::optional<float> alphaDiscard; AlphaCompare alphaCompare;
std::array<zeus::CColor, MaxTevRegs> colorRegs; std::array<zeus::CColor, MaxTevRegs> colorRegs;
std::array<zeus::CColor, GX::MAX_KCOLOR> kcolors; std::array<zeus::CColor, GX::MAX_KCOLOR> kcolors;
std::array<ColorChannelConfig, MaxColorChannels> colorChannelConfig; std::array<ColorChannelConfig, MaxColorChannels> colorChannelConfig;
@ -152,7 +161,7 @@ struct ShaderConfig {
std::array<std::optional<TevStage>, MaxTevStages> tevStages; std::array<std::optional<TevStage>, MaxTevStages> tevStages;
std::array<ColorChannelConfig, MaxColorChannels> colorChannels; std::array<ColorChannelConfig, MaxColorChannels> colorChannels;
std::array<TcgConfig, MaxTexCoord> tcgs; std::array<TcgConfig, MaxTexCoord> tcgs;
std::optional<float> alphaDiscard; AlphaCompare alphaCompare;
bool hasIndexedAttributes = false; bool hasIndexedAttributes = false;
bool operator==(const ShaderConfig&) const = default; bool operator==(const ShaderConfig&) const = default;
}; };
@ -281,8 +290,8 @@ inline void xxh3_update(XXH3_state_t& state, const gfx::gx::ShaderConfig& input)
for (const auto& item : input.tcgs) { for (const auto& item : input.tcgs) {
xxh3_update(state, item); xxh3_update(state, item);
} }
if (input.alphaDiscard) { if (input.alphaCompare) {
XXH3_64bits_update(&state, &*input.alphaDiscard, sizeof(float)); XXH3_64bits_update(&state, &input.alphaCompare, sizeof(gfx::gx::AlphaCompare));
} }
XXH3_64bits_update(&state, &input.hasIndexedAttributes, sizeof(gfx::gx::ShaderConfig::hasIndexedAttributes)); XXH3_64bits_update(&state, &input.hasIndexedAttributes, sizeof(gfx::gx::ShaderConfig::hasIndexedAttributes));
} }

View File

@ -344,6 +344,31 @@ static std::string_view tev_bias(GX::TevBias bias) {
} }
} }
static std::string alpha_compare(GX::Compare comp, float ref, bool& valid) {
switch (comp) {
case GX::NEVER:
return "false";
case GX::LESS:
return fmt::format(FMT_STRING("(prev.a < {}f)"), ref);
case GX::LEQUAL:
return fmt::format(FMT_STRING("(prev.a <= {}f)"), ref);
case GX::EQUAL:
return fmt::format(FMT_STRING("(prev.a == {}f)"), ref);
case GX::NEQUAL:
return fmt::format(FMT_STRING("(prev.a != {}f)"), ref);
case GX::GEQUAL:
return fmt::format(FMT_STRING("(prev.a >= {}f)"), ref);
case GX::GREATER:
return fmt::format(FMT_STRING("(prev.a < {}f)"), ref);
case GX::ALWAYS:
valid = false;
return "true";
default:
Log.report(logvisor::Fatal, FMT_STRING("invalid compare {}"), comp);
unreachable();
}
}
static std::string_view tev_scale(GX::TevScale scale) { static std::string_view tev_scale(GX::TevScale scale) {
switch (scale) { switch (scale) {
case GX::CS_SCALE_1: case GX::CS_SCALE_1:
@ -468,7 +493,9 @@ std::pair<wgpu::ShaderModule, ShaderInfo> build_shader(const ShaderConfig& confi
tcg.postMtx, tcg.type, tcg.normalize); tcg.postMtx, tcg.type, tcg.normalize);
} }
} }
Log.report(logvisor::Info, FMT_STRING(" alphaDiscard: {}"), config.alphaDiscard.value_or(0.f)); Log.report(logvisor::Info, FMT_STRING(" alphaCompare: comp0 {} ref0 {} op {} comp1 {} ref1 {}"),
config.alphaCompare.comp0, config.alphaCompare.ref0, config.alphaCompare.op, config.alphaCompare.comp1,
config.alphaCompare.ref1);
Log.report(logvisor::Info, FMT_STRING(" hasIndexedAttributes: {}"), config.hasIndexedAttributes); Log.report(logvisor::Info, FMT_STRING(" hasIndexedAttributes: {}"), config.hasIndexedAttributes);
Log.report(logvisor::Info, FMT_STRING(" fogType: {}"), config.fogType); Log.report(logvisor::Info, FMT_STRING(" fogType: {}"), config.fogType);
} }
@ -810,9 +837,35 @@ var<storage, read> v_packed_uvs: Vec2Block;
texBindIdx, i); texBindIdx, i);
++texBindIdx; ++texBindIdx;
} }
if (config.alphaDiscard) {
fragmentFn += fmt::format(FMT_STRING("\n if (prev.a < {}f) {{ discard; }}"), *config.alphaDiscard); if (config.alphaCompare) {
bool comp0Valid = true;
bool comp1Valid = true;
std::string comp0 = alpha_compare(config.alphaCompare.comp0, config.alphaCompare.ref0, comp0Valid);
std::string comp1 = alpha_compare(config.alphaCompare.comp1, config.alphaCompare.ref1, comp1Valid);
if (comp0Valid || comp1Valid) {
switch (config.alphaCompare.op) {
case GX::AOP_AND:
fragmentFn += fmt::format(FMT_STRING("\n if (!({} && {})) {{ discard; }}"), comp0, comp1);
break;
case GX::AOP_OR:
fragmentFn += fmt::format(FMT_STRING("\n if (!({} || {})) {{ discard; }}"), comp0, comp1);
break;
case GX::AOP_XOR:
fragmentFn += fmt::format(FMT_STRING("\n if (!({} ^^ {})) {{ discard; }}"), comp0, comp1);
break;
case GX::AOP_XNOR:
fragmentFn += fmt::format(FMT_STRING("\n if (({} ^^ {})) {{ discard; }}"), comp0, comp1);
break;
default:
Log.report(logvisor::Fatal, FMT_STRING("invalid alpha compare op {}"), config.alphaCompare.op);
unreachable();
} }
}
}
// if (config.alphaDiscard) {
// fragmentFn += fmt::format(FMT_STRING("\n if (prev.a < {}f) {{ discard; }}"), *config.alphaDiscard);
// }
const auto shaderSource = const auto shaderSource =
fmt::format(FMT_STRING(R"""({uniformPre} fmt::format(FMT_STRING(R"""({uniformPre}