Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOmar Emara <mail@OmarEmara.dev>2022-09-09 14:57:04 +0300
committerOmar Emara <mail@OmarEmara.dev>2022-09-09 14:58:54 +0300
commit04ae0fe46ba1f08ef141a051187bea3763afda8d (patch)
treeb8766dc1956ca91109c8bff92bec88d2b5c7c036 /source/blender/gpu
parent1339fec22a1aef25a719885977c4da3aab0e93fb (diff)
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
Diffstat (limited to 'source/blender/gpu')
-rw-r--r--source/blender/gpu/CMakeLists.txt5
-rw-r--r--source/blender/gpu/shaders/compositor/compositor_symmetric_blur.glsl77
-rw-r--r--source/blender/gpu/shaders/compositor/compositor_symmetric_separable_blur.glsl53
-rw-r--r--source/blender/gpu/shaders/compositor/infos/compositor_symmetric_blur_info.hh13
-rw-r--r--source/blender/gpu/shaders/compositor/infos/compositor_symmetric_separable_blur_info.hh14
-rw-r--r--source/blender/gpu/shaders/compositor/library/gpu_shader_compositor_blur_common.glsl32
6 files changed, 194 insertions, 0 deletions
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 done
+ * by the gamma_correct_blur_input function. */
+vec4 gamma_uncorrect_blur_output(vec4 color)
+{
+ /* Unpremultiply alpha. */
+ color.rgb /= color.a > 0.0 ? color.a : 1.0;
+
+ /* Take the square root of the color channel if it is positive, otherwise zero it. */
+ color.rgb = mix(sqrt(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;
+}