Blender V4.3
symmetric_separable_blur_variable_size.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include "BLI_assert.h"
6#include "BLI_math_base.hh"
7#include "BLI_math_vector.hh"
9
10#include "GPU_shader.hh"
11#include "GPU_texture.hh"
12
13#include "COM_context.hh"
14#include "COM_result.hh"
15#include "COM_utilities.hh"
16
18
20
22
23static const char *get_blur_shader(ResultType type)
24{
25 switch (type) {
27 return "compositor_symmetric_separable_blur_variable_size_float";
29 return "compositor_symmetric_separable_blur_variable_size_float2";
32 return "compositor_symmetric_separable_blur_variable_size_float4";
34 /* GPU module does not support float3 outputs. */
35 break;
37 /* Blur does not support integer types. */
38 break;
39 }
40
42 return nullptr;
43}
44
46 Context &context, Result &input, Result &radius, int filter_type, int weights_resolution)
47{
48 GPUShader *shader = context.get_shader(get_blur_shader(input.type()));
49 GPU_shader_bind(shader);
50
51 GPU_shader_uniform_1b(shader, "is_vertical_pass", false);
52
53 input.bind_as_texture(shader, "input_tx");
54
55 const SymmetricSeparableBlurWeights &weights =
56 context.cache_manager().symmetric_separable_blur_weights.get(
57 context, filter_type, weights_resolution);
58 weights.bind_as_texture(shader, "weights_tx");
59
60 radius.bind_as_texture(shader, "radius_tx");
61
62 /* We allocate an output image of a transposed size, that is, with a height equivalent to the
63 * width of the input and vice versa. This is done as a performance optimization. The shader
64 * will blur the image horizontally and write it to the intermediate output transposed. Then
65 * the vertical pass will execute the same horizontal blur shader, but since its input is
66 * transposed, it will effectively do a vertical blur and write to the output transposed,
67 * effectively undoing the transposition in the horizontal pass. This is done to improve
68 * spatial cache locality in the shader and to avoid having two separate shaders for each blur
69 * pass. */
70 Domain domain = input.domain();
71 const int2 transposed_domain = int2(domain.size.y, domain.size.x);
72
73 Result output = context.create_result(input.type());
74 output.allocate_texture(transposed_domain);
75 output.bind_as_image(shader, "output_img");
76
77 compute_dispatch_threads_at_least(shader, domain.size);
78
80 input.unbind_as_texture();
81 weights.unbind_as_texture();
82 radius.unbind_as_texture();
83 output.unbind_as_image();
84
85 return output;
86}
87
88static void vertical_pass(Context &context,
89 Result &original_input,
90 Result &horizontal_pass_result,
91 Result &output,
92 Result &radius,
93 int filter_type,
94 int weights_resolution)
95{
96 GPUShader *shader = context.get_shader(get_blur_shader(original_input.type()));
97 GPU_shader_bind(shader);
98
99 GPU_shader_uniform_1b(shader, "is_vertical_pass", true);
100
101 horizontal_pass_result.bind_as_texture(shader, "input_tx");
102
103 const SymmetricSeparableBlurWeights &weights =
104 context.cache_manager().symmetric_separable_blur_weights.get(
105 context, filter_type, weights_resolution);
106 weights.bind_as_texture(shader, "weights_tx");
107
108 radius.bind_as_texture(shader, "radius_tx");
109
110 Domain domain = original_input.domain();
111 output.allocate_texture(domain);
112 output.bind_as_image(shader, "output_img");
113
114 /* Notice that the domain is transposed, see the note on the horizontal pass method for more
115 * information on the reasoning behind this. */
116 compute_dispatch_threads_at_least(shader, int2(domain.size.y, domain.size.x));
117
119 horizontal_pass_result.unbind_as_texture();
120 output.unbind_as_image();
121 weights.unbind_as_texture();
122 radius.unbind_as_texture();
123}
124
126 Result &input,
127 Result &output,
128 Result &radius,
129 int filter_type,
130 int weights_resolution)
131{
132 Result horizontal_pass_result = horizontal_pass(
133 context, input, radius, filter_type, weights_resolution);
135 context, input, horizontal_pass_result, output, radius, filter_type, weights_resolution);
136 horizontal_pass_result.release();
137}
138
139} // namespace blender::realtime_compositor
#define BLI_assert_unreachable()
Definition BLI_assert.h:97
void GPU_shader_bind(GPUShader *shader)
void GPU_shader_uniform_1b(GPUShader *sh, const char *name, bool value)
void GPU_shader_unbind()
struct GPUShader GPUShader
#define output
const Domain & domain() const
Definition result.cc:712
void allocate_texture(Domain domain, bool from_pool=true)
Definition result.cc:204
static ResultType type(eGPUTextureFormat format)
Definition result.cc:148
void bind_as_texture(GPUShader *shader, const char *texture_name) const
Definition result.cc:253
void bind_as_texture(GPUShader *shader, const char *texture_name) const
static const char * get_blur_shader(ResultType type)
void symmetric_separable_blur_variable_size(Context &context, Result &input, Result &output, Result &radius, int filter_type=R_FILTER_GAUSS, int weights_resolution=128)
static void vertical_pass(Context &context, Result &original_input, Result &horizontal_pass_result, Result &output, int distance, int falloff_type)
static Result horizontal_pass(Context &context, Result &input, int distance, int falloff_type)
void compute_dispatch_threads_at_least(GPUShader *shader, int2 threads_range, int2 local_size=int2(16))
Definition utilities.cc:131
VecBase< int32_t, 2 > int2