From a32dab4565d72f83dcb6c9ab7ce64c8b6234d97e Mon Sep 17 00:00:00 2001 From: Omar Emara Date: Tue, 7 Mar 2023 17:49:16 +0200 Subject: [PATCH] Realtime Compositor: Implement bicubic interpolation This patch implements the bicubic interpolation option in the transform nodes. The path merely reuse the code in the shader image texture and adds bicubic variants to the domain realization shader. --- .../intern/realize_on_domain_operation.cc | 26 +++++-- .../shaders/compositor_realize_on_domain.glsl | 3 +- .../compositor_realize_on_domain_info.hh | 29 +++++++- source/blender/gpu/CMakeLists.txt | 1 + .../gpu_shader_bicubic_sampler_lib.glsl | 68 +++++++++++++++++++ .../gpu_shader_material_tex_image.glsl | 65 ++---------------- 6 files changed, 120 insertions(+), 72 deletions(-) create mode 100644 source/blender/gpu/shaders/common/gpu_shader_bicubic_sampler_lib.glsl diff --git a/source/blender/compositor/realtime_compositor/intern/realize_on_domain_operation.cc b/source/blender/compositor/realtime_compositor/intern/realize_on_domain_operation.cc index c9ea395cfa6..5f0ddf6719a 100644 --- a/source/blender/compositor/realtime_compositor/intern/realize_on_domain_operation.cc +++ b/source/blender/compositor/realtime_compositor/intern/realize_on_domain_operation.cc @@ -76,13 +76,25 @@ void RealizeOnDomainOperation::execute() GPUShader *RealizeOnDomainOperation::get_realization_shader() { - switch (get_result().type()) { - case ResultType::Color: - return shader_manager().get("compositor_realize_on_domain_color"); - case ResultType::Vector: - return shader_manager().get("compositor_realize_on_domain_vector"); - case ResultType::Float: - return shader_manager().get("compositor_realize_on_domain_float"); + if (get_input().get_realization_options().interpolation == Interpolation::Bicubic) { + switch (get_result().type()) { + case ResultType::Color: + return shader_manager().get("compositor_realize_on_domain_bicubic_color"); + case ResultType::Vector: + return shader_manager().get("compositor_realize_on_domain_bicubic_vector"); + case ResultType::Float: + return shader_manager().get("compositor_realize_on_domain_bicubic_float"); + } + } + else { + switch (get_result().type()) { + case ResultType::Color: + return shader_manager().get("compositor_realize_on_domain_color"); + case ResultType::Vector: + return shader_manager().get("compositor_realize_on_domain_vector"); + case ResultType::Float: + return shader_manager().get("compositor_realize_on_domain_float"); + } } BLI_assert_unreachable(); diff --git a/source/blender/compositor/realtime_compositor/shaders/compositor_realize_on_domain.glsl b/source/blender/compositor/realtime_compositor/shaders/compositor_realize_on_domain.glsl index 4ae6e2fb700..604783d54eb 100644 --- a/source/blender/compositor/realtime_compositor/shaders/compositor_realize_on_domain.glsl +++ b/source/blender/compositor/realtime_compositor/shaders/compositor_realize_on_domain.glsl @@ -1,3 +1,4 @@ +#pragma BLENDER_REQUIRE(gpu_shader_bicubic_sampler_lib.glsl) #pragma BLENDER_REQUIRE(gpu_shader_compositor_texture_utilities.glsl) void main() @@ -25,5 +26,5 @@ void main() * the sampler's expected [0, 1] range. */ vec2 normalized_coordinates = (coordinates - offset) / vec2(input_size); - imageStore(domain_img, texel, texture(input_tx, normalized_coordinates)); + imageStore(domain_img, texel, SAMPLER_FUNCTION(input_tx, normalized_coordinates)); } diff --git a/source/blender/compositor/realtime_compositor/shaders/infos/compositor_realize_on_domain_info.hh b/source/blender/compositor/realtime_compositor/shaders/infos/compositor_realize_on_domain_info.hh index 4528649ae98..2de84e1ba75 100644 --- a/source/blender/compositor/realtime_compositor/shaders/infos/compositor_realize_on_domain_info.hh +++ b/source/blender/compositor/realtime_compositor/shaders/infos/compositor_realize_on_domain_info.hh @@ -8,17 +8,40 @@ GPU_SHADER_CREATE_INFO(compositor_realize_on_domain_shared) .sampler(0, ImageType::FLOAT_2D, "input_tx") .compute_source("compositor_realize_on_domain.glsl"); -GPU_SHADER_CREATE_INFO(compositor_realize_on_domain_color) +GPU_SHADER_CREATE_INFO(compositor_realize_on_domain_standard_shared) .additional_info("compositor_realize_on_domain_shared") + .define("SAMPLER_FUNCTION", "texture"); + +GPU_SHADER_CREATE_INFO(compositor_realize_on_domain_bicubic_shared) + .additional_info("compositor_realize_on_domain_shared") + .define("SAMPLER_FUNCTION", "texture_bicubic"); + +GPU_SHADER_CREATE_INFO(compositor_realize_on_domain_color) + .additional_info("compositor_realize_on_domain_standard_shared") .image(0, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, "domain_img") .do_static_compilation(true); GPU_SHADER_CREATE_INFO(compositor_realize_on_domain_vector) - .additional_info("compositor_realize_on_domain_shared") + .additional_info("compositor_realize_on_domain_standard_shared") .image(0, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, "domain_img") .do_static_compilation(true); GPU_SHADER_CREATE_INFO(compositor_realize_on_domain_float) - .additional_info("compositor_realize_on_domain_shared") + .additional_info("compositor_realize_on_domain_standard_shared") + .image(0, GPU_R16F, Qualifier::WRITE, ImageType::FLOAT_2D, "domain_img") + .do_static_compilation(true); + +GPU_SHADER_CREATE_INFO(compositor_realize_on_domain_bicubic_color) + .additional_info("compositor_realize_on_domain_bicubic_shared") + .image(0, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, "domain_img") + .do_static_compilation(true); + +GPU_SHADER_CREATE_INFO(compositor_realize_on_domain_bicubic_vector) + .additional_info("compositor_realize_on_domain_bicubic_shared") + .image(0, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, "domain_img") + .do_static_compilation(true); + +GPU_SHADER_CREATE_INFO(compositor_realize_on_domain_bicubic_float) + .additional_info("compositor_realize_on_domain_bicubic_shared") .image(0, GPU_R16F, Qualifier::WRITE, ImageType::FLOAT_2D, "domain_img") .do_static_compilation(true); diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index ee14eab1920..556ce5e22c6 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -410,6 +410,7 @@ set(GLSL_SRC shaders/gpu_shader_codegen_lib.glsl + shaders/common/gpu_shader_bicubic_sampler_lib.glsl shaders/common/gpu_shader_common_color_ramp.glsl shaders/common/gpu_shader_common_color_utils.glsl shaders/common/gpu_shader_common_curves.glsl diff --git a/source/blender/gpu/shaders/common/gpu_shader_bicubic_sampler_lib.glsl b/source/blender/gpu/shaders/common/gpu_shader_bicubic_sampler_lib.glsl new file mode 100644 index 00000000000..6ec7a23246e --- /dev/null +++ b/source/blender/gpu/shaders/common/gpu_shader_bicubic_sampler_lib.glsl @@ -0,0 +1,68 @@ +/** \param f: Offset from texel center in pixel space. */ +void cubic_bspline_coefficients(vec2 f, out vec2 w0, out vec2 w1, out vec2 w2, out vec2 w3) +{ + vec2 f2 = f * f; + vec2 f3 = f2 * f; + /* Optimized formulae for cubic B-Spline coefficients. */ + w3 = f3 / 6.0; + w0 = -w3 + f2 * 0.5 - f * 0.5 + 1.0 / 6.0; + w1 = f3 * 0.5 - f2 * 1.0 + 2.0 / 3.0; + w2 = 1.0 - w0 - w1 - w3; +} + +/* Samples the given 2D sampler at the given coordinates using Bicubic interpolation. This function + * uses an optimized algorithm which assumes a linearly filtered sampler, so the caller needs to + * take that into account when setting up the sampler. */ +vec4 texture_bicubic(sampler2D sampler, vec2 coordinates) +{ + vec2 texture_size = vec2(textureSize(sampler, 0).xy); + coordinates.xy *= texture_size; + + vec2 w0, w1, w2, w3; + vec2 texel_center = floor(coordinates.xy - 0.5) + 0.5; + cubic_bspline_coefficients(coordinates.xy - texel_center, w0, w1, w2, w3); + +#if 1 /* Optimized version using 4 filtered taps. */ + vec2 s0 = w0 + w1; + vec2 s1 = w2 + w3; + + vec2 f0 = w1 / (w0 + w1); + vec2 f1 = w3 / (w2 + w3); + + vec4 sampling_coordinates; + sampling_coordinates.xy = texel_center - 1.0 + f0; + sampling_coordinates.zw = texel_center + 1.0 + f1; + + sampling_coordinates /= texture_size.xyxy; + + vec4 sampled_color = textureLod(sampler, sampling_coordinates.xy, 0.0) * s0.x * s0.y; + sampled_color += textureLod(sampler, sampling_coordinates.zy, 0.0) * s1.x * s0.y; + sampled_color += textureLod(sampler, sampling_coordinates.xw, 0.0) * s0.x * s1.y; + sampled_color += textureLod(sampler, sampling_coordinates.zw, 0.0) * s1.x * s1.y; + + return sampled_color; + +#else /* Reference brute-force 16 taps. */ + vec4 color = texelFetch(sampler, ivec2(texel_center + vec2(-1.0, -1.0)), 0) * w0.x * w0.y; + color += texelFetch(sampler, ivec2(texel_center + vec2(0.0, -1.0)), 0) * w1.x * w0.y; + color += texelFetch(sampler, ivec2(texel_center + vec2(1.0, -1.0)), 0) * w2.x * w0.y; + color += texelFetch(sampler, ivec2(texel_center + vec2(2.0, -1.0)), 0) * w3.x * w0.y; + + color += texelFetch(sampler, ivec2(texel_center + vec2(-1.0, 0.0)), 0) * w0.x * w1.y; + color += texelFetch(sampler, ivec2(texel_center + vec2(0.0, 0.0)), 0) * w1.x * w1.y; + color += texelFetch(sampler, ivec2(texel_center + vec2(1.0, 0.0)), 0) * w2.x * w1.y; + color += texelFetch(sampler, ivec2(texel_center + vec2(2.0, 0.0)), 0) * w3.x * w1.y; + + color += texelFetch(sampler, ivec2(texel_center + vec2(-1.0, 1.0)), 0) * w0.x * w2.y; + color += texelFetch(sampler, ivec2(texel_center + vec2(0.0, 1.0)), 0) * w1.x * w2.y; + color += texelFetch(sampler, ivec2(texel_center + vec2(1.0, 1.0)), 0) * w2.x * w2.y; + color += texelFetch(sampler, ivec2(texel_center + vec2(2.0, 1.0)), 0) * w3.x * w2.y; + + color += texelFetch(sampler, ivec2(texel_center + vec2(-1.0, 2.0)), 0) * w0.x * w3.y; + color += texelFetch(sampler, ivec2(texel_center + vec2(0.0, 2.0)), 0) * w1.x * w3.y; + color += texelFetch(sampler, ivec2(texel_center + vec2(1.0, 2.0)), 0) * w2.x * w3.y; + color += texelFetch(sampler, ivec2(texel_center + vec2(2.0, 2.0)), 0) * w3.x * w3.y; + + return color; +#endif +} diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_image.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_image.glsl index df949f7358b..acf24596f84 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_tex_image.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_image.glsl @@ -1,3 +1,5 @@ +#pragma BLENDER_REQUIRE(gpu_shader_bicubic_sampler_lib.glsl) + void point_texco_remap_square(vec3 vin, out vec3 vout) { vout = vin * 2.0 - 1.0; @@ -54,68 +56,9 @@ void node_tex_image_linear(vec3 co, sampler2D ima, out vec4 color, out float alp alpha = color.a; } -/** \param f: Signed distance to texel center. */ -void cubic_bspline_coefs(vec2 f, out vec2 w0, out vec2 w1, out vec2 w2, out vec2 w3) -{ - vec2 f2 = f * f; - vec2 f3 = f2 * f; - /* Bspline coefs (optimized) */ - w3 = f3 / 6.0; - w0 = -w3 + f2 * 0.5 - f * 0.5 + 1.0 / 6.0; - w1 = f3 * 0.5 - f2 * 1.0 + 2.0 / 3.0; - w2 = 1.0 - w0 - w1 - w3; -} - void node_tex_image_cubic(vec3 co, sampler2D ima, out vec4 color, out float alpha) { - vec2 tex_size = vec2(textureSize(ima, 0).xy); - - co.xy *= tex_size; - /* texel center */ - vec2 tc = floor(co.xy - 0.5) + 0.5; - vec2 w0, w1, w2, w3; - cubic_bspline_coefs(co.xy - tc, w0, w1, w2, w3); - -#if 1 /* Optimized version using 4 filtered tap. */ - vec2 s0 = w0 + w1; - vec2 s1 = w2 + w3; - - vec2 f0 = w1 / (w0 + w1); - vec2 f1 = w3 / (w2 + w3); - - vec4 final_co; - final_co.xy = tc - 1.0 + f0; - final_co.zw = tc + 1.0 + f1; - - final_co /= tex_size.xyxy; - - color = safe_color(textureLod(ima, final_co.xy, 0.0)) * s0.x * s0.y; - color += safe_color(textureLod(ima, final_co.zy, 0.0)) * s1.x * s0.y; - color += safe_color(textureLod(ima, final_co.xw, 0.0)) * s0.x * s1.y; - color += safe_color(textureLod(ima, final_co.zw, 0.0)) * s1.x * s1.y; - -#else /* Reference bruteforce 16 tap. */ - color = texelFetch(ima, ivec2(tc + vec2(-1.0, -1.0)), 0) * w0.x * w0.y; - color += texelFetch(ima, ivec2(tc + vec2(0.0, -1.0)), 0) * w1.x * w0.y; - color += texelFetch(ima, ivec2(tc + vec2(1.0, -1.0)), 0) * w2.x * w0.y; - color += texelFetch(ima, ivec2(tc + vec2(2.0, -1.0)), 0) * w3.x * w0.y; - - color += texelFetch(ima, ivec2(tc + vec2(-1.0, 0.0)), 0) * w0.x * w1.y; - color += texelFetch(ima, ivec2(tc + vec2(0.0, 0.0)), 0) * w1.x * w1.y; - color += texelFetch(ima, ivec2(tc + vec2(1.0, 0.0)), 0) * w2.x * w1.y; - color += texelFetch(ima, ivec2(tc + vec2(2.0, 0.0)), 0) * w3.x * w1.y; - - color += texelFetch(ima, ivec2(tc + vec2(-1.0, 1.0)), 0) * w0.x * w2.y; - color += texelFetch(ima, ivec2(tc + vec2(0.0, 1.0)), 0) * w1.x * w2.y; - color += texelFetch(ima, ivec2(tc + vec2(1.0, 1.0)), 0) * w2.x * w2.y; - color += texelFetch(ima, ivec2(tc + vec2(2.0, 1.0)), 0) * w3.x * w2.y; - - color += texelFetch(ima, ivec2(tc + vec2(-1.0, 2.0)), 0) * w0.x * w3.y; - color += texelFetch(ima, ivec2(tc + vec2(0.0, 2.0)), 0) * w1.x * w3.y; - color += texelFetch(ima, ivec2(tc + vec2(1.0, 2.0)), 0) * w2.x * w3.y; - color += texelFetch(ima, ivec2(tc + vec2(2.0, 2.0)), 0) * w3.x * w3.y; -#endif - + color = safe_color(texture_bicubic(ima, co.xy)); alpha = color.a; } @@ -263,7 +206,7 @@ void node_tex_tile_cubic( /* texel center */ vec2 tc = floor(co.xy - 0.5) + 0.5; vec2 w0, w1, w2, w3; - cubic_bspline_coefs(co.xy - tc, w0, w1, w2, w3); + cubic_bspline_coefficients(co.xy - tc, w0, w1, w2, w3); vec2 s0 = w0 + w1; vec2 s1 = w2 + w3; -- 2.30.2