mirror of
https://github.com/RPCS3/rpcs3.git
synced 2026-10-12 02:09:17 +00:00
rsx: Update programmable blending code to be in line with current emulator state
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
R"(
|
||||
|
||||
#define _MRT_BUFFERS_COUNT 4 // TODO
|
||||
|
||||
#ifdef _32_BIT_OUTPUT
|
||||
// Everything is fp32 on ouput channels
|
||||
#define _mrt_color_t(expr) expr
|
||||
@@ -15,16 +17,24 @@ R"(
|
||||
// Default. Used when we're not utilizing native fp16
|
||||
vec4 round_to_8bit(const in vec4 v4)
|
||||
{
|
||||
uvec4 raw = uvec4(max(floor(fma(_fx12_truncate(v4), vec4(255.), vec4(0.5))), vec4(0.)));
|
||||
const uvec4 raw = uvec4(max(floor(fma(_fx12_truncate(v4), vec4(255.), vec4(0.5))), vec4(0.)));
|
||||
return vec4(raw) / vec4(255.);
|
||||
}
|
||||
#ifndef _32_BIT_OUTPUT
|
||||
f16vec4 round_to_8bit(const in f16vec4 v4)
|
||||
{
|
||||
uvec4 raw = uvec4(max(floor(fma(_fx12_truncate(vec4(v4)), f16vec4(255.), f16vec4(0.5))), vec4(0.)));
|
||||
const uvec4 raw = uvec4(max(floor(fma(_fx12_truncate(vec4(v4)), f16vec4(255.), f16vec4(0.5))), vec4(0.)));
|
||||
return f16vec4(raw) / f16vec4(255.);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Scalar variant of 8-bit rounding is only available for f32.
|
||||
float round_to_8bit(const in float v)
|
||||
{
|
||||
const uint raw = uint(max(floor(fma(_fx12_truncate(v), 255.f, 0.5f)), 0.f));
|
||||
return float(raw) / 255.f;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef _DISABLE_EARLY_DISCARD
|
||||
|
||||
@@ -35,6 +35,14 @@ R"(
|
||||
#define BLEND_FUNC_ADD_SIGNED 0x0000F006
|
||||
#define BLEND_FUNC_REVERSE_ADD_SIGNED 0x0000F007
|
||||
|
||||
#ifdef INT_FRAMEBUFFER_BIT
|
||||
#define _blend_saturate _saturate
|
||||
#define _blend_saturate_signed(v) clamp(v, -1.f, 1.f)
|
||||
#else
|
||||
#define _blend_saturate(v) v
|
||||
#define _blend_saturate_signed(v) v
|
||||
#endif
|
||||
|
||||
float get_blend_factor_a(const in uint op, const in vec4 src, const in vec4 dst)
|
||||
{
|
||||
switch (op)
|
||||
@@ -51,9 +59,9 @@ float get_blend_factor_a(const in uint op, const in vec4 src, const in vec4 dst)
|
||||
case BLEND_FACTOR_ONE_MINUS_DST_COLOR: return 1. - dst.a;
|
||||
case BLEND_FACTOR_SRC_ALPHA_SATURATE: return 1;
|
||||
case BLEND_FACTOR_CONSTANT_COLOR:
|
||||
case BLEND_FACTOR_CONSTANT_ALPHA: return constants.a;
|
||||
case BLEND_FACTOR_CONSTANT_ALPHA: return blend_constants.a;
|
||||
case BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR:
|
||||
case BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA: return 1. - constants.a;
|
||||
case BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA: return 1. - blend_constants.a;
|
||||
}
|
||||
return 0.;
|
||||
}
|
||||
@@ -69,10 +77,10 @@ vec3 get_blend_factor_rgb(const in uint op, const in vec4 src, const in vec4 dst
|
||||
case BLEND_FACTOR_ONE_MINUS_SRC_COLOR: return 1. - src.rgb;
|
||||
case BLEND_FACTOR_ONE_MINUS_SRC_ALPHA: return 1. - src.aaa;
|
||||
case BLEND_FACTOR_DST_COLOR: return dst.rgb;
|
||||
case BLEND_FACTOR_DST_ALPHA: return dst.a;
|
||||
case BLEND_FACTOR_DST_ALPHA: return dst.aaa;
|
||||
case BLEND_FACTOR_ONE_MINUS_DST_COLOR: return 1. - dst.rgb;
|
||||
case BLEND_FACTOR_ONE_MINUS_DST_ALPHA: return 1. - dst.a;
|
||||
case BLEND_FACTOR_SRC_ALPHA_SATURATE: return src.rgb;
|
||||
case BLEND_FACTOR_ONE_MINUS_DST_ALPHA: return 1. - dst.aaa;
|
||||
case BLEND_FACTOR_SRC_ALPHA_SATURATE: return vec3(min(src.a, 1. - dst.a));
|
||||
case BLEND_FACTOR_CONSTANT_COLOR: return blend_constants.rgb;
|
||||
case BLEND_FACTOR_CONSTANT_ALPHA: return blend_constants.aaa;
|
||||
case BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR: return 1. - blend_constants.rgb;
|
||||
@@ -96,17 +104,17 @@ float apply_blend_func_a(const in vec4 src, const in vec4 dst)
|
||||
|
||||
switch (func)
|
||||
{
|
||||
case BLEND_FUNC_ADD: return _saturate(s) + d;
|
||||
case BLEND_MIN: return min(_saturate(s), d);
|
||||
case BLEND_MAX: return max(_saturate(s), d);
|
||||
case BLEND_FUNC_SUBTRACT: return _saturate(s) - d;
|
||||
case BLEND_FUNC_REVERSE_SUBTRACT: return d - _saturate(s);
|
||||
case BLEND_FUNC_REVERSE_SUBTRACT_SIGNED: return d - s;
|
||||
case BLEND_FUNC_ADD_SIGNED: return s + d;
|
||||
case BLEND_FUNC_REVERSE_ADD_SIGNED: return s + d;
|
||||
case BLEND_FUNC_ADD: return _blend_saturate(s) + d;
|
||||
case BLEND_MIN: return min(_blend_saturate(src.a), dst.a);
|
||||
case BLEND_MAX: return max(_blend_saturate(src.a), dst.a);
|
||||
case BLEND_FUNC_SUBTRACT: return _blend_saturate(s) - d;
|
||||
case BLEND_FUNC_REVERSE_SUBTRACT: return d - _blend_saturate(s);
|
||||
case BLEND_FUNC_REVERSE_SUBTRACT_SIGNED: return d - _blend_saturate_signed(s);
|
||||
case BLEND_FUNC_ADD_SIGNED: return _blend_saturate_signed(s) + d;
|
||||
case BLEND_FUNC_REVERSE_ADD_SIGNED: return _blend_saturate(s) + _blend_saturate_signed(d);
|
||||
}
|
||||
|
||||
return vec3(0.);
|
||||
return 0.f;
|
||||
}
|
||||
|
||||
vec3 apply_blend_func_rgb(const in vec4 src, const in vec4 dst)
|
||||
@@ -124,14 +132,14 @@ vec3 apply_blend_func_rgb(const in vec4 src, const in vec4 dst)
|
||||
|
||||
switch (func)
|
||||
{
|
||||
case BLEND_FUNC_ADD: return _saturate(s) + d;
|
||||
case BLEND_MIN: return min(_saturate(s), d);
|
||||
case BLEND_MAX: return max(_saturate(s), d);
|
||||
case BLEND_FUNC_SUBTRACT: return _saturate(s) - d;
|
||||
case BLEND_FUNC_REVERSE_SUBTRACT: return d - _saturate(s);
|
||||
case BLEND_FUNC_REVERSE_SUBTRACT_SIGNED: return d - s;
|
||||
case BLEND_FUNC_ADD_SIGNED: return s + d;
|
||||
case BLEND_FUNC_REVERSE_ADD_SIGNED: return s + d;
|
||||
case BLEND_FUNC_ADD: return _blend_saturate(s) + d;
|
||||
case BLEND_MIN: return min(_blend_saturate(src.rgb), dst.rgb);
|
||||
case BLEND_MAX: return max(_blend_saturate(src.rgb), dst.rgb);
|
||||
case BLEND_FUNC_SUBTRACT: return _blend_saturate(s) - d;
|
||||
case BLEND_FUNC_REVERSE_SUBTRACT: return d - _blend_saturate(s);
|
||||
case BLEND_FUNC_REVERSE_SUBTRACT_SIGNED: return d - _blend_saturate_signed(s);
|
||||
case BLEND_FUNC_ADD_SIGNED: return _blend_saturate_signed(s) + d;
|
||||
case BLEND_FUNC_REVERSE_ADD_SIGNED: return _blend_saturate(s) + _blend_saturate_signed(d);
|
||||
}
|
||||
|
||||
return vec3(0.);
|
||||
@@ -145,8 +153,12 @@ vec4 do_blend(const in vec4 src, const in vec4 dst)
|
||||
apply_blend_func_a(src, dst)
|
||||
);
|
||||
|
||||
#ifdef _ENABLE_ROP_OUTPUT_ROUNDING
|
||||
// Accurate int conversion with wrapping
|
||||
return round_to_8bit(result);
|
||||
#else
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
)"
|
||||
|
||||
@@ -7,25 +7,17 @@ R"(
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _ENABLE_FRAMEBUFFER_SRGB
|
||||
col0.rgb = _mrt_color_t(linear_to_srgb(col0)).rgb;
|
||||
col1.rgb = _mrt_color_t(linear_to_srgb(col1)).rgb;
|
||||
col2.rgb = _mrt_color_t(linear_to_srgb(col2)).rgb;
|
||||
col3.rgb = _mrt_color_t(linear_to_srgb(col3)).rgb;
|
||||
#endif
|
||||
|
||||
#ifdef _ENABLE_ROP_OUTPUT_ROUNDING
|
||||
col0 = round_to_8bit(col0);
|
||||
col1 = round_to_8bit(col1);
|
||||
col2 = round_to_8bit(col2);
|
||||
col3 = round_to_8bit(col3);
|
||||
#endif
|
||||
|
||||
// Post-output stages
|
||||
// Alpha Testing
|
||||
// Alpha Testing. This stage always runs even without a color output.
|
||||
#ifdef _ENABLE_ALPHA_TEST
|
||||
// TODO: Verify that alpha test actually runs on quantized output!
|
||||
// Behavior was inferred from game observations but real tests will be needed here.
|
||||
#if defined(_ENABLE_ROP_OUTPUT_ROUNDING)
|
||||
#define _alpha_quantize(v) round_to_8bit(v)
|
||||
#else
|
||||
#define _alpha_quantize(v) (v)
|
||||
#endif
|
||||
const uint alpha_func = _get_bits(rop_control, ALPHA_TEST_FUNC_OFFSET, ALPHA_TEST_FUNC_LENGTH);
|
||||
if (!comparison_passes(col0.a, alpha_ref, alpha_func))
|
||||
if (!comparison_passes(_alpha_quantize(col0.a), alpha_ref, alpha_func))
|
||||
{
|
||||
discard;
|
||||
}
|
||||
@@ -38,6 +30,71 @@ R"(
|
||||
}
|
||||
#endif
|
||||
|
||||
// ================= Post-output color stages =================
|
||||
|
||||
#if _MRT_BUFFERS_COUNT >= 1
|
||||
|
||||
#ifdef _ENABLE_PROGRAMMABLE_BLENDING
|
||||
// Stash the raw source data
|
||||
vec4 blend_s0 = col0;
|
||||
vec4 blend_s1 = col1;
|
||||
vec4 blend_s2 = col2;
|
||||
vec4 blend_s3 = col3;
|
||||
#endif
|
||||
|
||||
#if defined(_ENABLE_ROP_OUTPUT_ROUNDING) && !defined(_ENABLE_PROGRAMMABLE_BLENDING)
|
||||
col0 = round_to_8bit(col0);
|
||||
col1 = round_to_8bit(col1);
|
||||
col2 = round_to_8bit(col2);
|
||||
col3 = round_to_8bit(col3);
|
||||
#endif
|
||||
|
||||
// NOTE: Blending happens before output remapping as per hardware tests.
|
||||
// Sources = raw shader output, Dest = Remapped output from previous draw
|
||||
#ifdef _ENABLE_PROGRAMMABLE_BLENDING
|
||||
#if _MRT_BUFFERS_COUNT >= 1
|
||||
col0 = _mrt_color_t(do_blend(blend_s0, mrt_color[0]));
|
||||
#endif
|
||||
|
||||
#if _MRT_BUFFERS_COUNT >= 2
|
||||
col1 = _mrt_color_t(do_blend(blend_s1, mrt_color[1]));
|
||||
#endif
|
||||
|
||||
#if _MRT_BUFFERS_COUNT >= 3
|
||||
col2 = _mrt_color_t(do_blend(blend_s2, mrt_color[2]));
|
||||
#endif
|
||||
|
||||
#if _MRT_BUFFERS_COUNT == 4
|
||||
col3 = _mrt_color_t(do_blend(blend_s3, mrt_color[3]));
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef _ENABLE_ROP_CHANNEL_REMAPPING
|
||||
const uint ROP_remap = get_ROP_channel_remap();
|
||||
col0 = _mrt_color_t(remap_ROP_output(col0, ROP_remap));
|
||||
col1 = _mrt_color_t(remap_ROP_output(col1, ROP_remap));
|
||||
col2 = _mrt_color_t(remap_ROP_output(col2, ROP_remap));
|
||||
col3 = _mrt_color_t(remap_ROP_output(col3, ROP_remap));
|
||||
#endif
|
||||
|
||||
// TODO: Check order on real hw. Does this happen before quantization or after?
|
||||
#ifdef _ENABLE_FRAMEBUFFER_SRGB
|
||||
col0.rgb = _mrt_color_t(linear_to_srgb(col0)).rgb;
|
||||
col1.rgb = _mrt_color_t(linear_to_srgb(col1)).rgb;
|
||||
col2.rgb = _mrt_color_t(linear_to_srgb(col2)).rgb;
|
||||
col3.rgb = _mrt_color_t(linear_to_srgb(col3)).rgb;
|
||||
#endif
|
||||
|
||||
// Commit COLOR aspect
|
||||
ocol0 = col0;
|
||||
ocol1 = col1;
|
||||
ocol2 = col2;
|
||||
ocol3 = col3;
|
||||
|
||||
#endif // _MRT_BUFFERS_COUNT >= 1
|
||||
|
||||
//// ====================== Depth Export ===========================
|
||||
|
||||
#ifdef _ENABLE_DEPTH_COMPARE
|
||||
#ifdef _ENABLE_DEPTH_BUFFER_MULTISAMPLED
|
||||
float dstDepth = texelFetch(frag_depth, ivec2(gl_FragCoord.xy), gl_SampleID).r;
|
||||
@@ -57,36 +114,4 @@ R"(
|
||||
gl_FragDepth = srcDepth;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _ENABLE_ROP_CHANNEL_REMAPPING
|
||||
const uint ROP_remap = get_ROP_channel_remap();
|
||||
col0 = _mrt_color_t(remap_ROP_output(col0, ROP_remap));
|
||||
col1 = _mrt_color_t(remap_ROP_output(col1, ROP_remap));
|
||||
col2 = _mrt_color_t(remap_ROP_output(col2, ROP_remap));
|
||||
col3 = _mrt_color_t(remap_ROP_output(col3, ROP_remap));
|
||||
#endif
|
||||
|
||||
#ifdef _ENABLE_PROGRAMMABLE_BLENDING
|
||||
switch (framebufferCount)
|
||||
{
|
||||
case 4:
|
||||
col3 = do_blend(col3, mrt_color[3]);
|
||||
// Fallthrough
|
||||
case 3:
|
||||
col2 = do_blend(col2, mrt_color[2]);
|
||||
// Fallthrough
|
||||
case 2:
|
||||
col1 = do_blend(col1, mrt_color[1]);
|
||||
// Fallthrough
|
||||
default:
|
||||
col0 = do_blend(col0, mrt_color[0]);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Commit
|
||||
ocol0 = col0;
|
||||
ocol1 = col1;
|
||||
ocol2 = col2;
|
||||
ocol3 = col3;
|
||||
)"
|
||||
|
||||
@@ -19,11 +19,12 @@ R"(
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _ENABLE_PROGRAMMABLE_BLENDING
|
||||
vec4 mrt_color[4];
|
||||
for (int n = 0; n < framebufferCount; ++n)
|
||||
#if defined(_ENABLE_PROGRAMMABLE_BLENDING) && _MRT_BUFFERS_COUNT >= 1
|
||||
// TODO: Multisampled output support.
|
||||
vec4 mrt_color[_MRT_BUFFERS_COUNT];
|
||||
for (int n = 0; n < _MRT_BUFFERS_COUNT; ++n)
|
||||
{
|
||||
mrt_color[n] = subPassLoad(mrtAttachments[n]);
|
||||
mrt_color[n] = subpassLoad(mrtAttachments[n]);
|
||||
}
|
||||
#endif
|
||||
)"
|
||||
|
||||
@@ -450,10 +450,13 @@ namespace gcm
|
||||
RSX_SHADER_CONTROL_USED_REGS_MASK = 0x0000000f,
|
||||
RSX_SHADER_CONTROL_USED_TEMP_REGS_MASK = 0xff000000,
|
||||
|
||||
RSX_SHADER_CONTROL_USES_KIL = 0x00000080, // program uses KIL op
|
||||
RSX_SHADER_CONTROL_UNKNOWN0 = 0x00000400, // seemingly always set
|
||||
RSX_SHADER_CONTROL_USES_KIL = 0x00000080, // program uses KIL op
|
||||
RSX_SHADER_CONTROL_UNKNOWN0 = 0x00000400, // seemingly always set
|
||||
RSX_SHADER_CONTROL_UNKNOWN1 = 0x00008000, // seemingly set when srgb packer is used??
|
||||
|
||||
// Meta
|
||||
RSX_SHADER_CONTROL_GCM_FLAGS_MASK = 0x000007ff, // Reserved range for GCM flags. We don't care about most GCM-specific flags.
|
||||
|
||||
// Custom
|
||||
RSX_SHADER_CONTROL_FLAT_SHADING = 0x00000800, // Interpolate front/back colors using the provoking vertex
|
||||
RSX_SHADER_CONTROL_ATTRIBUTE_INTERPOLATION = 0x00010000, // Rasterizing triangles and not lines or points
|
||||
|
||||
Reference in New Issue
Block a user