From a56e6e0987674af205cf91bd526dd13d42eb6754 Mon Sep 17 00:00:00 2001 From: Splendide Imaginarius <119545140+Splendide-Imaginarius@users.noreply.github.com> Date: Tue, 31 Oct 2023 12:42:24 +0000 Subject: [PATCH] Add bicubic scaling --- mkxp.json | 2 +- shader/bicubic.frag | 41 ++++++++++++++++++++++++++++++++++++++ shader/meson.build | 1 + src/display/gl/gl-meta.cpp | 18 +++++++++++++++++ src/display/gl/shader.cpp | 15 ++++++++++++++ src/display/gl/shader.h | 10 ++++++++++ src/etc/etc.h | 2 +- 7 files changed, 87 insertions(+), 2 deletions(-) create mode 100644 shader/bicubic.frag diff --git a/mkxp.json b/mkxp.json index f1f06f35..78f37212 100644 --- a/mkxp.json +++ b/mkxp.json @@ -81,7 +81,7 @@ // is upscaled // 0: Nearest-Neighbor // 1: Bilinear - // 2: (Reserved) + // 2: Bicubic // 3: Lanczos3 // (default: 0) // diff --git a/shader/bicubic.frag b/shader/bicubic.frag new file mode 100644 index 00000000..645017b3 --- /dev/null +++ b/shader/bicubic.frag @@ -0,0 +1,41 @@ +// From https://raw.githubusercontent.com/Sentmoraap/doing-sdl-right/f1a0183692abbd5d899fb432ab8dafe228a4929a/assets/bicubic.frag +// Copyright 2020 Lilian Gimenez (Sentmoraap). +// mkxp-z modifications Copyright 2022-2023 Splendide Imaginarius. +// MIT license. + +uniform sampler2D texture; +uniform vec2 sourceSize; +uniform vec2 texSizeInv; +varying vec2 v_texCoord; +uniform vec2 bc; + +void main() +{ + vec2 pixel = v_texCoord * sourceSize + 0.5; + vec2 frac = fract(pixel); + vec2 frac2 = frac * frac; + vec2 frac3 = frac * frac2; + vec2 onePixel = texSizeInv; + pixel = floor(pixel) * texSizeInv - onePixel / 2.0; + vec4 colours[4]; + // 16 reads, unoptimized but forks for every Mitchell-Netravali filter + for(int i = -1; i <= 2; i++) + { + vec4 p0 = texture2D(texture, pixel + vec2( -onePixel.x, float(i) * onePixel.y)).rgba; + vec4 p1 = texture2D(texture, pixel + vec2( 0, float(i) * onePixel.y)).rgba; + vec4 p2 = texture2D(texture, pixel + vec2( onePixel.x, float(i) * onePixel.y)).rgba; + vec4 p3 = texture2D(texture, pixel + vec2(2.0 * onePixel.x, float(i) * onePixel.y)).rgba; + colours[i + 1] = ((-bc.x / 6.0 - bc . y) * p0 + (- 1.5 * bc.x - bc.y + 2.0) * p1 + + (1.5 * bc.x + bc.y - 2.0) * p2 + (bc.x / 6.0 + bc.y) * p3) * frac3.x + + ((0.5 * bc.x + 2.0 * bc.y) * p0 + (2.0 * bc.x + bc.y - 3.0) * p1 + + (-2.5 * bc.x - 2.0 * bc.y + 3.0) * p2 - bc.y * p3) * frac2.x + + ((-0.5 * bc.x - bc.y) * p0 + (0.5 * bc.x + bc.y) * p2) * frac.x + + p0 * bc.x / 6.0 + (-bc.x / 3.0 + 1.0) * p1 + p2 * bc.x / 6.0; + } + gl_FragColor = ((-bc.x / 6.0 - bc . y) * colours[0] + (- 1.5 * bc.x - bc.y + 2.0) * colours[1] + + (1.5 * bc.x + bc.y - 2.0) * colours[2] + (bc.x / 6.0 + bc.y) * colours[3]) * frac3.y + + ((0.5 * bc.x + 2.0 * bc.y) * colours[0] + (2.0 * bc.x + bc.y - 3.0) * colours[1] + + (-2.5 * bc.x - 2.0 * bc.y + 3.0) * colours[2] - bc.y * colours[3]) * frac2.y + + ((-0.5 * bc.x - bc.y) * colours[0] + (0.5 * bc.x + bc.y) * colours[2]) * frac.y + + colours[0] * bc.x / 6.0 + (-bc.x / 3.0 + 1.0) * colours[1] + colours[2] * bc.x / 6.0; +} diff --git a/shader/meson.build b/shader/meson.build index 4b5e2496..018518b5 100644 --- a/shader/meson.build +++ b/shader/meson.build @@ -15,6 +15,7 @@ embedded_shaders = [ 'simpleAlphaUni.frag', 'tilemap.frag', 'flashMap.frag', + 'bicubic.frag', 'lanczos3.frag', 'minimal.vert', 'simple.vert', diff --git a/src/display/gl/gl-meta.cpp b/src/display/gl/gl-meta.cpp index ded309a3..938429fd 100644 --- a/src/display/gl/gl-meta.cpp +++ b/src/display/gl/gl-meta.cpp @@ -154,6 +154,16 @@ static void _blitBegin(FBO::ID fbo, const Vec2i &size) switch (shState->config().smoothScaling) { + case Bicubic: + { + BicubicShader &shader = shState->shaders().bicubic; + shader.bind(); + shader.applyViewportProj(); + shader.setTranslation(Vec2i()); + shader.setTexSize(Vec2i(size.x, size.y)); + } + + break; case Lanczos3: { Lanczos3Shader &shader = shState->shaders().lanczos3; @@ -234,6 +244,14 @@ void blitSource(TEXFBO &source) { switch (shState->config().smoothScaling) { + case Bicubic: + { + BicubicShader &shader = shState->shaders().bicubic; + shader.bind(); + shader.setTexSize(Vec2i(blitSrcWidthHires, blitSrcHeightHires)); + } + + break; case Lanczos3: { Lanczos3Shader &shader = shState->shaders().lanczos3; diff --git a/src/display/gl/shader.cpp b/src/display/gl/shader.cpp index 28bb2ed0..c90d6715 100644 --- a/src/display/gl/shader.cpp +++ b/src/display/gl/shader.cpp @@ -46,6 +46,7 @@ #include "simpleAlphaUni.frag.xxd" #include "tilemap.frag.xxd" #include "flashMap.frag.xxd" +#include "bicubic.frag.xxd" #include "lanczos3.frag.xxd" #include "minimal.vert.xxd" #include "simple.vert.xxd" @@ -767,6 +768,20 @@ void BltShader::setOpacity(float value) gl.Uniform1f(u_opacity, value); } +BicubicShader::BicubicShader() +{ + INIT_SHADER(simple, bicubic, BicubicShader); + + ShaderBase::init(); + + GET_U(texOffsetX); + GET_U(sourceSize); + GET_U(bc); + + // TODO: Maybe expose this as a setting? + gl.Uniform2f(u_bc, 0.0, 0.5); +} + Lanczos3Shader::Lanczos3Shader() { INIT_SHADER(simple, lanczos3, Lanczos3Shader); diff --git a/src/display/gl/shader.h b/src/display/gl/shader.h index fd79dfbc..5dd3dbda 100644 --- a/src/display/gl/shader.h +++ b/src/display/gl/shader.h @@ -341,6 +341,15 @@ protected: GLint u_sourceSize; }; +class BicubicShader : public Lanczos3Shader +{ +public: + BicubicShader(); + +protected: + GLint u_bc; +}; + /* Global object containing all available shaders */ struct ShaderSet { @@ -362,6 +371,7 @@ struct ShaderSet SimpleMatrixShader simpleMatrix; BlurShader blur; TilemapVXShader tilemapVX; + BicubicShader bicubic; Lanczos3Shader lanczos3; }; diff --git a/src/etc/etc.h b/src/etc/etc.h index a7e79861..5a926c1e 100644 --- a/src/etc/etc.h +++ b/src/etc/etc.h @@ -204,7 +204,7 @@ enum InterpolationMethod { NearestNeighbor = 0, Bilinear = 1, - // Reserving 2 for Bicubic + Bicubic = 2, Lanczos3 = 3, };