diff --git a/config/ConfigFormUnit.cpp b/config/ConfigFormUnit.cpp index ed1c372..1e5bdac 100644 --- a/config/ConfigFormUnit.cpp +++ b/config/ConfigFormUnit.cpp @@ -788,6 +788,7 @@ void __fastcall TConfigForm::FormCreate(TObject *Sender) ShaderCbx->AddItem("Bilinear", NULL); ShaderCbx->AddItem("Bicubic", NULL); ShaderCbx->AddItem("Lanczos", NULL); + ShaderCbx->AddItem("xBR-lv2", NULL); } auto shader = ini->ReadString("ddraw", "shader", "Bicubic"); diff --git a/inc/openglshader.h b/inc/openglshader.h index e84b60c..2e2875a 100644 --- a/inc/openglshader.h +++ b/inc/openglshader.h @@ -262,5 +262,351 @@ static char LANCZOS2_FRAG_SHADER[] = " FragColor.xyz = color;\n" "}\n"; +/* +// The following code is licensed under the MIT license: +// Hyllian's xBR-lv2 Shader +// Copyright (C) 2011-2016 Hyllian - sergiogdb@gmail.com +// https://github.com/libretro/glsl-shaders/blob/09e2942efbab2f51b60ff0b93b7761b0b0570910/xbr/shaders/xbr-lv2.glsl +*/ + +static char XBR_LV2_VERT_SHADER[] = + "#version 130\n" + " \n" + "#define texCoord TEX0\n" + "#define t1 TEX1\n" + "#define t2 TEX2\n" + "#define t3 TEX3\n" + "#define t4 TEX4\n" + "#define t5 TEX5\n" + "#define t6 TEX6\n" + "#define t7 TEX7\n" + "\n" + "in vec4 VertexCoord;\n" + "in vec4 Color;\n" + "in vec2 TexCoord;\n" + "\n" + "out vec4 color;\n" + "out vec2 texCoord;\n" + "out vec4 t1;\n" + "out vec4 t2;\n" + "out vec4 t3;\n" + "out vec4 t4;\n" + "out vec4 t5;\n" + "out vec4 t6;\n" + "out vec4 t7;\n" + "\n" + "uniform mat4 MVPMatrix;\n" + "uniform int FrameDirection;\n" + "uniform int FrameCount;\n" + "uniform vec2 OutputSize;\n" + "uniform vec2 TextureSize;\n" + "uniform vec2 InputSize;\n" + "\n" + "void main()\n" + "{\n" + " gl_Position = MVPMatrix * VertexCoord;\n" + " color = Color;\n" + "\n" + " float dx = (1.0/TextureSize.x);\n" + " float dy = (1.0/TextureSize.y);\n" + "\n" + " texCoord = TexCoord;\n" + " texCoord.x *= 1.00000001;\n" + " t1 = TexCoord.xxxy + vec4( -dx, 0, dx,-2.0*dy); // A1 B1 C1\n" + " t2 = TexCoord.xxxy + vec4( -dx, 0, dx, -dy); // A B C\n" + " t3 = TexCoord.xxxy + vec4( -dx, 0, dx, 0); // D E F\n" + " t4 = TexCoord.xxxy + vec4( -dx, 0, dx, dy); // G H I\n" + " t5 = TexCoord.xxxy + vec4( -dx, 0, dx, 2.0*dy); // G5 H5 I5\n" + " t6 = TexCoord.xyyy + vec4(-2.0*dx,-dy, 0, dy); // A0 D0 G0\n" + " t7 = TexCoord.xyyy + vec4( 2.0*dx,-dy, 0, dy); // C4 F4 I4\n" + "}\n"; + +static char XBR_LV2_FRAG_SHADER[] = + "#version 130\n" + "\n" + "//#pragma parameter XBR_SCALE \"xBR Scale\" 3.0 1.0 5.0 1.0\n" + "#pragma parameter XBR_Y_WEIGHT \"Y Weight\" 48.0 0.0 100.0 1.0\n" + "#pragma parameter XBR_EQ_THRESHOLD \"Eq Threshold\" 15.0 0.0 50.0 1.0\n" + "#pragma parameter XBR_LV1_COEFFICIENT \"Lv1 Coefficient\" 0.5 0.0 30.0 0.5\n" + "#pragma parameter XBR_LV2_COEFFICIENT \"Lv2 Coefficient\" 2.0 1.0 3.0 0.1\n" + "#pragma parameter small_details \"Preserve Small Details\" 0.0 0.0 1.0 1.0\n" + "\n" + "#define mul(a,b) (b*a)\n" + "\n" + "// Uncomment just one of the three params below to choose the corner detection\n" + "//#define CORNER_A\n" + "//#define CORNER_B\n" + "#define CORNER_C\n" + "//#define CORNER_D\n" + "\n" + "#ifndef CORNER_A\n" + " #define SMOOTH_TIPS\n" + "#endif\n" + "\n" + "#define XBR_SCALE 3.0\n" + "\n" + "#define lv2_cf XBR_LV2_COEFFICIENT\n" + " \n" + "#define texCoord TEX0\n" + "#define t1 TEX1\n" + "#define t2 TEX2\n" + "#define t3 TEX3\n" + "#define t4 TEX4\n" + "#define t5 TEX5\n" + "#define t6 TEX6\n" + "#define t7 TEX7\n" + "\n" + "\n" + "//#pragma parameter XBR_SCALE \"xBR Scale\" 3.0 1.0 5.0 1.0\n" + "#pragma parameter XBR_Y_WEIGHT \"Y Weight\" 48.0 0.0 100.0 1.0\n" + "#pragma parameter XBR_EQ_THRESHOLD \"Eq Threshold\" 15.0 0.0 50.0 1.0\n" + "#pragma parameter XBR_LV1_COEFFICIENT \"Lv1 Coefficient\" 0.5 0.0 30.0 0.5\n" + "#pragma parameter XBR_LV2_COEFFICIENT \"Lv2 Coefficient\" 2.0 1.0 3.0 0.1\n" + "#pragma parameter small_details \"Preserve Small Details\" 0.0 0.0 1.0 1.0\n" + "\n" + "#define mul(a,b) (b*a)\n" + "\n" + "// Uncomment just one of the three params below to choose the corner detection\n" + "//#define CORNER_A\n" + "//#define CORNER_B\n" + "#define CORNER_C\n" + "//#define CORNER_D\n" + "\n" + "#ifndef CORNER_A\n" + " #define SMOOTH_TIPS\n" + "#endif\n" + "\n" + "#define XBR_SCALE 3.0\n" + "\n" + "#define lv2_cf XBR_LV2_COEFFICIENT\n" + " \n" + "#define texCoord TEX0\n" + "#define t1 TEX1\n" + "#define t2 TEX2\n" + "#define t3 TEX3\n" + "#define t4 TEX4\n" + "#define t5 TEX5\n" + "#define t6 TEX6\n" + "#define t7 TEX7\n" + "\n" + "out vec4 FragColor;\n" + "uniform int FrameDirection;\n" + "uniform int FrameCount;\n" + "uniform vec2 OutputSize;\n" + "uniform vec2 TextureSize;\n" + "uniform vec2 InputSize;\n" + "uniform sampler2D decal;\n" + "in vec2 texCoord;\n" + "in vec4 t1;\n" + "in vec4 t2;\n" + "in vec4 t3;\n" + "in vec4 t4;\n" + "in vec4 t5;\n" + "in vec4 t6;\n" + "in vec4 t7;\n" + "\n" + "#ifdef PARAMETER_UNIFORM\n" + "uniform float XBR_Y_WEIGHT;\n" + "uniform float XBR_EQ_THRESHOLD;\n" + "uniform float XBR_LV1_COEFFICIENT;\n" + "uniform float XBR_LV2_COEFFICIENT;\n" + "uniform float small_details;\n" + "#else\n" + "#define XBR_Y_WEIGHT 48.0\n" + "#define XBR_EQ_THRESHOLD 15.0\n" + "#define XBR_LV1_COEFFICIENT 0.5\n" + "#define XBR_LV2_COEFFICIENT 2.0\n" + "#define small_details 0.0\n" + "#endif\n" + "// END PARAMETERS //\n" + "\n" + "const float coef = 2.0;\n" + "const vec3 rgbw = vec3(14.352, 28.176, 5.472);\n" + "const vec4 eq_threshold = vec4(15.0, 15.0, 15.0, 15.0);\n" + "\n" + "vec4 delta = vec4(1.0/XBR_SCALE, 1.0/XBR_SCALE, 1.0/XBR_SCALE, 1.0/XBR_SCALE);\n" + "vec4 delta_l = vec4(0.5/XBR_SCALE, 1.0/XBR_SCALE, 0.5/XBR_SCALE, 1.0/XBR_SCALE);\n" + "vec4 delta_u = delta_l.yxwz;\n" + "\n" + "const vec4 Ao = vec4( 1.0, -1.0, -1.0, 1.0 );\n" + "const vec4 Bo = vec4( 1.0, 1.0, -1.0,-1.0 );\n" + "const vec4 Co = vec4( 1.5, 0.5, -0.5, 0.5 );\n" + "const vec4 Ax = vec4( 1.0, -1.0, -1.0, 1.0 );\n" + "const vec4 Bx = vec4( 0.5, 2.0, -0.5,-2.0 );\n" + "const vec4 Cx = vec4( 1.0, 1.0, -0.5, 0.0 );\n" + "const vec4 Ay = vec4( 1.0, -1.0, -1.0, 1.0 );\n" + "const vec4 By = vec4( 2.0, 0.5, -2.0,-0.5 );\n" + "const vec4 Cy = vec4( 2.0, 0.0, -1.0, 0.5 );\n" + "const vec4 Ci = vec4(0.25, 0.25, 0.25, 0.25);\n" + "\n" + "const vec3 Y = vec3(0.2126, 0.7152, 0.0722);\n" + "\n" + "// Difference between vector components.\n" + "vec4 df(vec4 A, vec4 B)\n" + "{\n" + " return vec4(abs(A-B));\n" + "}\n" + "\n" + "// Compare two vectors and return their components are different.\n" + "vec4 diff(vec4 A, vec4 B)\n" + "{\n" + " return vec4(notEqual(A, B));\n" + "}\n" + "\n" + "// Determine if two vector components are equal based on a threshold.\n" + "vec4 eq(vec4 A, vec4 B)\n" + "{\n" + " return (step(df(A, B), vec4(XBR_EQ_THRESHOLD)));\n" + "}\n" + "\n" + "// Determine if two vector components are NOT equal based on a threshold.\n" + "vec4 neq(vec4 A, vec4 B)\n" + "{\n" + " return (vec4(1.0, 1.0, 1.0, 1.0) - eq(A, B));\n" + "}\n" + "\n" + "// Weighted distance.\n" + "vec4 wd(vec4 a, vec4 b, vec4 c, vec4 d, vec4 e, vec4 f, vec4 g, vec4 h)\n" + "{\n" + " return (df(a,b) + df(a,c) + df(d,e) + df(d,f) + 4.0*df(g,h));\n" + "}\n" + "\n" + "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)\n" + "{\n" + " return (df(a,b) + df(a,c) + df(d,e) + df(d,f) + df(i,j) + df(k,l) + 2.0*df(g,h));\n" + "}\n" + "\n" + "float c_df(vec3 c1, vec3 c2) \n" + "{\n" + " vec3 df = abs(c1 - c2);\n" + " return df.r + df.g + df.b;\n" + "}\n" + "\n" + "void main()\n" + "{\n" + " vec4 edri, edr, edr_l, edr_u, px; // px = pixel, edr = edge detection rule\n" + " vec4 irlv0, irlv1, irlv2l, irlv2u, block_3d;\n" + " vec4 fx, fx_l, fx_u; // inequations of straight lines.\n" + "\n" + " vec2 fp = fract(texCoord*TextureSize);\n" + "\n" + " vec3 A1 = texture(decal, t1.xw ).xyz;\n" + " vec3 B1 = texture(decal, t1.yw ).xyz;\n" + " vec3 C1 = texture(decal, t1.zw ).xyz;\n" + " vec3 A = texture(decal, t2.xw ).xyz;\n" + " vec3 B = texture(decal, t2.yw ).xyz;\n" + " vec3 C = texture(decal, t2.zw ).xyz;\n" + " vec3 D = texture(decal, t3.xw ).xyz;\n" + " vec3 E = texture(decal, t3.yw ).xyz;\n" + " vec3 F = texture(decal, t3.zw ).xyz;\n" + " vec3 G = texture(decal, t4.xw ).xyz;\n" + " vec3 H = texture(decal, t4.yw ).xyz;\n" + " vec3 I = texture(decal, t4.zw ).xyz;\n" + " vec3 G5 = texture(decal, t5.xw ).xyz;\n" + " vec3 H5 = texture(decal, t5.yw ).xyz;\n" + " vec3 I5 = texture(decal, t5.zw ).xyz;\n" + " vec3 A0 = texture(decal, t6.xy ).xyz;\n" + " vec3 D0 = texture(decal, t6.xz ).xyz;\n" + " vec3 G0 = texture(decal, t6.xw ).xyz;\n" + " vec3 C4 = texture(decal, t7.xy ).xyz;\n" + " vec3 F4 = texture(decal, t7.xz ).xyz;\n" + " vec3 I4 = texture(decal, t7.xw ).xyz;\n" + "\n" + " vec4 b = vec4(dot(B ,rgbw), dot(D ,rgbw), dot(H ,rgbw), dot(F ,rgbw));\n" + " vec4 c = vec4(dot(C ,rgbw), dot(A ,rgbw), dot(G ,rgbw), dot(I ,rgbw));\n" + " vec4 d = b.yzwx;\n" + " vec4 e = vec4(dot(E,rgbw));\n" + " vec4 f = b.wxyz;\n" + " vec4 g = c.zwxy;\n" + " vec4 h = b.zwxy;\n" + " vec4 i = c.wxyz;\n" + " \n" + " vec4 i4, i5, h5, f4;\n" + " \n" + " float y_weight = XBR_Y_WEIGHT;\n" + " \n" + " if (small_details < 0.5)\n" + " {\n" + " i4 = vec4(dot(I4,rgbw), dot(C1,rgbw), dot(A0,rgbw), dot(G5,rgbw));\n" + " i5 = vec4(dot(I5,rgbw), dot(C4,rgbw), dot(A1,rgbw), dot(G0,rgbw));\n" + " h5 = vec4(dot(H5,rgbw), dot(F4,rgbw), dot(B1,rgbw), dot(D0,rgbw));\n" + " }\n" + " else\n" + " {\n" + " i4 = mul( mat4x3(I4, C1, A0, G5), y_weight * Y );\n" + " i5 = mul( mat4x3(I5, C4, A1, G0), y_weight * Y );\n" + " h5 = mul( mat4x3(H5, F4, B1, D0), y_weight * Y );\n" + " }\n" + "\n" + " // These inequations define the line below which interpolation occurs.\n" + " fx = (Ao*fp.y+Bo*fp.x); \n" + " fx_l = (Ax*fp.y+Bx*fp.x);\n" + " fx_u = (Ay*fp.y+By*fp.x);\n" + "\n" + " irlv1 = irlv0 = diff(e,f) * diff(e,h);\n" + "\n" + "#ifdef CORNER_B\n" + " irlv1 = (irlv0 * ( neq(f,b) * neq(h,d) + eq(e,i) * neq(f,i4) * neq(h,i5) + eq(e,g) + eq(e,c) ) );\n" + "#endif\n" + "#ifdef CORNER_D\n" + " vec4 c1 = i4.yzwx;\n" + " vec4 g0 = i5.wxyz;\n" + " 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)));\n" + "#endif\n" + "#ifdef CORNER_C\n" + " 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)) );\n" + "#endif\n" + "\n" + " irlv2l = diff(e,g) * diff(d,g);\n" + " irlv2u = diff(e,c) * diff(b,c);\n" + "\n" + " vec4 fx45i = clamp((fx + delta -Co - Ci)/(2.0*delta ), 0.0, 1.0);\n" + " vec4 fx45 = clamp((fx + delta -Co )/(2.0*delta ), 0.0, 1.0);\n" + " vec4 fx30 = clamp((fx_l + delta_l -Cx )/(2.0*delta_l), 0.0, 1.0);\n" + " vec4 fx60 = clamp((fx_u + delta_u -Cy )/(2.0*delta_u), 0.0, 1.0);\n" + "\n" + " vec4 wd1, wd2;\n" + " if (small_details < 0.5)\n" + " {\n" + " wd1 = wd( e, c, g, i, h5, f4, h, f);\n" + " wd2 = wd( h, d, i5, f, i4, b, e, i);\n" + " }\n" + " else\n" + " {\n" + " wd1 = weighted_distance( e, c, g, i, f4, h5, h, f, b, d, i4, i5);\n" + " wd2 = weighted_distance( h, d, i5, f, b, i4, e, i, g, h5, c, f4);\n" + " }\n" + "\n" + " edri = step(wd1, wd2) * irlv0;\n" + " edr = step(wd1 + vec4(0.1, 0.1, 0.1, 0.1), wd2) * step(vec4(0.5, 0.5, 0.5, 0.5), irlv1);\n" + " edr_l = step( lv2_cf*df(f,g), df(h,c) ) * irlv2l * edr;\n" + " edr_u = step( lv2_cf*df(h,c), df(f,g) ) * irlv2u * edr;\n" + "\n" + " fx45 = edr * fx45;\n" + " fx30 = edr_l * fx30;\n" + " fx60 = edr_u * fx60;\n" + " fx45i = edri * fx45i;\n" + "\n" + " px = step(df(e,f), df(e,h));\n" + "\n" + "#ifdef SMOOTH_TIPS\n" + " vec4 maximos = max(max(fx30, fx60), max(fx45, fx45i));\n" + "#endif\n" + "#ifndef SMOOTH_TIPS\n" + " vec4 maximos = max(max(fx30, fx60), fx45);\n" + "#endif\n" + "\n" + " vec3 res1 = E;\n" + " res1 = mix(res1, mix(H, F, px.x), maximos.x);\n" + " res1 = mix(res1, mix(B, D, px.z), maximos.z);\n" + " \n" + " vec3 res2 = E;\n" + " res2 = mix(res2, mix(F, B, px.y), maximos.y);\n" + " res2 = mix(res2, mix(D, H, px.w), maximos.w);\n" + " \n" + " vec3 res = mix(res1, res2, step(c_df(E, res1), c_df(E, res2)));\n" + "\n" + " FragColor.xyz = res;\n" + "}\n"; #endif diff --git a/src/config.c b/src/config.c index 28c4bf9..5756745 100644 --- a/src/config.c +++ b/src/config.c @@ -276,7 +276,7 @@ static void cfg_create_ini() "; Preliminary libretro shader support - (Requires 'renderer=opengl*') https://github.com/libretro/glsl-shaders\n" "; 2x scaling example: https://imgur.com/a/kxsM1oY - 4x scaling example: https://imgur.com/a/wjrhpFV\n" "; You can specify a full path to a .glsl shader file here or use one of the values listed below\n" - "; Possible values: Nearest neighbor, Bilinear, Bicubic, Lanczos\n" + "; Possible values: Nearest neighbor, Bilinear, Bicubic, Lanczos, xBR-lv2\n" "shader=Shaders\\cubic\\catmull-rom-bilinear.glsl\n" "\n" "; Window position, -32000 = center to screen\n" diff --git a/src/render_ogl.c b/src/render_ogl.c index 2a9871c..160e0bd 100644 --- a/src/render_ogl.c +++ b/src/render_ogl.c @@ -179,16 +179,19 @@ static void ogl_build_programs() { g_ogl.scale_program = oglu_build_program( + _stricmp(g_ddraw->shader, "xBR-lv2") == 0 ? XBR_LV2_VERT_SHADER : PASSTHROUGH_VERT_SHADER, _stricmp(g_ddraw->shader, "Nearest neighbor") == 0 ? PASSTHROUGH_FRAG_SHADER : _stricmp(g_ddraw->shader, "Bilinear") == 0 ? PASSTHROUGH_FRAG_SHADER : _stricmp(g_ddraw->shader, "Lanczos") == 0 ? LANCZOS2_FRAG_SHADER : + _stricmp(g_ddraw->shader, "xBR-lv2") == 0 ? XBR_LV2_FRAG_SHADER : CATMULL_ROM_FRAG_SHADER, core_profile); bilinear = _stricmp(g_ddraw->shader, "Nearest neighbor") != 0 && - _stricmp(g_ddraw->shader, "Lanczos") != 0; + _stricmp(g_ddraw->shader, "Lanczos") != 0 && + _stricmp(g_ddraw->shader, "xBR-lv2") != 0; } } }