mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-07-11 01:25:07 +02:00
Merge pull request #20745 from Benjamin-Wegener/master
Add FSR (FidelityFX Super Resolution) shaders for upscaling and sharpening
This commit is contained in:
@@ -248,4 +248,22 @@ SettingStep1=0.05
|
||||
Name=Sharp Bilinear Upscaler
|
||||
Fragment=upscale_sharp_bilinear.fsh
|
||||
Vertex=upscale_sharp_bilinear.vsh
|
||||
OutputResolution=True
|
||||
OutputResolution=True
|
||||
[FSR-EASU]
|
||||
Name=FSR-EASU (upscale)
|
||||
Author=Advanced Micro Devices, Inc.
|
||||
Fragment=fsr_easu.fsh
|
||||
Vertex=fxaa.vsh
|
||||
OutputResolution=True
|
||||
Upscaling=True
|
||||
[FSR-RCAS]
|
||||
Name=FSR-RCAS (sharpen)
|
||||
Author=Advanced Micro Devices, Inc.
|
||||
Fragment=fsr_rcas.fsh
|
||||
Vertex=fxaa.vsh
|
||||
; Slider definition
|
||||
SettingName1=Sharpness
|
||||
SettingDefaultValue1=0.5 ; starting value
|
||||
SettingMaxValue1=1.0 ; upper bound
|
||||
SettingMinValue1=0.0 ; lower bound
|
||||
SettingStep1=0.05 ; step size
|
||||
|
||||
@@ -0,0 +1,182 @@
|
||||
// MIT License
|
||||
//
|
||||
// Copyright (c) 2021 Advanced Micro Devices, Inc. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#ifdef GL_ES
|
||||
precision mediump float;
|
||||
precision mediump int;
|
||||
#endif
|
||||
|
||||
uniform sampler2D sampler0;
|
||||
uniform vec2 u_texelDelta; // = 1 / textureSize
|
||||
uniform vec2 u_pixelDelta; // not used
|
||||
|
||||
varying vec2 v_texcoord0;
|
||||
|
||||
#ifdef GL_FRAGMENT_PRECISION_HIGH
|
||||
#define HIGHP highp
|
||||
#else
|
||||
#define HIGHP mediump
|
||||
#endif
|
||||
|
||||
// ---------- FSR-EASU core (unchanged) ----------
|
||||
void FsrEasuCon(
|
||||
out vec4 con0, out vec4 con1, out vec4 con2, out vec4 con3,
|
||||
vec2 inputViewportInPixels,
|
||||
vec2 inputSizeInPixels,
|
||||
vec2 outputSizeInPixels)
|
||||
{
|
||||
con0 = vec4(
|
||||
inputViewportInPixels.x / outputSizeInPixels.x,
|
||||
inputViewportInPixels.y / outputSizeInPixels.y,
|
||||
0.5 * inputViewportInPixels.x / outputSizeInPixels.x - 0.5,
|
||||
0.5 * inputViewportInPixels.y / outputSizeInPixels.y - 0.5);
|
||||
|
||||
con1 = vec4(1.0, 1.0, 1.0, -1.0) / inputSizeInPixels.xyxy;
|
||||
con2 = vec4(-1.0, 2.0, 1.0, 2.0) / inputSizeInPixels.xyxy;
|
||||
con3 = vec4( 0.0, 4.0, 0.0, 0.0) / inputSizeInPixels.xyxy;
|
||||
}
|
||||
|
||||
void FsrEasuTapF(
|
||||
inout vec3 aC, inout float aW,
|
||||
vec2 off,
|
||||
vec2 dir, vec2 len,
|
||||
float lob, float clp,
|
||||
vec3 c)
|
||||
{
|
||||
vec2 v = vec2(dot(off, dir), dot(off, vec2(-dir.y, dir.x))) * len;
|
||||
float d2 = min(dot(v, v), clp);
|
||||
float wB = 0.4 * d2 - 1.0;
|
||||
float wA = lob * d2 - 1.0;
|
||||
wB *= wB; wA *= wA;
|
||||
wB = 1.5625 * wB - 0.5625;
|
||||
float w = wB * wA;
|
||||
aC += c * w;
|
||||
aW += w;
|
||||
}
|
||||
|
||||
void FsrEasuSetF(
|
||||
inout vec2 dir, inout float len,
|
||||
float w,
|
||||
float lA, float lB, float lC, float lD, float lE)
|
||||
{
|
||||
float lenX = max(abs(lD - lC), abs(lC - lB));
|
||||
float dirX = lD - lB;
|
||||
dir.x += dirX * w;
|
||||
lenX = clamp(abs(dirX) / (lenX + 1e-5), 0.0, 1.0);
|
||||
lenX *= lenX;
|
||||
len += lenX * w;
|
||||
|
||||
float lenY = max(abs(lE - lC), abs(lC - lA));
|
||||
float dirY = lE - lA;
|
||||
dir.y += dirY * w;
|
||||
lenY = clamp(abs(dirY) / (lenY + 1e-5), 0.0, 1.0);
|
||||
lenY *= lenY;
|
||||
len += lenY * w;
|
||||
}
|
||||
|
||||
vec3 FsrEasuF(vec2 ip, vec4 con0, vec4 con1, vec4 con2, vec4 con3)
|
||||
{
|
||||
vec2 pp = ip * con0.xy + con0.zw;
|
||||
vec2 fp = floor(pp);
|
||||
pp -= fp;
|
||||
|
||||
vec2 p0 = fp * con1.xy + con1.zw;
|
||||
vec2 p1 = p0 + con2.xy;
|
||||
vec2 p2 = p0 + con2.zw;
|
||||
vec2 p3 = p0 + con3.xy;
|
||||
|
||||
vec4 off = vec4(-0.5, 0.5, -0.5, 0.5) * con1.xxyy;
|
||||
|
||||
vec3 bC = texture2D(sampler0, p0 + off.xw).rgb; float bL = bC.g + 0.5*(bC.r + bC.b);
|
||||
vec3 cC = texture2D(sampler0, p0 + off.yw).rgb; float cL = cC.g + 0.5*(cC.r + cC.b);
|
||||
vec3 iC = texture2D(sampler0, p1 + off.xw).rgb; float iL = iC.g + 0.5*(iC.r + iC.b);
|
||||
vec3 jC = texture2D(sampler0, p1 + off.yw).rgb; float jL = jC.g + 0.5*(jC.r + jC.b);
|
||||
vec3 fC = texture2D(sampler0, p1 + off.yz).rgb; float fL = fC.g + 0.5*(fC.r + fC.b);
|
||||
vec3 eC = texture2D(sampler0, p1 + off.xz).rgb; float eL = eC.g + 0.5*(eC.r + eC.b);
|
||||
vec3 kC = texture2D(sampler0, p2 + off.xw).rgb; float kL = kC.g + 0.5*(kC.r + kC.b);
|
||||
vec3 lC = texture2D(sampler0, p2 + off.yw).rgb; float lL = lC.g + 0.5*(lC.r + lC.b);
|
||||
vec3 hC = texture2D(sampler0, p2 + off.yz).rgb; float hL = hC.g + 0.5*(hC.r + hC.b);
|
||||
vec3 gC = texture2D(sampler0, p2 + off.xz).rgb; float gL = gC.g + 0.5*(gC.r + gC.b);
|
||||
vec3 oC = texture2D(sampler0, p3 + off.yz).rgb; float oL = oC.g + 0.5*(oC.r + oC.b);
|
||||
vec3 nC = texture2D(sampler0, p3 + off.xz).rgb; float nL = nC.g + 0.5*(nC.r + nC.b);
|
||||
|
||||
vec2 dir = vec2(0.0);
|
||||
float len = 0.0;
|
||||
|
||||
FsrEasuSetF(dir, len, (1.0 - pp.x)*(1.0 - pp.y), bL, eL, fL, gL, jL);
|
||||
FsrEasuSetF(dir, len, pp.x *(1.0 - pp.y), cL, fL, gL, hL, kL);
|
||||
FsrEasuSetF(dir, len, (1.0 - pp.x)* pp.y , fL, iL, jL, kL, nL);
|
||||
FsrEasuSetF(dir, len, pp.x * pp.y , gL, jL, kL, lL, oL);
|
||||
|
||||
vec2 dir2 = dir * dir;
|
||||
float dirR = dir2.x + dir2.y;
|
||||
bool zro = dirR < 1.0/32768.0;
|
||||
dirR = inversesqrt(dirR);
|
||||
dirR = zro ? 1.0 : dirR;
|
||||
dir = zro ? vec2(1.0, 0.0) : (dir * dirR);
|
||||
|
||||
len = len * 0.5;
|
||||
len *= len;
|
||||
|
||||
float stretch = dot(dir, dir) / max(abs(dir.x), abs(dir.y));
|
||||
vec2 len2 = vec2(1.0 + (stretch - 1.0)*len,
|
||||
1.0 - 0.5*len);
|
||||
|
||||
float lob = 0.5 - 0.29*len;
|
||||
float clp = 1.0/lob;
|
||||
|
||||
vec3 aC = vec3(0.0);
|
||||
float aW = 0.0;
|
||||
|
||||
FsrEasuTapF(aC, aW, vec2( 0,-1)-pp, dir, len2, lob, clp, bC);
|
||||
FsrEasuTapF(aC, aW, vec2( 1,-1)-pp, dir, len2, lob, clp, cC);
|
||||
FsrEasuTapF(aC, aW, vec2(-1, 1)-pp, dir, len2, lob, clp, iC);
|
||||
FsrEasuTapF(aC, aW, vec2( 0, 1)-pp, dir, len2, lob, clp, jC);
|
||||
FsrEasuTapF(aC, aW, vec2( 0, 0)-pp, dir, len2, lob, clp, fC);
|
||||
FsrEasuTapF(aC, aW, vec2(-1, 0)-pp, dir, len2, lob, clp, eC);
|
||||
FsrEasuTapF(aC, aW, vec2( 1, 1)-pp, dir, len2, lob, clp, kC);
|
||||
FsrEasuTapF(aC, aW, vec2( 2, 1)-pp, dir, len2, lob, clp, lC);
|
||||
FsrEasuTapF(aC, aW, vec2( 2, 0)-pp, dir, len2, lob, clp, hC);
|
||||
FsrEasuTapF(aC, aW, vec2( 1, 0)-pp, dir, len2, lob, clp, gC);
|
||||
FsrEasuTapF(aC, aW, vec2( 1, 2)-pp, dir, len2, lob, clp, oC);
|
||||
FsrEasuTapF(aC, aW, vec2( 0, 2)-pp, dir, len2, lob, clp, nC);
|
||||
|
||||
vec3 min4 = min(min(fC, gC), min(jC, kC));
|
||||
vec3 max4 = max(max(fC, gC), max(jC, kC));
|
||||
return min(max4, max(min4, aC / aW));
|
||||
}
|
||||
|
||||
// ---------- entry point ----------
|
||||
void main() {
|
||||
vec2 texSize = vec2(1.0) / u_texelDelta; // texture resolution
|
||||
vec2 outSize = vec2(1.0) / u_texelDelta; // if canvas == texture, same
|
||||
|
||||
vec4 con0, con1, con2, con3;
|
||||
FsrEasuCon(con0, con1, con2, con3,
|
||||
texSize, texSize, outSize);
|
||||
|
||||
// Convert 0-1 texcoord to integer pixel in output space
|
||||
vec2 ip = v_texcoord0 * outSize - vec2(0.5);
|
||||
|
||||
vec3 rgb = FsrEasuF(ip, con0, con1, con2, con3);
|
||||
gl_FragColor = vec4(rgb, 1.0);
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
// MIT License
|
||||
//
|
||||
// Copyright (c) 2021 Advanced Micro Devices, Inc. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#ifdef GL_ES
|
||||
precision mediump float;
|
||||
precision mediump int;
|
||||
#endif
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// Texture & uniforms
|
||||
// ------------------------------------------------------------------
|
||||
#ifdef SHADER_API_D3D11
|
||||
uniform sampler2D sampler0 : register(s0);
|
||||
#else
|
||||
uniform sampler2D sampler0;
|
||||
#endif
|
||||
|
||||
uniform vec2 u_texelDelta; // 1.0 / viewportSize
|
||||
uniform vec4 u_setting; // x = user sharpness (0…1)
|
||||
|
||||
varying vec2 v_texcoord0;
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// Constants
|
||||
// ------------------------------------------------------------------
|
||||
const vec3 lumCoef = vec3(0.2126, 0.7152, 0.0722); // Rec.709
|
||||
const float rcasPeak = 8.0 - 3.0; // = 5.0
|
||||
const float rcasInvP = 1.0 / rcasPeak;
|
||||
const float FSR_EPS = 0.0001;
|
||||
|
||||
// Offsets for 4-tap cross pattern
|
||||
const vec2 offN = vec2( 0.0,-1.0);
|
||||
const vec2 offW = vec2(-1.0, 0.0);
|
||||
const vec2 offE = vec2( 1.0, 0.0);
|
||||
const vec2 offS = vec2( 0.0, 1.0);
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// RCAS kernel – unchanged logic
|
||||
// ------------------------------------------------------------------
|
||||
vec4 FsrRcasVanilla(vec2 uv)
|
||||
{
|
||||
vec3 C = texture2D(sampler0, uv).rgb;
|
||||
float CL = dot(C, lumCoef);
|
||||
|
||||
vec3 N = texture2D(sampler0, uv + offN * u_texelDelta).rgb;
|
||||
vec3 W = texture2D(sampler0, uv + offW * u_texelDelta).rgb;
|
||||
vec3 E = texture2D(sampler0, uv + offE * u_texelDelta).rgb;
|
||||
vec3 S = texture2D(sampler0, uv + offS * u_texelDelta).rgb;
|
||||
|
||||
float NL = dot(N, lumCoef);
|
||||
float WL = dot(W, lumCoef);
|
||||
float EL = dot(E, lumCoef);
|
||||
float SL = dot(S, lumCoef);
|
||||
|
||||
// Adaptive range
|
||||
vec3 minRGB = min(min(min(N, W), min(E, S)), C);
|
||||
vec3 maxRGB = max(max(max(N, W), max(E, S)), C);
|
||||
vec3 invMax = 1.0 / (maxRGB + FSR_EPS);
|
||||
vec3 amp = clamp(min(minRGB, 2.0 - maxRGB) * invMax, 0.0, 1.0);
|
||||
amp = inversesqrt(amp + FSR_EPS);
|
||||
|
||||
float w = -rcasInvP / dot(amp, lumCoef);
|
||||
|
||||
float sumL = NL + WL + EL + SL;
|
||||
float invDen = 1.0 / (4.0 * w + 1.0);
|
||||
float sharpL = clamp((sumL * w + CL) * invDen, 0.0, 1.0);
|
||||
|
||||
vec3 chroma = C - vec3(CL);
|
||||
vec3 sharpColor = chroma + vec3(sharpL);
|
||||
|
||||
vec3 outColor = mix(C, sharpColor, u_setting.x);
|
||||
return vec4(outColor, 1.0);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
void main()
|
||||
{
|
||||
gl_FragColor = FsrRcasVanilla(v_texcoord0);
|
||||
}
|
||||
Reference in New Issue
Block a user