Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
GS: Manually do bilinear sampling when converting RGBA to depth
Shader bilinear doesn't properly handle the case where r overflows into g (or g overflows into b, etc)
  • Loading branch information
TellowKrinkle authored and refractionpcsx2 committed Aug 20, 2022
1 parent 882c09b commit 91601e5
Show file tree
Hide file tree
Showing 12 changed files with 413 additions and 109 deletions.
86 changes: 74 additions & 12 deletions bin/resources/shaders/dx11/convert.fx
Expand Up @@ -162,36 +162,98 @@ PS_OUTPUT ps_convert_float16_rgb5a1(PS_INPUT input)

return output;
}
float ps_convert_rgba8_float32(PS_INPUT input) : SV_Depth

float rgba8_to_depth32(float4 val)
{
// Convert a RRGBA texture into a float depth texture
uint4 c = uint4(sample_c(input.t) * 255.0f + 0.5f);
uint4 c = uint4(val * 255.5f);
return float(c.r | (c.g << 8) | (c.b << 16) | (c.a << 24)) * exp2(-32.0f);
}

float rgba8_to_depth24(float4 val)
{
uint3 c = uint3(val.rgb * 255.5f);
return float(c.r | (c.g << 8) | (c.b << 16)) * exp2(-32.0f);
}

float rgba8_to_depth16(float4 val)
{
uint2 c = uint2(val.rg * 255.5f);
return float(c.r | (c.g << 8)) * exp2(-32.0f);
}

float rgb5a1_to_depth16(float4 val)
{
uint4 c = uint4(val * 255.5f);
return float(((c.r & 0xF8u) >> 3) | ((c.g & 0xF8u) << 2) | ((c.b & 0xF8u) << 7) | ((c.a & 0x80u) << 8)) * exp2(-32.0f);
}

float ps_convert_rgba8_float32(PS_INPUT input) : SV_Depth
{
// Convert an RGBA texture into a float depth texture
return rgba8_to_depth32(sample_c(input.t));
}

float ps_convert_rgba8_float24(PS_INPUT input) : SV_Depth
{
// Same as above but without the alpha channel (24 bits Z)

// Convert a RRGBA texture into a float depth texture
uint3 c = uint3(sample_c(input.t).rgb * 255.0f + 0.5f);
return float(c.r | (c.g << 8) | (c.b << 16)) * exp2(-32.0f);
// Convert an RGBA texture into a float depth texture
return rgba8_to_depth24(sample_c(input.t));
}

float ps_convert_rgba8_float16(PS_INPUT input) : SV_Depth
{
// Same as above but without the A/B channels (16 bits Z)

// Convert a RRGBA texture into a float depth texture
uint2 c = uint2(sample_c(input.t).rg * 255.0f + 0.5f);
return float(c.r | (c.g << 8)) * exp2(-32.0f);
// Convert an RGBA texture into a float depth texture
return rgba8_to_depth16(sample_c(input.t));
}

float ps_convert_rgb5a1_float16(PS_INPUT input) : SV_Depth
{
// Convert a RGB5A1 (saved as RGBA8) color to a 16 bit Z
uint4 c = uint4(sample_c(input.t) * 255.0f + 0.5f);
return float(((c.r & 0xF8u) >> 3) | ((c.g & 0xF8u) << 2) | ((c.b & 0xF8u) << 7) | ((c.a & 0x80u) << 8)) * exp2(-32.0f);
// Convert an RGB5A1 (saved as RGBA8) color to a 16 bit Z
return rgb5a1_to_depth16(sample_c(input.t));
}

#define SAMPLE_RGBA_DEPTH_BILN(CONVERT_FN) \
uint width, height; \
Texture.GetDimensions(width, height); \
float2 top_left_f = input.t * float2(width, height) - 0.5f; \
int2 top_left = int2(floor(top_left_f)); \
int4 coords = clamp(int4(top_left, top_left + 1), int4(0, 0, 0, 0), int2(width - 1, height - 1).xyxy); \
float2 mix_vals = frac(top_left_f); \
float depthTL = CONVERT_FN(Texture.Load(int3(coords.xy, 0))); \
float depthTR = CONVERT_FN(Texture.Load(int3(coords.zy, 0))); \
float depthBL = CONVERT_FN(Texture.Load(int3(coords.xw, 0))); \
float depthBR = CONVERT_FN(Texture.Load(int3(coords.zw, 0))); \
return lerp(lerp(depthTL, depthTR, mix_vals.x), lerp(depthBL, depthBR, mix_vals.x), mix_vals.y);

float ps_convert_rgba8_float32_biln(PS_INPUT input) : SV_Depth
{
// Convert an RGBA texture into a float depth texture
SAMPLE_RGBA_DEPTH_BILN(rgba8_to_depth32);
}

float ps_convert_rgba8_float24_biln(PS_INPUT input) : SV_Depth
{
// Same as above but without the alpha channel (24 bits Z)

// Convert an RGBA texture into a float depth texture
SAMPLE_RGBA_DEPTH_BILN(rgba8_to_depth24);
}

float ps_convert_rgba8_float16_biln(PS_INPUT input) : SV_Depth
{
// Same as above but without the A/B channels (16 bits Z)

// Convert an RGBA texture into a float depth texture
SAMPLE_RGBA_DEPTH_BILN(rgba8_to_depth16);
}

float ps_convert_rgb5a1_float16_biln(PS_INPUT input) : SV_Depth
{
// Convert an RGB5A1 (saved as RGBA8) color to a 16 bit Z
SAMPLE_RGBA_DEPTH_BILN(rgb5a1_to_depth16);
}

PS_OUTPUT ps_convert_rgba_8i(PS_INPUT input)
Expand Down
92 changes: 80 additions & 12 deletions bin/resources/shaders/opengl/convert.glsl
Expand Up @@ -97,12 +97,35 @@ void ps_convert_float16_rgb5a1()
}
#endif

float rgba8_to_depth32(vec4 unorm)
{
uvec4 c = uvec4(unorm * vec4(255.5f));
return float(c.r | (c.g << 8) | (c.b << 16) | (c.a << 24)) * exp2(-32.0f);
}

float rgba8_to_depth24(vec4 unorm)
{
uvec3 c = uvec3(unorm.rgb * vec3(255.5f));
return float(c.r | (c.g << 8) | (c.b << 16)) * exp2(-32.0f);
}

float rgba8_to_depth16(vec4 unorm)
{
uvec2 c = uvec2(unorm.rg * vec2(255.5f));
return float(c.r | (c.g << 8)) * exp2(-32.0f);
}

float rgb5a1_to_depth16(vec4 unorm)
{
uvec4 c = uvec4(unorm * vec4(255.5f));
return float(((c.r & 0xF8u) >> 3) | ((c.g & 0xF8u) << 2) | ((c.b & 0xF8u) << 7) | ((c.a & 0x80u) << 8)) * exp2(-32.0f);
}

#ifdef ps_convert_rgba8_float32
void ps_convert_rgba8_float32()
{
// Convert a RRGBA texture into a float depth texture
uvec4 c = uvec4(sample_c() * vec4(255.0f) + vec4(0.5f));
gl_FragDepth = float(c.r | (c.g << 8) | (c.b << 16) | (c.a << 24)) * exp2(-32.0f);
// Convert an RGBA texture into a float depth texture
gl_FragDepth = rgba8_to_depth32(sample_c());
}
#endif

Expand All @@ -111,9 +134,8 @@ void ps_convert_rgba8_float24()
{
// Same as above but without the alpha channel (24 bits Z)

// Convert a RRGBA texture into a float depth texture
uvec3 c = uvec3(sample_c().rgb * vec3(255.0f) + vec3(0.5f));
gl_FragDepth = float(c.r | (c.g << 8) | (c.b << 16)) * exp2(-32.0f);
// Convert an RGBA texture into a float depth texture
gl_FragDepth = rgba8_to_depth24(sample_c());
}
#endif

Expand All @@ -122,18 +144,64 @@ void ps_convert_rgba8_float16()
{
// Same as above but without the A/B channels (16 bits Z)

// Convert a RRGBA texture into a float depth texture
uvec2 c = uvec2(sample_c().rg * vec2(255.0f) + vec2(0.5f));
gl_FragDepth = float(c.r | (c.g << 8)) * exp2(-32.0f);
// Convert an RGBA texture into a float depth texture
gl_FragDepth = rgba8_to_depth16(sample_c());
}
#endif

#ifdef ps_convert_rgb5a1_float16
void ps_convert_rgb5a1_float16()
{
// Convert a RGB5A1 (saved as RGBA8) color to a 16 bit Z
uvec4 c = uvec4(sample_c() * vec4(255.0f) + vec4(0.5f));
gl_FragDepth = float(((c.r & 0xF8u) >> 3) | ((c.g & 0xF8u) << 2) | ((c.b & 0xF8u) << 7) | ((c.a & 0x80u) << 8)) * exp2(-32.0f);
// Convert an RGB5A1 (saved as RGBA8) color to a 16 bit Z
gl_FragDepth = rgb5a1_to_depth16(sample_c());
}
#endif

#define SAMPLE_RGBA_DEPTH_BILN(CONVERT_FN) \
ivec2 dims = textureSize(TextureSampler, 0); \
vec2 top_left_f = PSin_t * vec2(dims) - 0.5f; \
ivec2 top_left = ivec2(floor(top_left_f)); \
ivec4 coords = clamp(ivec4(top_left, top_left + 1), ivec4(0), dims.xyxy - 1); \
vec2 mix_vals = fract(top_left_f); \
float depthTL = CONVERT_FN(texelFetch(TextureSampler, coords.xy, 0)); \
float depthTR = CONVERT_FN(texelFetch(TextureSampler, coords.zy, 0)); \
float depthBL = CONVERT_FN(texelFetch(TextureSampler, coords.xw, 0)); \
float depthBR = CONVERT_FN(texelFetch(TextureSampler, coords.zw, 0)); \
gl_FragDepth = mix(mix(depthTL, depthTR, mix_vals.x), mix(depthBL, depthBR, mix_vals.x), mix_vals.y);

#ifdef ps_convert_rgba8_float32_biln
void ps_convert_rgba8_float32_biln()
{
// Convert an RGBA texture into a float depth texture
SAMPLE_RGBA_DEPTH_BILN(rgba8_to_depth32);
}
#endif

#ifdef ps_convert_rgba8_float24_biln
void ps_convert_rgba8_float24_biln()
{
// Same as above but without the alpha channel (24 bits Z)

// Convert an RGBA texture into a float depth texture
SAMPLE_RGBA_DEPTH_BILN(rgba8_to_depth24);
}
#endif

#ifdef ps_convert_rgba8_float16_biln
void ps_convert_rgba8_float16_biln()
{
// Same as above but without the A/B channels (16 bits Z)

// Convert an RGBA texture into a float depth texture
SAMPLE_RGBA_DEPTH_BILN(rgba8_to_depth16);
}
#endif

#ifdef ps_convert_rgb5a1_float16_biln
void ps_convert_rgb5a1_float16_biln()
{
// Convert an RGB5A1 (saved as RGBA8) color to a 16 bit Z
SAMPLE_RGBA_DEPTH_BILN(rgb5a1_to_depth16);
}
#endif

Expand Down
92 changes: 80 additions & 12 deletions bin/resources/shaders/vulkan/convert.glsl
Expand Up @@ -128,12 +128,35 @@ void ps_convert_float16_rgb5a1()
}
#endif

float rgba8_to_depth32(vec4 unorm)
{
uvec4 c = uvec4(unorm * vec4(255.5f));
return float(c.r | (c.g << 8) | (c.b << 16) | (c.a << 24)) * exp2(-32.0f);
}

float rgba8_to_depth24(vec4 unorm)
{
uvec3 c = uvec3(unorm.rgb * vec3(255.5f));
return float(c.r | (c.g << 8) | (c.b << 16)) * exp2(-32.0f);
}

float rgba8_to_depth16(vec4 unorm)
{
uvec2 c = uvec2(unorm.rg * vec2(255.5f));
return float(c.r | (c.g << 8)) * exp2(-32.0f);
}

float rgb5a1_to_depth16(vec4 unorm)
{
uvec4 c = uvec4(unorm * vec4(255.5f));
return float(((c.r & 0xF8u) >> 3) | ((c.g & 0xF8u) << 2) | ((c.b & 0xF8u) << 7) | ((c.a & 0x80u) << 8)) * exp2(-32.0f);
}

#ifdef ps_convert_rgba8_float32
void ps_convert_rgba8_float32()
{
// Convert a RRGBA texture into a float depth texture
uvec4 c = uvec4(sample_c(v_tex) * vec4(255.0f) + vec4(0.5f));
gl_FragDepth = float(c.r | (c.g << 8) | (c.b << 16) | (c.a << 24)) * exp2(-32.0f);
// Convert an RGBA texture into a float depth texture
gl_FragDepth = rgba8_to_depth32(sample_c(v_tex));
}
#endif

Expand All @@ -142,9 +165,8 @@ void ps_convert_rgba8_float24()
{
// Same as above but without the alpha channel (24 bits Z)

// Convert a RRGBA texture into a float depth texture
uvec3 c = uvec3(sample_c(v_tex).rgb * vec3(255.0f) + vec3(0.5f));
gl_FragDepth = float(c.r | (c.g << 8) | (c.b << 16)) * exp2(-32.0f);
// Convert an RGBA texture into a float depth texture
gl_FragDepth = rgba8_to_depth24(sample_c(v_tex));
}
#endif

Expand All @@ -153,18 +175,64 @@ void ps_convert_rgba8_float16()
{
// Same as above but without the A/B channels (16 bits Z)

// Convert a RRGBA texture into a float depth texture
uvec2 c = uvec2(sample_c(v_tex).rg * vec2(255.0f) + vec2(0.5f));
gl_FragDepth = float(c.r | (c.g << 8)) * exp2(-32.0f);
// Convert an RGBA texture into a float depth texture
gl_FragDepth = rgba8_to_depth16(sample_c(v_tex));
}
#endif

#ifdef ps_convert_rgb5a1_float16
void ps_convert_rgb5a1_float16()
{
// Convert a RGB5A1 (saved as RGBA8) color to a 16 bit Z
uvec4 c = uvec4(sample_c(v_tex) * vec4(255.0f) + vec4(0.5f));
gl_FragDepth = float(((c.r & 0xF8u) >> 3) | ((c.g & 0xF8u) << 2) | ((c.b & 0xF8u) << 7) | ((c.a & 0x80u) << 8)) * exp2(-32.0f);
// Convert an RGB5A1 (saved as RGBA8) color to a 16 bit Z
gl_FragDepth = rgb5a1_to_depth16(sample_c(v_tex));
}
#endif

#define SAMPLE_RGBA_DEPTH_BILN(CONVERT_FN) \
ivec2 dims = textureSize(samp0, 0); \
vec2 top_left_f = v_tex * vec2(dims) - 0.5f; \
ivec2 top_left = ivec2(floor(top_left_f)); \
ivec4 coords = clamp(ivec4(top_left, top_left + 1), ivec4(0), dims.xyxy - 1); \
vec2 mix_vals = fract(top_left_f); \
float depthTL = CONVERT_FN(texelFetch(samp0, coords.xy, 0)); \
float depthTR = CONVERT_FN(texelFetch(samp0, coords.zy, 0)); \
float depthBL = CONVERT_FN(texelFetch(samp0, coords.xw, 0)); \
float depthBR = CONVERT_FN(texelFetch(samp0, coords.zw, 0)); \
gl_FragDepth = mix(mix(depthTL, depthTR, mix_vals.x), mix(depthBL, depthBR, mix_vals.x), mix_vals.y);

#ifdef ps_convert_rgba8_float32_biln
void ps_convert_rgba8_float32_biln()
{
// Convert an RGBA texture into a float depth texture
SAMPLE_RGBA_DEPTH_BILN(rgba8_to_depth32);
}
#endif

#ifdef ps_convert_rgba8_float24_biln
void ps_convert_rgba8_float24_biln()
{
// Same as above but without the alpha channel (24 bits Z)

// Convert an RGBA texture into a float depth texture
SAMPLE_RGBA_DEPTH_BILN(rgba8_to_depth24);
}
#endif

#ifdef ps_convert_rgba8_float16_biln
void ps_convert_rgba8_float16_biln()
{
// Same as above but without the A/B channels (16 bits Z)

// Convert an RGBA texture into a float depth texture
SAMPLE_RGBA_DEPTH_BILN(rgba8_to_depth16);
}
#endif

#ifdef ps_convert_rgb5a1_float16_biln
void ps_convert_rgb5a1_float16_biln()
{
// Convert an RGB5A1 (saved as RGBA8) color to a 16 bit Z
SAMPLE_RGBA_DEPTH_BILN(rgb5a1_to_depth16);
}
#endif

Expand Down
38 changes: 21 additions & 17 deletions pcsx2/GS/Renderers/Common/GSDevice.cpp
Expand Up @@ -23,23 +23,27 @@ const char* shaderName(ShaderConvert value)
switch (value)
{
// clang-format off
case ShaderConvert::COPY: return "ps_copy";
case ShaderConvert::RGBA8_TO_16_BITS: return "ps_convert_rgba8_16bits";
case ShaderConvert::DATM_1: return "ps_datm1";
case ShaderConvert::DATM_0: return "ps_datm0";
case ShaderConvert::MOD_256: return "ps_mod256";
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";
case ShaderConvert::FLOAT32_TO_RGBA8: return "ps_convert_float32_rgba8";
case ShaderConvert::FLOAT16_TO_RGB5A1: return "ps_convert_float16_rgb5a1";
case ShaderConvert::RGBA8_TO_FLOAT32: return "ps_convert_rgba8_float32";
case ShaderConvert::RGBA8_TO_FLOAT24: return "ps_convert_rgba8_float24";
case ShaderConvert::RGBA8_TO_FLOAT16: return "ps_convert_rgba8_float16";
case ShaderConvert::RGB5A1_TO_FLOAT16: return "ps_convert_rgb5a1_float16";
case ShaderConvert::DEPTH_COPY: return "ps_depth_copy";
case ShaderConvert::RGBA_TO_8I: return "ps_convert_rgba_8i";
case ShaderConvert::YUV: return "ps_yuv";
case ShaderConvert::COPY: return "ps_copy";
case ShaderConvert::RGBA8_TO_16_BITS: return "ps_convert_rgba8_16bits";
case ShaderConvert::DATM_1: return "ps_datm1";
case ShaderConvert::DATM_0: return "ps_datm0";
case ShaderConvert::MOD_256: return "ps_mod256";
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";
case ShaderConvert::FLOAT32_TO_RGBA8: return "ps_convert_float32_rgba8";
case ShaderConvert::FLOAT16_TO_RGB5A1: return "ps_convert_float16_rgb5a1";
case ShaderConvert::RGBA8_TO_FLOAT32: return "ps_convert_rgba8_float32";
case ShaderConvert::RGBA8_TO_FLOAT24: return "ps_convert_rgba8_float24";
case ShaderConvert::RGBA8_TO_FLOAT16: return "ps_convert_rgba8_float16";
case ShaderConvert::RGB5A1_TO_FLOAT16: return "ps_convert_rgb5a1_float16";
case ShaderConvert::RGBA8_TO_FLOAT32_BILN: return "ps_convert_rgba8_float32_biln";
case ShaderConvert::RGBA8_TO_FLOAT24_BILN: return "ps_convert_rgba8_float24_biln";
case ShaderConvert::RGBA8_TO_FLOAT16_BILN: return "ps_convert_rgba8_float16_biln";
case ShaderConvert::RGB5A1_TO_FLOAT16_BILN: return "ps_convert_rgb5a1_float16_biln";
case ShaderConvert::DEPTH_COPY: return "ps_depth_copy";
case ShaderConvert::RGBA_TO_8I: return "ps_convert_rgba_8i";
case ShaderConvert::YUV: return "ps_yuv";
// clang-format on
default:
ASSERT(0);
Expand Down

0 comments on commit 91601e5

Please sign in to comment.