[Bf-blender-cvs] [04ae0fe46ba] master: Realtime Compositor: Implement blur node

Omar Emara noreply at git.blender.org
Fri Sep 9 13:59:03 CEST 2022


Commit: 04ae0fe46ba1f08ef141a051187bea3763afda8d
Author: Omar Emara
Date:   Fri Sep 9 13:57:04 2022 +0200
Branches: master
https://developer.blender.org/rB04ae0fe46ba1f08ef141a051187bea3763afda8d

Realtime Compositor: Implement blur node

This patch implements the blur node for the realtime compositor. The patch is
still missing the Variable Size option because it depends on the Erode/Dilate
node, which is yet to be implemented. Furthermore, there are a number of
optimizations that can be implemented, the most important of which is the IIR
implementation of the Fast Gaussian filter, as well as the use of hardware
filtering and thread local memory. The latter of which was attempted but was
not robust enough, so it will be submitted as separate patch.

Differential Revision: https://developer.blender.org/D15663

Reviewed By: Clement Foucault

===================================================================

M	source/blender/gpu/CMakeLists.txt
A	source/blender/gpu/shaders/compositor/compositor_symmetric_blur.glsl
A	source/blender/gpu/shaders/compositor/compositor_symmetric_separable_blur.glsl
A	source/blender/gpu/shaders/compositor/infos/compositor_symmetric_blur_info.hh
A	source/blender/gpu/shaders/compositor/infos/compositor_symmetric_separable_blur_info.hh
A	source/blender/gpu/shaders/compositor/library/gpu_shader_compositor_blur_common.glsl
M	source/blender/nodes/composite/nodes/node_composite_blur.cc
M	source/blender/render/intern/initrender.cc

===================================================================

diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt
index 47d4feb7ec9..cb5bb4331f9 100644
--- a/source/blender/gpu/CMakeLists.txt
+++ b/source/blender/gpu/CMakeLists.txt
@@ -345,8 +345,11 @@ set(GLSL_SRC
   shaders/compositor/compositor_screen_lens_distortion.glsl
   shaders/compositor/compositor_set_alpha.glsl
   shaders/compositor/compositor_split_viewer.glsl
+  shaders/compositor/compositor_symmetric_blur.glsl
+  shaders/compositor/compositor_symmetric_separable_blur.glsl
 
   shaders/compositor/library/gpu_shader_compositor_alpha_over.glsl
+  shaders/compositor/library/gpu_shader_compositor_blur_common.glsl
   shaders/compositor/library/gpu_shader_compositor_bright_contrast.glsl
   shaders/compositor/library/gpu_shader_compositor_channel_matte.glsl
   shaders/compositor/library/gpu_shader_compositor_chroma_matte.glsl
@@ -620,6 +623,8 @@ set(SRC_SHADER_CREATE_INFOS
   shaders/compositor/infos/compositor_screen_lens_distortion_info.hh
   shaders/compositor/infos/compositor_set_alpha_info.hh
   shaders/compositor/infos/compositor_split_viewer_info.hh
+  shaders/compositor/infos/compositor_symmetric_blur_info.hh
+  shaders/compositor/infos/compositor_symmetric_separable_blur_info.hh
 )
 
 set(SRC_SHADER_CREATE_INFOS_MTL
diff --git a/source/blender/gpu/shaders/compositor/compositor_symmetric_blur.glsl b/source/blender/gpu/shaders/compositor/compositor_symmetric_blur.glsl
new file mode 100644
index 00000000000..df08991a35c
--- /dev/null
+++ b/source/blender/gpu/shaders/compositor/compositor_symmetric_blur.glsl
@@ -0,0 +1,77 @@
+#pragma BLENDER_REQUIRE(gpu_shader_compositor_blur_common.glsl)
+#pragma BLENDER_REQUIRE(gpu_shader_compositor_texture_utilities.glsl)
+
+vec4 load_input(ivec2 texel)
+{
+  vec4 color;
+  if (extend_bounds) {
+    /* If bounds are extended, then we treat the input as padded by a radius amount of pixels. So
+     * we load the input with an offset by the radius amount and fallback to a transparent color if
+     * it is out of bounds. Notice that we subtract 1 because the weights texture have an extra
+     * center weight, see the SymmetricBlurWeights for more information. */
+    ivec2 blur_size = texture_size(weights_tx) - 1;
+    color = texture_load(input_tx, texel - blur_size, vec4(0.0));
+  }
+  else {
+    color = texture_load(input_tx, texel);
+  }
+
+  if (gamma_correct) {
+    color = gamma_correct_blur_input(color);
+  }
+
+  return color;
+}
+
+void main()
+{
+  ivec2 texel = ivec2(gl_GlobalInvocationID.xy);
+
+  vec4 accumulated_color = vec4(0.0);
+
+  /* First, compute the contribution of the center pixel. */
+  vec4 center_color = load_input(texel);
+  accumulated_color += center_color * texture_load(weights_tx, ivec2(0)).x;
+
+  ivec2 weights_size = texture_size(weights_tx);
+
+  /* Then, compute the contributions of the pixels along the x axis of the filter, noting that the
+   * weights texture only stores the weights for the positive half, but since the filter is
+   * symmetric, the same weight is used for the negative half and we add both of their
+   * contributions. */
+  for (int x = 1; x < weights_size.x; x++) {
+    float weight = texture_load(weights_tx, ivec2(x, 0)).x;
+    accumulated_color += load_input(texel + ivec2(x, 0)) * weight;
+    accumulated_color += load_input(texel + ivec2(-x, 0)) * weight;
+  }
+
+  /* Then, compute the contributions of the pixels along the y axis of the filter, noting that the
+   * weights texture only stores the weights for the positive half, but since the filter is
+   * symmetric, the same weight is used for the negative half and we add both of their
+   * contributions. */
+  for (int y = 1; y < weights_size.y; y++) {
+    float weight = texture_load(weights_tx, ivec2(0, y)).x;
+    accumulated_color += load_input(texel + ivec2(0, y)) * weight;
+    accumulated_color += load_input(texel + ivec2(0, -y)) * weight;
+  }
+
+  /* Finally, compute the contributions of the pixels in the four quadrants of the filter, noting
+   * that the weights texture only stores the weights for the upper right quadrant, but since the
+   * filter is symmetric, the same weight is used for the rest of the quadrants and we add all four
+   * of their contributions. */
+  for (int y = 1; y < weights_size.y; y++) {
+    for (int x = 1; x < weights_size.x; x++) {
+      float weight = texture_load(weights_tx, ivec2(x, y)).x;
+      accumulated_color += load_input(texel + ivec2(x, y)) * weight;
+      accumulated_color += load_input(texel + ivec2(-x, y)) * weight;
+      accumulated_color += load_input(texel + ivec2(x, -y)) * weight;
+      accumulated_color += load_input(texel + ivec2(-x, -y)) * weight;
+    }
+  }
+
+  if (gamma_correct) {
+    accumulated_color = gamma_uncorrect_blur_output(accumulated_color);
+  }
+
+  imageStore(output_img, texel, accumulated_color);
+}
diff --git a/source/blender/gpu/shaders/compositor/compositor_symmetric_separable_blur.glsl b/source/blender/gpu/shaders/compositor/compositor_symmetric_separable_blur.glsl
new file mode 100644
index 00000000000..ab0c7baa787
--- /dev/null
+++ b/source/blender/gpu/shaders/compositor/compositor_symmetric_separable_blur.glsl
@@ -0,0 +1,53 @@
+#pragma BLENDER_REQUIRE(gpu_shader_compositor_blur_common.glsl)
+#pragma BLENDER_REQUIRE(gpu_shader_compositor_texture_utilities.glsl)
+
+vec4 load_input(ivec2 texel)
+{
+  vec4 color;
+  if (extend_bounds) {
+    /* If bounds are extended, then we treat the input as padded by a radius amount of pixels. So
+     * we load the input with an offset by the radius amount and fallback to a transparent color if
+     * it is out of bounds. Notice that we subtract 1 because the weights texture have an extra
+     * center weight, see the SymmetricSeparableBlurWeights for more information. */
+    int blur_size = texture_size(weights_tx) - 1;
+    color = texture_load(input_tx, texel - ivec2(blur_size, 0), vec4(0.0));
+  }
+  else {
+    color = texture_load(input_tx, texel);
+  }
+
+  if (gamma_correct_input) {
+    color = gamma_correct_blur_input(color);
+  }
+
+  return color;
+}
+
+void main()
+{
+  ivec2 texel = ivec2(gl_GlobalInvocationID.xy);
+
+  vec4 accumulated_color = vec4(0.0);
+
+  /* First, compute the contribution of the center pixel. */
+  vec4 center_color = load_input(texel);
+  accumulated_color += center_color * texture_load(weights_tx, 0).x;
+
+  /* Then, compute the contributions of the pixel to the right and left, noting that the
+   * weights texture only stores the weights for the positive half, but since the filter is
+   * symmetric, the same weight is used for the negative half and we add both of their
+   * contributions. */
+  for (int i = 1; i < texture_size(weights_tx); i++) {
+    float weight = texture_load(weights_tx, i).x;
+    accumulated_color += load_input(texel + ivec2(i, 0)) * weight;
+    accumulated_color += load_input(texel + ivec2(-i, 0)) * weight;
+  }
+
+  if (gamma_uncorrect_output) {
+    accumulated_color = gamma_uncorrect_blur_output(accumulated_color);
+  }
+
+  /* Write the color using the transposed texel. See the execute_separable_blur_horizontal_pass
+   * method for more information on the rational behind this. */
+  imageStore(output_img, texel.yx, accumulated_color);
+}
diff --git a/source/blender/gpu/shaders/compositor/infos/compositor_symmetric_blur_info.hh b/source/blender/gpu/shaders/compositor/infos/compositor_symmetric_blur_info.hh
new file mode 100644
index 00000000000..8ba2b4e04ef
--- /dev/null
+++ b/source/blender/gpu/shaders/compositor/infos/compositor_symmetric_blur_info.hh
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_CREATE_INFO(compositor_symmetric_blur)
+    .local_group_size(16, 16)
+    .push_constant(Type::BOOL, "extend_bounds")
+    .push_constant(Type::BOOL, "gamma_correct")
+    .sampler(0, ImageType::FLOAT_2D, "input_tx")
+    .sampler(1, ImageType::FLOAT_2D, "weights_tx")
+    .image(0, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, "output_img")
+    .compute_source("compositor_symmetric_blur.glsl")
+    .do_static_compilation(true);
diff --git a/source/blender/gpu/shaders/compositor/infos/compositor_symmetric_separable_blur_info.hh b/source/blender/gpu/shaders/compositor/infos/compositor_symmetric_separable_blur_info.hh
new file mode 100644
index 00000000000..57247dba4b8
--- /dev/null
+++ b/source/blender/gpu/shaders/compositor/infos/compositor_symmetric_separable_blur_info.hh
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_CREATE_INFO(compositor_symmetric_separable_blur)
+    .local_group_size(16, 16)
+    .push_constant(Type::BOOL, "extend_bounds")
+    .push_constant(Type::BOOL, "gamma_correct_input")
+    .push_constant(Type::BOOL, "gamma_uncorrect_output")
+    .sampler(0, ImageType::FLOAT_2D, "input_tx")
+    .sampler(1, ImageType::FLOAT_1D, "weights_tx")
+    .image(0, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, "output_img")
+    .compute_source("compositor_symmetric_separable_blur.glsl")
+    .do_static_compilation(true);
diff --git a/source/blender/gpu/shaders/compositor/library/gpu_shader_compositor_blur_common.glsl b/source/blender/gpu/shaders/compositor/library/gpu_shader_compositor_blur_common.glsl
new file mode 100644
index 00000000000..e404c03bbb0
--- /dev/null
+++ b/source/blender/gpu/shaders/compositor/library/gpu_shader_compositor_blur_common.glsl
@@ -0,0 +1,32 @@
+/* Preprocess the input of the blur filter by squaring it in its alpha straight form, assuming the
+ * given color is alpha premultiplied. */
+vec4 gamma_correct_blur_input(vec4 color)
+{
+  /* Unpremultiply alpha. */
+  color.rgb /= color.a > 0.0 ? color.a : 1.0;
+
+  /* Square color channel if it is positive, otherwise zero it. */
+  color.rgb *= mix(color.rgb, vec3(0.0), lessThan(color.rgb, vec3(0.0)));
+
+  /* Premultiply alpha to undo previous alpha unpremultiplication. */
+  color.rgb *= color.a > 0.0 ? color.a : 1.0;
+
+  return color;
+}
+
+/* Postprocess the output of the blur filter by taking its square root it in its alpha straight
+ * form, assuming the given color is alpha premultiplied. This essential undoes the processing do

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list