mirror of https://github.com/PCSX2/pcsx2.git
GS/HW: Improve accuracy of RGB_ONLY AFAIL
Instead of breaking the draw into two passes, which breaks when fragments overlap each other and blending is enabled, use blending to leave the value of Ad intact when a pixel fails the alpha test. In the case of DATE being enabled, prefer PrimID over stencil, as since we are changing Ad on a per-fragment basis, with some fragments not being modified, stencil DATE will become desynchronized with the value of Ad.
This commit is contained in:
parent
b644f85f51
commit
a317e9c038
|
@ -701,29 +701,30 @@ float4 tfx(float4 T, float4 C)
|
|||
return C_out;
|
||||
}
|
||||
|
||||
void atst(float4 C)
|
||||
bool atst(float4 C)
|
||||
{
|
||||
float a = C.a;
|
||||
|
||||
if(PS_ATST == 0)
|
||||
if(PS_ATST == 1)
|
||||
{
|
||||
// nothing to do
|
||||
}
|
||||
else if(PS_ATST == 1)
|
||||
{
|
||||
if (a > AREF) discard;
|
||||
return (a <= AREF);
|
||||
}
|
||||
else if(PS_ATST == 2)
|
||||
{
|
||||
if (a < AREF) discard;
|
||||
return (a >= AREF);
|
||||
}
|
||||
else if(PS_ATST == 3)
|
||||
{
|
||||
if (abs(a - AREF) > 0.5f) discard;
|
||||
return (abs(a - AREF) <= 0.5f);
|
||||
}
|
||||
else if(PS_ATST == 4)
|
||||
{
|
||||
if (abs(a - AREF) < 0.5f) discard;
|
||||
return (abs(a - AREF) >= 0.5f);
|
||||
}
|
||||
else
|
||||
{
|
||||
// nothing to do
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -786,8 +787,6 @@ float4 ps_color(PS_INPUT input)
|
|||
|
||||
float4 C = tfx(T, input.c);
|
||||
|
||||
atst(C);
|
||||
|
||||
C = fog(C, input.t.z);
|
||||
|
||||
return C;
|
||||
|
@ -964,6 +963,12 @@ void ps_blend(inout float4 Color, inout float4 As_rgba, float2 pos_xy)
|
|||
PS_OUTPUT ps_main(PS_INPUT input)
|
||||
{
|
||||
float4 C = ps_color(input);
|
||||
bool atst_pass = atst(C);
|
||||
|
||||
#if PS_AFAIL == 0 // KEEP or ATST off
|
||||
if (!atst_pass)
|
||||
discard;
|
||||
#endif
|
||||
|
||||
PS_OUTPUT output;
|
||||
|
||||
|
@ -1119,6 +1124,11 @@ PS_OUTPUT ps_main(PS_INPUT input)
|
|||
|
||||
ps_fbmask(C, input.p.xy);
|
||||
|
||||
#if PS_AFAIL == 3 // RGB_ONLY
|
||||
// Use alpha blend factor to determine whether to update A.
|
||||
alpha_blend.a = float(atst_pass);
|
||||
#endif
|
||||
|
||||
#if !PS_NO_COLOR
|
||||
output.c0.a = PS_RTA_CORRECTION ? C.a / 128.0f : C.a / 255.0f;
|
||||
output.c0.rgb = PS_HDR ? float3(C.rgb / 65535.0f) : C.rgb / 255.0f;
|
||||
|
|
|
@ -640,20 +640,21 @@ vec4 tfx(vec4 T, vec4 C)
|
|||
return C_out;
|
||||
}
|
||||
|
||||
void atst(vec4 C)
|
||||
bool atst(vec4 C)
|
||||
{
|
||||
float a = C.a;
|
||||
|
||||
#if (PS_ATST == 0)
|
||||
// nothing to do
|
||||
#elif (PS_ATST == 1)
|
||||
if (a > AREF) discard;
|
||||
#if (PS_ATST == 1)
|
||||
return (a <= AREF);
|
||||
#elif (PS_ATST == 2)
|
||||
if (a < AREF) discard;
|
||||
return (a >= AREF);
|
||||
#elif (PS_ATST == 3)
|
||||
if (abs(a - AREF) > 0.5f) discard;
|
||||
return (abs(a - AREF) <= 0.5f);
|
||||
#elif (PS_ATST == 4)
|
||||
if (abs(a - AREF) < 0.5f) discard;
|
||||
return (abs(a - AREF) >= 0.5f);
|
||||
#else
|
||||
// nothing to do
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -984,6 +985,12 @@ void ps_main()
|
|||
#endif
|
||||
|
||||
vec4 C = ps_color();
|
||||
bool atst_pass = atst(C);
|
||||
|
||||
#if PS_AFAIL == 0 // KEEP or ATST off
|
||||
if (!atst_pass)
|
||||
discard;
|
||||
#endif
|
||||
|
||||
// Must be done before alpha correction
|
||||
|
||||
|
@ -1102,6 +1109,11 @@ void ps_main()
|
|||
|
||||
ps_fbmask(C);
|
||||
|
||||
#if PS_AFAIL == 3 // RGB_ONLY
|
||||
// Use alpha blend factor to determine whether to update A.
|
||||
alpha_blend.a = float(atst_pass);
|
||||
#endif
|
||||
|
||||
#if !PS_NO_COLOR
|
||||
#if PS_RTA_CORRECTION
|
||||
SV_Target0.a = C.a / 128.0f;
|
||||
|
|
|
@ -260,6 +260,7 @@ void main()
|
|||
#define PS_TFX 0
|
||||
#define PS_TCC 1
|
||||
#define PS_ATST 1
|
||||
#define PS_AFAIL 0
|
||||
#define PS_FOG 0
|
||||
#define PS_BLEND_HW 0
|
||||
#define PS_A_MASKED 0
|
||||
|
@ -885,29 +886,30 @@ vec4 tfx(vec4 T, vec4 C)
|
|||
return C_out;
|
||||
}
|
||||
|
||||
void atst(vec4 C)
|
||||
bool atst(vec4 C)
|
||||
{
|
||||
float a = C.a;
|
||||
|
||||
#if (PS_ATST == 0)
|
||||
#if (PS_ATST == 1)
|
||||
{
|
||||
// nothing to do
|
||||
}
|
||||
#elif (PS_ATST == 1)
|
||||
{
|
||||
if (a > AREF) discard;
|
||||
return (a <= AREF);
|
||||
}
|
||||
#elif (PS_ATST == 2)
|
||||
{
|
||||
if (a < AREF) discard;
|
||||
return (a >= AREF);
|
||||
}
|
||||
#elif (PS_ATST == 3)
|
||||
{
|
||||
if (abs(a - AREF) > 0.5f) discard;
|
||||
return (abs(a - AREF) <= 0.5f);
|
||||
}
|
||||
#elif (PS_ATST == 4)
|
||||
{
|
||||
if (abs(a - AREF) < 0.5f) discard;
|
||||
return (abs(a - AREF) >= 0.5f);
|
||||
}
|
||||
#else
|
||||
{
|
||||
// nothing to do
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -968,8 +970,6 @@ vec4 ps_color()
|
|||
|
||||
vec4 C = tfx(T, vsIn.c);
|
||||
|
||||
atst(C);
|
||||
|
||||
C = fog(C, vsIn.t.z);
|
||||
|
||||
return C;
|
||||
|
@ -1238,6 +1238,12 @@ void main()
|
|||
#endif
|
||||
|
||||
vec4 C = ps_color();
|
||||
bool atst_pass = atst(C);
|
||||
|
||||
#if PS_AFAIL == 0 // KEEP or ATST off
|
||||
if (!atst_pass)
|
||||
discard;
|
||||
#endif
|
||||
|
||||
// Must be done before alpha correction
|
||||
|
||||
|
@ -1258,7 +1264,7 @@ void main()
|
|||
vec4 alpha_blend = vec4(C.a / 128.0f);
|
||||
#endif
|
||||
|
||||
// Correct the ALPHA value based on the output format
|
||||
// Correct the ALPHA value based on the output format
|
||||
#if (PS_DST_FMT == FMT_16)
|
||||
float A_one = 128.0f; // alpha output will be 0x80
|
||||
C.a = (PS_FBA != 0) ? A_one : step(128.0f, C.a) * A_one;
|
||||
|
@ -1357,6 +1363,11 @@ void main()
|
|||
|
||||
ps_fbmask(C);
|
||||
|
||||
#if PS_AFAIL == 3 // RGB_ONLY
|
||||
// Use alpha blend factor to determine whether to update A.
|
||||
alpha_blend.a = float(atst_pass);
|
||||
#endif
|
||||
|
||||
#if !PS_NO_COLOR
|
||||
#if PS_RTA_CORRECTION
|
||||
o_col0.a = C.a / 128.0f;
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
// SPDX-FileCopyrightText: 2002-2023 PCSX2 Dev Team
|
||||
// SPDX-FileCopyrightText: 2002-2024 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: LGPL-3.0+
|
||||
|
||||
#include "GSDrawingContext.h"
|
||||
#include "GSGL.h"
|
||||
#include "GS.h"
|
||||
#include "GS/GSDrawingContext.h"
|
||||
#include "GS/GSGL.h"
|
||||
#include "GS/GS.h"
|
||||
#include "GS/GSUtil.h"
|
||||
|
||||
static int findmax(int tl, int br, int limit, int wm, int minuv, int maxuv)
|
||||
{
|
||||
|
@ -258,14 +259,14 @@ void GSDrawingContext::Dump(const std::string& filename)
|
|||
fprintf(fp,
|
||||
"TEST\n"
|
||||
"\tATE:%u\n"
|
||||
"\tATST:%u\n"
|
||||
"\tATST:%s\n"
|
||||
"\tAREF:%u\n"
|
||||
"\tAFAIL:%u\n"
|
||||
"\tAFAIL:%s\n"
|
||||
"\tDATE:%u\n"
|
||||
"\tDATM:%u\n"
|
||||
"\tZTE:%u\n"
|
||||
"\tZTST:%u\n\n",
|
||||
TEST.ATE, TEST.ATST, TEST.AREF, TEST.AFAIL, TEST.DATE, TEST.DATM, TEST.ZTE, TEST.ZTST);
|
||||
TEST.ATE, GSUtil::GetATSTName(TEST.ATST), TEST.AREF, GSUtil::GetAFAILName(TEST.AFAIL), TEST.DATE, TEST.DATM, TEST.ZTE, TEST.ZTST);
|
||||
|
||||
fprintf(fp,
|
||||
"FBA\n"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// SPDX-FileCopyrightText: 2002-2023 PCSX2 Dev Team
|
||||
// SPDX-FileCopyrightText: 2002-2024 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: LGPL-3.0+
|
||||
|
||||
#include "GS/GS.h"
|
||||
|
@ -7,6 +7,8 @@
|
|||
#include "MultiISA.h"
|
||||
#include "common/StringUtil.h"
|
||||
|
||||
#include <array>
|
||||
|
||||
#ifdef ENABLE_VULKAN
|
||||
#include "GS/Renderers/Vulkan/GSDeviceVK.h"
|
||||
#endif
|
||||
|
@ -115,6 +117,19 @@ void GSUtil::Init()
|
|||
s_maps.Init();
|
||||
}
|
||||
|
||||
const char* GSUtil::GetATSTName(u32 atst)
|
||||
{
|
||||
static constexpr const char* names[] = {
|
||||
"NEVER", "ALWAYS", "LESS", "LEQUAL", "EQUAL", "GEQUAL", "GREATER", "NOTEQUAL" };
|
||||
return (atst < std::size(names)) ? names[atst] : "";
|
||||
}
|
||||
|
||||
const char* GSUtil::GetAFAILName(u32 afail)
|
||||
{
|
||||
static constexpr const char* names[] = {"KEEP", "FB_ONLY", "ZB_ONLY", "RGB_ONLY"};
|
||||
return (afail < std::size(names)) ? names[afail] : "";
|
||||
}
|
||||
|
||||
GS_PRIM_CLASS GSUtil::GetPrimClass(u32 prim)
|
||||
{
|
||||
return (GS_PRIM_CLASS)s_maps.PrimClassField[prim];
|
||||
|
|
|
@ -11,6 +11,9 @@ class GSUtil
|
|||
public:
|
||||
static void Init();
|
||||
|
||||
static const char* GetATSTName(u32 atst);
|
||||
static const char* GetAFAILName(u32 afail);
|
||||
|
||||
static GS_PRIM_CLASS GetPrimClass(u32 prim);
|
||||
static int GetVertexCount(u32 prim);
|
||||
static int GetClassVertexCount(u32 primclass);
|
||||
|
|
|
@ -304,6 +304,7 @@ struct alignas(16) GSHWDrawConfig
|
|||
// Pixel test
|
||||
u32 date : 3;
|
||||
u32 atst : 3;
|
||||
u32 afail : 2;
|
||||
// Color sampling
|
||||
u32 fst : 1; // Investigate to do it on the VS
|
||||
u32 tfx : 3;
|
||||
|
|
|
@ -1667,6 +1667,7 @@ void GSDevice11::SetupPS(const PSSelector& sel, const GSHWDrawConfig::PSConstant
|
|||
sm.AddMacro("PS_TCC", sel.tcc);
|
||||
sm.AddMacro("PS_DATE", sel.date);
|
||||
sm.AddMacro("PS_ATST", sel.atst);
|
||||
sm.AddMacro("PS_AFAIL", sel.afail);
|
||||
sm.AddMacro("PS_FOG", sel.fog);
|
||||
sm.AddMacro("PS_IIP", sel.iip);
|
||||
sm.AddMacro("PS_BLEND_HW", sel.blend_hw);
|
||||
|
|
|
@ -2821,6 +2821,7 @@ const ID3DBlob* GSDevice12::GetTFXPixelShader(const GSHWDrawConfig::PSSelector&
|
|||
sm.AddMacro("PS_TCC", sel.tcc);
|
||||
sm.AddMacro("PS_DATE", sel.date);
|
||||
sm.AddMacro("PS_ATST", sel.atst);
|
||||
sm.AddMacro("PS_AFAIL", sel.afail);
|
||||
sm.AddMacro("PS_FOG", sel.fog);
|
||||
sm.AddMacro("PS_IIP", sel.iip);
|
||||
sm.AddMacro("PS_BLEND_HW", sel.blend_hw);
|
||||
|
|
|
@ -2290,7 +2290,7 @@ void GSRendererHW::Draw()
|
|||
if (PRIM->FST)
|
||||
{
|
||||
pxAssert(lcm == 1);
|
||||
pxAssert(((m_vt.m_min.t.uph(m_vt.m_max.t) == GSVector4::zero()).mask() & 3) == 3); // ratchet and clank (menu)
|
||||
//pxAssert(((m_vt.m_min.t.uph(m_vt.m_max.t) == GSVector4::zero()).mask() & 3) == 3); // ratchet and clank (menu)
|
||||
|
||||
lcm = 1;
|
||||
}
|
||||
|
@ -5054,9 +5054,6 @@ __ri void GSRendererHW::DrawPrims(GSTextureCache::Target* rt, GSTextureCache::Ta
|
|||
bool DATE_BARRIER = false;
|
||||
bool DATE_one = false;
|
||||
|
||||
const bool ate_first_pass = m_cached_ctx.TEST.DoFirstPass();
|
||||
const bool ate_second_pass = m_cached_ctx.TEST.DoSecondPass();
|
||||
|
||||
ResetStates();
|
||||
|
||||
const float scale_factor = rt ? rt->GetScale() : ds->GetScale();
|
||||
|
@ -5443,6 +5440,80 @@ __ri void GSRendererHW::DrawPrims(GSTextureCache::Target* rt, GSTextureCache::Ta
|
|||
}
|
||||
}
|
||||
|
||||
// Warning must be done after EmulateZbuffer
|
||||
// Depth test is always true so it can be executed in 2 passes (no order required) unlike color.
|
||||
// The idea is to compute first the color which is independent of the alpha test. And then do a 2nd
|
||||
// pass to handle the depth based on the alpha test.
|
||||
const bool ate_first_pass = m_cached_ctx.TEST.DoFirstPass();
|
||||
bool ate_second_pass = m_cached_ctx.TEST.DoSecondPass();
|
||||
bool ate_RGBA_then_Z = false;
|
||||
bool ate_RGB_then_Z = false;
|
||||
GL_INS("%sAlpha Test, ATST=%s, AFAIL=%s", (ate_first_pass && ate_second_pass) ? "Complex" : "",
|
||||
GSUtil::GetATSTName(m_cached_ctx.TEST.ATST), GSUtil::GetAFAILName(m_cached_ctx.TEST.AFAIL));
|
||||
if (ate_first_pass && ate_second_pass)
|
||||
{
|
||||
const bool commutative_depth = (m_conf.depth.ztst == ZTST_GEQUAL && m_vt.m_eq.z) || (m_conf.depth.ztst == ZTST_ALWAYS) || !m_conf.depth.zwe;
|
||||
const bool commutative_alpha = (m_context->ALPHA.C != 1) || !m_conf.colormask.wa; // when either Alpha Src or a constant, or not updating A
|
||||
const u32 afail = m_cached_ctx.TEST.GetAFAIL(m_cached_ctx.FRAME.PSM);
|
||||
|
||||
ate_RGBA_then_Z = (afail == AFAIL_FB_ONLY) && commutative_depth;
|
||||
ate_RGB_then_Z = (afail == AFAIL_RGB_ONLY) && commutative_depth && commutative_alpha;
|
||||
}
|
||||
|
||||
if (ate_RGBA_then_Z)
|
||||
{
|
||||
GL_INS("Alternate ATE handling: ate_RGBA_then_Z");
|
||||
// Render all color but don't update depth
|
||||
// ATE is disabled here
|
||||
m_conf.depth.zwe = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
float aref = m_conf.cb_ps.FogColor_AREF.a;
|
||||
EmulateATST(aref, m_conf.ps, false);
|
||||
|
||||
// avoid redundant cbuffer updates
|
||||
m_conf.cb_ps.FogColor_AREF.a = aref;
|
||||
m_conf.alpha_second_pass.ps_aref = aref;
|
||||
|
||||
if (ate_RGB_then_Z)
|
||||
{
|
||||
GL_INS("Alternate ATE handling: ate_RGB_then_Z");
|
||||
|
||||
// Blending might be off, ensure it's enabled.
|
||||
// We write the alpha pass/fail to SRC1_ALPHA, which is used to update A.
|
||||
m_conf.ps.afail = AFAIL_RGB_ONLY;
|
||||
m_conf.ps.no_color1 = false;
|
||||
if (!m_conf.blend.enable)
|
||||
{
|
||||
m_conf.blend = GSHWDrawConfig::BlendState(true, GSDevice::CONST_ONE, GSDevice::CONST_ZERO,
|
||||
GSDevice::OP_ADD, GSDevice::SRC1_ALPHA, GSDevice::INV_SRC1_ALPHA, false, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_conf.blend.src_factor_alpha = GSDevice::SRC1_ALPHA;
|
||||
m_conf.blend.dst_factor_alpha = GSDevice::INV_SRC1_ALPHA;
|
||||
}
|
||||
|
||||
// If Z writes are on, unfortunately we can't single pass it.
|
||||
// But we can write Z in the second pass instead.
|
||||
ate_RGBA_then_Z = m_conf.depth.zwe;
|
||||
ate_second_pass &= ate_RGBA_then_Z;
|
||||
m_conf.depth.zwe = false;
|
||||
|
||||
// Swap stencil DATE for PrimID DATE, for both Z on and off cases.
|
||||
// Because we're making some pixels pass, but not update A, the stencil won't be synced.
|
||||
if (DATE && !DATE_BARRIER && features.primitive_id)
|
||||
{
|
||||
if (!DATE_PRIMID)
|
||||
GL_INS("Swap stencil DATE for PrimID, due to AFAIL");
|
||||
|
||||
DATE_one = false;
|
||||
DATE_PRIMID = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// No point outputting colours if we're just writing depth.
|
||||
// We might still need the framebuffer for DATE, though.
|
||||
if (!rt || m_conf.colormask.wrgba == 0)
|
||||
|
@ -5580,47 +5651,6 @@ __ri void GSRendererHW::DrawPrims(GSTextureCache::Target* rt, GSTextureCache::Ta
|
|||
m_conf.cb_ps.FogColor_AREF = fc.blend32<8>(m_conf.cb_ps.FogColor_AREF);
|
||||
}
|
||||
|
||||
// Warning must be done after EmulateZbuffer
|
||||
// Depth test is always true so it can be executed in 2 passes (no order required) unlike color.
|
||||
// The idea is to compute first the color which is independent of the alpha test. And then do a 2nd
|
||||
// pass to handle the depth based on the alpha test.
|
||||
bool ate_RGBA_then_Z = false;
|
||||
bool ate_RGB_then_ZA = false;
|
||||
if (ate_first_pass && ate_second_pass)
|
||||
{
|
||||
GL_DBG("Complex Alpha Test");
|
||||
const bool commutative_depth = (m_conf.depth.ztst == ZTST_GEQUAL && m_vt.m_eq.z) || (m_conf.depth.ztst == ZTST_ALWAYS);
|
||||
const bool commutative_alpha = (m_context->ALPHA.C != 1); // when either Alpha Src or a constant
|
||||
|
||||
ate_RGBA_then_Z = m_cached_ctx.TEST.GetAFAIL(m_cached_ctx.FRAME.PSM) == AFAIL_FB_ONLY && commutative_depth;
|
||||
ate_RGB_then_ZA = m_cached_ctx.TEST.GetAFAIL(m_cached_ctx.FRAME.PSM) == AFAIL_RGB_ONLY && commutative_depth && commutative_alpha;
|
||||
}
|
||||
|
||||
if (ate_RGBA_then_Z)
|
||||
{
|
||||
GL_DBG("Alternate ATE handling: ate_RGBA_then_Z");
|
||||
// Render all color but don't update depth
|
||||
// ATE is disabled here
|
||||
m_conf.depth.zwe = false;
|
||||
}
|
||||
else if (ate_RGB_then_ZA)
|
||||
{
|
||||
GL_DBG("Alternate ATE handling: ate_RGB_then_ZA");
|
||||
// Render RGB color but don't update depth/alpha
|
||||
// ATE is disabled here
|
||||
m_conf.depth.zwe = false;
|
||||
m_conf.colormask.wa = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
float aref = m_conf.cb_ps.FogColor_AREF.a;
|
||||
EmulateATST(aref, m_conf.ps, false);
|
||||
|
||||
// avoid redundant cbuffer updates
|
||||
m_conf.cb_ps.FogColor_AREF.a = aref;
|
||||
m_conf.alpha_second_pass.ps_aref = aref;
|
||||
}
|
||||
|
||||
GSTexture* tex_copy = nullptr;
|
||||
if (tex)
|
||||
{
|
||||
|
@ -5666,11 +5696,14 @@ __ri void GSRendererHW::DrawPrims(GSTextureCache::Target* rt, GSTextureCache::Ta
|
|||
if (ate_second_pass)
|
||||
{
|
||||
pxAssert(!env.PABE.PABE);
|
||||
memcpy(&m_conf.alpha_second_pass.ps, &m_conf.ps, sizeof(m_conf.ps));
|
||||
memcpy(&m_conf.alpha_second_pass.colormask, &m_conf.colormask, sizeof(m_conf.colormask));
|
||||
memcpy(&m_conf.alpha_second_pass.depth, &m_conf.depth, sizeof(m_conf.depth));
|
||||
std::memcpy(&m_conf.alpha_second_pass.ps, &m_conf.ps, sizeof(m_conf.ps));
|
||||
std::memcpy(&m_conf.alpha_second_pass.colormask, &m_conf.colormask, sizeof(m_conf.colormask));
|
||||
std::memcpy(&m_conf.alpha_second_pass.depth, &m_conf.depth, sizeof(m_conf.depth));
|
||||
|
||||
if (ate_RGBA_then_Z || ate_RGB_then_ZA)
|
||||
// Not doing single pass AFAIL.
|
||||
m_conf.alpha_second_pass.ps.afail = AFAIL_KEEP;
|
||||
|
||||
if (ate_RGBA_then_Z)
|
||||
{
|
||||
// Enable ATE as first pass to update the depth
|
||||
// of pixels that passed the alpha test
|
||||
|
@ -5683,7 +5716,6 @@ __ri void GSRendererHW::DrawPrims(GSTextureCache::Target* rt, GSTextureCache::Ta
|
|||
EmulateATST(m_conf.alpha_second_pass.ps_aref, m_conf.alpha_second_pass.ps, true);
|
||||
}
|
||||
|
||||
|
||||
bool z = m_conf.depth.zwe;
|
||||
bool r = m_conf.colormask.wr;
|
||||
bool g = m_conf.colormask.wg;
|
||||
|
@ -5706,12 +5738,6 @@ __ri void GSRendererHW::DrawPrims(GSTextureCache::Target* rt, GSTextureCache::Ta
|
|||
z = !m_cached_ctx.ZBUF.ZMSK;
|
||||
r = g = b = a = false;
|
||||
}
|
||||
else if (ate_RGB_then_ZA)
|
||||
{
|
||||
z = !m_cached_ctx.ZBUF.ZMSK;
|
||||
a = (m_cached_ctx.FRAME.FBMSK & 0xFF000000) != 0xFF000000;
|
||||
r = g = b = false;
|
||||
}
|
||||
|
||||
if (z || r || g || b || a)
|
||||
{
|
||||
|
@ -5738,9 +5764,9 @@ __ri void GSRendererHW::DrawPrims(GSTextureCache::Target* rt, GSTextureCache::Ta
|
|||
}
|
||||
|
||||
// RenderHW always renders first pass, replace first pass with second
|
||||
memcpy(&m_conf.ps, &m_conf.alpha_second_pass.ps, sizeof(m_conf.ps));
|
||||
memcpy(&m_conf.colormask, &m_conf.alpha_second_pass.colormask, sizeof(m_conf.colormask));
|
||||
memcpy(&m_conf.depth, &m_conf.alpha_second_pass.depth, sizeof(m_conf.depth));
|
||||
std::memcpy(&m_conf.ps, &m_conf.alpha_second_pass.ps, sizeof(m_conf.ps));
|
||||
std::memcpy(&m_conf.colormask, &m_conf.alpha_second_pass.colormask, sizeof(m_conf.colormask));
|
||||
std::memcpy(&m_conf.depth, &m_conf.alpha_second_pass.depth, sizeof(m_conf.depth));
|
||||
m_conf.cb_ps.FogColor_AREF.a = m_conf.alpha_second_pass.ps_aref;
|
||||
m_conf.alpha_second_pass.enable = false;
|
||||
}
|
||||
|
|
|
@ -1803,6 +1803,7 @@ void GSDeviceMTL::MRESetHWPipelineState(GSHWDrawConfig::VSSelector vssel, GSHWDr
|
|||
setFnConstantB(m_fn_constants, pssel.fog, GSMTLConstantIndex_PS_FOG);
|
||||
setFnConstantI(m_fn_constants, pssel.date, GSMTLConstantIndex_PS_DATE);
|
||||
setFnConstantI(m_fn_constants, pssel.atst, GSMTLConstantIndex_PS_ATST);
|
||||
setFnConstantI(m_fn_constants, pssel.afail, GSMTLConstantIndex_PS_AFAIL);
|
||||
setFnConstantI(m_fn_constants, pssel.tfx, GSMTLConstantIndex_PS_TFX);
|
||||
setFnConstantB(m_fn_constants, pssel.tcc, GSMTLConstantIndex_PS_TCC);
|
||||
setFnConstantI(m_fn_constants, pssel.wms, GSMTLConstantIndex_PS_WMS);
|
||||
|
|
|
@ -162,6 +162,7 @@ enum GSMTLFnConstants
|
|||
GSMTLConstantIndex_PS_FOG,
|
||||
GSMTLConstantIndex_PS_DATE,
|
||||
GSMTLConstantIndex_PS_ATST,
|
||||
GSMTLConstantIndex_PS_AFAIL,
|
||||
GSMTLConstantIndex_PS_TFX,
|
||||
GSMTLConstantIndex_PS_TCC,
|
||||
GSMTLConstantIndex_PS_WMS,
|
||||
|
|
|
@ -25,6 +25,7 @@ constant bool PS_FBA [[function_constant(GSMTLConstantIndex_PS_FB
|
|||
constant bool PS_FOG [[function_constant(GSMTLConstantIndex_PS_FOG)]];
|
||||
constant uint PS_DATE [[function_constant(GSMTLConstantIndex_PS_DATE)]];
|
||||
constant uint PS_ATST [[function_constant(GSMTLConstantIndex_PS_ATST)]];
|
||||
constant uint PS_AFAIL [[function_constant(GSMTLConstantIndex_PS_AFAIL)]];
|
||||
constant uint PS_TFX [[function_constant(GSMTLConstantIndex_PS_TFX)]];
|
||||
constant bool PS_TCC [[function_constant(GSMTLConstantIndex_PS_TCC)]];
|
||||
constant uint PS_WMS [[function_constant(GSMTLConstantIndex_PS_WMS)]];
|
||||
|
@ -850,8 +851,7 @@ struct PSMain
|
|||
}
|
||||
|
||||
float4 C = tfx(T, IIP ? in.c : in.fc);
|
||||
if (!atst(C))
|
||||
discard_fragment();
|
||||
|
||||
fog(C, in.t.z);
|
||||
|
||||
return C;
|
||||
|
@ -1054,6 +1054,9 @@ struct PSMain
|
|||
}
|
||||
|
||||
float4 C = ps_color();
|
||||
bool atst_pass = atst(C);
|
||||
if (PS_AFAIL == 0 && !atst_pass)
|
||||
discard_fragment();
|
||||
|
||||
// Must be done before alpha correction
|
||||
|
||||
|
@ -1189,6 +1192,10 @@ struct PSMain
|
|||
|
||||
ps_fbmask(C);
|
||||
|
||||
// Use alpha blend factor to determine whether to update A.
|
||||
if (PS_AFAIL == 3) // RGB_ONLY
|
||||
alpha_blend.a = float(atst_pass);
|
||||
|
||||
if (PS_COLOR0)
|
||||
out.c0.a = PS_RTA_CORRECTION ? C.a / 128.f : C.a / 255.f;
|
||||
out.c0.rgb = PS_HDR ? float3(C.rgb / 65535.f) : C.rgb / 255.f;
|
||||
|
|
|
@ -1348,6 +1348,7 @@ std::string GSDeviceOGL::GetPSSource(const PSSelector& sel)
|
|||
+ fmt::format("#define PS_TFX {}\n", sel.tfx)
|
||||
+ fmt::format("#define PS_TCC {}\n", sel.tcc)
|
||||
+ fmt::format("#define PS_ATST {}\n", sel.atst)
|
||||
+ fmt::format("#define PS_AFAIL {}\n", sel.afail)
|
||||
+ fmt::format("#define PS_FOG {}\n", sel.fog)
|
||||
+ fmt::format("#define PS_BLEND_HW {}\n", sel.blend_hw)
|
||||
+ fmt::format("#define PS_A_MASKED {}\n", sel.a_masked)
|
||||
|
|
|
@ -4791,6 +4791,7 @@ VkShaderModule GSDeviceVK::GetTFXFragmentShader(const GSHWDrawConfig::PSSelector
|
|||
AddMacro(ss, "PS_TFX", sel.tfx);
|
||||
AddMacro(ss, "PS_TCC", sel.tcc);
|
||||
AddMacro(ss, "PS_ATST", sel.atst);
|
||||
AddMacro(ss, "PS_AFAIL", sel.afail);
|
||||
AddMacro(ss, "PS_FOG", sel.fog);
|
||||
AddMacro(ss, "PS_BLEND_HW", sel.blend_hw);
|
||||
AddMacro(ss, "PS_A_MASKED", sel.a_masked);
|
||||
|
|
|
@ -3,4 +3,4 @@
|
|||
|
||||
/// Version number for GS and other shaders. Increment whenever any of the contents of the
|
||||
/// shaders change, to invalidate the cache.
|
||||
static constexpr u32 SHADER_CACHE_VERSION = 43;
|
||||
static constexpr u32 SHADER_CACHE_VERSION = 44;
|
||||
|
|
Loading…
Reference in New Issue