GPU: Fix Catmull-Rom weight calculation resulting in much sharper image, add XBR pixel art upscaling (MIT license implementation taken from libretro), add Mitchell bicubic option as a softer alternative to C-R

This commit is contained in:
logarithm
2019-11-29 17:53:50 +02:00
parent 9022b4f65e
commit 6017609882
8 changed files with 545 additions and 90 deletions

View File

@@ -220,6 +220,8 @@ public class GpuPlugin extends Plugin implements DrawCallbacks
private int uniBrightness;
private int uniTex;
private int uniTexSamplingMode;
private int uniTexSourceDimensions;
private int uniTexTargetDimensions;
private int uniTextures;
private int uniTextureOffsets;
private int uniBlockSmall;
@@ -501,10 +503,14 @@ public class GpuPlugin extends Plugin implements DrawCallbacks
glUiProgram = gl.glCreateProgram();
glUiVertexShader = gl.glCreateShader(gl.GL_VERTEX_SHADER);
glUiFragmentShader = gl.glCreateShader(gl.GL_FRAGMENT_SHADER);
template = new Template(resourceLoader);
vertSource = template.process(resourceLoader.apply("vertui.glsl"));
template = new Template(resourceLoader);
fragSource = template.process(resourceLoader.apply("fragui.glsl"));
GLUtil.loadShaders(gl, glUiProgram, glUiVertexShader, -1, glUiFragmentShader,
inputStreamToString(getClass().getResourceAsStream("vertui.glsl")),
vertSource,
null,
inputStreamToString(getClass().getResourceAsStream("fragui.glsl")));
fragSource);
initUniforms();
}
@@ -521,6 +527,8 @@ public class GpuPlugin extends Plugin implements DrawCallbacks
uniTex = gl.glGetUniformLocation(glUiProgram, "tex");
uniTexSamplingMode = gl.glGetUniformLocation(glUiProgram, "samplingMode");
uniTexTargetDimensions = gl.glGetUniformLocation(glUiProgram, "targetDimensions");
uniTexSourceDimensions = gl.glGetUniformLocation(glUiProgram, "sourceDimensions");
uniTextures = gl.glGetUniformLocation(glProgram, "textures");
uniTextureOffsets = gl.glGetUniformLocation(glProgram, "textureOffsets");
@@ -1156,20 +1164,24 @@ public class GpuPlugin extends Plugin implements DrawCallbacks
gl.glTexSubImage2D(gl.GL_TEXTURE_2D, 0, 0, 0, width, height, gl.GL_BGRA, gl.GL_UNSIGNED_INT_8_8_8_8_REV, interfaceBuffer);
}
if (client.isStretchedEnabled())
{
Dimension dim = client.getStretchedDimensions();
glDpiAwareViewport(0, 0, dim.width, dim.height);
}
else
{
glDpiAwareViewport(0, 0, canvasWidth, canvasHeight);
}
// Use the texture bound in the first pass
gl.glUseProgram(glUiProgram);
gl.glUniform1i(uniTex, 0);
gl.glUniform1i(uniTexSamplingMode, config.uiScalingMode().getMode());
gl.glUniform2i(uniTexSourceDimensions, canvasWidth, canvasHeight);
if (client.isStretchedEnabled())
{
Dimension dim = client.getStretchedDimensions();
glDpiAwareViewport(0, 0, dim.width, dim.height);
gl.glUniform2i(uniTexTargetDimensions, dim.width, dim.height);
}
else
{
glDpiAwareViewport(0, 0, canvasWidth, canvasHeight);
gl.glUniform2i(uniTexTargetDimensions, canvasWidth, canvasHeight);
}
// Set the sampling function used when stretching the UI.
// This is probably better done with sampler objects instead of texture parameters, but this is easier and likely more portable.

View File

@@ -33,7 +33,9 @@ public enum UIScalingMode
{
NEAREST("Nearest Neighbor", 0),
LINEAR("Bilinear", 0),
CATMULL_ROM("Bicubic (Catmull-Rom)", 1);
MITCHELL("Bicubic (Mitchell)", 1),
CATMULL_ROM("Bicubic (Catmull-Rom)", 2),
XBR("XBR (use Integer Scaling)", 3);
private final String name;
private final int mode;

View File

@@ -26,93 +26,36 @@
uniform sampler2D tex;
// Modes:
// 0 - default sampling, either GL_LINEAR or GL_NEAREST depending on texture attributes
// 1 - bicubic sampling with Catmull-Rom spline values
#define SAMPLING_DEFAULT 0
#define SAMPLING_MITCHELL 1
#define SAMPLING_CATROM 2
#define SAMPLING_XBR 3
uniform int samplingMode;
uniform ivec2 sourceDimensions;
uniform ivec2 targetDimensions;
#include scale/bicubic.glsl
#include scale/xbr_lv2_frag.glsl
#include scale/hq2x.glsl
in vec2 TexCoord;
in XBRTable xbrTable;
out vec4 FragColor;
// Cubic filter with Catmull-Rom parameters
float catmull_rom(float x)
{
/* A generalized cubic filter as described by Mitchell and Netravali is defined by the piecewise equation:
* if abs(x) < 1
* y = 1/6 * ( (12 - 9b - 6c) * abs(x)^3 + (-18 + 12b + 6c) * abs(x)^2 + (6 - 2b) )
* if abs(x) >= 1 and < 2
* y = 1/6 * ( (-1b - 6c) * abs(x)^3 + (6b + 30c) * abs(x)^2 + (-12b - 48c) * abs(x) + (8b + 24c) )
* otherwise
* y = 0
* Generally favorable results in image upscaling are given by the values b = 0 and c = 0.5.
* This is known as the Catmull-Rom filter.
* Placing these values into the piecewise equations gives us a more compact representation of:
* y = 1.5 * abs(x)^3 - 2.5 * abs(x)^2 + 1 // abs(x) < 1
* y = -0.5 * abs(x)^3 + 2.5 * abs(x)^2 - 4 * abs(x) + 2 // 1 <= abs(x) < 2
*/
float t = abs(x); // absolute value of the x coordinate
float t2 = t * t; // t squared
float t3 = t * t * t; // t cubed
if (t < 1)
return 1.5 * t3 - 2.5 * t2 + 1;
else if (t < 2)
return -0.5 * t3 + 2.5 * t2 - 4 * t + 2;
else
return 0;
}
// Samples a texture using a 4x4 filtering kernel.
vec4 textureFiltered(sampler2D sampler, vec2 texCoords){
vec2 texSize = textureSize(tex, 0);
vec2 texelSize = 1.0 / texSize;
texCoords *= texSize;
texCoords -= 0.5;
vec4 nSum = vec4( 0.0, 0.0, 0.0, 0.0 );
vec4 nDenom = vec4( 0.0, 0.0, 0.0, 0.0 );
ivec2 texelCoords = ivec2(floor(texCoords));
vec2 coordFract = fract(texCoords);
if (samplingMode == 1)
{
for (int m = -1; m <= 2; m++)
{
for (int n = -1; n <= 2; n++)
{
// get the raw texel, bypassing any other filters
vec4 vecData = texelFetch(sampler, texelCoords + ivec2(m, n), 0);
// calculate weights based on distance of the current texel offset from the sub-texel position of the sampling location
float cx = catmull_rom( m - coordFract.x );
float cy = catmull_rom( n - coordFract.y );
// build the weighted average
nSum += vecData * cx * cy;
nDenom += cx * cy;
}
}
}
else
{
// Undefined sampling mode, fall back to default sampler
return texture(sampler, texCoords);
}
// calculate and return the weighted average
return nSum / nDenom;
}
void main() {
vec4 c;
if (samplingMode == 0)
if (samplingMode == SAMPLING_DEFAULT)
c = texture(tex, TexCoord);
else
c = textureFiltered(tex, TexCoord);
else if (samplingMode == SAMPLING_CATROM || samplingMode == SAMPLING_MITCHELL)
c = textureCubic(tex, TexCoord, samplingMode);
else if (samplingMode == SAMPLING_XBR)
{
float scaleFactor = ceil(1.0 * targetDimensions.x / sourceDimensions.x);
c = texture(tex, TexCoord);
c.xyz = textureXBR(tex, TexCoord, xbrTable, scaleFactor);
}
FragColor = c;
}

View File

@@ -0,0 +1,160 @@
/*
* Copyright (c) 2019 logarrhythmic <https://github.com/logarrhythmic>
* 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.
* 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
*/
// Cubic filter with Catmull-Rom parameters
float catmull_rom(float x)
{
/* A generalized cubic filter as described by Mitchell and Netravali is defined by the piecewise equation:
* if abs(x) < 1
* y = 1/6 * ( (12 - 9b - 6c) * abs(x)^3 + (-18 + 12b + 6c) * abs(x)^2 + (6 - 2b) )
* if abs(x) >= 1 and < 2
* y = 1/6 * ( (-1b - 6c) * abs(x)^3 + (6b + 30c) * abs(x)^2 + (-12b - 48c) * abs(x) + (8b + 24c) )
* otherwise
* y = 0
* Generally favorable results in image upscaling are given by the values b = 0 and c = 0.5.
* This is known as the Catmull-Rom filter, and it closely approximates Jinc upscaling with Lanczos input values.
* Placing these values into the piecewise equations gives us a more compact representation of:
* y = 1.5 * abs(x)^3 - 2.5 * abs(x)^2 + 1 // abs(x) < 1
* y = -0.5 * abs(x)^3 + 2.5 * abs(x)^2 - 4 * abs(x) + 2 // 1 <= abs(x) < 2
*/
float t = abs(x); // absolute value of the x coordinate
float t2 = t * t; // t squared
float t3 = t * t * t; // t cubed
if (t < 1)
return 1.5 * t3 - 2.5 * t2 + 1;
else if (t < 2)
return -0.5 * t3 + 2.5 * t2 - 4 * t + 2;
else
return 0;
}
float mitchell(float x)
{
/*
* This is another cubic filter with less aggressive sharpening than Catmull-Rom, which some users may prefer.
* B = 1/3, C = 1/3.
*/
float t = abs(x); // absolute value of the x coordinate
float t2 = t * t; // t squared
float t3 = t * t * t; // t cubed
if (t < 1)
return 7.0/6 * t3 + -2 * t2 + 8.0/9;
else if (t < 2)
return -7.0/18 * t3 + 2 * t2 - 10.0/3 * t + 16.0/9;
else
return 0;
}
float cubic_custom(float x, float b, float c)
{
float t = abs(x); // absolute value of the x coordinate
float t2 = t * t; // t squared
float t3 = t * t * t; // t cubed
if (t < 1)
return 1.0/6 * ( (12 - 9 * b - 6 * c) * t3 + (-18 + 12 * b + 6 * c) * t2 + (6 - 2 * b) );
else if (t < 2)
return 1.0/6 * ( (-1 * b - 6 * c) * t3 + (6 * b + 30 * c) * t2 + (-12 * b - 48 * c) * t + (8 * b + 24 * c) );
else
return 0;
}
#define CR_AR_STRENGTH 0.9
#define FLT_MAX 3.402823466e+38
#define FLT_MIN 1.175494351e-38
// Calculates the distance between two points
float d(vec2 pt1, vec2 pt2)
{
vec2 v = pt2 - pt1;
return sqrt(dot(v,v));
}
// Samples a texture using a 4x4 kernel.
vec4 textureCubic(sampler2D sampler, vec2 texCoords, int mode){
vec2 texSize = textureSize(sampler, 0);
vec2 texelSize = 1.0 / texSize;
texCoords *= texSize;
texCoords -= 0.5;
vec4 nSum = vec4( 0.0, 0.0, 0.0, 0.0 );
vec4 nDenom = vec4( 0.0, 0.0, 0.0, 0.0 );
ivec2 texelCoords = ivec2(floor(texCoords));
vec2 coordFract = fract(texCoords);
vec4 c;
vec4 min_sample = vec4(FLT_MAX);
vec4 max_sample = vec4(FLT_MIN);
for (int m = -1; m <= 2; m++)
{
for (int n = -1; n <= 2; n++)
{
// get the raw texel, bypassing any other filters
vec4 vecData = texelFetch(sampler, texelCoords + ivec2(m, n), 0);
min_sample = min(min_sample, vecData);
max_sample = max(max_sample, vecData);
float w;
// calculate weight based on distance of the current texel offset from the sub-texel position of the sampling location
switch (mode){
case SAMPLING_CATROM:
w = catmull_rom( d(vec2(m, n), coordFract) );
break;
case SAMPLING_MITCHELL:
w = mitchell( d(vec2(m, n), coordFract) );
break;
default:
w = 0;
break;
}
// build the weighted average
nSum += vecData * w;
nDenom += w;
}
}
// calculate weighted average
c = nSum / nDenom;
if (mode == SAMPLING_CATROM) {
// anti-ringing
vec4 aux = c;
c = clamp(c, min_sample, max_sample);
c = mix(aux, c, CR_AR_STRENGTH);
}
// return the weighted average
return c;
}

View File

@@ -0,0 +1,37 @@
/*
Hyllian's xBR-lv2 Shader
Copyright (C) 2011-2016 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.
*/
struct XBRTable
{
vec2 texCoord;
vec4 t1;
vec4 t2;
vec4 t3;
vec4 t4;
vec4 t5;
vec4 t6;
vec4 t7;
};

View File

@@ -0,0 +1,239 @@
/*
Hyllian's xBR-lv2 Shader
Copyright (C) 2011-2016 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.
*/
#define mul(a,b) (b*a)
// Uncomment just one of the three params below to choose the corner detection
//#define CORNER_A
//#define CORNER_B
#define CORNER_C
//#define CORNER_D
#ifndef CORNER_A
#define SMOOTH_TIPS
#endif
#define lv2_cf XBR_LV2_COEFFICIENT
#define XBR_Y_WEIGHT 48.0
#define XBR_EQ_THRESHOLD 15.0
#define XBR_LV1_COEFFICIENT 0.5
#define XBR_LV2_COEFFICIENT 2.0
#define small_details 1.0
// END PARAMETERS //
const float coef = 2.0;
const vec3 rgbw = vec3(14.352, 28.176, 5.472);
const vec4 eq_threshold = vec4(15.0, 15.0, 15.0, 15.0);
const vec4 Ao = vec4( 1.0, -1.0, -1.0, 1.0 );
const vec4 Bo = vec4( 1.0, 1.0, -1.0,-1.0 );
const vec4 Co = vec4( 1.5, 0.5, -0.5, 0.5 );
const vec4 Ax = vec4( 1.0, -1.0, -1.0, 1.0 );
const vec4 Bx = vec4( 0.5, 2.0, -0.5,-2.0 );
const vec4 Cx = vec4( 1.0, 1.0, -0.5, 0.0 );
const vec4 Ay = vec4( 1.0, -1.0, -1.0, 1.0 );
const vec4 By = vec4( 2.0, 0.5, -2.0,-0.5 );
const vec4 Cy = vec4( 2.0, 0.0, -1.0, 0.5 );
const vec4 Ci = vec4(0.25, 0.25, 0.25, 0.25);
const vec3 Y = vec3(0.2126, 0.7152, 0.0722);
// Difference between vector components.
vec4 df(vec4 A, vec4 B)
{
return vec4(abs(A-B));
}
// Compare two vectors and return their components are different.
vec4 diff(vec4 A, vec4 B)
{
return vec4(notEqual(A, B));
}
// Determine if two vector components are equal based on a threshold.
vec4 eq(vec4 A, vec4 B)
{
return (step(df(A, B), vec4(XBR_EQ_THRESHOLD)));
}
// Determine if two vector components are NOT equal based on a threshold.
vec4 neq(vec4 A, vec4 B)
{
return (vec4(1.0, 1.0, 1.0, 1.0) - eq(A, B));
}
// Weighted distance.
vec4 wd(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));
}
vec4 weighted_distance(vec4 a, vec4 b, vec4 c, vec4 d, vec4 e, vec4 f, vec4 g, vec4 h, vec4 i, vec4 j, vec4 k, vec4 l)
{
return (df(a,b) + df(a,c) + df(d,e) + df(d,f) + df(i,j) + df(k,l) + 2.0*df(g,h));
}
float c_df(vec3 c1, vec3 c2)
{
vec3 df = abs(c1 - c2);
return df.r + df.g + df.b;
}
#include scale/xbr_lv2_common.glsl
vec3 textureXBR(sampler2D image, vec2 texCoord, XBRTable t, float scale)
{
vec4 delta = vec4(1.0/scale, 1.0/scale, 1.0/scale, 1.0/scale);
vec4 delta_l = vec4(0.5/scale, 1.0/scale, 0.5/scale, 1.0/scale);
vec4 delta_u = delta_l.yxwz;
vec2 textureDimensions = textureSize(image, 0);
vec4 edri, edr, edr_l, edr_u, px; // px = pixel, edr = edge detection rule
vec4 irlv0, irlv1, irlv2l, irlv2u, block_3d;
vec4 fx, fx_l, fx_u; // inequations of straight lines.
vec2 fp = fract(texCoord*textureDimensions);
vec3 A1 = texture(image, t.t1.xw ).xyz;
vec3 B1 = texture(image, t.t1.yw ).xyz;
vec3 C1 = texture(image, t.t1.zw ).xyz;
vec3 A = texture(image, t.t2.xw ).xyz;
vec3 B = texture(image, t.t2.yw ).xyz;
vec3 C = texture(image, t.t2.zw ).xyz;
vec3 D = texture(image, t.t3.xw ).xyz;
vec3 E = texture(image, t.t3.yw ).xyz;
vec3 F = texture(image, t.t3.zw ).xyz;
vec3 G = texture(image, t.t4.xw ).xyz;
vec3 H = texture(image, t.t4.yw ).xyz;
vec3 I = texture(image, t.t4.zw ).xyz;
vec3 G5 = texture(image, t.t5.xw ).xyz;
vec3 H5 = texture(image, t.t5.yw ).xyz;
vec3 I5 = texture(image, t.t5.zw ).xyz;
vec3 A0 = texture(image, t.t6.xy ).xyz;
vec3 D0 = texture(image, t.t6.xz ).xyz;
vec3 G0 = texture(image, t.t6.xw ).xyz;
vec3 C4 = texture(image, t.t7.xy ).xyz;
vec3 F4 = texture(image, t.t7.xz ).xyz;
vec3 I4 = texture(image, t.t7.xw ).xyz;
vec4 b = vec4(dot(B ,rgbw), dot(D ,rgbw), dot(H ,rgbw), dot(F ,rgbw));
vec4 c = vec4(dot(C ,rgbw), dot(A ,rgbw), dot(G ,rgbw), dot(I ,rgbw));
vec4 d = b.yzwx;
vec4 e = vec4(dot(E,rgbw));
vec4 f = b.wxyz;
vec4 g = c.zwxy;
vec4 h = b.zwxy;
vec4 i = c.wxyz;
vec4 i4, i5, h5, f4;
float y_weight = XBR_Y_WEIGHT;
if (small_details < 0.5)
{
i4 = vec4(dot(I4,rgbw), dot(C1,rgbw), dot(A0,rgbw), dot(G5,rgbw));
i5 = vec4(dot(I5,rgbw), dot(C4,rgbw), dot(A1,rgbw), dot(G0,rgbw));
h5 = vec4(dot(H5,rgbw), dot(F4,rgbw), dot(B1,rgbw), dot(D0,rgbw));
}
else
{
i4 = mul( mat4x3(I4, C1, A0, G5), y_weight * Y );
i5 = mul( mat4x3(I5, C4, A1, G0), y_weight * Y );
h5 = mul( mat4x3(H5, F4, B1, D0), y_weight * Y );
}
// These inequations define the line below which interpolation occurs.
fx = (Ao*fp.y+Bo*fp.x);
fx_l = (Ax*fp.y+Bx*fp.x);
fx_u = (Ay*fp.y+By*fp.x);
irlv1 = irlv0 = diff(e,f) * diff(e,h);
#ifdef CORNER_B
irlv1 = (irlv0 * ( neq(f,b) * neq(h,d) + eq(e,i) * neq(f,i4) * neq(h,i5) + eq(e,g) + eq(e,c) ) );
#endif
#ifdef CORNER_D
vec4 c1 = i4.yzwx;
vec4 g0 = i5.wxyz;
irlv1 = (irlv0 * ( neq(f,b) * neq(h,d) + eq(e,i) * neq(f,i4) * neq(h,i5) + eq(e,g) + eq(e,c) ) * (diff(f,f4) * diff(f,i) + diff(h,h5) * diff(h,i) + diff(h,g) + diff(f,c) + eq(b,c1) * eq(d,g0)));
#endif
#ifdef CORNER_C
irlv1 = (irlv0 * ( neq(f,b) * neq(f,c) + neq(h,d) * neq(h,g) + eq(e,i) * (neq(f,f4) * neq(f,i4) + neq(h,h5) * neq(h,i5)) + eq(e,g) + eq(e,c)) );
#endif
irlv2l = diff(e,g) * diff(d,g);
irlv2u = diff(e,c) * diff(b,c);
vec4 fx45i = clamp((fx + delta -Co - Ci)/(2.0*delta ), 0.0, 1.0);
vec4 fx45 = clamp((fx + delta -Co )/(2.0*delta ), 0.0, 1.0);
vec4 fx30 = clamp((fx_l + delta_l -Cx )/(2.0*delta_l), 0.0, 1.0);
vec4 fx60 = clamp((fx_u + delta_u -Cy )/(2.0*delta_u), 0.0, 1.0);
vec4 wd1, wd2;
if (small_details < 0.5)
{
wd1 = wd( e, c, g, i, h5, f4, h, f);
wd2 = wd( h, d, i5, f, i4, b, e, i);
}
else
{
wd1 = weighted_distance( e, c, g, i, f4, h5, h, f, b, d, i4, i5);
wd2 = weighted_distance( h, d, i5, f, b, i4, e, i, g, h5, c, f4);
}
edri = step(wd1, wd2) * irlv0;
edr = step(wd1 + vec4(0.1, 0.1, 0.1, 0.1), wd2) * step(vec4(0.5, 0.5, 0.5, 0.5), irlv1);
edr_l = step( lv2_cf*df(f,g), df(h,c) ) * irlv2l * edr;
edr_u = step( lv2_cf*df(h,c), df(f,g) ) * irlv2u * edr;
fx45 = edr * fx45;
fx30 = edr_l * fx30;
fx60 = edr_u * fx60;
fx45i = edri * fx45i;
px = step(df(e,f), df(e,h));
#ifdef SMOOTH_TIPS
vec4 maximos = max(max(fx30, fx60), max(fx45, fx45i));
#endif
#ifndef SMOOTH_TIPS
vec4 maximos = max(max(fx30, fx60), fx45);
#endif
vec3 res1 = E;
res1 = mix(res1, mix(H, F, px.x), maximos.x);
res1 = mix(res1, mix(B, D, px.z), maximos.z);
vec3 res2 = E;
res2 = mix(res2, mix(F, B, px.y), maximos.y);
res2 = mix(res2, mix(D, H, px.w), maximos.w);
vec3 res = mix(res1, res2, step(c_df(E, res1), c_df(E, res2)));
return res;
}

View File

@@ -0,0 +1,48 @@
/*
Hyllian's xBR-lv2 Shader
Copyright (C) 2011-2016 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.
*/
#include scale/xbr_lv2_common.glsl
XBRTable xbr_vert(vec2 texCoord, ivec2 sourceDimensions)
{
float dx = (1.0/sourceDimensions.x);
float dy = (1.0/sourceDimensions.y);
XBRTable tab = XBRTable(
texCoord,
texCoord.xxxy + vec4( -dx, 0, dx,-2.0*dy), // A1 B1 C1
texCoord.xxxy + vec4( -dx, 0, dx, -dy), // A B C
texCoord.xxxy + vec4( -dx, 0, dx, 0), // D E F
texCoord.xxxy + vec4( -dx, 0, dx, dy), // G H I
texCoord.xxxy + vec4( -dx, 0, dx, 2.0*dy), // G5 H5 I5
texCoord.xyyy + vec4(-2.0*dx,-dy, 0, dy), // A0 D0 G0
texCoord.xyyy + vec4( 2.0*dx,-dy, 0, dy) // C4 F4 I4
);
tab.texCoord.x *= 1.00000001;
return tab;
}

View File

@@ -24,13 +24,27 @@
*/
#version 330
#define SAMPLING_DEFAULT 0
#define SAMPLING_MITCHELL 1
#define SAMPLING_CATROM 2
#define SAMPLING_XBR 3
uniform int samplingMode;
uniform ivec2 sourceDimensions;
uniform ivec2 targetDimensions;
#include scale/xbr_lv2_vert.glsl
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec2 aTexCoord;
out vec2 TexCoord;
out XBRTable xbrTable;
void main()
{
gl_Position = vec4(aPos, 1.0);
TexCoord = aTexCoord;
if (samplingMode == SAMPLING_XBR)
xbrTable = xbr_vert(TexCoord, sourceDimensions);
}