#version 450 // AMD FidelityFX Super Resolution 1.0.2 - EASU (Edge Adaptive Spatial Upsampling) #include "compiled.inc" uniform sampler2D tex; uniform vec2 screenSize; in vec2 texCoord; out vec4 fragColor; // Helper functions from AMD ffx_a.h float APrxLoRcpF1(float a) { return uintBitsToFloat(uint(0x7ef07ebb) - floatBitsToUint(a)); } float AMax3F1(float x, float y, float z) { return max(x, max(y, z)); } float AMin3F1(float x, float y, float z) { return min(x, min(y, z)); } // Attempt to use textureGather for efficiency when available #if __VERSION__ >= 400 void FsrEasuTap( inout vec3 aC, inout float aW, vec2 off, vec2 dir, vec2 len, float lob, float clp, vec3 c ) { vec2 v = off * dir; float d2 = v.x + v.y; d2 = clamp(d2 * APrxLoRcpF1(max(abs(v.x), abs(v.y))), 0.0, 1.0); d2 = d2 * d2; d2 = d2 * len.x + len.y; float wB = 2.0 / 5.0 * d2 - 1.0; float wA = lob * d2 - 1.0; wB *= wB; wA *= wA; float w = 25.0 / 16.0 * wA * wB; w = min(w, clp); w = max(w, 0.0); aC += c * w; aW += w; } vec3 FsrEasuF(vec2 ip) { vec2 inputSize = textureSize(tex, 0); vec2 inputRcp = 1.0 / inputSize; // Position in input pixels vec2 pp = ip * inputSize - 0.5; vec2 fp = floor(pp); pp -= fp; // 12-tap kernel // b c // e f g h // i j k l // n o ivec2 sp = ivec2(fp); vec3 b = texelFetch(tex, sp + ivec2(0, -1), 0).rgb; vec3 c = texelFetch(tex, sp + ivec2(1, -1), 0).rgb; vec3 e = texelFetch(tex, sp + ivec2(-1, 0), 0).rgb; vec3 f = texelFetch(tex, sp + ivec2(0, 0), 0).rgb; vec3 g = texelFetch(tex, sp + ivec2(1, 0), 0).rgb; vec3 h = texelFetch(tex, sp + ivec2(2, 0), 0).rgb; vec3 i = texelFetch(tex, sp + ivec2(-1, 1), 0).rgb; vec3 j = texelFetch(tex, sp + ivec2(0, 1), 0).rgb; vec3 k = texelFetch(tex, sp + ivec2(1, 1), 0).rgb; vec3 l = texelFetch(tex, sp + ivec2(2, 1), 0).rgb; vec3 n = texelFetch(tex, sp + ivec2(0, 2), 0).rgb; vec3 o = texelFetch(tex, sp + ivec2(1, 2), 0).rgb; // Luma for edge detection (using green channel approximation) float bL = b.g + 0.5 * (b.r + b.b); float cL = c.g + 0.5 * (c.r + c.b); float eL = e.g + 0.5 * (e.r + e.b); float fL = f.g + 0.5 * (f.r + f.b); float gL = g.g + 0.5 * (g.r + g.b); float hL = h.g + 0.5 * (h.r + h.b); float iL = i.g + 0.5 * (i.r + i.b); float jL = j.g + 0.5 * (j.r + j.b); float kL = k.g + 0.5 * (k.r + k.b); float lL = l.g + 0.5 * (l.r + l.b); float nL = n.g + 0.5 * (n.r + n.b); float oL = o.g + 0.5 * (o.r + o.b); // Gradient detection float dirX = (cL - bL) + (gL - fL) + (kL - jL) + (oL - nL); float dirY = (eL - iL) + (fL - jL) + (gL - kL) + (hL - lL); // Normalize direction float dirR = APrxLoRcpF1(max(abs(dirX), abs(dirY))); dirX *= dirR; dirY *= dirR; // Calculate stretch based on edge direction float len = length(vec2(dirX, dirY)); len = len * 0.5; len *= len; float stretch = (dirX * dirX + dirY * dirY) * APrxLoRcpF1(max(abs(dirX), abs(dirY))); vec2 len2 = vec2(1.0 + (stretch - 1.0) * len, 1.0 - 0.5 * len); float lob = 0.5 + (0.25 - 0.04 - 0.5) * len; float clp = APrxLoRcpF1(lob); // Accumulate samples vec3 aC = vec3(0.0); float aW = 0.0; vec2 dir = vec2(dirX, dirY); FsrEasuTap(aC, aW, vec2(0.0, -1.0) - pp, dir, len2, lob, clp, b); FsrEasuTap(aC, aW, vec2(1.0, -1.0) - pp, dir, len2, lob, clp, c); FsrEasuTap(aC, aW, vec2(-1.0, 0.0) - pp, dir, len2, lob, clp, e); FsrEasuTap(aC, aW, vec2(0.0, 0.0) - pp, dir, len2, lob, clp, f); FsrEasuTap(aC, aW, vec2(1.0, 0.0) - pp, dir, len2, lob, clp, g); FsrEasuTap(aC, aW, vec2(2.0, 0.0) - pp, dir, len2, lob, clp, h); FsrEasuTap(aC, aW, vec2(-1.0, 1.0) - pp, dir, len2, lob, clp, i); FsrEasuTap(aC, aW, vec2(0.0, 1.0) - pp, dir, len2, lob, clp, j); FsrEasuTap(aC, aW, vec2(1.0, 1.0) - pp, dir, len2, lob, clp, k); FsrEasuTap(aC, aW, vec2(2.0, 1.0) - pp, dir, len2, lob, clp, l); FsrEasuTap(aC, aW, vec2(0.0, 2.0) - pp, dir, len2, lob, clp, n); FsrEasuTap(aC, aW, vec2(1.0, 2.0) - pp, dir, len2, lob, clp, o); // Normalize vec3 pix = aC / aW; // Clamp to neighborhood min/max to prevent ringing vec3 mn = min(min(min(f, g), j), k); vec3 mx = max(max(max(f, g), j), k); pix = clamp(pix, mn, mx); return pix; } #else // Fallback for older GLSL - simple bilinear vec3 FsrEasuF(vec2 ip) { return texture(tex, ip).rgb; } #endif void main() { vec3 col = FsrEasuF(texCoord); fragColor = vec4(col, 1.0); }