Skip to content

Commit

Permalink
GS/HW: Implement BLEND_HW4.
Browse files Browse the repository at this point in the history
Cases: `Cs*(Ad + 1)`and `Cs*(Ad + 1) - Cd*A`

What we want to accomplish is to do Cs + Cs*Ad in shader since hw blending can't be done with alpha value above 1.0f.

Will only work when RT alpha min > 0.
  • Loading branch information
lightningterror committed Dec 1, 2023
1 parent e8d43f0 commit ad637e2
Show file tree
Hide file tree
Showing 8 changed files with 50 additions and 10 deletions.
9 changes: 9 additions & 0 deletions bin/resources/shaders/dx11/tfx.fx
Original file line number Diff line number Diff line change
Expand Up @@ -921,6 +921,15 @@ void ps_blend(inout float4 Color, inout float4 As_rgba, float2 pos_xy)
float color_compensate = 255.0f / max(128.0f, max_color);
Color.rgb *= (float3)color_compensate;
}
else if (PS_BLEND_HW == 4)
{
// Needed for Cs*(Ad + 1), Cs*(Ad + 1) - Cd*A
// What we want to accomplish is to do Cs + Cs*Ad in shader since
// hw blending can't be done with alpha value above 1.0f.
// Will only work when RT alpha min > 0.
float3 color_blended = Color.rgb * (float3)Af;
Color.rgb += color_blended;
}
}
}

Expand Down
7 changes: 7 additions & 0 deletions bin/resources/shaders/opengl/tfx_fs.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -901,6 +901,13 @@ float As = As_rgba.a;
float max_color = max(max(Color.r, Color.g), Color.b);
float color_compensate = 255.0f / max(128.0f, max_color);
Color.rgb *= vec3(color_compensate);
#elif PS_BLEND_HW == 4
// Needed for Cs*(Ad + 1), Cs*(Ad + 1) - Cd*A
// What we want to accomplish is to do Cs + Cs*Ad in shader since
// hw blending can't be done with alpha value above 1.0f.
// Will only work when RT alpha min > 0.
vec3 color_blended = Color.rgb * vec3(Af);
Color.rgb += color_blended;
#endif

#endif
Expand Down
7 changes: 7 additions & 0 deletions bin/resources/shaders/vulkan/tfx.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -1150,6 +1150,13 @@ void ps_blend(inout vec4 Color, inout vec4 As_rgba)
float max_color = max(max(Color.r, Color.g), Color.b);
float color_compensate = 255.0f / max(128.0f, max_color);
Color.rgb *= vec3(color_compensate);
#elif PS_BLEND_HW == 4
// Needed for Cs*(Ad + 1), Cs*(Ad + 1) - Cd*A
// What we want to accomplish is to do Cs + Cs*Ad in shader since
// hw blending can't be done with alpha value above 1.0f.
// Will only work when RT alpha min > 0.
vec3 color_blended = Color.rgb * vec3(Af);
Color.rgb += color_blended;
#endif
#endif
}
Expand Down
4 changes: 2 additions & 2 deletions pcsx2/GS/Renderers/Common/GSDevice.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -802,7 +802,7 @@ const std::array<HWBlend, 3*3*3*3> GSDevice::m_blendMap =
{ BLEND_A_MAX | BLEND_MIX2 , OP_SUBTRACT , CONST_ONE , SRC1_ALPHA} , // 0100: (Cs - Cd)*As + Cs ==> Cs*(As + 1) - Cd*As
{ BLEND_MIX1 , OP_ADD , SRC1_ALPHA , INV_SRC1_ALPHA} , // 0101: (Cs - Cd)*As + Cd ==> Cs*As + Cd*(1 - As)
{ BLEND_MIX1 , OP_SUBTRACT , SRC1_ALPHA , SRC1_ALPHA} , // 0102: (Cs - Cd)*As + 0 ==> Cs*As - Cd*As
{ BLEND_A_MAX , OP_SUBTRACT , CONST_ONE , DST_ALPHA} , // 0110: (Cs - Cd)*Ad + Cs ==> Cs*(Ad + 1) - Cd*Ad
{ BLEND_A_MAX | BLEND_HW4 , OP_SUBTRACT , CONST_ONE , DST_ALPHA} , // 0110: (Cs - Cd)*Ad + Cs ==> Cs*(Ad + 1) - Cd*Ad
{ 0 , OP_ADD , DST_ALPHA , INV_DST_ALPHA} , // 0111: (Cs - Cd)*Ad + Cd ==> Cs*Ad + Cd*(1 - Ad)
{ 0 , OP_SUBTRACT , DST_ALPHA , DST_ALPHA} , // 0112: (Cs - Cd)*Ad + 0 ==> Cs*Ad - Cd*Ad
{ BLEND_A_MAX | BLEND_MIX2 , OP_SUBTRACT , CONST_ONE , CONST_COLOR} , // 0120: (Cs - Cd)*F + Cs ==> Cs*(F + 1) - Cd*F
Expand All @@ -811,7 +811,7 @@ const std::array<HWBlend, 3*3*3*3> GSDevice::m_blendMap =
{ BLEND_NO_REC , OP_ADD , CONST_ONE , CONST_ZERO} , // 0200: (Cs - 0)*As + Cs ==> Cs*(As + 1)
{ BLEND_ACCU , OP_ADD , SRC1_ALPHA , CONST_ONE} , // 0201: (Cs - 0)*As + Cd ==> Cs*As + Cd
{ BLEND_NO_REC , OP_ADD , SRC1_ALPHA , CONST_ZERO} , // 0202: (Cs - 0)*As + 0 ==> Cs*As
{ BLEND_A_MAX , OP_ADD , CONST_ONE , CONST_ZERO} , // 0210: (Cs - 0)*Ad + Cs ==> Cs*(Ad + 1)
{ BLEND_A_MAX | BLEND_HW4 , OP_ADD , CONST_ONE , CONST_ZERO} , // 0210: (Cs - 0)*Ad + Cs ==> Cs*(Ad + 1)
{ BLEND_HW3 , OP_ADD , DST_ALPHA , CONST_ONE} , // 0211: (Cs - 0)*Ad + Cd ==> Cs*Ad + Cd
{ BLEND_HW3 , OP_ADD , DST_ALPHA , CONST_ZERO} , // 0212: (Cs - 0)*Ad + 0 ==> Cs*Ad
{ BLEND_NO_REC , OP_ADD , CONST_ONE , CONST_ZERO} , // 0220: (Cs - 0)*F + Cs ==> Cs*(F + 1)
Expand Down
15 changes: 8 additions & 7 deletions pcsx2/GS/Renderers/Common/GSDevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -222,12 +222,13 @@ enum HWBlendFlags
BLEND_HW1 = 0x2, // Clear color blending (use directly the destination color as blending factor)
BLEND_HW2 = 0x4, // Clear color blending (use directly the destination color as blending factor)
BLEND_HW3 = 0x8, // Multiply Cs by (255/128) to compensate for wrong Ad/255 value, should be Ad/128
BLEND_MIX1 = 0x10, // Mix of hw and sw, do Cs*F or Cs*As in shader
BLEND_MIX2 = 0x20, // Mix of hw and sw, do Cs*(As + 1) or Cs*(F + 1) in shader
BLEND_MIX3 = 0x40, // Mix of hw and sw, do Cs*(1 - As) or Cs*(1 - F) in shader
BLEND_ACCU = 0x80, // Allow to use a mix of SW and HW blending to keep the best of the 2 worlds
BLEND_NO_REC = 0x100, // Doesn't require sampling of the RT as a texture
BLEND_A_MAX = 0x200, // Impossible blending uses coeff bigger than 1
BLEND_HW4 = 0x10, // Partial clear color blending, additional color can be added
BLEND_MIX1 = 0x20, // Mix of hw and sw, do Cs*F or Cs*As in shader
BLEND_MIX2 = 0x40, // Mix of hw and sw, do Cs*(As + 1) or Cs*(F + 1) in shader
BLEND_MIX3 = 0x80, // Mix of hw and sw, do Cs*(1 - As) or Cs*(1 - F) in shader
BLEND_ACCU = 0x100, // Allow to use a mix of SW and HW blending to keep the best of the 2 worlds
BLEND_NO_REC = 0x200, // Doesn't require sampling of the RT as a texture
BLEND_A_MAX = 0x400, // Impossible blending uses coeff bigger than 1
};

// Determines the HW blend function for DX11/OGL
Expand Down Expand Up @@ -324,7 +325,7 @@ struct alignas(16) GSHWDrawConfig
u32 blend_c : 2;
u32 blend_d : 2;
u32 fixed_one_a : 1;
u32 blend_hw : 2;
u32 blend_hw : 3;
u32 a_masked : 1;
u32 hdr : 1;
u32 colclip : 1;
Expand Down
7 changes: 7 additions & 0 deletions pcsx2/GS/Renderers/HW/GSRendererHW.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4105,6 +4105,13 @@ void GSRendererHW::EmulateBlending(int rt_alpha_min, int rt_alpha_max, bool& DAT
{
m_conf.ps.blend_hw = 3;
}
else if (blend_flag & BLEND_HW4)
{
// For Cs*(Ad + 1) - Cd*Ad divide the alpha by 255 so it matches the Ad in hw blend,
// otherwise for Cs*(Ad + 1) divide by 128.
m_conf.ps.blend_hw = 4;
m_conf.cb_ps.TA_MaxDepth_Af.a = static_cast<float>(rt_alpha_min) / (m_conf.ps.blend_b == 1 ? 255.0f : 128.0f);
}

if (blend_ad_alpha_masked)
{
Expand Down
9 changes: 9 additions & 0 deletions pcsx2/GS/Renderers/Metal/tfx.metal
Original file line number Diff line number Diff line change
Expand Up @@ -983,6 +983,15 @@ struct PSMain
float color_compensate = 255.f / max(128.f, max_color);
Color.rgb *= float3(color_compensate);
}
else if (PS_BLEND_HW == 4)
{
// Needed for Cs*(Ad + 1), Cs*(Ad + 1) - Cd*A
// What we want to accomplish is to do Cs + Cs*Ad in shader since
// hw blending can't be done with alpha value above 1.0f.
// Will only work when RT alpha min > 0.
float3 color_blended = Color.rgb * float3(cb.alpha_fix);
Color.rgb += color_blended;
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion pcsx2/ShaderCacheVersion.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,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 = 36;
static constexpr u32 SHADER_CACHE_VERSION = 37;

0 comments on commit ad637e2

Please sign in to comment.