Realtime Compositor: Implement bicubic interpolation #105533

Merged
Omar Emara merged 1 commits from OmarEmaraDev/blender:realtime-compositor-bicubic-interpolation into main 2023-03-07 18:02:33 +01:00
6 changed files with 120 additions and 72 deletions

View File

@ -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();

View File

@ -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));
}

View File

@ -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);

View File

@ -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

View File

@ -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
}

View File

@ -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;