super-xbr.fx (16040B)
1 #include "ReShade.fxh" 2 3 /* 4 ******* Super XBR Shader ******* 5 6 Copyright (c) 2015-2024 Hyllian - sergiogdb@gmail.com 7 8 Permission is hereby granted, free of charge, to any person obtaining a copy 9 of this software and associated documentation files (the "Software"), to deal 10 in the Software without restriction, including without limitation the rights 11 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 copies of the Software, and to permit persons to whom the Software is 13 furnished to do so, subject to the following conditions: 14 15 The above copyright notice and this permission notice shall be included in 16 all copies or substantial portions of the Software. 17 18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 THE SOFTWARE. 25 26 */ 27 28 29 uniform float XBR_EDGE_STR_P0 < 30 ui_category = "Super-xBR:"; 31 ui_type = "drag"; 32 ui_min = 0.0; 33 ui_max = 5.0; 34 ui_step = 0.5; 35 ui_label = "Xbr - Edge Strength"; 36 > = 5.0; 37 38 uniform float XBR_WEIGHT < 39 ui_category = "Super-xBR:"; 40 ui_type = "drag"; 41 ui_min = 0.0; 42 ui_max = 1.0; 43 ui_step = 0.1; 44 ui_label = "Xbr - Filter Weight"; 45 > = 1.0; 46 47 48 uniform float JINC2_WINDOW_SINC < 49 ui_category = "Jinc2:"; 50 ui_type = "drag"; 51 ui_min = 0.0; 52 ui_max = 1.0; 53 ui_step = 0.01; 54 ui_label = "Window Sinc Param"; 55 > = 0.5; 56 57 uniform float JINC2_SINC < 58 ui_category = "Jinc2:"; 59 ui_type = "drag"; 60 ui_min = 0.0; 61 ui_max = 1.0; 62 ui_step = 0.01; 63 ui_label = "Sinc Param"; 64 > = 0.88; 65 66 uniform float JINC2_AR_STRENGTH < 67 ui_category = "Jinc2:"; 68 ui_type = "drag"; 69 ui_min = 0.0; 70 ui_max = 1.0; 71 ui_step = 0.01; 72 ui_label = "Anti-ringing Strength"; 73 > = 0.5; 74 75 uniform float2 BufferToViewportRatio < source = "buffer_to_viewport_ratio"; >; 76 uniform float2 NormalizedNativePixelSize < source = "normalized_native_pixel_size"; >; 77 78 texture2D tBackBufferY{Width=BUFFER_WIDTH;Height=BUFFER_HEIGHT;Format=RGBA8;}; 79 sampler2D sBackBufferY{Texture=tBackBufferY;AddressU=CLAMP;AddressV=CLAMP;AddressW=CLAMP;MagFilter=POINT;MinFilter=POINT;}; 80 81 texture2D tSuper_xBR_P0 < pooled = true; > {Width=BUFFER_WIDTH;Height=BUFFER_HEIGHT;Format=RGBA8;}; 82 sampler2D sSuper_xBR_P0{Texture=tSuper_xBR_P0;AddressU=CLAMP;AddressV=CLAMP;AddressW=CLAMP;MagFilter=POINT;MinFilter=POINT;}; 83 84 texture2D tSuper_xBR_P1 < pooled = true; > {Width=BUFFER_WIDTH;Height=BUFFER_HEIGHT;Format=RGBA8;}; 85 sampler2D sSuper_xBR_P1{Texture=tSuper_xBR_P1;AddressU=CLAMP;AddressV=CLAMP;AddressW=CLAMP;MagFilter=POINT;MinFilter=POINT;}; 86 87 texture2D tSuper_xBR_P2 < pooled = true; > {Width=BUFFER_WIDTH;Height=BUFFER_HEIGHT;Format=RGBA8;}; 88 sampler2D sSuper_xBR_P2{Texture=tSuper_xBR_P2;AddressU=CLAMP;AddressV=CLAMP;AddressW=CLAMP;MagFilter=POINT;MinFilter=POINT;}; 89 90 #define weight1 (XBR_WEIGHT*1.29633/10.0) 91 #define weight2 (XBR_WEIGHT*1.75068/10.0/2.0) 92 #define limits (XBR_EDGE_STR_P0+0.000001) 93 94 static const float3 Y = float3(.2126,.7152,.0722); 95 static const float wp0[6] = {2.0, 1.0, -1.0, 4.0, -1.0, 1.0}; 96 static const float wp1[6] = {1.0, 0.0, 0.0, 0.0, 0.0, 0.0}; 97 static const float wp2[6] = {0.0, 0.0, 0.0, 1.0, 0.0, 0.0}; 98 99 float luma(float3 color) 100 { 101 return dot(color, Y); 102 } 103 104 float df(float A, float B) 105 { 106 return abs(A-B); 107 } 108 109 /* 110 P1 111 |P0|B |C |P1| C F4 |a0|b1|c2|d3| 112 |D |E |F |F4| B F I4 |b0|c1|d2|e3| |e1|i1|i2|e2| 113 |G |H |I |I4| P0 E A I P3 |c0|d1|e2|f3| |e3|i3|i4|e4| 114 |P2|H5|I5|P3| D H I5 |d0|e1|f2|g3| 115 G H5 116 P2 117 */ 118 119 120 float d_wd(float wp[6], float b0, float b1, float c0, float c1, float c2, float d0, float d1, float d2, float d3, float e1, float e2, float e3, float f2, float f3) 121 { 122 return (wp[0]*(df(c1,c2) + df(c1,c0) + df(e2,e1) + df(e2,e3)) + wp[1]*(df(d2,d3) + df(d0,d1)) + wp[2]*(df(d1,d3) + df(d0,d2)) + wp[3]*df(d1,d2) + wp[4]*(df(c0,c2) + df(e1,e3)) + wp[5]*(df(b0,b1) + df(f2,f3))); 123 } 124 125 126 float hv_wd(float wp[6], float i1, float i2, float i3, float i4, float e1, float e2, float e3, float e4) 127 { 128 return ( wp[3]*(df(i1,i2)+df(i3,i4)) + wp[0]*(df(i1,e1)+df(i2,e2)+df(i3,e3)+df(i4,e4)) + wp[2]*(df(i1,e2)+df(i3,e4)+df(e1,i2)+df(e3,i4))); 129 } 130 131 float3 min4(float3 a, float3 b, float3 c, float3 d) 132 { 133 return min(a, min(b, min(c, d))); 134 } 135 136 float3 max4(float3 a, float3 b, float3 c, float3 d) 137 { 138 return max(a, max(b, max(c, d))); 139 } 140 141 float max4float(float a, float b, float c, float d) 142 { 143 return max(a, max(b, max(c, d))); 144 } 145 146 float3 super_xbr(float wp[6], float4 P0, float4 B, float4 C, float4 P1, float4 D, float4 E, float4 F, float4 F4, float4 G, float4 H, float4 I, float4 I4, float4 P2, float4 H5, float4 I5, float4 P3) 147 { 148 float b = B.a; float c = C.a; float d = D.a; float e = E.a; 149 float f = F.a; float g = G.a; float h = H.a; float i = I.a; 150 float i4 = I4.a; float p0 = P0.a; float i5 = I5.a; float p1 = P1.a; 151 float h5 = H5.a; float p2 = P2.a; float f4 = F4.a; float p3 = P3.a; 152 153 /* Calc edgeness in diagonal directions. */ 154 float d_edge = (d_wd( wp, d, b, g, e, c, p2, h, f, p1, h5, i, f4, i5, i4 ) - d_wd( wp, c, f4, b, f, i4, p0, e, i, p3, d, h, i5, g, h5 )); 155 156 /* Calc edgeness in horizontal/vertical directions. */ 157 float hv_edge = (hv_wd(wp, f, i, e, h, c, i5, b, h5) - hv_wd(wp, e, f, h, i, d, f4, g, i4)); 158 159 float edge_strength = smoothstep(0.0, limits, abs(d_edge)); 160 161 float4 w1, w2; 162 float3 c3, c4; 163 164 /* Filter weights. Two taps only. */ 165 w1 = float4(-weight1, weight1+0.50, weight1+0.50, -weight1); 166 w2 = float4(-weight2, weight2+0.25, weight2+0.25, -weight2); 167 c3 = mul(w2, float4x3(D.rgb+G.rgb, E.rgb+H.rgb, F.rgb+I.rgb, F4.rgb+I4.rgb)); 168 c4 = mul(w2, float4x3(C.rgb+B.rgb, F.rgb+E.rgb, I.rgb+H.rgb, I5.rgb+H5.rgb)); 169 170 /* Filtering and normalization in four direction generating four colors. */ 171 float3 c1 = mul(w1, float4x3( P2.rgb, H.rgb, F.rgb, P1.rgb )); 172 float3 c2 = mul(w1, float4x3( P0.rgb, E.rgb, I.rgb, P3.rgb )); 173 174 /* Smoothly blends the two strongest directions (one in diagonal and the other in vert/horiz direction). */ 175 float3 color = lerp(lerp(c1, c2, step(0.0, d_edge)), lerp(c3, c4, step(0.0, hv_edge)), 1. - edge_strength); 176 177 /* Anti-ringing code. */ 178 float3 min_sample = min4( E.rgb, F.rgb, H.rgb, I.rgb ); 179 float3 max_sample = max4( E.rgb, F.rgb, H.rgb, I.rgb ); 180 color = clamp(color, min_sample, max_sample); 181 182 return color; 183 } 184 185 float4 PS_BackBufferY(float4 pos: SV_Position, float2 vTexCoord : TEXCOORD) : SV_Target 186 { 187 float2 tc = (floor(vTexCoord / NormalizedNativePixelSize)+float2(0.5,0.5)) * NormalizedNativePixelSize; 188 189 float3 color = tex2D(ReShade::BackBuffer, tc).rgb; 190 191 return float4(color, luma(color)); 192 } 193 194 195 float4 PS_Super_xBR_P0(float4 pos: SV_Position, float2 vTexCoord : TEXCOORD) : SV_Target 196 { 197 float2 ps = NormalizedNativePixelSize; 198 199 float4 P0 = tex2D(sBackBufferY, vTexCoord.xy + ps*float2(-1.0, -1.0)); 200 float4 B = tex2D(sBackBufferY, vTexCoord.xy + ps*float2( 0.0, -1.0)); 201 float4 C = tex2D(sBackBufferY, vTexCoord.xy + ps*float2( 1.0, -1.0)); 202 float4 P1 = tex2D(sBackBufferY, vTexCoord.xy + ps*float2( 2.0, -1.0)); 203 204 float4 D = tex2D(sBackBufferY, vTexCoord.xy + ps*float2(-1.0, 0.0)); 205 float4 E = tex2D(sBackBufferY, vTexCoord.xy ); 206 float4 F = tex2D(sBackBufferY, vTexCoord.xy + ps*float2( 1.0, 0.0)); 207 float4 F4 = tex2D(sBackBufferY, vTexCoord.xy + ps*float2( 2.0, 0.0)); 208 209 float4 G = tex2D(sBackBufferY, vTexCoord.xy + ps*float2(-1.0, 1.0)); 210 float4 H = tex2D(sBackBufferY, vTexCoord.xy + ps*float2( 0.0, 1.0)); 211 float4 I = tex2D(sBackBufferY, vTexCoord.xy + ps*float2( 1.0, 1.0)); 212 float4 I4 = tex2D(sBackBufferY, vTexCoord.xy + ps*float2( 2.0, 1.0)); 213 214 float4 P2 = tex2D(sBackBufferY, vTexCoord.xy + ps*float2(-1.0, 2.0)); 215 float4 H5 = tex2D(sBackBufferY, vTexCoord.xy + ps*float2( 0.0, 2.0)); 216 float4 I5 = tex2D(sBackBufferY, vTexCoord.xy + ps*float2( 1.0, 2.0)); 217 float4 P3 = tex2D(sBackBufferY, vTexCoord.xy + ps*float2( 2.0, 2.0)); 218 219 float3 color = super_xbr(wp0, P0, B, C, P1, D, E, F, F4, G, H, I, I4, P2, H5, I5, P3); 220 221 return float4(color, luma(color)); 222 } 223 224 225 226 227 float4 PS_Super_xBR_P1(float4 pos: SV_Position, float2 vTexCoord : TEXCOORD) : SV_Target 228 { 229 float2 ps = NormalizedNativePixelSize; 230 231 //Skip pixels on wrong grid 232 float2 fp = frac(vTexCoord.xy / ps); 233 float2 dir = fp - float2(0.5,0.5); 234 235 if ((dir.x*dir.y)>0.0) 236 { 237 return lerp( tex2D(sBackBufferY, vTexCoord), tex2D(sSuper_xBR_P0, vTexCoord), step(0.0, dir.x)); 238 } 239 else 240 { 241 float2 g1 = (fp.x>0.5) ? float2(0.5*ps.x, 0.0) : float2(0.0, 0.5*ps.y); 242 float2 g2 = (fp.x>0.5) ? float2(0.0, 0.5*ps.y) : float2(0.5*ps.x, 0.0); 243 244 float4 P0 = tex2D( sBackBufferY, vTexCoord -3.0*g1 ); 245 float4 P1 = tex2D(sSuper_xBR_P0, vTexCoord -3.0*g2); 246 float4 P2 = tex2D(sSuper_xBR_P0, vTexCoord +3.0*g2); 247 float4 P3 = tex2D( sBackBufferY, vTexCoord +3.0*g1 ); 248 249 float4 B = tex2D(sSuper_xBR_P0, vTexCoord -2.0*g1 -g2); 250 float4 C = tex2D( sBackBufferY, vTexCoord -g1 -2.0*g2); 251 float4 D = tex2D(sSuper_xBR_P0, vTexCoord -2.0*g1 +g2); 252 float4 E = tex2D( sBackBufferY, vTexCoord -g1 ); 253 float4 F = tex2D(sSuper_xBR_P0, vTexCoord -g2); 254 float4 G = tex2D( sBackBufferY, vTexCoord -g1 +2.0*g2); 255 float4 H = tex2D(sSuper_xBR_P0, vTexCoord +g2); 256 float4 I = tex2D( sBackBufferY, vTexCoord +g1 ); 257 258 float4 F4 = tex2D(sBackBufferY, vTexCoord +g1 -2.0*g2); 259 float4 I4 = tex2D( sSuper_xBR_P0, vTexCoord +2.0*g1 -g2); 260 float4 H5 = tex2D(sBackBufferY, vTexCoord +g1 +2.0*g2); 261 float4 I5 = tex2D( sSuper_xBR_P0, vTexCoord +2.0*g1 +g2); 262 263 float3 color = super_xbr(wp1, P0, B, C, P1, D, E, F, F4, G, H, I, I4, P2, H5, I5, P3); 264 265 return float4(color, luma(color)); 266 } 267 } 268 269 270 float4 PS_Super_xBR_P2(float4 pos: SV_Position, float2 vTexCoord : TEXCOORD) : SV_Target 271 { 272 float2 ps = 0.5*NormalizedNativePixelSize; 273 274 float4 P0 = tex2D(sSuper_xBR_P1, vTexCoord.xy + ps*float2(-2.0, -2.0)); 275 float4 B = tex2D(sSuper_xBR_P1, vTexCoord.xy + ps*float2(-1.0, -2.0)); 276 float4 C = tex2D(sSuper_xBR_P1, vTexCoord.xy + ps*float2( 0.0, -2.0)); 277 float4 P1 = tex2D(sSuper_xBR_P1, vTexCoord.xy + ps*float2( 1.0, -2.0)); 278 279 float4 D = tex2D(sSuper_xBR_P1, vTexCoord.xy + ps*float2(-2.0, -1.0)); 280 float4 E = tex2D(sSuper_xBR_P1, vTexCoord.xy + ps*float2(-1.0, -1.0)); 281 float4 F = tex2D(sSuper_xBR_P1, vTexCoord.xy + ps*float2( 0.0, -1.0)); 282 float4 F4 = tex2D(sSuper_xBR_P1, vTexCoord.xy + ps*float2( 1.0, -1.0)); 283 284 float4 G = tex2D(sSuper_xBR_P1, vTexCoord.xy + ps*float2(-2.0, 0.0)); 285 float4 H = tex2D(sSuper_xBR_P1, vTexCoord.xy + ps*float2(-1.0, 0.0)); 286 float4 I = tex2D(sSuper_xBR_P1, vTexCoord.xy + ps*float2( 0.0, 0.0)); 287 float4 I4 = tex2D(sSuper_xBR_P1, vTexCoord.xy + ps*float2( 1.0, 0.0)); 288 289 float4 P2 = tex2D(sSuper_xBR_P1, vTexCoord.xy + ps*float2(-2.0, 1.0)); 290 float4 H5 = tex2D(sSuper_xBR_P1, vTexCoord.xy + ps*float2(-1.0, 1.0)); 291 float4 I5 = tex2D(sSuper_xBR_P1, vTexCoord.xy + ps*float2( 0.0, 1.0)); 292 float4 P3 = tex2D(sSuper_xBR_P1, vTexCoord.xy + ps*float2( 1.0, 1.0)); 293 294 float3 color = super_xbr(wp2, P0, B, C, P1, D, E, F, F4, G, H, I, I4, P2, H5, I5, P3); 295 296 return float4(color, 1.0); 297 } 298 299 300 #define halfpi 1.5707963267948966192313216916398 301 #define pi 3.1415926535897932384626433832795 302 #define wa (JINC2_WINDOW_SINC*pi) 303 #define wb (JINC2_SINC*pi) 304 305 306 307 // Calculates the distance between two points 308 float dst(float2 pt1, float2 pt2) 309 { 310 float2 v = pt2 - pt1; 311 return sqrt(dot(v,v)); 312 } 313 314 315 316 float4 resampler(float4 x) 317 { 318 float4 res; 319 320 res.x = (x.x==0.0) ? (wa*wb) : sin(x.x*wa)*sin(x.x*wb)/(x.x*x.x); 321 res.y = (x.y==0.0) ? (wa*wb) : sin(x.y*wa)*sin(x.y*wb)/(x.y*x.y); 322 res.z = (x.z==0.0) ? (wa*wb) : sin(x.z*wa)*sin(x.z*wb)/(x.z*x.z); 323 res.w = (x.w==0.0) ? (wa*wb) : sin(x.w*wa)*sin(x.w*wb)/(x.w*x.w); 324 325 return res; 326 } 327 328 329 float4 PS_Jinc2(float4 pos: SV_Position, float2 vTexCoord : TEXCOORD) : SV_Target 330 { 331 float2 ps = 0.5*NormalizedNativePixelSize; 332 333 float3 color; 334 float4x4 weights; 335 336 float2 dx = float2(1.0, 0.0); 337 float2 dy = float2(0.0, 1.0); 338 339 float2 pc = vTexCoord / ps; 340 341 float2 tc = (floor(pc-float2(0.5,0.5))+float2(0.5,0.5)); 342 343 weights[0] = resampler(float4(dst(pc, tc -dx -dy), dst(pc, tc -dy), dst(pc, tc +dx -dy), dst(pc, tc+2.0*dx -dy))); 344 weights[1] = resampler(float4(dst(pc, tc -dx ), dst(pc, tc ), dst(pc, tc +dx ), dst(pc, tc+2.0*dx ))); 345 weights[2] = resampler(float4(dst(pc, tc -dx +dy), dst(pc, tc +dy), dst(pc, tc +dx +dy), dst(pc, tc+2.0*dx +dy))); 346 weights[3] = resampler(float4(dst(pc, tc -dx+2.0*dy), dst(pc, tc +2.0*dy), dst(pc, tc +dx+2.0*dy), dst(pc, tc+2.0*dx+2.0*dy))); 347 348 //weights[0][0] = weights[0][3] = weights[3][0] = weights[3][3] = 0.0; 349 350 dx = dx * ps; 351 dy = dy * ps; 352 tc = tc * ps; 353 354 // reading the texels 355 356 float3 c00 = tex2D(sSuper_xBR_P2, tc -dx -dy).xyz; 357 float3 c10 = tex2D(sSuper_xBR_P2, tc -dy).xyz; 358 float3 c20 = tex2D(sSuper_xBR_P2, tc +dx -dy).xyz; 359 float3 c30 = tex2D(sSuper_xBR_P2, tc+2.0*dx -dy).xyz; 360 float3 c01 = tex2D(sSuper_xBR_P2, tc -dx ).xyz; 361 float3 c11 = tex2D(sSuper_xBR_P2, tc ).xyz; 362 float3 c21 = tex2D(sSuper_xBR_P2, tc +dx ).xyz; 363 float3 c31 = tex2D(sSuper_xBR_P2, tc+2.0*dx ).xyz; 364 float3 c02 = tex2D(sSuper_xBR_P2, tc -dx +dy).xyz; 365 float3 c12 = tex2D(sSuper_xBR_P2, tc +dy).xyz; 366 float3 c22 = tex2D(sSuper_xBR_P2, tc +dx +dy).xyz; 367 float3 c32 = tex2D(sSuper_xBR_P2, tc+2.0*dx +dy).xyz; 368 float3 c03 = tex2D(sSuper_xBR_P2, tc -dx+2.0*dy).xyz; 369 float3 c13 = tex2D(sSuper_xBR_P2, tc +2.0*dy).xyz; 370 float3 c23 = tex2D(sSuper_xBR_P2, tc +dx+2.0*dy).xyz; 371 float3 c33 = tex2D(sSuper_xBR_P2, tc+2.0*dx+2.0*dy).xyz; 372 373 color = mul(weights[0], float4x3(c00, c10, c20, c30)); 374 color+= mul(weights[1], float4x3(c01, c11, c21, c31)); 375 color+= mul(weights[2], float4x3(c02, c12, c22, c32)); 376 color+= mul(weights[3], float4x3(c03, c13, c23, c33)); 377 color = color/(dot(mul(weights, float4(1.,1.,1.,1.)), float4(1.,1.,1.,1.))); 378 379 // Anti-ringing 380 // Get min/max samples 381 float3 min_sample = min4(c11, c21, c12, c22); 382 float3 max_sample = max4(c11, c21, c12, c22); 383 384 float3 aux = color; 385 386 color = clamp(color, min_sample, max_sample); 387 color = lerp(aux, color, JINC2_AR_STRENGTH); 388 389 return float4(color, 1.0); 390 } 391 392 393 technique Super_xBR 394 { 395 pass 396 { 397 VertexShader = PostProcessVS; 398 PixelShader = PS_BackBufferY; 399 RenderTarget = tBackBufferY; 400 } 401 pass 402 { 403 VertexShader = PostProcessVS; 404 PixelShader = PS_Super_xBR_P0; 405 RenderTarget = tSuper_xBR_P0; 406 } 407 pass 408 { 409 VertexShader = PostProcessVS; 410 PixelShader = PS_Super_xBR_P1; 411 RenderTarget = tSuper_xBR_P1; 412 } 413 pass 414 { 415 VertexShader = PostProcessVS; 416 PixelShader = PS_Super_xBR_P2; 417 RenderTarget = tSuper_xBR_P2; 418 } 419 pass 420 { 421 VertexShader = PostProcessVS; 422 PixelShader = PS_Jinc2; 423 } 424 }