GS/HW: Adjust line AA1 blur with upscaling.

This commit is contained in:
TJnotJT
2026-06-20 22:09:33 +02:00
committed by lightningterror
parent 342db51523
commit e2a3670d65
10 changed files with 92 additions and 36 deletions
+15 -6
View File
@@ -290,6 +290,12 @@ cbuffer cb1
float4x4 DitherMatrix; float4x4 DitherMatrix;
float ScaledScaleFactor; float ScaledScaleFactor;
float RcpScaleFactor; float RcpScaleFactor;
float _pad0_cb1;
float _pad1_cb1;
float LineCovScale;
float _pad2_cb1;
float _pad3_cb1;
float _pad4_cb1;
}; };
float4 RtLoad(int2 xy) float4 RtLoad(int2 xy)
@@ -1362,7 +1368,12 @@ void ps_main(PS_INPUT input)
float4 C = ps_color(input); float4 C = ps_color(input);
#if PS_AA1 #if PS_AA1
float cov = clamp(1.0f - abs(input.inv_cov), 0.0f, 1.0f); #if PS_AA1 == PS_AA1_LINE
// Blur only outer part of the line by scaling coverage.
float cov = clamp(LineCovScale * (1.0f - abs(input.inv_cov)), 0.0f, 1.0f);
#else
float cov = clamp(1.0f - abs(input.inv_cov), 0.0f, 1.0f);
#endif
#if PS_ABE #if PS_ABE
if (floor(C.a) == 128.0f) // The coverage is only used if the fragment alpha is 128. if (floor(C.a) == 128.0f) // The coverage is only used if the fragment alpha is 128.
C.a = 128.0f * cov; C.a = 128.0f * cov;
@@ -1632,7 +1643,7 @@ cbuffer cb0
float2 TextureOffset; float2 TextureOffset;
float2 PointSize; float2 PointSize;
uint MaxDepth; uint MaxDepth;
uint _cb0_pad0; float LineAA1Width;
}; };
#ifdef DX12 #ifdef DX12
@@ -1875,11 +1886,9 @@ VS_OUTPUT vs_main_expand(uint vid : SV_VertexID)
// Use bottom minus top for delta regardless of which vertex we are expanding. // Use bottom minus top for delta regardless of which vertex we are expanding.
float2 line_delta = is_bottom ? (vtx.p.xy - other.p.xy) : (other.p.xy - vtx.p.xy); float2 line_delta = is_bottom ? (vtx.p.xy - other.p.xy) : (other.p.xy - vtx.p.xy);
float2 line_vector = normalize(line_delta / VertexScale); float2 line_vector = normalize(line_delta / VertexScale);
#if VS_EXPAND == VS_EXPAND_LINE
float2 line_expand = float2(line_vector.y, -line_vector.x); float2 line_expand = float2(line_vector.y, -line_vector.x);
#elif VS_EXPAND == VS_EXPAND_LINE_AA1 #if VS_EXPAND == VS_EXPAND_LINE_AA1
// Expand in y direction for shallow lines and x direction for steep lines. line_expand *= 2.0f * LineAA1Width;
float2 line_expand = abs(line_vector.x) >= abs(line_vector.y) ? float2(0.0f, 2.0f) : float2(2.0f, 0.0f);
#endif #endif
float2 line_width = (line_expand * PointSize) / 2; float2 line_width = (line_expand * PointSize) / 2;
float2 offset = is_right ? line_width : -line_width; float2 offset = is_right ? line_width : -line_width;
+13 -1
View File
@@ -93,6 +93,13 @@ layout(std140, binding = 0) uniform cb21
float ScaledScaleFactor; float ScaledScaleFactor;
float RcpScaleFactor; float RcpScaleFactor;
float _pad0_cb1;
float _pad1_cb1;
float LineCovScale;
float _pad2_cb1;
float _pad3_cb1;
float _pad4_cb1;
}; };
in SHADER in SHADER
@@ -1250,7 +1257,12 @@ void ps_main()
vec4 C = ps_color(); vec4 C = ps_color();
#if PS_AA1 #if PS_AA1
float cov = clamp(1.0f - abs(PSin.inv_cov), 0.0f, 1.0f); #if PS_AA1 == PS_AA1_LINE
// Blur only outer part of the line by scaling coverage.
float cov = clamp(LineCovScale * (1.0f - abs(PSin.inv_cov)), 0.0f, 1.0f);
#else
float cov = clamp(1.0f - abs(PSin.inv_cov), 0.0f, 1.0f);
#endif
#if PS_ABE #if PS_ABE
if (floor(C.a) == 128.0f) // The coverage is only used if the fragment alpha is 128. if (floor(C.a) == 128.0f) // The coverage is only used if the fragment alpha is 128.
C.a = 128.0f * cov; C.a = 128.0f * cov;
+4 -6
View File
@@ -12,8 +12,9 @@ layout(std140, binding = 1) uniform cb20
vec2 TextureOffset; vec2 TextureOffset;
vec2 PointSize; vec2 PointSize;
uint MaxDepth; uint MaxDepth;
uint pad_cb20; float LineAA1Width;
}; };
#ifdef VERTEX_SHADER #ifdef VERTEX_SHADER
@@ -323,11 +324,8 @@ void main()
// Use bottom minus top for delta regardless of which vertex we are expanding. // Use bottom minus top for delta regardless of which vertex we are expanding.
vec2 line_delta = is_bottom ? (vtx.p.xy - other.p.xy) : (other.p.xy - vtx.p.xy); vec2 line_delta = is_bottom ? (vtx.p.xy - other.p.xy) : (other.p.xy - vtx.p.xy);
vec2 line_vector = normalize(line_delta / VertexScale); vec2 line_vector = normalize(line_delta / VertexScale);
#if VS_EXPAND == VS_EXPAND_LINE if VS_EXPAND == VS_EXPAND_LINE_AA1
vec2 line_expand = vec2(line_vector.y, -line_vector.x); line_expand *= 2.0f * LineAA1Width;
#elif VS_EXPAND == VS_EXPAND_LINE_AA1
// Expand in y direction for shallow lines and x direction for steep lines.
vec2 line_expand = abs(line_vector.x) >= abs(line_vector.y) ? vec2(0.0f, 2.0f) : vec2(2.0f, 0.0f);
#endif #endif
vec2 line_width = (line_expand * PointSize) / 2; vec2 line_width = (line_expand * PointSize) / 2;
vec2 offset = is_right ? line_width : -line_width; vec2 offset = is_right ? line_width : -line_width;
+15 -6
View File
@@ -24,7 +24,7 @@ layout(std140, set = 0, binding = 0) uniform cb0
vec2 TextureOffset; vec2 TextureOffset;
vec2 PointSize; vec2 PointSize;
uint MaxDepth; uint MaxDepth;
uint pad_cb0; float LineAA1Width;
}; };
layout(location = 0) out VSOutput layout(location = 0) out VSOutput
@@ -319,11 +319,9 @@ void main()
// Use bottom minus top for delta regardless of which vertex we are expanding. // Use bottom minus top for delta regardless of which vertex we are expanding.
vec2 line_delta = is_bottom ? (vtx.p.xy - other.p.xy) : (other.p.xy - vtx.p.xy); vec2 line_delta = is_bottom ? (vtx.p.xy - other.p.xy) : (other.p.xy - vtx.p.xy);
vec2 line_vector = normalize(line_delta / VertexScale); vec2 line_vector = normalize(line_delta / VertexScale);
#if VS_EXPAND == VS_EXPAND_LINE
vec2 line_expand = vec2(line_vector.y, -line_vector.x); vec2 line_expand = vec2(line_vector.y, -line_vector.x);
#elif VS_EXPAND == VS_EXPAND_LINE_AA1 #if VS_EXPAND == VS_EXPAND_LINE_AA1
// Expand in y direction for shallow lines and x direction for steep lines. line_expand *= 2.0f * LineAA1Width;
vec2 line_expand = abs(line_vector.x) >= abs(line_vector.y) ? vec2(0.0f, 2.0f) : vec2(2.0f, 0.0f);
#endif #endif
vec2 line_width = (line_expand * PointSize) / 2; vec2 line_width = (line_expand * PointSize) / 2;
vec2 offset = is_right ? line_width : -line_width; vec2 offset = is_right ? line_width : -line_width;
@@ -624,6 +622,12 @@ layout(std140, set = 0, binding = 1) uniform cb1
mat4 DitherMatrix; mat4 DitherMatrix;
float ScaledScaleFactor; float ScaledScaleFactor;
float RcpScaleFactor; float RcpScaleFactor;
float _pad0_cb1;
float _pad1_cb1;
float LineCovScale;
float _pad2_cb1;
float _pad3_cb1;
float _pad4_cb1;
}; };
layout(location = 0) in VSOutput layout(location = 0) in VSOutput
@@ -1804,7 +1808,12 @@ void main()
vec4 C = ps_color(); vec4 C = ps_color();
#if PS_AA1 #if PS_AA1
float cov = clamp(1.0f - abs(vsIn.inv_cov), 0.0f, 1.0f); #if PS_AA1 == PS_AA1_LINE
// Blur only outer part of the line by scaling coverage.
float cov = clamp(LineCovScale * (1.0f - abs(vsIn.inv_cov)), 0.0f, 1.0f);
#else
float cov = clamp(1.0f - abs(vsIn.inv_cov), 0.0f, 1.0f);
#endif
#if PS_ABE #if PS_ABE
if (floor(C.a) == 128.0f) // The coverage is only used if the fragment alpha is 128. if (floor(C.a) == 128.0f) // The coverage is only used if the fragment alpha is 128.
C.a = 128.0f * cov; C.a = 128.0f * cov;
+3 -1
View File
@@ -1705,6 +1705,7 @@ static void DumpPSConstantBuffer(DrawConfigWriter& out, const GSHWDrawConfig::PS
DumpVector4(out, "DitherMatrix_2", cb.DitherMatrix[2]); DumpVector4(out, "DitherMatrix_2", cb.DitherMatrix[2]);
DumpVector4(out, "DitherMatrix_3", cb.DitherMatrix[3]); DumpVector4(out, "DitherMatrix_3", cb.DitherMatrix[3]);
DumpVector4(out, "ScaleFactor", cb.ScaleFactor); DumpVector4(out, "ScaleFactor", cb.ScaleFactor);
out.WriteLn("LineCovScale: {}", cb.LineCovScale);
} }
static void DumpVSConstantBuffer(DrawConfigWriter& out, const GSHWDrawConfig::VSConstantBuffer& cb) static void DumpVSConstantBuffer(DrawConfigWriter& out, const GSHWDrawConfig::VSConstantBuffer& cb)
@@ -1714,7 +1715,8 @@ static void DumpVSConstantBuffer(DrawConfigWriter& out, const GSHWDrawConfig::VS
DumpVector2(out, "texture_scale", cb.texture_scale); DumpVector2(out, "texture_scale", cb.texture_scale);
DumpVector2(out, "texture_offset", cb.texture_offset); DumpVector2(out, "texture_offset", cb.texture_offset);
DumpVector2(out, "point_size", cb.point_size); DumpVector2(out, "point_size", cb.point_size);
DumpVector2(out, "max_depth", cb.max_depth); out.WriteLn("max_depth: {}", cb.max_depth);
out.WriteLn("line_aa1_width: {}", cb.line_aa1_width);
} }
static void DumpConfig(DrawConfigWriter& out, const GSHWDrawConfig& conf, static void DumpConfig(DrawConfigWriter& out, const GSHWDrawConfig& conf,
+6 -1
View File
@@ -1027,7 +1027,8 @@ struct alignas(16) GSHWDrawConfig
GSVector2 texture_scale; GSVector2 texture_scale;
GSVector2 texture_offset; GSVector2 texture_offset;
GSVector2 point_size; GSVector2 point_size;
GSVector2i max_depth; u32 max_depth;
float line_aa1_width;
__fi VSConstantBuffer() __fi VSConstantBuffer()
{ {
memset(static_cast<void*>(this), 0, sizeof(*this)); memset(static_cast<void*>(this), 0, sizeof(*this));
@@ -1117,6 +1118,10 @@ struct alignas(16) GSHWDrawConfig
GSVector4 DitherMatrix[4]; GSVector4 DitherMatrix[4];
GSVector4 ScaleFactor; GSVector4 ScaleFactor;
float LineCovScale;
float _pad0;
float _pad1;
float _pad2;
__fi PSConstantBuffer() __fi PSConstantBuffer()
{ {
+21 -2
View File
@@ -5442,6 +5442,25 @@ void GSRendererHW::SetupIA(float target_scale, float sx, float sy, bool req_vert
GL_INS("HW: AA1 line expand."); GL_INS("HW: AA1 line expand.");
m_conf.vs.expand = GSHWDrawConfig::VSExpand::LineAA1; m_conf.vs.expand = GSHWDrawConfig::VSExpand::LineAA1;
m_conf.cb_vs.point_size = GSVector2(16.0f * sx, 16.0f * sy); m_conf.cb_vs.point_size = GSVector2(16.0f * sx, 16.0f * sy);
if (target_scale == 1.0f)
{
m_conf.cb_vs.line_aa1_width = 1.0f; // 1 native pixel on each side.
m_conf.cb_ps.LineCovScale = 1.0f; // Linear falloff on both sides.
}
else
{
// Reduce the amount of blur with upscaling.
constexpr float half_native_px = 0.5f;
const float upscaled_px = 1.0f / target_scale;
// Half a native pixel + 1 upscaled pixel on both sides.
m_conf.cb_vs.line_aa1_width = half_native_px + upscaled_px;
// Opaque in middle and linear falloff on last 2 upscaled pixels on each side.
m_conf.cb_ps.LineCovScale = (half_native_px + upscaled_px) / (2 * upscaled_px);
}
m_conf.topology = GSHWDrawConfig::Topology::Triangle; m_conf.topology = GSHWDrawConfig::Topology::Triangle;
m_conf.indices_per_prim = 6; m_conf.indices_per_prim = 6;
ExpandLineIndices(); ExpandLineIndices();
@@ -5583,7 +5602,7 @@ void GSRendererHW::EmulateZbuffer(const GSTextureCache::Target* ds)
// No interpolation for flat Z so we can make some optimizations. // No interpolation for flat Z so we can make some optimizations.
const bool flat_z = m_vt.m_eq.z || m_vt.m_primclass == GS_POINT_CLASS || m_vt.m_primclass == GS_SPRITE_CLASS; const bool flat_z = m_vt.m_eq.z || m_vt.m_primclass == GS_POINT_CLASS || m_vt.m_primclass == GS_SPRITE_CLASS;
m_conf.cb_vs.max_depth = GSVector2i(0xFFFFFFFF); m_conf.cb_vs.max_depth = 0xFFFFFFFF;
m_conf.cb_ps.TA_MaxDepth_Af.z = 0.0f; m_conf.cb_ps.TA_MaxDepth_Af.z = 0.0f;
m_conf.ps.zclamp = false; m_conf.ps.zclamp = false;
@@ -5597,7 +5616,7 @@ void GSRendererHW::EmulateZbuffer(const GSTextureCache::Target* ds)
if (flat_z) if (flat_z)
{ {
// Clamp in vertex shader. // Clamp in vertex shader.
m_conf.cb_vs.max_depth = GSVector2i(max_z); m_conf.cb_vs.max_depth = max_z;
} }
else else
{ {
+6 -1
View File
@@ -98,7 +98,7 @@ struct GSMTLMainVSUniform
vector_float2 texture_offset; vector_float2 texture_offset;
vector_float2 point_size; vector_float2 point_size;
uint max_depth; uint max_depth;
uint _pad0; float line_aa1_width;
}; };
struct GSMTLMainPSUniform struct GSMTLMainPSUniform
@@ -140,6 +140,11 @@ struct GSMTLMainPSUniform
matrix_float4x4 dither_matrix; matrix_float4x4 dither_matrix;
vector_float4 scale_factor; vector_float4 scale_factor;
float line_cov_scale;
float _pad0;
float _pad1;
float _pad2;
}; };
enum GSMTLAttributes enum GSMTLAttributes
+8 -11
View File
@@ -398,16 +398,11 @@ vertex MainVSOut vs_main_expand(
// Use bottom minus top for delta regardless of which vertex we are expanding. // Use bottom minus top for delta regardless of which vertex we are expanding.
float2 line_delta = is_bottom ? point.p.xy - other.p.xy : other.p.xy - point.p.xy; float2 line_delta = is_bottom ? point.p.xy - other.p.xy : other.p.xy - point.p.xy;
float2 line_vector = normalize(line_delta / cb.vertex_scale); float2 line_vector = normalize(line_delta / cb.vertex_scale);
float2 line_expand; float2 line_expand = float2(line_vector.y, -line_vector.x);
if (VS_EXPAND_TYPE == VSExpand::Line)
{ if (VS_EXPAND_TYPE == VSExpand::LineAA1)
line_expand = float2(line_vector.y, -line_vector.x); line_expand *= 2.f * cb.line_aa1_width;
}
else
{
// Expand in y direction for shallow lines and x direction for steep lines.
line_expand = abs(line_vector.x) >= abs(line_vector.y) ? float2(0, 2) : float2(2, 0);
}
float2 line_width = (line_expand * cb.point_size) / 2; float2 line_width = (line_expand * cb.point_size) / 2;
float2 offset = is_right ? line_width : -line_width; float2 offset = is_right ? line_width : -line_width;
point.p.xy += offset; point.p.xy += offset;
@@ -1507,7 +1502,9 @@ struct PSMain
if (PS_AA1 != AA1::NONE) if (PS_AA1 != AA1::NONE)
{ {
float cov = saturate(1.f - abs(in.inv_cov)); float cov = PS_AA1 == AA1::LINE ?
saturate(cb.line_cov_scale * (1.f - abs(in.inv_cov))) : // Blur only outer part of the line by scaling coverage.
saturate(1.f - abs(in.inv_cov));
if (!PS_ABE || floor(C.a) == 128.f) // The coverage is only used if the fragment alpha is 128. if (!PS_ABE || floor(C.a) == 128.f) // The coverage is only used if the fragment alpha is 128.
C.a = 128.f * cov; C.a = 128.f * cov;
} }
+1 -1
View File
@@ -3,4 +3,4 @@
/// Version number for GS and other shaders. Increment whenever any of the contents of the /// Version number for GS and other shaders. Increment whenever any of the contents of the
/// shaders change, to invalidate the cache. /// shaders change, to invalidate the cache.
static constexpr u32 SHADER_CACHE_VERSION = 101; // Last changed in PR 14547 static constexpr u32 SHADER_CACHE_VERSION = 102; // Last changed in PR 14480