Skip to content

Commit

Permalink
GS/HW: Initial support for RTA correction.
Browse files Browse the repository at this point in the history
Copy the rt and change it's AD value then copy it back to the rt.
  • Loading branch information
lightningterror committed Feb 23, 2024
1 parent f00f0cc commit f869641
Show file tree
Hide file tree
Showing 13 changed files with 146 additions and 21 deletions.
16 changes: 16 additions & 0 deletions bin/resources/shaders/dx11/convert.fx
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,22 @@ PS_OUTPUT ps_datm0(PS_INPUT input)
return output;
}

PS_OUTPUT ps_rta_correction(PS_INPUT input)
{
PS_OUTPUT output;
float4 value = sample_c(input.t);
output.c = float4(value.rgb, trunc(value.a * 255 + 0.1) / 128);
return output;
}

PS_OUTPUT ps_rta_decorrection(PS_INPUT input)
{
PS_OUTPUT output;
float4 value = sample_c(input.t);
output.c = float4(value.rgb, (value.a * 128) / 255);
return output;
}

PS_OUTPUT ps_hdr_init(PS_INPUT input)
{
PS_OUTPUT output;
Expand Down
4 changes: 3 additions & 1 deletion bin/resources/shaders/dx11/tfx.fx
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
#define PS_TALES_OF_ABYSS_HLE 0
#define PS_URBAN_CHAOS_HLE 0
#define PS_HDR 0
#define PS_RTA_CORRECTION 0
#define PS_COLCLIP 0
#define PS_BLEND_A 0
#define PS_BLEND_B 0
Expand Down Expand Up @@ -1069,7 +1070,8 @@ PS_OUTPUT ps_main(PS_INPUT input)
ps_fbmask(C, input.p.xy);

#if !PS_NO_COLOR
output.c0 = PS_HDR ? float4(C.rgb / 65535.0f, C.a / 255.0f) : C / 255.0f;
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;
#if !PS_NO_COLOR1
output.c1 = alpha_blend;
#endif
Expand Down
16 changes: 16 additions & 0 deletions bin/resources/shaders/opengl/convert.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,22 @@ void ps_datm0()
}
#endif

#ifdef ps_rta_correction
void ps_rta_correction()
{
vec4 value = sample_c();
SV_Target0 = vec4(value.rgb, trunc(value.a * 255 + 0.1) / 128);
}
#endif

#ifdef ps_rta_decorrection
void ps_rta_decorrection()
{
vec4 value = sample_c(v_tex);
o_col0 = vec4(value.rgb, value.a * 128 / 255);
}
#endif

#ifdef ps_hdr_init
void ps_hdr_init()
{
Expand Down
16 changes: 16 additions & 0 deletions bin/resources/shaders/vulkan/convert.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,22 @@ void ps_datm0()
}
#endif

#ifdef ps_rta_correction
void ps_rta_correction()
{
vec4 value = sample_c(v_tex);
o_col0 = vec4(value.rgb, trunc(value.a * 255 + 0.1) / 128);
}
#endif

#ifdef ps_rta_decorrection
void ps_rta_decorrection()
{
vec4 value = sample_c(v_tex);
o_col0 = vec4(value.rgb, value.a * 128 / 255);
}
#endif

#ifdef ps_hdr_init
void ps_hdr_init()
{
Expand Down
2 changes: 2 additions & 0 deletions pcsx2/GS/Renderers/Common/GSDevice.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ const char* shaderName(ShaderConvert value)
case ShaderConvert::DATM_0: return "ps_datm0";
case ShaderConvert::HDR_INIT: return "ps_hdr_init";
case ShaderConvert::HDR_RESOLVE: return "ps_hdr_resolve";
case ShaderConvert::RTA_CORRECTION: return "ps_rta_correction";
case ShaderConvert::RTA_DECORRECTION: return "ps_rta_decorrection";
case ShaderConvert::TRANSPARENCY_FILTER: return "ps_filter_transparency";
case ShaderConvert::FLOAT32_TO_16_BITS: return "ps_convert_float32_32bits";
case ShaderConvert::FLOAT32_TO_32_BITS: return "ps_convert_float32_32bits";
Expand Down
35 changes: 19 additions & 16 deletions pcsx2/GS/Renderers/Common/GSDevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ enum class ShaderConvert
DATM_0,
HDR_INIT,
HDR_RESOLVE,
RTA_CORRECTION,
RTA_DECORRECTION,
TRANSPARENCY_FILTER,
FLOAT32_TO_16_BITS,
FLOAT32_TO_32_BITS,
Expand Down Expand Up @@ -307,22 +309,23 @@ struct alignas(16) GSHWDrawConfig
u32 fbmask : 1;

// Blend and Colclip
u32 blend_a : 2;
u32 blend_b : 2;
u32 blend_c : 2;
u32 blend_d : 2;
u32 fixed_one_a : 1;
u32 blend_hw : 2;
u32 a_masked : 1;
u32 hdr : 1;
u32 colclip : 1;
u32 blend_mix : 2;
u32 round_inv : 1; // Blending will invert the value, so rounding needs to go the other way
u32 pabe : 1;
u32 no_color : 1; // disables color output entirely (depth only)
u32 no_color1 : 1; // disables second color output (when unnecessary)
u32 no_ablend : 1; // output alpha blend in col0 (for no-DSB)
u32 only_alpha : 1; // don't bother computing RGB
u32 blend_a : 2;
u32 blend_b : 2;
u32 blend_c : 2;
u32 blend_d : 2;
u32 fixed_one_a : 1;
u32 blend_hw : 2;
u32 a_masked : 1;
u32 hdr : 1;
u32 rta_correction : 1;
u32 colclip : 1;
u32 blend_mix : 2;
u32 round_inv : 1; // Blending will invert the value, so rounding needs to go the other way
u32 pabe : 1;
u32 no_color : 1; // disables color output entirely (depth only)
u32 no_color1 : 1; // disables second color output (when unnecessary)
u32 no_ablend : 1; // output alpha blend in col0 (for no-DSB)
u32 only_alpha : 1; // don't bother computing RGB

// Others ways to fetch the texture
u32 channel : 3;
Expand Down
1 change: 1 addition & 0 deletions pcsx2/GS/Renderers/DX12/GSDevice12.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2814,6 +2814,7 @@ const ID3DBlob* GSDevice12::GetTFXPixelShader(const GSHWDrawConfig::PSSelector&
sm.AddMacro("PS_DEPTH_FMT", sel.depth_fmt);
sm.AddMacro("PS_PAL_FMT", sel.pal_fmt);
sm.AddMacro("PS_HDR", sel.hdr);
sm.AddMacro("PS_RTA_CORRECTION", sel.rta_correction);
sm.AddMacro("PS_COLCLIP", sel.colclip);
sm.AddMacro("PS_BLEND_A", sel.blend_a);
sm.AddMacro("PS_BLEND_B", sel.blend_b);
Expand Down
19 changes: 16 additions & 3 deletions pcsx2/GS/Renderers/HW/GSRendererHW.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3691,7 +3691,7 @@ __ri bool GSRendererHW::EmulateChannelShuffle(GSTextureCache::Target* src, bool
return true;
}

void GSRendererHW::EmulateBlending(int rt_alpha_min, int rt_alpha_max, bool& DATE_PRIMID, bool& DATE_BARRIER, bool& blending_alpha_pass)
void GSRendererHW::EmulateBlending(int rt_alpha_min, int rt_alpha_max, bool& DATE_PRIMID, bool& DATE_BARRIER, bool& blending_alpha_pass, GSTextureCache::Target* rt)
{
{
// AA1: Blending needs to be enabled on draw.
Expand Down Expand Up @@ -4276,6 +4276,10 @@ void GSRendererHW::EmulateBlending(int rt_alpha_min, int rt_alpha_max, bool& DAT
m_conf.ps.blend_b = 0;
m_conf.ps.blend_d = 0;

// TODO: When alpha source is higher than 128 then we need to replace the TC target with
// double alpha, aka new target.
const bool rta_correction = (!m_cached_ctx.TEST.DATE && !blend_ad_alpha_masked && m_conf.ps.blend_c == 1);

// Care for hw blend value, 6 is for hw/sw, sw blending used.
if (blend_flag & BLEND_HW_CLR1)
{
Expand All @@ -4288,7 +4292,7 @@ void GSRendererHW::EmulateBlending(int rt_alpha_min, int rt_alpha_max, bool& DAT

m_conf.ps.blend_hw = 2;
}
else if (blend_flag & BLEND_HW_CLR3)
else if (!rta_correction && blend_flag & BLEND_HW_CLR3)
{
m_conf.ps.blend_hw = 3;
}
Expand All @@ -4299,6 +4303,13 @@ void GSRendererHW::EmulateBlending(int rt_alpha_min, int rt_alpha_max, bool& DAT
m_conf.require_one_barrier |= true;
}

if (rta_correction)
{
rt->RTACorrect(rt);
m_conf.ps.rta_correction = rt->m_rt_alpha_scale && m_conf.colormask.wa;
m_conf.rt = rt->m_texture;
}

const HWBlend blend(GSDevice::GetBlend(blend_index, replace_dual_src));
m_conf.blend = {true, blend.src, blend.dst, blend.op, m_conf.ps.blend_c == 2, AFIX};

Expand Down Expand Up @@ -5269,7 +5280,7 @@ __ri void GSRendererHW::DrawPrims(GSTextureCache::Target* rt, GSTextureCache::Ta
bool blending_alpha_pass = false;
if ((!IsOpaque() || m_context->ALPHA.IsBlack()) && rt && ((m_conf.colormask.wrgba & 0x7) || (m_texture_shuffle && !m_copy_16bit_to_target_shuffle && !m_same_group_texture_shuffle)))
{
EmulateBlending(blend_alpha_min, blend_alpha_max, DATE_PRIMID, DATE_BARRIER, blending_alpha_pass);
EmulateBlending(blend_alpha_min, blend_alpha_max, DATE_PRIMID, DATE_BARRIER, blending_alpha_pass, rt);
}
else
{
Expand Down Expand Up @@ -5613,6 +5624,8 @@ __ri void GSRendererHW::DrawPrims(GSTextureCache::Target* rt, GSTextureCache::Ta
g_gs_device->Recycle(tex_copy);
if (temp_ds)
g_gs_device->Recycle(temp_ds);

rt->RTADecorrect(rt);
}

// If the EE uploaded a new CLUT since the last draw, use that.
Expand Down
2 changes: 1 addition & 1 deletion pcsx2/GS/Renderers/HW/GSRendererHW.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ class GSRendererHW : public GSRenderer
void SetupIA(float target_scale, float sx, float sy);
void EmulateTextureShuffleAndFbmask(GSTextureCache::Target* rt, GSTextureCache::Source* tex);
bool EmulateChannelShuffle(GSTextureCache::Target* src, bool test_only);
void EmulateBlending(int rt_alpha_min, int rt_alpha_max, bool& DATE_PRIMID, bool& DATE_BARRIER, bool& blending_alpha_pass);
void EmulateBlending(int rt_alpha_min, int rt_alpha_max, bool& DATE_PRIMID, bool& DATE_BARRIER, bool& blending_alpha_pass, GSTextureCache::Target* rt);
void CleanupDraw(bool invalidate_temp_src);

void EmulateTextureSampler(const GSTextureCache::Target* rt, const GSTextureCache::Target* ds,
Expand Down
36 changes: 36 additions & 0 deletions pcsx2/GS/Renderers/HW/GSTextureCache.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2643,6 +2643,42 @@ GSTextureCache::Target* GSTextureCache::LookupDisplayTarget(GIFRegTEX0 TEX0, con
return can_create ? CreateTarget(TEX0, size, size, scale, RenderTarget, true, 0, true) : nullptr;
}

void GSTextureCache::Target::RTACorrect(Target* rt)
{
if (!rt->m_rt_alpha_scale)
{
const GSVector4 rtsize(rt->m_texture->GetSize());
if (GSTexture* temp_rt = g_gs_device->CreateRenderTarget(rtsize.x, rtsize.y, GSTexture::Format::Color, false))
{
const GSVector4 dRect(rt->m_texture->GetRect());
const GSVector4 sRect = dRect / GSVector4(rtsize.x, rtsize.y).xyxy();
g_gs_device->StretchRect(rt->m_texture, sRect, temp_rt, dRect, ShaderConvert::RTA_CORRECTION, false);
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
g_gs_device->Recycle(rt->m_texture);
rt->m_texture = temp_rt;
rt->m_rt_alpha_scale = true;
}
}
}

void GSTextureCache::Target::RTADecorrect(Target* rt)
{
if (rt->m_rt_alpha_scale)
{
const GSVector4 rtsize(rt->m_texture->GetSize());
if (GSTexture* temp_rt = g_gs_device->CreateRenderTarget(rtsize.x, rtsize.y, GSTexture::Format::Color, false))
{
const GSVector4 dRect(rt->m_texture->GetRect());
const GSVector4 sRect = dRect / GSVector4(rtsize.x, rtsize.y).xyxy();
g_gs_device->StretchRect(rt->m_texture, sRect, temp_rt, dRect, ShaderConvert::RTA_DECORRECTION, false);
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
g_gs_device->Recycle(rt->m_texture);
rt->m_texture = temp_rt;
rt->m_rt_alpha_scale = false;
}
}
}

void GSTextureCache::ScaleTargetForDisplay(Target* t, const GIFRegTEX0& dispfb, int real_w, int real_h)
{
// This handles a case where you have two images stacked on top of one another (usually FMVs), and
Expand Down
4 changes: 4 additions & 0 deletions pcsx2/GS/Renderers/HW/GSTextureCache.h
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,7 @@ class GSTextureCache
bool m_valid_alpha_low = false;
bool m_valid_alpha_high = false;
bool m_valid_rgb = false;
bool m_rt_alpha_scale = false;

bool m_is_frame = false;
bool m_used = false;
Expand All @@ -237,6 +238,9 @@ class GSTextureCache
void ResizeValidity(const GSVector4i& rect);
void UpdateValidity(const GSVector4i& rect, bool can_resize = true);

void RTACorrect(Target* rt);
void RTADecorrect(Target* rt);

void Update();

/// Updates the target, if the dirty area intersects with the specified rectangle.
Expand Down
4 changes: 4 additions & 0 deletions pcsx2/GS/Renderers/Metal/GSDeviceMTL.mm
Original file line number Diff line number Diff line change
Expand Up @@ -2137,6 +2137,8 @@ static bool usesStencil(GSHWDrawConfig::DestinationAlphaMode dstalpha)
break;
}

RTACorrect(config, rtsize);

GSTexture* hdr_rt = nullptr;
if (config.ps.hdr)
{
Expand Down Expand Up @@ -2219,6 +2221,8 @@ static bool usesStencil(GSHWDrawConfig::DestinationAlphaMode dstalpha)

if (primid_tex)
Recycle(primid_tex);

RTADecorrect(config, rtsize);
}}

void GSDeviceMTL::SendHWDraw(GSHWDrawConfig& config, id<MTLRenderCommandEncoder> enc, id<MTLBuffer> buffer, size_t off)
Expand Down
12 changes: 12 additions & 0 deletions pcsx2/GS/Renderers/Metal/convert.metal
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,18 @@ fragment float4 ps_primid_init_datm1(float4 p [[position]], DirectReadTextureIn<
return tex.read(p).a < (127.5f / 255.f) ? -1 : FLT_MAX;
}

fragment float4 ps_rta_correction(float4 p [[position]], DirectReadTextureIn<float> tex)
{
float4 in = tex.read(p);
return float4(in.rgb, trunc(in.a * 255 + 0.1) / 128);
}

fragment float4 ps_rta_decorrection(float4 p [[position]], DirectReadTextureIn<float> tex)
{
float4 in = tex.read(p);
return float4(in.rgb, in.a * 128 / 255);
}

fragment float4 ps_hdr_init(float4 p [[position]], DirectReadTextureIn<float> tex)
{
float4 in = tex.read(p);
Expand Down

0 comments on commit f869641

Please sign in to comment.