diff --git a/misc/anti-flicker.slang b/misc/anti-flicker.slang new file mode 100644 index 0000000..ed596a2 --- /dev/null +++ b/misc/anti-flicker.slang @@ -0,0 +1,74 @@ +#version 450 + +/* + Anti-Flicker shader + by hunterk + License: public domain + + This shader detects +*/ + +layout(push_constant) uniform Push +{ + vec4 SourceSize; + vec4 OriginalSize; + vec4 OutputSize; + uint FrameCount; + float THRESH; +} params; + +#pragma parameter THRESH "Luma Diff Threshold" 0.25 0.0 1.0 0.05 + +layout(std140, set = 0, binding = 0) uniform UBO +{ + mat4 MVP; +} global; + +#pragma stage vertex +layout(location = 0) in vec4 Position; +layout(location = 1) in vec2 TexCoord; +layout(location = 0) out vec2 vTexCoord; + +void main() +{ + gl_Position = global.MVP * Position; + vTexCoord = TexCoord; +} + +#pragma stage fragment +layout(location = 0) in vec2 vTexCoord; +layout(location = 0) out vec4 FragColor; +layout(set = 0, binding = 2) uniform sampler2D Source; +layout(set = 0, binding = 3) uniform sampler2D OriginalHistory1; +layout(set = 0, binding = 4) uniform sampler2D OriginalHistory2; +layout(set = 0, binding = 5) uniform sampler2D OriginalHistory3; + +void main() +{ + // sample the textures + vec4 current = texture(Source, vTexCoord); + vec4 prev1 = texture(OriginalHistory1, vTexCoord); + vec4 prev2 = texture(OriginalHistory2, vTexCoord); + vec4 prev3 = texture(OriginalHistory3, vTexCoord); + + // get luma for comparison + float cur_lum = dot(current.rgb, vec3(0.2125, 0.7154, 0.0721)); + float prev1_lum = dot(prev1.rgb, vec3(0.2125, 0.7154, 0.0721)); + float prev2_lum = dot(prev2.rgb, vec3(0.2125, 0.7154, 0.0721)); + float prev3_lum = dot(prev3.rgb, vec3(0.2125, 0.7154, 0.0721)); + + // Test whether the luma difference between the pixel in the current frame and that of + // the previous frame exceeds the threshold while the difference between the current frame + // and 2 frames previous is below the threshold. + // Repeat the process for the previous frame's pixel to reduce false-positives + bool flicker = (abs(cur_lum - prev1_lum) > params.THRESH && abs(cur_lum - prev2_lum) < params.THRESH) && + (abs(prev1_lum - prev2_lum) > params.THRESH && abs(prev1_lum - prev3_lum) < params.THRESH); + + // Average the current frame with the previous frame in linear color space to avoid over-darkening + vec4 blended = (pow(current, vec4(2.2)) + pow(prev1, vec4(2.2))) / 2.0; + + // delinearize the averaged result + blended = pow(blended, vec4(1.0 / 2.2)); + + FragColor = (!flicker) ? current : blended; +} \ No newline at end of file