/* FSR - [RCAS] ROBUST CONTRAST ADAPTIVE SHARPENING Ported from https://www.shadertoy.com/view/stXSWB, MIT license */ #pragma parameter FSR_SHARPENING "FSR RCAS Sharpening Amount (Lower = Sharper)" 0.6 0.0 2.0 0.1 #if defined(VERTEX) #if __VERSION__ >= 130 #define COMPAT_VARYING out #define COMPAT_ATTRIBUTE in #define COMPAT_TEXTURE texture #else #define COMPAT_VARYING varying #define COMPAT_ATTRIBUTE attribute #define COMPAT_TEXTURE texture2D #endif #ifdef GL_ES #define COMPAT_PRECISION mediump #else #define COMPAT_PRECISION #endif COMPAT_ATTRIBUTE vec4 VertexCoord; COMPAT_ATTRIBUTE vec4 COLOR; COMPAT_ATTRIBUTE vec4 TexCoord; COMPAT_VARYING vec4 COL0; COMPAT_VARYING vec4 TEX0; uniform mat4 MVPMatrix; uniform COMPAT_PRECISION int FrameDirection; uniform COMPAT_PRECISION int FrameCount; uniform COMPAT_PRECISION vec2 OutputSize; uniform COMPAT_PRECISION vec2 TextureSize; uniform COMPAT_PRECISION vec2 InputSize; void main() { gl_Position = MVPMatrix * VertexCoord; COL0 = COLOR; TEX0.xy = TexCoord.xy; } #elif defined(FRAGMENT) #if __VERSION__ >= 130 #define COMPAT_VARYING in #define COMPAT_TEXTURE texture out vec4 FragColor; #else #define COMPAT_VARYING varying #define FragColor gl_FragColor #define COMPAT_TEXTURE texture2D #endif #ifdef GL_ES #ifdef GL_FRAGMENT_PRECISION_HIGH precision highp float; #else precision mediump float; #endif #define COMPAT_PRECISION mediump #else #define COMPAT_PRECISION #endif uniform COMPAT_PRECISION int FrameDirection; uniform COMPAT_PRECISION int FrameCount; uniform COMPAT_PRECISION vec2 OutputSize; uniform COMPAT_PRECISION vec2 TextureSize; uniform COMPAT_PRECISION vec2 InputSize; uniform sampler2D Texture; COMPAT_VARYING vec4 TEX0; // compatibility #defines #define Source Texture #define vTexCoord TEX0.xy #define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize #define outsize vec4(OutputSize, 1.0 / OutputSize) #ifdef PARAMETER_UNIFORM uniform COMPAT_PRECISION float FSR_SHARPENING; #else #define FSR_SHARPENING 0.6 #endif #define FSR_RCAS_LIMIT (0.25-(1.0/16.0)) //#define FSR_RCAS_DENOISE // Input callback prototypes that need to be implemented by calling shader vec4 FsrRcasLoadF(vec2 p); //------------------------------------------------------------------------------------------------------------------------------ void FsrRcasCon( out float con, // The scale is {0.0 := maximum, to N>0, where N is the number of stops (halving) of the reduction of sharpness}. float sharpness ){ // Transform from stops to linear value. con = exp2(-sharpness); } vec3 FsrRcasF( vec2 ip, // Integer pixel position in output. float con ) { // Constant generated by RcasSetup(). // Algorithm uses minimal 3x3 pixel neighborhood. // b // d e f // h vec2 sp = vec2(ip); vec3 b = FsrRcasLoadF(sp + vec2( 0,-1)).rgb; vec3 d = FsrRcasLoadF(sp + vec2(-1, 0)).rgb; vec3 e = FsrRcasLoadF(sp).rgb; vec3 f = FsrRcasLoadF(sp+vec2( 1, 0)).rgb; vec3 h = FsrRcasLoadF(sp+vec2( 0, 1)).rgb; // Luma times 2. float bL = b.g + .5 * (b.b + b.r); float dL = d.g + .5 * (d.b + d.r); float eL = e.g + .5 * (e.b + e.r); float fL = f.g + .5 * (f.b + f.r); float hL = h.g + .5 * (h.b + h.r); // Noise detection. float nz = .25 * (bL + dL + fL + hL) - eL; nz=clamp( abs(nz) /( max(max(bL,dL),max(eL,max(fL,hL))) -min(min(bL,dL),min(eL,min(fL,hL))) ), 0., 1. ); nz=1.-.5*nz; // Min and max of ring. vec3 mn4 = min(b, min(f, h)); vec3 mx4 = max(b, max(f, h)); // Immediate constants for peak range. vec2 peakC = vec2(1., -4.); // Limiters, these need to be high precision RCPs. vec3 hitMin = mn4 / (4. * mx4); vec3 hitMax = (peakC.x - mx4) / (4.* mn4 + peakC.y); vec3 lobeRGB = max(-hitMin, hitMax); float lobe = max( -FSR_RCAS_LIMIT, min(max(lobeRGB.r, max(lobeRGB.g, lobeRGB.b)), 0.) )*con; // Apply noise removal. #ifdef FSR_RCAS_DENOISE lobe *= nz; #endif // Resolve, which needs the medium precision rcp approximation to avoid visible tonality changes. return (lobe * (b + d + h + f) + e) / (4. * lobe + 1.); } vec4 FsrRcasLoadF(vec2 p) { return COMPAT_TEXTURE(Source,p/OutputSize.xy); } void main() { vec2 fragCoord = vTexCoord.xy * OutputSize.xy; // Set up constants float con; FsrRcasCon(con, FSR_SHARPENING); // Perform RCAS pass vec3 col = FsrRcasF(fragCoord, con); FragColor = vec4(col,1); } #endif