forked from LeenkxTeam/LNXSDK
158 lines
4.6 KiB
GLSL
158 lines
4.6 KiB
GLSL
#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);
|
|
}
|