diff --git a/sharpen/adaptive-sharpen-multipass.slangp b/sharpen/adaptive-sharpen-multipass.slangp new file mode 100644 index 0000000..2bd57f4 --- /dev/null +++ b/sharpen/adaptive-sharpen-multipass.slangp @@ -0,0 +1,8 @@ +shaders = 2 + +shader0 = shaders/adaptive-sharpen-pass1.slang +filter_linear0 = false +scale_type_0 = source +shader1 = shaders/adaptive-sharpen-pass2.slang +filter_linear1 = false +scale_type_1 = source diff --git a/sharpen/shaders/adaptive-sharpen-pass1.slang b/sharpen/shaders/adaptive-sharpen-pass1.slang new file mode 100644 index 0000000..d5557b7 --- /dev/null +++ b/sharpen/shaders/adaptive-sharpen-pass1.slang @@ -0,0 +1,119 @@ +#version 450 + +/* Ported by Hyllian and hunterk - 2015 / 2017 */ + +// Copyright (c) 2015-2017, bacondither +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer +// in this position and unchanged. +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR +// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +// IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +// NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// First pass, MUST BE PLACED IMMEDIATELY BEFORE THE SECOND PASS IN THE CHAIN + +// Adaptive sharpen - version 2017-04-11 - (requires ps >= 3.0) +// Tuned for use post-resize, EXPECTS FULL RANGE GAMMA LIGHT + +// Compatibility defines: +#define mul(a,b) (b*a) +#define saturate(c) clamp(c, 0.0, 1.0) + +//------------------------------------------------------------------------------------------------- +#define w_offset 1.0 // Edge channel offset, must be the same in all passes +//------------------------------------------------------------------------------------------------- + +// Get destination pixel values +#define get(x,y) ( saturate(texture(Source, coord + vec2(x*(px), y*(py))).rgb) ) + +// Component-wise distance +#define b_diff(pix) ( abs(blur - c[pix]) ) + +layout(push_constant) uniform Push +{ + vec4 SourceSize; + vec4 OriginalSize; + vec4 OutputSize; + uint FrameCount; +} params; + +layout(std140, set = 0, binding = 0) uniform UBO +{ + mat4 MVP; +} global; + +#pragma stage vertex +layout(location = 0) in vec4 Position; +layout(location = 1) in vec2 TexCoord; +layout(location = 0) out vec2 vTexCoord; + +void main() +{ + gl_Position = global.MVP * Position; + vTexCoord = TexCoord; +} + +#pragma stage fragment +layout(location = 0) in vec2 vTexCoord; +layout(location = 0) out vec4 FragColor; +layout(set = 0, binding = 2) uniform sampler2D Source; + +vec4 frag_op(sampler2D Source, vec2 coord, float px, float py) +{ + // Get points and clip out of range values (BTB & WTW) + // [ c9 ] + // [ c1, c2, c3 ] + // [ c10, c4, c0, c5, c11 ] + // [ c6, c7, c8 ] + // [ c12 ] + vec3 c[13] = { get( 0, 0), get(-1,-1), get( 0,-1), get( 1,-1), get(-1, 0), + get( 1, 0), get(-1, 1), get( 0, 1), get( 1, 1), get( 0,-2), + get(-2, 0), get( 2, 0), get( 0, 2) }; + + // Blur, gauss 3x3 + vec3 blur = (2.*(c[2]+c[4]+c[5]+c[7]) + (c[1]+c[3]+c[6]+c[8]) + 4.*c[0])/16.; + float blur_Y = (blur.r/3. + blur.g/3. + blur.b/3.); + + // Contrast compression, center = 0.5, scaled to 1/3 + float c_comp = saturate(0.266666681 + 0.9*exp2(-7.4*blur_Y)); + + // Edge detection + // Relative matrix weights + // [ 1, ] + // [ 4, 5, 4 ] + // [ 1, 5, 6, 5, 1 ] + // [ 4, 5, 4 ] + // [ 1 ] + float edge = length( 1.38*(b_diff(0)) + + 1.15*(b_diff(2) + b_diff(4) + b_diff(5) + b_diff(7)) + + 0.92*(b_diff(1) + b_diff(3) + b_diff(6) + b_diff(8)) + + 0.23*(b_diff(9) + b_diff(10) + b_diff(11) + b_diff(12)) ); + + return vec4( (texture(Source, coord).rgb), (edge*c_comp + w_offset) ); +} + +void main() +{ + vec2 tex = vTexCoord; + + float px = 1.0 / params.SourceSize.x; + float py = 1.0 / params.SourceSize.y; + + FragColor = vec4(frag_op(Source, tex, px, py)); +} \ No newline at end of file diff --git a/sharpen/shaders/adaptive-sharpen-pass2.slang b/sharpen/shaders/adaptive-sharpen-pass2.slang new file mode 100644 index 0000000..b39473d --- /dev/null +++ b/sharpen/shaders/adaptive-sharpen-pass2.slang @@ -0,0 +1,295 @@ +#version 450 + +/* Ported by Hyllian and hunterk - 2015 / 2017 */ + +// Copyright (c) 2015-2017, bacondither +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer +// in this position and unchanged. +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR +// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +// IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +// NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Second pass, MUST BE PLACED IMMEDIATELY AFTER THE FIRST PASS IN THE CHAIN + +// Adaptive sharpen - version 2017-04-11 - (requires ps >= 3.0) +// Tuned for use post-resize, EXPECTS FULL RANGE GAMMA LIGHT + +layout(push_constant) uniform Push +{ + vec4 SourceSize; + vec4 OriginalSize; + vec4 OutputSize; + uint FrameCount; + float CURVE_HEIGHT; + float VIDEO_LEVEL_OUT; +} params; + +#pragma parameter CURVE_HEIGHT "AS Curve Height" 1.0 0.3 2.0 0.1 +#pragma parameter VIDEO_LEVEL_OUT "AS Video Lvl Out" 0.0 0.0 1.0 1.0 + +#define mul(a,b) (b*a) +#define saturate(c) clamp(c, 0.0, 1.0) + +layout(std140, set = 0, binding = 0) uniform UBO +{ + mat4 MVP; +} global; + +//--------------------------------------- Settings ------------------------------------------------ + +#define curve_height params.CURVE_HEIGHT // Main sharpening strength, POSITIVE VALUES ONLY! + // 0.3 <-> 2.0 is a reasonable range of values + +#define video_level_out params.VIDEO_LEVEL_OUT // True to preserve BTB & WTW (minor summation error) + // Normally it should be set to false + +//------------------------------------------------------------------------------------------------- +// Defined values under this row are "optimal" DO NOT CHANGE IF YOU DO NOT KNOW WHAT YOU ARE DOING! + +#define curveslope 0.4 // Sharpening curve slope, high edge values + +#define L_overshoot 0.003 // Max light overshoot before compression [>0.001] +#define L_compr_low 0.169 // Light compression, default (0.169=~9x) +#define L_compr_high 0.337 // Light compression, surrounded by edges (0.337=~4x) + +#define D_overshoot 0.009 // Max dark overshoot before compression [>0.001] +#define D_compr_low 0.253 // Dark compression, default (0.253=~6x) +#define D_compr_high 0.504 // Dark compression, surrounded by edges (0.504=~2.5x) + +#define scale_lim 0.1 // Abs max change before compression [>0.01] +#define scale_cs 0.056 // Compression slope above scale_lim + +#define dW_lothr 0.3 // Start interpolating between W1 and W2 +#define dW_hithr 0.8 // When dW is equal to W2 + +#define lowthr_mxw 0.11 // Edge value for max lowthr weight [>0.01] + +#define pm_p 0.75 // Power mean p-value [>0-1.0] + +#define alpha_out 1.0 // MPDN requires the alpha channel output to be 1.0 + +//------------------------------------------------------------------------------------------------- +#define w_offset 1.0 // Edge channel offset, must be the same in all passes +#define bounds_check true // If edge data is outside bounds, make pixels green +//------------------------------------------------------------------------------------------------- + +// Soft if, fast approx +#define soft_if(a,b,c) ( saturate((a + b + c - 3*w_offset + 0.06)/(abs(maxedge) + 0.03) - 0.85) ) + +// Soft limit, modified tanh +#define soft_lim(v,s) ( ((exp(2.*min(abs(v), s*24.)/s) - 1.)/(exp(2*min(abs(v), s*24.)/s) + 1.))*s ) + +// Weighted power mean +#define wpmean(a,b,w) ( pow((w*pow(abs(a), pm_p) + abs(1-w)*pow(abs(b), pm_p)), (1.0/pm_p)) ) + +// Get destination pixel values +#define get(x,y) ( texture(Source, coord + vec2(x*(px), y*(py))) ) +#define sat(inp) ( vec4(saturate((inp).xyz), (inp).w) ) + +// Maximum of four values +#define max4(a,b,c,d) ( max(max(a, b), max(c, d)) ) + +// Colour to luma, fast approx gamma, avg of rec. 709 & 601 luma coeffs +#define CtL(RGB) ( sqrt(dot(vec3(0.2558, 0.6511, 0.0931), saturate((RGB)*abs(RGB)).rgb)) ) + +// Center pixel diff +#define mdiff(a,b,c,d,e,f,g) ( abs(luma[g]-luma[a]) + abs(luma[g]-luma[b]) \ + + abs(luma[g]-luma[c]) + abs(luma[g]-luma[d]) \ + + 0.5*(abs(luma[g]-luma[e]) + abs(luma[g]-luma[f])) ) + +#pragma stage vertex +layout(location = 0) in vec4 Position; +layout(location = 1) in vec2 TexCoord; +layout(location = 0) out vec2 vTexCoord; + +void main() +{ + gl_Position = global.MVP * Position; + vTexCoord = TexCoord; +} + +#pragma stage fragment +layout(location = 0) in vec2 vTexCoord; +layout(location = 0) out vec4 FragColor; +layout(set = 0, binding = 2) uniform sampler2D Source; + +vec4 frag_op(vec4 orig, vec2 coord, float c_edge, float px, float py) +{ + if (bounds_check == true) + { + if (c_edge > 24. || c_edge < -0.5) { return vec4( 0., 1.0, 0., alpha_out ); } + } + + // Get points, clip out of range colour data in c[0] + // [ c22 ] + // [ c24, c9, c23 ] + // [ c21, c1, c2, c3, c18 ] + // [ c19, c10, c4, c0, c5, c11, c16 ] + // [ c20, c6, c7, c8, c17 ] + // [ c15, c12, c14 ] + // [ c13 ] + vec4 c[25] = { sat( orig), get(-1,-1), get( 0,-1), get( 1,-1), get(-1, 0), + get( 1, 0), get(-1, 1), get( 0, 1), get( 1, 1), get( 0,-2), + get(-2, 0), get( 2, 0), get( 0, 2), get( 0, 3), get( 1, 2), + get(-1, 2), get( 3, 0), get( 2, 1), get( 2,-1), get(-3, 0), + get(-2, 1), get(-2,-1), get( 0,-3), get( 1,-2), get(-1,-2) }; + + // Allow for higher overshoot if the current edge pixel is surrounded by similar edge pixels + float maxedge = max4( max4(c[1].w,c[2].w,c[3].w,c[4].w), max4(c[5].w,c[6].w,c[7].w,c[8].w), + max4(c[9].w,c[10].w,c[11].w,c[12].w), c[0].w ) - w_offset; + + // [ x ] + // [ z, x, w ] + // [ z, z, x, w, w ] + // [ y, y, y, 0, y, y, y ] + // [ w, w, x, z, z ] + // [ w, x, z ] + // [ x ] + float sbe = soft_if(c[2].w,c[9].w,c[22].w) *soft_if(c[7].w,c[12].w,c[13].w) // x dir + + soft_if(c[4].w,c[10].w,c[19].w)*soft_if(c[5].w,c[11].w,c[16].w) // y dir + + soft_if(c[1].w,c[24].w,c[21].w)*soft_if(c[8].w,c[14].w,c[17].w) // z dir + + soft_if(c[3].w,c[23].w,c[18].w)*soft_if(c[6].w,c[20].w,c[15].w); // w dir + + vec2 cs = mix( vec2(L_compr_low, D_compr_low), + vec2(L_compr_high, D_compr_high), smoothstep(2, 3.1, sbe) ); + + // RGB to luma + float c0_Y = CtL(c[0]); + + float luma[25] = { c0_Y, CtL(c[1]), CtL(c[2]), CtL(c[3]), CtL(c[4]), CtL(c[5]), CtL(c[6]), + CtL(c[7]), CtL(c[8]), CtL(c[9]), CtL(c[10]), CtL(c[11]), CtL(c[12]), + CtL(c[13]), CtL(c[14]), CtL(c[15]), CtL(c[16]), CtL(c[17]), CtL(c[18]), + CtL(c[19]), CtL(c[20]), CtL(c[21]), CtL(c[22]), CtL(c[23]), CtL(c[24]) }; + + // Pre-calculated default squared kernel weights + const vec3 W1 = vec3(0.5, 1.0, 1.41421356237); // 0.25, 1.0, 2.0 + const vec3 W2 = vec3(0.86602540378, 1.0, 0.5477225575); // 0.75, 1.0, 0.3 + + // Transition to a concave kernel if the center edge val is above thr + vec3 dW = pow(mix( W1, W2, smoothstep(dW_lothr, dW_hithr, c_edge) ), vec3(2.0)); + + float mdiff_c0 = 0.02 + 3*( abs(luma[0]-luma[2]) + abs(luma[0]-luma[4]) + + abs(luma[0]-luma[5]) + abs(luma[0]-luma[7]) + + 0.25*(abs(luma[0]-luma[1]) + abs(luma[0]-luma[3]) + +abs(luma[0]-luma[6]) + abs(luma[0]-luma[8])) ); + + // Use lower weights for pixels in a more active area relative to center pixel area + // This results in narrower and less visible overshoots around sharp edges + float weights[12] = { ( min(mdiff_c0/mdiff(24, 21, 2, 4, 9, 10, 1), dW.y) ), // c1 + ( dW.x ), // c2 + ( min(mdiff_c0/mdiff(23, 18, 5, 2, 9, 11, 3), dW.y) ), // c3 + ( dW.x ), // c4 + ( dW.x ), // c5 + ( min(mdiff_c0/mdiff(4, 20, 15, 7, 10, 12, 6), dW.y) ), // c6 + ( dW.x ), // c7 + ( min(mdiff_c0/mdiff(5, 7, 17, 14, 12, 11, 8), dW.y) ), // c8 + ( min(mdiff_c0/mdiff(2, 24, 23, 22, 1, 3, 9), dW.z) ), // c9 + ( min(mdiff_c0/mdiff(20, 19, 21, 4, 1, 6, 10), dW.z) ), // c10 + ( min(mdiff_c0/mdiff(17, 5, 18, 16, 3, 8, 11), dW.z) ), // c11 + ( min(mdiff_c0/mdiff(13, 15, 7, 14, 6, 8, 12), dW.z) ) }; // c12 + + weights[0] = (max(max((weights[8] + weights[9])/4, weights[0]), 0.25) + weights[0])/2; + weights[2] = (max(max((weights[8] + weights[10])/4, weights[2]), 0.25) + weights[2])/2; + weights[5] = (max(max((weights[9] + weights[11])/4, weights[5]), 0.25) + weights[5])/2; + weights[7] = (max(max((weights[10] + weights[11])/4, weights[7]), 0.25) + weights[7])/2; + + // Calculate the negative part of the laplace kernel and the low threshold weight + float lowthrsum = 0.; + float weightsum = 0.; + float neg_laplace = 0.; + + //[unroll] + for (int pix = 0; pix < 12; ++pix) + { + float x = saturate((c[pix + 1].w - w_offset - 0.01)/(lowthr_mxw - 0.01)); + float lowthr = x*x*(2.97 - 1.98*x) + 0.01; // x*x((3.0-c*3.) - (2.0-c*2.)*x) + c + + neg_laplace += pow(luma[pix + 1] + 0.06, 2.4)*(weights[pix]*lowthr); + weightsum += weights[pix]*lowthr; + lowthrsum += lowthr/12.; + } + + neg_laplace = pow(abs(neg_laplace/weightsum), (1.0/2.4)) - 0.06; + + // Compute sharpening magnitude function + float sharpen_val = curve_height/(curve_height*curveslope*pow(abs(c_edge), 3.5) + 0.5); + + // Calculate sharpening diff and scale + float sharpdiff = (c0_Y - neg_laplace)*(lowthrsum*sharpen_val*0.8 + 0.01); + + // Calculate local near min & max, partial sort + //[unroll] + for (int i = 0; i < 3; ++i) + { + float temp; + + for (int i1 = i; i1 < 24-i; i1 += 2) + { + temp = luma[i1]; + luma[i1] = min(luma[i1], luma[i1+1]); + luma[i1+1] = max(temp, luma[i1+1]); + } + + for (int i2 = 24-i; i2 > i; i2 -= 2) + { + temp = luma[i]; + luma[i] = min(luma[i], luma[i2]); + luma[i2] = max(temp, luma[i2]); + + temp = luma[24-i]; + luma[24-i] = max(luma[24-i], luma[i2-1]); + luma[i2-1] = min(temp, luma[i2-1]); + } + } + + float nmax = (max(luma[22] + luma[23]*2., c0_Y*3.) + luma[24])/4.; + float nmin = (min(luma[2] + luma[1]*2., c0_Y*3.) + luma[0])/4.; + + // Calculate tanh scale factor, pos/neg + float nmax_scale = nmax - c0_Y + min(L_overshoot, 1.0001 - nmax); + float nmin_scale = c0_Y - nmin + min(D_overshoot, 0.0001 + nmin); + + nmax_scale = min(nmax_scale, scale_lim*(1. - scale_cs) + nmax_scale*scale_cs); + nmin_scale = min(nmin_scale, scale_lim*(1. - scale_cs) + nmin_scale*scale_cs); + + // Soft limited anti-ringing with tanh, wpmean to control compression slope + sharpdiff = wpmean( max(sharpdiff, 0.), soft_lim( max(sharpdiff, 0.), nmax_scale ), cs.x ) + - wpmean( min(sharpdiff, 0.), soft_lim( min(sharpdiff, 0.), nmin_scale ), cs.y ); + + // Compensate for saturation loss/gain while making pixels brighter/darker + float sharpdiff_lim = saturate(c0_Y + sharpdiff) - c0_Y; + float satmul = (c0_Y + sharpdiff_lim + 0.03)/(c0_Y + 0.03); + vec3 res = c0_Y + (sharpdiff_lim*3 + sharpdiff)/4 + (c[0].rgb - c0_Y)*satmul; + + return vec4( (video_level_out == 1.0 ? orig.rgb + (res - c[0].rgb) : res), alpha_out ); +} + +void main() +{ + vec2 tex = vTexCoord; + + float px = 1.0 / params.SourceSize.x; + float py = 1.0 / params.SourceSize.y; + + vec4 orig = texture(Source, tex); + float c_edge = orig.w - w_offset; + + FragColor = vec4(frag_op(orig, tex, c_edge, px, py)); +} \ No newline at end of file diff --git a/sharpen/shaders/diff.slang b/sharpen/shaders/diff.slang new file mode 100644 index 0000000..edba890 --- /dev/null +++ b/sharpen/shaders/diff.slang @@ -0,0 +1,71 @@ +#version 450 + +/* + Super-res shader - Shiandow + + Ported from Shiandow's code by Hyllian, 2016. + + This file is a part of MPDN Extensions. + https://github.com/zachsaw/MPDN_Extensions + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. +*/ + +layout(push_constant) uniform Push +{ + vec4 SourceSize; + vec4 OriginalSize; + vec4 OutputSize; + uint FrameCount; +} params; + +layout(std140, set = 0, binding = 0) uniform UBO +{ + mat4 MVP; +} global; + +#pragma stage vertex +layout(location = 0) in vec4 Position; +layout(location = 1) in vec2 TexCoord; +layout(location = 0) out vec2 vTexCoord; + +void main() +{ + gl_Position = global.MVP * Position; + vTexCoord = TexCoord; +} + +#pragma stage fragment +layout(location = 0) in vec2 vTexCoord; +layout(location = 0) out vec4 FragColor; +layout(set = 0, binding = 2) uniform sampler2D Source; +layout(set = 0, binding = 3) uniform sampler2D Original; + +const vec3 Y = vec3(.2126, .7152, .0722); + + +float RGBtoYUV(vec3 color) +{ + return dot(color, Y); +} + +void main() +{ + vec2 tex = vTexCoord; + + vec4 c0 = texture(Source, tex); + vec4 c1 = texture(Original, tex); + + FragColor = vec4(c0.xyz - c1.xyz, RGBtoYUV(c0.rgb)); +} \ No newline at end of file diff --git a/sharpen/shaders/super-res-ex.slang b/sharpen/shaders/super-res-ex.slang new file mode 100644 index 0000000..7910f05 --- /dev/null +++ b/sharpen/shaders/super-res-ex.slang @@ -0,0 +1,190 @@ +#version 450 + +/* + Super-res shader - Shiandow + + Ported from Shiandow's code by Hyllian, 2016. + + This file is a part of MPDN Extensions. + https://github.com/zachsaw/MPDN_Extensions + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. +*/ + +layout(push_constant) uniform Push +{ + vec4 SourceSize; + vec4 REFSize; + vec4 OutputSize; + uint FrameCount; +} params; + +layout(std140, set = 0, binding = 0) uniform UBO +{ + mat4 MVP; +} global; + +// -- Edge detection options -- +#define strength 0.8 +#define softness 0.3 +#define acuity 100.0 +#define radius 1.0 +#define power 2.0 + +#define originalSize vec2(params.REFSize.xy) + +#define dxdy (1.0 / vec2(params.SourceSize.xy)) +#define ddxddy (1.0 / originalSize) + +#define sqr(x) dot(x,x) + + +// -- Input processing -- +//Current high res value +#define Get(x,y) (texture(REF,ddxddy*(pos+ivec2(x,y)+0.5)).xyz) +#define GetY(x,y) (texture(Source,ddxddy*(pos+ivec2(x,y)+0.5)).a) +//Downsampled result +#define Diff(x,y) (texture(Source,ddxddy*(pos+ivec2(x,y)+0.5)).xyz) + +#pragma stage vertex +layout(location = 0) in vec4 Position; +layout(location = 1) in vec2 TexCoord; +layout(location = 0) out vec2 vTexCoord; + +void main() +{ + gl_Position = global.MVP * Position; + vTexCoord = TexCoord; +} + +#pragma stage fragment +layout(location = 0) in vec2 vTexCoord; +layout(location = 0) out vec4 FragColor; +layout(set = 0, binding = 2) uniform sampler2D Source; +layout(set = 0, binding = 3) uniform sampler2D REF; + +const vec3 Y = vec3(.2126, .7152, .0722); + + +float RGBtoYUV(vec3 color) +{ + return dot(color, Y); +} + +void main() +{ + vec2 tex = vTexCoord; + + vec4 c0 = texture(REF, tex); + + // Calculate position + vec2 pos = tex * params.REFSize.xy - 0.5; + vec2 offset = pos - round(pos); + pos -= offset; + + // Calculate faithfulness force + float W = 0.; + vec3 diff = vec3(0.0); + vec3 stab = vec3(0.0); + float var = 0.; + + float c0y = RGBtoYUV(c0.rgb); + + // Loop unrolled for better compatibility. + + float dI2 = sqr(acuity*(c0y - GetY(-1,-1))); + float dXY2 = sqr(vec2(-1,-1) - offset); + float w = exp(-dXY2/(2.*radius*radius))*pow(1. + dI2/power, - power); + diff += w*Diff(-1,-1); + stab += w*(c0.rgb - Get(-1,-1)); + var += w*dI2; + W += w; + + dI2 = sqr(acuity*(c0y - GetY(-1, 0))); + dXY2 = sqr(vec2(-1, 0) - offset); + w = exp(-dXY2/(2.*radius*radius))*pow(1. + dI2/power, - power); + diff += w*Diff(-1, 0); + stab += w*(c0.rgb - Get(-1, 0)); + var += w*dI2; + W += w; + + dI2 = sqr(acuity*(c0y - GetY(-1, 1))); + dXY2 = sqr(vec2(-1, 1) - offset); + w = exp(-dXY2/(2.*radius*radius))*pow(1. + dI2/power, - power); + diff += w*Diff(-1, 1); + stab += w*(c0.rgb - Get(-1, 1)); + var += w*dI2; + W += w; + + dI2 = sqr(acuity*(c0y - GetY( 0,-1))); + dXY2 = sqr(vec2( 0,-1) - offset); + w = exp(-dXY2/(2.*radius*radius))*pow(1. + dI2/power, - power); + diff += w*Diff( 0,-1); + stab += w*(c0.rgb - Get( 0,-1)); + var += w*dI2; + W += w; + + dI2 = sqr(acuity*(c0y - GetY( 0, 0))); + dXY2 = sqr(vec2( 0, 0) - offset); + w = exp(-dXY2/(2.*radius*radius))*pow(1. + dI2/power, - power); + diff += w*Diff( 0, 0); + stab += w*(c0.rgb - Get( 0, 0)); + var += w*dI2; + W += w; + + dI2 = sqr(acuity*(c0y - GetY( 0, 1))); + dXY2 = sqr(vec2( 0, 1) - offset); + w = exp(-dXY2/(2.*radius*radius))*pow(1. + dI2/power, - power); + diff += w*Diff( 0, 1); + stab += w*(c0.rgb - Get( 0, 1)); + var += w*dI2; + W += w; + + dI2 = sqr(acuity*(c0y - GetY( 1,-1))); + dXY2 = sqr(vec2( 1,-1) - offset); + w = exp(-dXY2/(2.*radius*radius))*pow(1. + dI2/power, - power); + diff += w*Diff( 1,-1); + stab += w*(c0.rgb - Get( 1,-1)); + var += w*dI2; + W += w; + + dI2 = sqr(acuity*(c0y - GetY( 1, 0))); + dXY2 = sqr(vec2( 1, 0) - offset); + w = exp(-dXY2/(2.*radius*radius))*pow(1. + dI2/power, - power); + diff += w*Diff( 1, 0); + stab += w*(c0.rgb - Get( 1, 0)); + var += w*dI2; + W += w; + + dI2 = sqr(acuity*(c0y - GetY( 1, 1))); + dXY2 = sqr(vec2( 1, 1) - offset); + w = exp(-dXY2/(2.*radius*radius))*pow(1. + dI2/power, - power); + diff += w*Diff( 1, 1); + stab += w*(c0.rgb - Get( 1, 1)); + var += w*dI2; + W += w; + + diff /= W; + stab /= W; + var = (var / W) - sqr(acuity*stab); + + // Calculate edge statistics + float varD = softness * sqr(acuity*stab); + float varS = (1. - softness) * var; + + // Apply force + c0.xyz -= strength*mix(diff, stab, softness); + + FragColor = vec4(c0); +} \ No newline at end of file diff --git a/sharpen/super-xbr-super-res.slangp b/sharpen/super-xbr-super-res.slangp new file mode 100644 index 0000000..bd77f35 --- /dev/null +++ b/sharpen/super-xbr-super-res.slangp @@ -0,0 +1,41 @@ +shaders = "9" + +shader0 = "../xbr/shaders/super-xbr/super-xbr-pass0.slang" +filter_linear0 = "false" +scale_type0 = "source" +scale0 = "1.000000" +shader1 = "../xbr/shaders/super-xbr/super-xbr-pass1.slang" +filter_linear1 = "false" +scale_type1 = "source" +scale1 = "2.000000" +shader2 = "../xbr/shaders/super-xbr/super-xbr-pass2.slang" +filter_linear2 = "false" +scale_type2 = "source" +scale2 = "1.000000" +alias2 = "REF" + +shader3 = "../cubic/shaders/cubic.slang" +filter_linear3 = "false" +scale_type3 = "source" +scale3 = "0.500000" +shader4 = "shaders/diff.slang" +filter_linear4 = "false" +scale_type4 = "source" +scale4 = "1.000000" +shader5 = "shaders/super-res-ex.slang" +filter_linear5 = "true" +scale_type5 = "source" +scale5 = "2.000000" + +shader6 = "../misc/deposterize-pass0.slang" +filter_linear6 = "false" +scale_type6 = "source" +scale6 = "1.000000" +shader7 = "../misc/deposterize-pass1.slang" +filter_linear7 = "false" +scale_type7 = "source" +scale7 = "1.000000" + +shader8 = "../xbr/shaders/super-xbr/custom-jinc2-sharper.slang" +filter_linear8 = "false" + diff --git a/xbr/shaders/super-xbr/super-xbr-pass0.slang b/xbr/shaders/super-xbr/super-xbr-pass0.slang index 7049275..14403be 100644 --- a/xbr/shaders/super-xbr/super-xbr-pass0.slang +++ b/xbr/shaders/super-xbr/super-xbr-pass0.slang @@ -171,7 +171,6 @@ void main() float h5 = RGBtoYUV( H5 ); float p2 = RGBtoYUV( P2 ); float f4 = RGBtoYUV( F4 ); float p3 = RGBtoYUV( P3 ); - /* Calc edgeness in diagonal directions. */ float d_edge = (d_wd( d, b, g, e, c, p2, h, f, p1, h5, i, f4, i5, i4 ) - d_wd( c, f4, b, f, i4, p0, e, i, p3, d, h, i5, g, h5 )); @@ -199,5 +198,5 @@ void main() vec3 max_sample = max4( E, F, H, I ) - (1.-XBR_ANTI_RINGING)*mix((P2-H)*(F-P1), (P0-E)*(I-P3), step(0.0, d_edge)); color = clamp(color, min_sample, max_sample); - FragColor = vec4(color, 1.0); + FragColor = vec4(color, 1.0); } \ No newline at end of file diff --git a/xbr/shaders/super-xbr/super-xbr-pass1.slang b/xbr/shaders/super-xbr/super-xbr-pass1.slang index e7dade8..a0070d2 100644 --- a/xbr/shaders/super-xbr/super-xbr-pass1.slang +++ b/xbr/shaders/super-xbr/super-xbr-pass1.slang @@ -116,12 +116,14 @@ layout(set = 0, binding = 3) uniform sampler2D Original; void main() { //Skip pixels on wrong grid - vec2 fp = fract(vTexCoord*params.SourceSize.xy); + vec2 fp = fract(vTexCoord.xy * params.SourceSize.xy); vec2 dir = fp - vec2(0.5,0.5); - if ((dir.x*dir.y)>0.0){ - FragColor = (fp.x>0.5) ? texture(Source, vTexCoord) : texture(Original, vTexCoord); - }else{ - + if ((dir.x*dir.y)>0.0) + { + FragColor = (fp.x>0.5) ? texture(Source, vTexCoord) : texture(Original, vTexCoord); + } + else + { vec2 g1 = (fp.x>0.5) ? vec2(0.5/params.SourceSize.x, 0.0) : vec2(0.0, 0.5/params.SourceSize.y); vec2 g2 = (fp.x>0.5) ? vec2(0.0, 0.5/params.SourceSize.y) : vec2(0.5/params.SourceSize.x, 0.0); @@ -185,6 +187,6 @@ void main() vec3 max_sample = max4( E, F, H, I ) - (1.-XBR_ANTI_RINGING)*mix((P2-H)*(F-P1), (P0-E)*(I-P3), step(0.0, d_edge)); color = clamp(color, min_sample, max_sample); - FragColor = vec4(color, 1.0); - } + FragColor = vec4(color, 1.0); + } } \ No newline at end of file diff --git a/xbr/shaders/xbr-lv3-multipass/xbr-lv3-pass0.slang b/xbr/shaders/xbr-lv3-multipass/xbr-lv3-pass0.slang new file mode 100644 index 0000000..388734a --- /dev/null +++ b/xbr/shaders/xbr-lv3-multipass/xbr-lv3-pass0.slang @@ -0,0 +1,290 @@ +#version 450 + +/* + Hyllian's xBR level 3 pass0 Shader + + Copyright (C) 2011-2015 Hyllian - sergiogdb@gmail.com + + 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. + + + Incorporates some of the ideas from SABR shader. Thanks to Joshua Street. +*/ + +layout(push_constant) uniform Push +{ + vec4 SourceSize; + vec4 OriginalSize; + vec4 OutputSize; + uint FrameCount; +} params; + +layout(std140, set = 0, binding = 0) uniform UBO +{ + mat4 MVP; +} global; + +#define mul(a,b) (b*a) +#define saturate(c) clamp(c, 0.0, 1.0) + +#pragma stage vertex +layout(location = 0) in vec4 Position; +layout(location = 1) in vec2 TexCoord; +layout(location = 0) out vec2 vTexCoord; +layout(location = 1) out vec4 t1; +layout(location = 2) out vec4 t2; +layout(location = 3) out vec4 t3; +layout(location = 4) out vec4 t4; +layout(location = 5) out vec4 t5; +layout(location = 6) out vec4 t6; +layout(location = 7) out vec4 t7; + +void main() +{ + gl_Position = global.MVP * Position; + vTexCoord = TexCoord * 1.0004; + + vec2 ps = vec2(1.0) / params.SourceSize.xy; + float dx = ps.x; + float dy = ps.y; + + // A1 B1 C1 + // A0 A B C C4 + // D0 D E F F4 + // G0 G H I I4 + // G5 H5 I5 + + t1 = vTexCoord.xxxy + vec4( -dx, 0, dx,-2.0*dy); // A1 B1 C1 + t2 = vTexCoord.xxxy + vec4( -dx, 0, dx, -dy); // A B C + t3 = vTexCoord.xxxy + vec4( -dx, 0, dx, 0); // D E F + t4 = vTexCoord.xxxy + vec4( -dx, 0, dx, dy); // G H I + t5 = vTexCoord.xxxy + vec4( -dx, 0, dx, 2.0*dy); // G5 H5 I5 + t6 = vTexCoord.xyyy + vec4(-2.0*dx,-dy, 0, dy); // A0 D0 G0 + t7 = vTexCoord.xyyy + vec4( 2.0*dx,-dy, 0, dy); // C4 F4 I4 +} + +#pragma stage fragment +layout(location = 0) in vec2 vTexCoord; +layout(location = 1) in vec4 t1; +layout(location = 2) in vec4 t2; +layout(location = 3) in vec4 t3; +layout(location = 4) in vec4 t4; +layout(location = 5) in vec4 t5; +layout(location = 6) in vec4 t6; +layout(location = 7) in vec4 t7; +layout(location = 0) out vec4 FragColor; +layout(set = 0, binding = 2) uniform sampler2D Source; + +const float coef = 2.0; +const float cf = 4.0; +const vec4 eq_threshold = vec4(15.0, 15.0, 15.0, 15.0); +const float y_weight = 48.0; +const float u_weight = 7.0; +const float v_weight = 6.0; +const mat3 yuv = mat3(0.299, 0.587, 0.114, -0.169, -0.331, 0.499, 0.499, -0.418, -0.0813); +const mat3 yuv_weighted = mat3(y_weight*yuv[0], u_weight*yuv[1], v_weight*yuv[2]); +const vec4 bin1 = vec4( 1.0, 2.0, 4.0, 8.0); +const vec4 bin2 = vec4(16.0, 32.0, 64.0, 128.0); +const vec4 maximo = vec4(255.0, 255.0, 255.0, 255.0); + +vec4 df(vec4 A, vec4 B) +{ + return vec4(abs(A-B)); +} + +vec4 remapTo01(vec4 v, vec4 high) +{ + return (v/high); +} + +vec4 remapFrom01(vec4 v, vec4 high) +{ + return (high*v + vec4(0.5, 0.5, 0.5, 0.5)); +} + +bvec4 eq(vec4 A, vec4 B) +{ + return lessThan(df(A, B) , eq_threshold); +} + + +vec4 weighted_distance(vec4 a, vec4 b, vec4 c, vec4 d, vec4 e, vec4 f, vec4 g, vec4 h) +{ + return (df(a,b) + df(a,c) + df(d,e) + df(d,f) + 4.0*df(g,h)); +} + +bvec4 and(bvec4 A, bvec4 B) +{ + return bvec4(A.x && B.x, A.y && B.y, A.z && B.z, A.w && B.w); +} + +bvec4 or(bvec4 A, bvec4 B) +{ + return bvec4(A.x || B.x, A.y || B.y, A.z || B.z, A.w || B.w); +} + +#define FILTRO(EDR0, EDR, LEFT, UP, LEFT3, UP3, PX0, PX3, PX1, LIN0, LIN3, LIN1, PX)\ + if (LEFT && (!UP))\ + {\ + PX0 = bvec2( 0, PX);\ + PX3 = bvec2(PX, 1);\ + if (LEFT3)\ + {\ + LIN0 = bvec4(0, 1, 0, 0);\ + LIN3 = bvec4(1, 0, 0, 0);\ + }\ + else \ + {\ + LIN0 = bvec4(0, 0, 1, 0);\ + LIN3 = bvec4(0, 1, 1, 0);\ + }\ + }\ + else if (UP && (!LEFT))\ + {\ + PX0 = bvec2(false, PX);\ + PX1 = bvec2( !PX, false);\ + if (UP3)\ + {\ + LIN0 = bvec4(0, 1, 0, 1);\ + LIN1 = bvec4(1, 0, 0, 1);\ + }\ + else \ + {\ + LIN0 = bvec4(0, 0, 1, 1);\ + LIN1 = bvec4(0, 1, 1, 1);\ + }\ + }\ + else if (EDR)\ + {\ + LEFT = UP = LEFT3 = UP3 = false;\ + PX0 = bvec2(false, PX);\ + LIN0 = bvec4(0, 0, 0, 1);\ + }\ + else if (EDR0)\ + {\ + LEFT = UP = LEFT3 = UP3 = false;\ + PX0 = bvec2(false, PX);\ + LIN0 = bvec4(0, 0, 0, 0);\ + }\ + +void main() +{ + bvec4 edr, edr_left, edr_up, edr3_left, edr3_up, px; // px = pixel, edr = edge detection rule + bvec4 interp_restriction_lv1, interp_restriction_lv2_left, interp_restriction_lv2_up; + bvec4 interp_restriction_lv3_left, interp_restriction_lv3_up; + bvec2 px0, px1, px2, px3; + bvec4 lin0, lin1, lin2, lin3; + + + vec3 A1 = texture(Source, t1.xw).rgb; + vec3 B1 = texture(Source, t1.yw).rgb; + vec3 C1 = texture(Source, t1.zw).rgb; + + vec3 A = texture(Source, t2.xw).rgb; + vec3 B = texture(Source, t2.yw).rgb; + vec3 C = texture(Source, t2.zw).rgb; + + vec3 D = texture(Source, t3.xw).rgb; + vec3 E = texture(Source, t3.yw).rgb; + vec3 F = texture(Source, t3.zw).rgb; + + vec3 G = texture(Source, t4.xw).rgb; + vec3 H = texture(Source, t4.yw).rgb; + vec3 I = texture(Source, t4.zw).rgb; + + vec3 G5 = texture(Source, t5.xw).rgb; + vec3 H5 = texture(Source, t5.yw).rgb; + vec3 I5 = texture(Source, t5.zw).rgb; + + vec3 A0 = texture(Source, t6.xy).rgb; + vec3 D0 = texture(Source, t6.xz).rgb; + vec3 G0 = texture(Source, t6.xw).rgb; + + vec3 C4 = texture(Source, t7.xy).rgb; + vec3 F4 = texture(Source, t7.xz).rgb; + vec3 I4 = texture(Source, t7.xw).rgb; + + vec4 b = mul( mat4x3(B, D, H, F), yuv_weighted[0] ); + vec4 c = mul( mat4x3(C, A, G, I), yuv_weighted[0] ); + vec4 e = mul( mat4x3(E, E, E, E), yuv_weighted[0] ); + vec4 d = b.yzwx; + vec4 f = b.wxyz; + vec4 g = c.zwxy; + vec4 h = b.zwxy; + vec4 i = c.wxyz; + + vec4 i4 = mul( mat4x3(I4, C1, A0, G5), yuv_weighted[0] ); + vec4 i5 = mul( mat4x3(I5, C4, A1, G0), yuv_weighted[0] ); + vec4 h5 = mul( mat4x3(H5, F4, B1, D0), yuv_weighted[0] ); + vec4 f4 = h5.yzwx; + + vec4 c1 = i4.yzwx; + vec4 g0 = i5.wxyz; + vec4 b1 = h5.zwxy; + vec4 d0 = h5.wxyz; + + + bvec4 interp_restriction_lv0 = and(notEqual(e,f) , notEqual(e,h)); + bvec4 comp1 = and(not(eq(h,h5)) , not(eq(h,i5))); + bvec4 comp2 = and(not(eq(h,d)) , not(eq(h,g))); + bvec4 comp3 = and(not(eq(f,f4)) , not(eq(f,i4))); + bvec4 comp4 = and( not(eq(f,b)) , not(eq(f,c)) ); + bvec4 comp5 = and(eq(e,i) , or(comp3 , comp1)); + interp_restriction_lv1 = or( comp4 , or(comp2 , or(comp5 , or(eq(e,g) , eq(e,c))))); + interp_restriction_lv2_left = and(notEqual(e,g) , notEqual(d,g)); + interp_restriction_lv2_up = and(notEqual(e,c) , notEqual(b,c)); + interp_restriction_lv3_left = and(notEqual(e,g0) , notEqual(d0,g0)); + interp_restriction_lv3_up = and(notEqual(e,c1) , notEqual(b1,c1)); + + bvec4 edr0 = and(lessThan(weighted_distance( e, c, g, i, h5, f4, h, f) , weighted_distance( h, d, i5, f, i4, b, e, i)) , interp_restriction_lv0); + + edr = and(edr0 , interp_restriction_lv1); + edr_left = and(lessThanEqual((coef*df(f,g)) , df(h,c)) , and(interp_restriction_lv2_left , edr)); + edr_up = and(greaterThanEqual(df(f,g) , (coef*df(h,c))) , and(interp_restriction_lv2_up , edr)); + edr3_left = and(lessThanEqual((cf*df(f,g0)) , df(h,c1)) , and(interp_restriction_lv3_left , edr_left)); + edr3_up = and(greaterThanEqual(df(f,g0) , (cf*df(h,c1))) , and(interp_restriction_lv3_up , edr_up)); + + px = lessThanEqual(df(e,f) , df(e,h)); + + lin0 = lin1 = lin2 = lin3 = bvec4(1, 1, 1, 1); + + FILTRO(edr0.x, edr.x, edr_left.x, edr_up.x, edr3_left.x, edr3_up.x, px0, px3, px1, lin0, lin3, lin1, px.x); + FILTRO(edr0.y, edr.y, edr_left.y, edr_up.y, edr3_left.y, edr3_up.y, px1, px0, px2, lin1, lin0, lin2, px.y); + FILTRO(edr0.z, edr.z, edr_left.z, edr_up.z, edr3_left.z, edr3_up.z, px2, px1, px3, lin2, lin1, lin3, px.z); + FILTRO(edr0.w, edr.w, edr_left.w, edr_up.w, edr3_left.w, edr3_up.w, px3, px2, px0, lin3, lin2, lin0, px.w); + + vec4 info = mul( + bin1, mat4( + edr3_left, + edr3_up, + px0.x, px1.x, px2.x, px3.x, + px0.y, px1.y, px2.y, px3.y + ) + ); + + info += mul(bin2, mat4( + lin0.x, lin1.x, lin2.x, lin3.x, + lin0.y, lin1.y, lin2.y, lin3.y, + lin0.z, lin1.z, lin2.z, lin3.z, + lin0.w, lin1.w, lin2.w, lin3.w + ) + ); + + FragColor = vec4(remapTo01(info, maximo)); +} \ No newline at end of file diff --git a/xbr/shaders/xbr-lv3-multipass/xbr-lv3-pass1.slang b/xbr/shaders/xbr-lv3-multipass/xbr-lv3-pass1.slang new file mode 100644 index 0000000..3d1c4df --- /dev/null +++ b/xbr/shaders/xbr-lv3-multipass/xbr-lv3-pass1.slang @@ -0,0 +1,203 @@ +#version 450 + +/* + Hyllian's xBR level 3 pass1 Shader + + Copyright (C) 2011-2015 Hyllian - sergiogdb@gmail.com + + 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. +*/ + +#define round(X) floor((X)+0.5) +#define saturate(c) clamp(c, 0.0, 1.0) +#define mul(a,b) (b*a) + +layout(push_constant) uniform Push +{ + vec4 SourceSize; + vec4 OriginalSize; + vec4 OutputSize; + uint FrameCount; +} params; + +layout(std140, set = 0, binding = 0) uniform UBO +{ + mat4 MVP; +} global; + +#pragma stage vertex +layout(location = 0) in vec4 Position; +layout(location = 1) in vec2 TexCoord; +layout(location = 0) out vec2 vTexCoord; +layout(location = 1) out vec4 t1; +layout(location = 2) out vec2 delta; + +void main() +{ + gl_Position = global.MVP * Position; + vTexCoord = TexCoord * 1.0004; + + vec2 ps = vec2(1.0/params.OriginalSize.x, 1.0/params.OriginalSize.y); + float dx = ps.x; + float dy = ps.y; + + // A3 B3 C3 + // A1 B1 C1 + //A2 A0 A B C C4 C6 + //D2 D0 D E F F4 F6 + //G2 G0 G H I I4 I6 + // G5 H5 I5 + // G7 H7 I7 + + t1 = vec4(dx, 0., 0., dy); // F H + delta = vec2(params.SourceSize.x/params.OutputSize.x, 0.5*params.SourceSize.x/params.OutputSize.x); // Delta is the thickness of interpolation +} + +#pragma stage fragment +layout(location = 0) in vec2 vTexCoord; +layout(location = 1) in vec4 t1; +layout(location = 2) in vec2 delta; +layout(location = 0) out vec4 FragColor; +layout(set = 0, binding = 2) uniform sampler2D Source; +layout(set = 0, binding = 3) uniform sampler2D Original; + +const mat2x4 sym_vectors = mat2x4(1., 1., -1., -1., 1., -1., -1., 1.); + +const vec3 lines[12] = { + vec3(1.0, 1.0, 0.75), + vec3(1.0, 1.0, 0.5), + vec3(2.0, 1.0, 0.5), + vec3(1.0, 2.0, 0.5), + vec3(3.0, 1.0, 0.5), + vec3(1.0, 3.0, 0.5), + + vec3(-1.0, 2.0, 0.5), + vec3(2.0, -1.0, 0.5), + vec3(-1.0, 3.0, 0.5), + vec3(3.0, -1.0, 0.5), + + vec3(3.0, 1.0, 1.5), + vec3(1.0, 3.0, 1.5) +}; + + +float remapFrom01(float v, float high) +{ + return (high*v + 0.5); +} + + +vec3 remapFrom01(vec3 v, vec3 low, vec3 high) +{ + return round(mix(low, high, v)); +} + +vec4 unpack_info(float i) +{ + vec4 info; + info.x = round(modf(i/2.0, i)); + info.y = round(modf(i/2.0, i)); + info.z = round(modf(i/2.0, i)); + info.w = i; + + return info; +} + +void main() +{ + vec2 px; // px = pixel to blend + float pxr, pxd, line, edr3_nrl, edr3_ndu; + + vec2 pos = fract(vTexCoord*params.SourceSize.xy)-vec2(0.5, 0.5); // pos = pixel position + vec2 dir = sign(pos); // dir = pixel direction + + vec2 g1 = dir*( saturate(-dir.y*dir.x)*t1.zw + saturate( dir.y*dir.x)*t1.xy); + vec2 g2 = dir*( saturate( dir.y*dir.x)*t1.zw + saturate(-dir.y*dir.x)*t1.xy); + + vec3 F = texture(Original, vTexCoord +g1).xyz; + vec3 B = texture(Original, vTexCoord -g2).xyz; + vec3 D = texture(Original, vTexCoord -g1).xyz; + vec3 H = texture(Original, vTexCoord +g2).xyz; + vec3 E = texture(Original, vTexCoord ).xyz; + + vec3 F4 = texture(Original, vTexCoord +2.0*g1).xyz; + vec3 I = texture(Original, vTexCoord +g1+g2).xyz; + vec3 H5 = texture(Original, vTexCoord +2.0*g2).xyz; + + vec4 icomp = round(saturate(mul(dir, sym_vectors))); // choose info component + float info = remapFrom01(dot(texture(Source, vTexCoord ), icomp), 255.0); // retrieve 1st pass info + float info_nr = remapFrom01(dot(texture(Source, vTexCoord+g1), icomp), 255.0); // 1st pass info from neighbor r + float info_nd = remapFrom01(dot(texture(Source, vTexCoord+g2), icomp), 255.0); // 1st pass info from neighbor d + + modf(info/2.0f, info); // discard info + modf(info/2.0f, info); // discard info + px.x = round(modf(info/2.0, info)); + px.y = round(modf(info/2.0, info)); + + vec4 flags = unpack_info(info); // retrieve 1st pass flags + + edr3_nrl = round(modf(info_nr/2.0, info_nr)); + modf(info_nr/2.0, info_nr); // discard info_nr + modf(info_nr/2.0, info_nr); // discard info_nr + pxr = round(modf(info_nr/2.0, info_nr)); + + modf(info_nd/2.0, info_nd); // discard info_nd + edr3_ndu = round(modf(info_nd/2.0, info_nd)); + modf(info_nd/2.0, info_nd); // discard info_nd + pxd = round(modf(info_nd/2.0, info_nd)); + + float aux = round(dot(vec4(8.0, 4.0, 2.0, 1.0), flags)); + vec3 slep; + + + if (aux >= 6.0) + { + slep = (aux==6.0 ? lines[6] : (aux==7.0 ? lines[7] : (aux==8.0 ? lines[8] : (aux==9.0 ? lines[9] : (aux==10.0 ? lines[10] : lines[11]))))); + } + else + { + slep = (aux==0.0 ? lines[0] : (aux==1.0 ? lines[1] : (aux==2.0 ? lines[2] : (aux==3.0 ? lines[3] : (aux==4.0 ? lines[4] : lines[5]))))); + } + + + vec2 fp = (dir.x*dir.y) > 0.0 ? abs(pos) : abs(pos.yx); + + vec3 fp1 = vec3(fp.yx, -1); + + vec3 color = E; + float fx; + + if (aux < 10.0) + { + fx = saturate(dot(fp1, slep)/(2.*delta.x)+0.5); + color = mix(E, mix(mix(H, F, px.y), mix(D, B, px.y), px.x), fx); // interpolate if there's edge + } + else if (edr3_nrl == 1.0) + { + fx = saturate(dot(fp1, lines[10])/(2.*delta.x)+0.5); + color = mix(E, mix(I, F4, pxr), fx); // interpolate if there's edge + } + else if (edr3_ndu == 1.0) + { + fx = saturate(dot(fp1, lines[11])/(2.*delta.x)+0.5); + color = mix(E, mix(H5, I, pxd), fx); // interpolate if there's edge + } + + FragColor = vec4(color, 1.0); +} \ No newline at end of file diff --git a/xbr/super-xbr-deposterize.slangp b/xbr/super-xbr-deposterize.slangp index 788e240..cb78a5f 100644 --- a/xbr/super-xbr-deposterize.slangp +++ b/xbr/super-xbr-deposterize.slangp @@ -29,9 +29,9 @@ alias2 = "" float_framebuffer2 = "false" srgb_framebuffer2 = "false" scale_type_x2 = "source" -scale_x2 = "2.000000" +scale_x2 = "1.000000" scale_type_y2 = "source" -scale_y2 = "2.000000" +scale_y2 = "1.000000" shader3 = "..\xbr\shaders\super-xbr\super-xbr-pass1.slang" filter_linear3 = "false" wrap_mode3 = "clamp_to_border" @@ -40,9 +40,9 @@ alias3 = "" float_framebuffer3 = "false" srgb_framebuffer3 = "false" scale_type_x3 = "source" -scale_x3 = "1.000000" +scale_x3 = "2.000000" scale_type_y3 = "source" -scale_y3 = "1.000000" +scale_y3 = "2.000000" shader4 = "..\xbr\shaders\super-xbr\super-xbr-pass2.slang" filter_linear4 = "false" wrap_mode4 = "clamp_to_border"