diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index a6f9860eb..53dbfe7b0 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt @@ -100,10 +100,8 @@ add_library(video_core STATIC set(SHADER_FILES renderer_opengl/texture_filters/anime4k/refine.frag - renderer_opengl/texture_filters/anime4k/refine.vert renderer_opengl/texture_filters/anime4k/x_gradient.frag renderer_opengl/texture_filters/anime4k/y_gradient.frag - renderer_opengl/texture_filters/anime4k/y_gradient.vert renderer_opengl/texture_filters/bicubic/bicubic.frag renderer_opengl/texture_filters/scale_force/scale_force.frag renderer_opengl/texture_filters/tex_coord.vert diff --git a/src/video_core/renderer_opengl/texture_filters/anime4k/anime4k_ultrafast.cpp b/src/video_core/renderer_opengl/texture_filters/anime4k/anime4k_ultrafast.cpp index b70cc14f4..69fda08a9 100644 --- a/src/video_core/renderer_opengl/texture_filters/anime4k/anime4k_ultrafast.cpp +++ b/src/video_core/renderer_opengl/texture_filters/anime4k/anime4k_ultrafast.cpp @@ -34,30 +34,14 @@ #include "video_core/renderer_opengl/texture_filters/anime4k/anime4k_ultrafast.h" #include "shaders/refine.frag" -#include "shaders/refine.vert" #include "shaders/tex_coord.vert" #include "shaders/x_gradient.frag" #include "shaders/y_gradient.frag" -#include "shaders/y_gradient.vert" namespace OpenGL { Anime4kUltrafast::Anime4kUltrafast(u16 scale_factor) : TextureFilterBase(scale_factor) { const OpenGLState cur_state = OpenGLState::GetCurState(); - const auto setup_temp_tex = [this](TempTex& texture, GLint internal_format, GLint format) { - texture.fbo.Create(); - texture.tex.Create(); - state.draw.draw_framebuffer = texture.fbo.handle; - state.Apply(); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_RECTANGLE, texture.tex.handle); - glTexImage2D(GL_TEXTURE_RECTANGLE, 0, internal_format, 1024 * internal_scale_factor, - 1024 * internal_scale_factor, 0, format, GL_HALF_FLOAT, nullptr); - glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE, - texture.tex.handle, 0); - }; - setup_temp_tex(LUMAD, GL_R16F, GL_RED); - setup_temp_tex(XY, GL_RG16F, GL_RG); vao.Create(); @@ -65,17 +49,17 @@ Anime4kUltrafast::Anime4kUltrafast(u16 scale_factor) : TextureFilterBase(scale_f samplers[idx].Create(); state.texture_units[idx].sampler = samplers[idx].handle; glSamplerParameteri(samplers[idx].handle, GL_TEXTURE_MIN_FILTER, - idx == 0 ? GL_LINEAR : GL_NEAREST); + idx != 2 ? GL_LINEAR : GL_NEAREST); glSamplerParameteri(samplers[idx].handle, GL_TEXTURE_MAG_FILTER, - idx == 0 ? GL_LINEAR : GL_NEAREST); + idx != 2 ? GL_LINEAR : GL_NEAREST); glSamplerParameteri(samplers[idx].handle, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glSamplerParameteri(samplers[idx].handle, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); } state.draw.vertex_array = vao.handle; gradient_x_program.Create(tex_coord_vert.data(), x_gradient_frag.data()); - gradient_y_program.Create(y_gradient_vert.data(), y_gradient_frag.data()); - refine_program.Create(refine_vert.data(), refine_frag.data()); + gradient_y_program.Create(tex_coord_vert.data(), y_gradient_frag.data()); + refine_program.Create(tex_coord_vert.data(), refine_frag.data()); state.draw.shader_program = gradient_y_program.handle; state.Apply(); @@ -84,8 +68,6 @@ Anime4kUltrafast::Anime4kUltrafast(u16 scale_factor) : TextureFilterBase(scale_f state.draw.shader_program = refine_program.handle; state.Apply(); glUniform1i(glGetUniformLocation(refine_program.handle, "LUMAD"), 1); - glUniform1f(glGetUniformLocation(refine_program.handle, "final_scale"), - static_cast(internal_scale_factor) / scale_factor); cur_state.Apply(); } @@ -95,20 +77,48 @@ void Anime4kUltrafast::Filter(GLuint src_tex, const Common::Rectangle& src_ GLuint read_fb_handle, GLuint draw_fb_handle) { const OpenGLState cur_state = OpenGLState::GetCurState(); + // These will have handles from the previous texture that was filtered, reset them to avoid + // binding invalid textures. + state.texture_units[0].texture_2d = 0; + state.texture_units[1].texture_2d = 0; + state.texture_units[2].texture_2d = 0; + + const auto setup_temp_tex = [this, &src_rect](GLint internal_format, GLint format) { + TempTex texture; + texture.fbo.Create(); + texture.tex.Create(); + state.texture_units[0].texture_2d = texture.tex.handle; + state.draw.draw_framebuffer = texture.fbo.handle; + state.Apply(); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, texture.tex.handle); + if (GL_ARB_texture_storage) { + glTexStorage2D(GL_TEXTURE_2D, 1, internal_format, + src_rect.GetWidth() * internal_scale_factor, + src_rect.GetHeight() * internal_scale_factor); + } else { + glTexImage2D( + GL_TEXTURE_2D, 0, internal_format, src_rect.GetWidth() * internal_scale_factor, + src_rect.GetHeight() * internal_scale_factor, 0, format, GL_HALF_FLOAT, nullptr); + } + glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, + texture.tex.handle, 0); + return texture; + }; + auto XY = setup_temp_tex(GL_RG16F, GL_RG); + auto LUMAD = setup_temp_tex(GL_R16F, GL_RED); + state.viewport = {static_cast(src_rect.left * internal_scale_factor), static_cast(src_rect.bottom * internal_scale_factor), static_cast(src_rect.GetWidth() * internal_scale_factor), static_cast(src_rect.GetHeight() * internal_scale_factor)}; state.texture_units[0].texture_2d = src_tex; + state.texture_units[1].texture_2d = LUMAD.tex.handle; + state.texture_units[2].texture_2d = XY.tex.handle; state.draw.draw_framebuffer = XY.fbo.handle; state.draw.shader_program = gradient_x_program.handle; state.Apply(); - glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_RECTANGLE, LUMAD.tex.handle); - glActiveTexture(GL_TEXTURE2); - glBindTexture(GL_TEXTURE_RECTANGLE, XY.tex.handle); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); // gradient y pass diff --git a/src/video_core/renderer_opengl/texture_filters/anime4k/anime4k_ultrafast.h b/src/video_core/renderer_opengl/texture_filters/anime4k/anime4k_ultrafast.h index 9e89da816..8175ed390 100644 --- a/src/video_core/renderer_opengl/texture_filters/anime4k/anime4k_ultrafast.h +++ b/src/video_core/renderer_opengl/texture_filters/anime4k/anime4k_ultrafast.h @@ -30,8 +30,6 @@ private: OGLTexture tex; OGLFramebuffer fbo; }; - TempTex LUMAD; - TempTex XY; std::array samplers; diff --git a/src/video_core/renderer_opengl/texture_filters/anime4k/refine.frag b/src/video_core/renderer_opengl/texture_filters/anime4k/refine.frag index 4417b96f6..569f30078 100644 --- a/src/video_core/renderer_opengl/texture_filters/anime4k/refine.frag +++ b/src/video_core/renderer_opengl/texture_filters/anime4k/refine.frag @@ -1,14 +1,12 @@ //? #version 330 +precision mediump float; + in vec2 tex_coord; -in vec2 input_max; out vec4 frag_color; uniform sampler2D HOOKED; -uniform sampler2DRect LUMAD; -uniform sampler2DRect LUMAG; - -uniform float final_scale; +uniform sampler2D LUMAD; const float LINE_DETECT_THRESHOLD = 0.4; const float STRENGTH = 0.6; @@ -21,12 +19,12 @@ struct RGBAL { }; vec4 getAverage(vec4 cc, vec4 a, vec4 b, vec4 c) { - return cc * (1 - STRENGTH) + ((a + b + c) / 3) * STRENGTH; + return cc * (1.0 - STRENGTH) + ((a + b + c) / 3.0) * STRENGTH; } -#define GetRGBAL(offset) \ - RGBAL(textureOffset(HOOKED, tex_coord, offset), \ - texture(LUMAD, clamp((gl_FragCoord.xy + offset) * final_scale, vec2(0.0), input_max)).x) +#define GetRGBAL(x_offset, y_offset) \ + RGBAL(textureLodOffset(HOOKED, tex_coord, 0.0, ivec2(x_offset, y_offset)), \ + textureLodOffset(LUMAD, tex_coord, 0.0, ivec2(x_offset, y_offset)).x) float min3v(float a, float b, float c) { return min(min(a, b), c); @@ -37,23 +35,23 @@ float max3v(float a, float b, float c) { } vec4 Compute() { - RGBAL cc = GetRGBAL(ivec2(0)); + RGBAL cc = GetRGBAL(0, 0); if (cc.l > LINE_DETECT_THRESHOLD) { return cc.c; } - RGBAL tl = GetRGBAL(ivec2(-1, -1)); - RGBAL t = GetRGBAL(ivec2(0, -1)); - RGBAL tr = GetRGBAL(ivec2(1, -1)); + RGBAL tl = GetRGBAL(-1, -1); + RGBAL t = GetRGBAL(0, -1); + RGBAL tr = GetRGBAL(1, -1); - RGBAL l = GetRGBAL(ivec2(-1, 0)); + RGBAL l = GetRGBAL(-1, 0); - RGBAL r = GetRGBAL(ivec2(1, 0)); + RGBAL r = GetRGBAL(1, 0); - RGBAL bl = GetRGBAL(ivec2(-1, 1)); - RGBAL b = GetRGBAL(ivec2(0, 1)); - RGBAL br = GetRGBAL(ivec2(1, 1)); + RGBAL bl = GetRGBAL(-1, 1); + RGBAL b = GetRGBAL(0, 1); + RGBAL br = GetRGBAL(1, 1); // Kernel 0 and 4 float maxDark = max3v(br.l, b.l, bl.l); diff --git a/src/video_core/renderer_opengl/texture_filters/anime4k/refine.vert b/src/video_core/renderer_opengl/texture_filters/anime4k/refine.vert deleted file mode 100644 index 552a218fb..000000000 --- a/src/video_core/renderer_opengl/texture_filters/anime4k/refine.vert +++ /dev/null @@ -1,14 +0,0 @@ -//? #version 330 -out vec2 tex_coord; -out vec2 input_max; - -uniform sampler2D HOOKED; - -const vec2 vertices[4] = - vec2[4](vec2(-1.0, -1.0), vec2(1.0, -1.0), vec2(-1.0, 1.0), vec2(1.0, 1.0)); - -void main() { - gl_Position = vec4(vertices[gl_VertexID], 0.0, 1.0); - tex_coord = (vertices[gl_VertexID] + 1.0) / 2.0; - input_max = textureSize(HOOKED, 0) * 2.0 - 1.0; -} diff --git a/src/video_core/renderer_opengl/texture_filters/anime4k/x_gradient.frag b/src/video_core/renderer_opengl/texture_filters/anime4k/x_gradient.frag index 49502fac7..8103cb77c 100644 --- a/src/video_core/renderer_opengl/texture_filters/anime4k/x_gradient.frag +++ b/src/video_core/renderer_opengl/texture_filters/anime4k/x_gradient.frag @@ -1,4 +1,6 @@ //? #version 330 +precision mediump float; + in vec2 tex_coord; out vec2 frag_color; @@ -7,7 +9,7 @@ uniform sampler2D tex_input; const vec3 K = vec3(0.2627, 0.6780, 0.0593); // TODO: improve handling of alpha channel -#define GetLum(xoffset) dot(K, textureOffset(tex_input, tex_coord, ivec2(xoffset, 0)).rgb) +#define GetLum(xoffset) dot(K, textureLodOffset(tex_input, tex_coord, 0.0, ivec2(xoffset, 0)).rgb) void main() { float l = GetLum(-1); diff --git a/src/video_core/renderer_opengl/texture_filters/anime4k/y_gradient.frag b/src/video_core/renderer_opengl/texture_filters/anime4k/y_gradient.frag index a0e820001..81e0d0f6e 100644 --- a/src/video_core/renderer_opengl/texture_filters/anime4k/y_gradient.frag +++ b/src/video_core/renderer_opengl/texture_filters/anime4k/y_gradient.frag @@ -1,16 +1,18 @@ //? #version 330 -in vec2 input_max; +precision mediump float; + +in vec2 tex_coord; out float frag_color; -uniform sampler2DRect tex_input; +uniform sampler2D tex_input; void main() { - vec2 t = texture(tex_input, min(gl_FragCoord.xy + vec2(0.0, 1.0), input_max)).xy; - vec2 c = texture(tex_input, gl_FragCoord.xy).xy; - vec2 b = texture(tex_input, max(gl_FragCoord.xy - vec2(0.0, 1.0), vec2(0.0))).xy; + vec2 t = textureLodOffset(tex_input, tex_coord, 0.0, ivec2(0, 1)).xy; + vec2 c = textureLod(tex_input, tex_coord, 0.0).xy; + vec2 b = textureLodOffset(tex_input, tex_coord, 0.0, ivec2(0, -1)).xy; - vec2 grad = vec2(t.x + 2 * c.x + b.x, b.y - t.y); + vec2 grad = vec2(t.x + 2.0 * c.x + b.x, b.y - t.y); - frag_color = 1 - length(grad); + frag_color = 1.0 - length(grad); } diff --git a/src/video_core/renderer_opengl/texture_filters/anime4k/y_gradient.vert b/src/video_core/renderer_opengl/texture_filters/anime4k/y_gradient.vert deleted file mode 100644 index 376a67b79..000000000 --- a/src/video_core/renderer_opengl/texture_filters/anime4k/y_gradient.vert +++ /dev/null @@ -1,12 +0,0 @@ -//? #version 330 -out vec2 input_max; - -uniform sampler2D tex_size; - -const vec2 vertices[4] = - vec2[4](vec2(-1.0, -1.0), vec2(1.0, -1.0), vec2(-1.0, 1.0), vec2(1.0, 1.0)); - -void main() { - gl_Position = vec4(vertices[gl_VertexID], 0.0, 1.0); - input_max = textureSize(tex_size, 0) * 2 - 1; -} diff --git a/src/video_core/renderer_opengl/texture_filters/bicubic/bicubic.frag b/src/video_core/renderer_opengl/texture_filters/bicubic/bicubic.frag index 2bdab3cf6..f384c7864 100644 --- a/src/video_core/renderer_opengl/texture_filters/bicubic/bicubic.frag +++ b/src/video_core/renderer_opengl/texture_filters/bicubic/bicubic.frag @@ -1,4 +1,6 @@ //? #version 330 +precision mediump float; + in vec2 tex_coord; out vec4 frag_color; @@ -18,7 +20,7 @@ vec4 cubic(float v) { vec4 textureBicubic(sampler2D sampler, vec2 texCoords) { - vec2 texSize = textureSize(sampler, 0); + vec2 texSize = vec2(textureSize(sampler, 0)); vec2 invTexSize = 1.0 / texSize; texCoords = texCoords * texSize - 0.5; diff --git a/src/video_core/renderer_opengl/texture_filters/xbrz/xbrz_freescale.frag b/src/video_core/renderer_opengl/texture_filters/xbrz/xbrz_freescale.frag index 4868d18f7..84f1b3503 100644 --- a/src/video_core/renderer_opengl/texture_filters/xbrz/xbrz_freescale.frag +++ b/src/video_core/renderer_opengl/texture_filters/xbrz/xbrz_freescale.frag @@ -1,4 +1,6 @@ //? #version 330 +precision mediump float; + in vec2 tex_coord; in vec2 source_size; in vec2 output_size; @@ -6,7 +8,7 @@ in vec2 output_size; out vec4 frag_color; uniform sampler2D tex; -uniform float scale; +uniform lowp float scale; const int BLEND_NONE = 0; const int BLEND_NORMAL = 1; @@ -42,12 +44,12 @@ float GetLeftRatio(vec2 center, vec2 origin, vec2 direction) { return smoothstep(-sqrt(2.0) / 2.0, sqrt(2.0) / 2.0, v); } -vec2 pos = fract(tex_coord * source_size) - vec2(0.5, 0.5); -vec2 coord = tex_coord - pos / source_size; - #define P(x, y) textureOffset(tex, coord, ivec2(x, y)) void main() { + vec2 pos = fract(tex_coord * source_size) - vec2(0.5, 0.5); + vec2 coord = tex_coord - pos / source_size; + //--------------------------------------- // Input Pixel Mapping: -|x|x|x|- // x|A|B|C|x @@ -142,15 +144,15 @@ void main() { (IsPixEqual(G, H) && IsPixEqual(H, I) && IsPixEqual(I, F) && IsPixEqual(F, C) && !IsPixEqual(E, I)))); vec2 origin = vec2(0.0, 1.0 / sqrt(2.0)); - ivec2 direction = ivec2(1, -1); + vec2 direction = vec2(1.0, -1.0); if (doLineBlend) { bool haveShallowLine = (STEEP_DIRECTION_THRESHOLD * dist_F_G <= dist_H_C) && E != G && D != G; bool haveSteepLine = (STEEP_DIRECTION_THRESHOLD * dist_H_C <= dist_F_G) && E != C && B != C; origin = haveShallowLine ? vec2(0.0, 0.25) : vec2(0.0, 0.5); - direction.x += haveShallowLine ? 1 : 0; - direction.y -= haveSteepLine ? 1 : 0; + direction.x += haveShallowLine ? 1.0 : 0.0; + direction.y -= haveSteepLine ? 1.0 : 0.0; } vec4 blendPix = mix(H, F, step(ColorDist(E, F), ColorDist(E, H))); res = mix(res, blendPix, GetLeftRatio(pos, origin, direction)); @@ -169,15 +171,15 @@ void main() { (IsPixEqual(A, D) && IsPixEqual(D, G) && IsPixEqual(G, H) && IsPixEqual(H, I) && !IsPixEqual(E, G)))); vec2 origin = vec2(-1.0 / sqrt(2.0), 0.0); - ivec2 direction = ivec2(1, 1); + vec2 direction = vec2(1.0, 1.0); if (doLineBlend) { bool haveShallowLine = (STEEP_DIRECTION_THRESHOLD * dist_H_A <= dist_D_I) && E != A && B != A; bool haveSteepLine = (STEEP_DIRECTION_THRESHOLD * dist_D_I <= dist_H_A) && E != I && F != I; origin = haveShallowLine ? vec2(-0.25, 0.0) : vec2(-0.5, 0.0); - direction.y += haveShallowLine ? 1 : 0; - direction.x += haveSteepLine ? 1 : 0; + direction.y += haveShallowLine ? 1.0 : 0.0; + direction.x += haveSteepLine ? 1.0 : 0.0; } origin = origin; direction = direction; @@ -198,15 +200,15 @@ void main() { (IsPixEqual(I, F) && IsPixEqual(F, C) && IsPixEqual(C, B) && IsPixEqual(B, A) && !IsPixEqual(E, C)))); vec2 origin = vec2(1.0 / sqrt(2.0), 0.0); - ivec2 direction = ivec2(-1, -1); + vec2 direction = vec2(-1.0, -1.0); if (doLineBlend) { bool haveShallowLine = (STEEP_DIRECTION_THRESHOLD * dist_B_I <= dist_F_A) && E != I && H != I; bool haveSteepLine = (STEEP_DIRECTION_THRESHOLD * dist_F_A <= dist_B_I) && E != A && D != A; origin = haveShallowLine ? vec2(0.25, 0.0) : vec2(0.5, 0.0); - direction.y -= haveShallowLine ? 1 : 0; - direction.x -= haveSteepLine ? 1 : 0; + direction.y -= haveShallowLine ? 1.0 : 0.0; + direction.x -= haveSteepLine ? 1.0 : 0.0; } vec4 blendPix = mix(F, B, step(ColorDist(E, B), ColorDist(E, F))); res = mix(res, blendPix, GetLeftRatio(pos, origin, direction)); @@ -225,15 +227,15 @@ void main() { (IsPixEqual(C, B) && IsPixEqual(B, A) && IsPixEqual(A, D) && IsPixEqual(D, G) && !IsPixEqual(E, A)))); vec2 origin = vec2(0.0, -1.0 / sqrt(2.0)); - ivec2 direction = ivec2(-1, 1); + vec2 direction = vec2(-1.0, 1.0); if (doLineBlend) { bool haveShallowLine = (STEEP_DIRECTION_THRESHOLD * dist_D_C <= dist_B_G) && E != C && F != C; bool haveSteepLine = (STEEP_DIRECTION_THRESHOLD * dist_B_G <= dist_D_C) && E != G && H != G; origin = haveShallowLine ? vec2(0.0, -0.25) : vec2(0.0, -0.5); - direction.x -= haveShallowLine ? 1 : 0; - direction.y += haveSteepLine ? 1 : 0; + direction.x -= haveShallowLine ? 1.0 : 0.0; + direction.y += haveSteepLine ? 1.0 : 0.0; } vec4 blendPix = mix(D, B, step(ColorDist(E, B), ColorDist(E, D))); res = mix(res, blendPix, GetLeftRatio(pos, origin, direction)); diff --git a/src/video_core/renderer_opengl/texture_filters/xbrz/xbrz_freescale.vert b/src/video_core/renderer_opengl/texture_filters/xbrz/xbrz_freescale.vert index adf45d564..63905075f 100644 --- a/src/video_core/renderer_opengl/texture_filters/xbrz/xbrz_freescale.vert +++ b/src/video_core/renderer_opengl/texture_filters/xbrz/xbrz_freescale.vert @@ -4,7 +4,7 @@ out vec2 source_size; out vec2 output_size; uniform sampler2D tex; -uniform float scale; +uniform lowp float scale; const vec2 vertices[4] = vec2[4](vec2(-1.0, -1.0), vec2(1.0, -1.0), vec2(-1.0, 1.0), vec2(1.0, 1.0)); @@ -12,6 +12,6 @@ const vec2 vertices[4] = void main() { gl_Position = vec4(vertices[gl_VertexID], 0.0, 1.0); tex_coord = (vertices[gl_VertexID] + 1.0) / 2.0; - source_size = textureSize(tex, 0); + source_size = vec2(textureSize(tex, 0)); output_size = source_size * scale; }