mirror of
https://github.com/RPCS3/rpcs3.git
synced 2026-04-07 07:25:20 +00:00
223 lines
6.4 KiB
GLSL
223 lines
6.4 KiB
GLSL
R"(
|
|
#version 420
|
|
#extension GL_ARB_separate_shader_objects : enable
|
|
|
|
%preprocessor
|
|
|
|
#ifdef VULKAN
|
|
#define USE_UBO 1
|
|
#endif
|
|
|
|
#define SAMPLER_MODE_NONE 0
|
|
#define SAMPLER_MODE_FONT2D 1
|
|
#define SAMPLER_MODE_FONT3D 2
|
|
#define SAMPLER_MODE_TEXTURE2D 3
|
|
|
|
#define SDF_DISABLED 0
|
|
#define SDF_ELLIPSE 1
|
|
#define SDF_BOX 2
|
|
#define SDF_ROUND_BOX 3
|
|
|
|
#ifdef VULKAN
|
|
layout(set=0, binding=0) uniform sampler2D fs0;
|
|
layout(set=0, binding=1) uniform sampler2DArray fs1;
|
|
#else
|
|
layout(binding=31) uniform sampler2D fs0;
|
|
layout(binding=30) uniform sampler2DArray fs1;
|
|
#endif
|
|
|
|
layout(location=0) in vec2 tc0;
|
|
layout(location=1) in vec4 color;
|
|
layout(location=2) in vec4 clip_rect;
|
|
|
|
layout(location=0) out vec4 ocol;
|
|
|
|
#if USE_UBO
|
|
layout(%push_block) uniform FragmentConfiguration
|
|
{
|
|
%push_block_offset
|
|
uint fragment_config;
|
|
float timestamp;
|
|
float blur_intensity;
|
|
vec4 sdf_params;
|
|
vec4 sdf_origin;
|
|
vec4 sdf_border_color;
|
|
};
|
|
#else
|
|
uniform uint fragment_config;
|
|
uniform float timestamp;
|
|
uniform float blur_intensity;
|
|
uniform vec4 sdf_params;
|
|
uniform vec2 sdf_origin;
|
|
uniform vec4 sdf_border_color;
|
|
#endif
|
|
|
|
struct config_t
|
|
{
|
|
bool clip_fragments;
|
|
bool use_pulse_glow;
|
|
uint sampler_mode;
|
|
uint sdf;
|
|
};
|
|
|
|
config_t unpack_fragment_options()
|
|
{
|
|
config_t result;
|
|
result.clip_fragments = bitfieldExtract(fragment_config, 0, 1) != 0;
|
|
result.use_pulse_glow = bitfieldExtract(fragment_config, 1, 1) != 0;
|
|
result.sampler_mode = bitfieldExtract(fragment_config, 2, 2);
|
|
result.sdf = bitfieldExtract(fragment_config, 4, 2);
|
|
return result;
|
|
}
|
|
|
|
vec4 SDF_blend(
|
|
const in float sd,
|
|
const in float border_width,
|
|
const in vec4 inner_color,
|
|
const in vec4 border_color,
|
|
const in vec4 outer_color)
|
|
{
|
|
// Crucially, we need to get the derivative without subracting the border width.
|
|
// Subtracting the border width makes the function non-continuous and makes the jaggies hard to get rid of.
|
|
float fw = fwidth(sd);
|
|
|
|
// Compute the two transition points. The inner edge is of course biased by the border amount as the clamping point
|
|
// Treat smoothstep as fancy clamp where e0 < x < e1
|
|
float a = smoothstep(-border_width + fw, -border_width - fw, sd); // inner edge transition
|
|
float b = smoothstep(fw, -fw, sd); // outer edge transition
|
|
|
|
// Mix the 3 colors with the transition values.
|
|
vec4 color = mix(outer_color, border_color, b);
|
|
color = mix(color, inner_color, a);
|
|
return color;
|
|
}
|
|
|
|
float SDF_fn(const in uint sdf)
|
|
{
|
|
const vec2 p = floor(gl_FragCoord.xy) - sdf_origin.xy; // Screen-spac distance
|
|
const vec2 hs = sdf_params.xy; // Half size
|
|
const float r = sdf_params.z; // Radius (for round box, ellipses use half size instead)
|
|
vec2 v; // Scratch
|
|
float d; // Distance calculated
|
|
|
|
switch (sdf)
|
|
{
|
|
case SDF_ELLIPSE:
|
|
// Slightly inaccurate hack, but good enough for classification and allows oval shapes
|
|
d = length(p / hs) - 1.f;
|
|
// Now we need to correct for the border because the circle was scaled down to a unit
|
|
return d * length(hs);
|
|
case SDF_BOX:
|
|
// Insanity, reduced junction of 3 functions
|
|
// If for each axis the axis-aligned distance = D then you can select/clamp each axis separately by doing a max(D, 0) on all dimensions
|
|
// Length then does the squareroot transformation.
|
|
// The second term is to add back the inner distance which is useful for rendering borders
|
|
v = abs(p) - hs;
|
|
return length(max(v, 0.f)) + min(max(v.x, v.y), 0.0);
|
|
case SDF_ROUND_BOX:
|
|
// Modified BOX SDF.
|
|
// The half box size is shrunk by R in it's diagonal, but we add radius back into the output to bias the output again
|
|
v = abs(p) - (hs - r);
|
|
return length(max(v, 0.f)) + min(max(v.x, v.y), 0.0) - r;
|
|
default:
|
|
return -1.f;
|
|
}
|
|
}
|
|
|
|
vec4 blur_sample(sampler2D tex, vec2 coord, vec2 tex_offset)
|
|
{
|
|
vec2 coords[9];
|
|
coords[0] = coord - tex_offset;
|
|
coords[1] = coord + vec2(0., -tex_offset.y);
|
|
coords[2] = coord + vec2(tex_offset.x, -tex_offset.y);
|
|
coords[3] = coord + vec2(-tex_offset.x, 0.);
|
|
coords[4] = coord;
|
|
coords[5] = coord + vec2(tex_offset.x, 0.);
|
|
coords[6] = coord + vec2(-tex_offset.x, tex_offset.y);
|
|
coords[7] = coord + vec2(0., tex_offset.y);
|
|
coords[8] = coord + tex_offset;
|
|
|
|
float weights[9] =
|
|
{
|
|
1., 2., 1.,
|
|
2., 4., 2.,
|
|
1., 2., 1.
|
|
};
|
|
|
|
vec4 blurred = vec4(0.);
|
|
for (int n = 0; n < 9; ++n)
|
|
{
|
|
blurred += texture(tex, coords[n]) * weights[n];
|
|
}
|
|
|
|
return blurred / 16.f;
|
|
}
|
|
|
|
vec4 sample_image(sampler2D tex, vec2 coord, float blur_strength)
|
|
{
|
|
vec4 original = texture(tex, coord);
|
|
if (blur_strength == 0) return original;
|
|
|
|
vec2 constraints = 1.f / vec2(640, 360);
|
|
vec2 res_offset = 1.f / textureSize(fs0, 0);
|
|
vec2 tex_offset = max(res_offset, constraints);
|
|
|
|
// Sample triangle pattern and average
|
|
// TODO: Nicer looking gaussian blur with less sampling
|
|
vec4 blur0 = blur_sample(tex, coord + vec2(-res_offset.x, 0.), tex_offset);
|
|
vec4 blur1 = blur_sample(tex, coord + vec2(res_offset.x, 0.), tex_offset);
|
|
vec4 blur2 = blur_sample(tex, coord + vec2(0., res_offset.y), tex_offset);
|
|
|
|
vec4 blurred = blur0 + blur1 + blur2;
|
|
blurred /= 3.;
|
|
return mix(original, blurred, blur_strength);
|
|
}
|
|
|
|
void main()
|
|
{
|
|
config_t config = unpack_fragment_options();
|
|
if (config.clip_fragments)
|
|
{
|
|
if (gl_FragCoord.x < clip_rect.x || gl_FragCoord.x > clip_rect.z ||
|
|
gl_FragCoord.y < clip_rect.y || gl_FragCoord.y > clip_rect.w)
|
|
{
|
|
discard;
|
|
return;
|
|
}
|
|
}
|
|
|
|
vec4 diff_color = color;
|
|
if (config.use_pulse_glow)
|
|
{
|
|
diff_color.a *= (sin(timestamp) + 1.f) * 0.5f;
|
|
}
|
|
|
|
if (config.sdf != SDF_DISABLED)
|
|
{
|
|
const float border_w = sdf_params.w; // Border width
|
|
const float d = SDF_fn(config.sdf);
|
|
diff_color = SDF_blend(d, border_w, diff_color, sdf_border_color, vec4(0.));
|
|
}
|
|
|
|
switch (config.sampler_mode)
|
|
{
|
|
default:
|
|
case SAMPLER_MODE_NONE:
|
|
ocol = diff_color;
|
|
break;
|
|
case SAMPLER_MODE_FONT2D:
|
|
ocol = texture(fs0, tc0).rrrr * diff_color;
|
|
break;
|
|
case SAMPLER_MODE_FONT3D:
|
|
ocol = texture(fs1, vec3(tc0.x, fract(tc0.y), trunc(tc0.y))).rrrr * diff_color;
|
|
break;
|
|
case SAMPLER_MODE_TEXTURE2D:
|
|
#ifdef VULKAN
|
|
ocol = sample_image(fs0, tc0, blur_intensity).bgra * diff_color;
|
|
#else
|
|
ocol = sample_image(fs0, tc0, blur_intensity).rgba * diff_color;
|
|
#endif
|
|
break;
|
|
}
|
|
}
|
|
)"
|