diff --git a/aurora/lib/gfx/gx.cpp b/aurora/lib/gfx/gx.cpp index 9d26e8f36..b0e3a8c87 100644 --- a/aurora/lib/gfx/gx.cpp +++ b/aurora/lib/gfx/gx.cpp @@ -108,14 +108,7 @@ void GXSetChanCtrl(GX::ChannelID id, bool lightingEnabled, GX::ColorSrc ambSrc, g_gxState.colorChannelState[idx].lightState = lightState; } 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.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(); - } + g_gxState.alphaCompare = {comp0, ref0, op, comp1, ref1}; } void GXSetTexCoordGen2(GX::TexCoordID dst, GX::TexGenType type, GX::TexGenSrc src, GX::TexMtx mtx, GXBool normalize, 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) { 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(), [](const auto type) { return type == GX::INDEX8 || type == GX::INDEX16; })) { config.shaderConfig.hasIndexedAttributes = true; diff --git a/aurora/lib/gfx/gx.hpp b/aurora/lib/gfx/gx.hpp index 3a7376728..ed5d944d4 100644 --- a/aurora/lib/gfx/gx.hpp +++ b/aurora/lib/gfx/gx.hpp @@ -99,6 +99,15 @@ struct 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 { zeus::CMatrix4f mv; zeus::CMatrix4f mvInv; @@ -112,7 +121,7 @@ struct GXState { GX::Compare depthFunc = GX::LEQUAL; zeus::CColor clearColor = zeus::skBlack; std::optional dstAlpha; - std::optional alphaDiscard; + AlphaCompare alphaCompare; std::array colorRegs; std::array kcolors; std::array colorChannelConfig; @@ -152,7 +161,7 @@ struct ShaderConfig { std::array, MaxTevStages> tevStages; std::array colorChannels; std::array tcgs; - std::optional alphaDiscard; + AlphaCompare alphaCompare; bool hasIndexedAttributes = false; 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) { xxh3_update(state, item); } - if (input.alphaDiscard) { - XXH3_64bits_update(&state, &*input.alphaDiscard, sizeof(float)); + if (input.alphaCompare) { + XXH3_64bits_update(&state, &input.alphaCompare, sizeof(gfx::gx::AlphaCompare)); } XXH3_64bits_update(&state, &input.hasIndexedAttributes, sizeof(gfx::gx::ShaderConfig::hasIndexedAttributes)); } diff --git a/aurora/lib/gfx/gx_shader.cpp b/aurora/lib/gfx/gx_shader.cpp index bb88b5887..edebb9cdb 100644 --- a/aurora/lib/gfx/gx_shader.cpp +++ b/aurora/lib/gfx/gx_shader.cpp @@ -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) { switch (scale) { case GX::CS_SCALE_1: @@ -468,7 +493,9 @@ std::pair build_shader(const ShaderConfig& confi 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(" fogType: {}"), config.fogType); } @@ -810,9 +837,35 @@ var v_packed_uvs: Vec2Block; texBindIdx, i); ++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 = fmt::format(FMT_STRING(R"""({uniformPre}