Blender V4.3
node_composite_vec_blur.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2006 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include <cstdint>
10
11#include "BLI_math_vector.hh"
12
13#include "UI_interface.hh"
14#include "UI_resources.hh"
15
16#include "GPU_compute.hh"
17#include "GPU_shader.hh"
18#include "GPU_state.hh"
19#include "GPU_storage_buffer.hh"
20#include "GPU_vertex_buffer.hh"
21
22#include "COM_node_operation.hh"
23#include "COM_result.hh"
24#include "COM_utilities.hh"
25
27
28/* **************** VECTOR BLUR ******************** */
29
31
33
35{
36 b.add_input<decl::Color>("Image")
37 .default_value({1.0f, 1.0f, 1.0f, 1.0f})
38 .compositor_domain_priority(0);
39 b.add_input<decl::Float>("Z").default_value(0.0f).min(0.0f).max(1.0f).compositor_domain_priority(
40 2);
41 b.add_input<decl::Vector>("Speed")
42 .default_value({0.0f, 0.0f, 0.0f})
43 .min(0.0f)
44 .max(1.0f)
46 .compositor_domain_priority(1);
47 b.add_output<decl::Color>("Image");
48}
49
50/* custom1: iterations, custom2: max_speed (0 = no_limit). */
51static void node_composit_init_vecblur(bNodeTree * /*ntree*/, bNode *node)
52{
53 NodeBlurData *nbd = MEM_cnew<NodeBlurData>(__func__);
54 node->storage = nbd;
55 nbd->samples = 32;
56 nbd->fac = 0.25f;
57}
58
60{
61 uiLayout *col = uiLayoutColumn(layout, false);
62 uiItemR(col, ptr, "samples", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
63 uiItemR(col, ptr, "factor", UI_ITEM_R_SPLIT_EMPTY_NAME, IFACE_("Blur"), ICON_NONE);
64}
65
66using namespace blender::realtime_compositor;
67
69 public:
71
72 void execute() override
73 {
74 Result &input = get_input("Image");
75 Result &output = get_result("Image");
76 if (input.is_single_value()) {
77 input.pass_through(output);
78 return;
79 }
80
81 Result max_tile_velocity = compute_max_tile_velocity();
82 GPUStorageBuf *tile_indirection_buffer = dilate_max_velocity(max_tile_velocity);
83 compute_motion_blur(max_tile_velocity, tile_indirection_buffer);
84 max_tile_velocity.release();
85 GPU_storagebuf_free(tile_indirection_buffer);
86 }
87
88 /* Reduces each 32x32 block of velocity pixels into a single velocity whose magnitude is largest.
89 * Each of the previous and next velocities are reduces independently. */
91 {
92 GPUShader *shader = context().get_shader("compositor_max_velocity");
93 GPU_shader_bind(shader);
94
95 GPU_shader_uniform_1b(shader, "is_initial_reduction", true);
96
97 Result &input = get_input("Speed");
98 input.bind_as_texture(shader, "input_tx");
99
100 Result output = context().create_result(ResultType::Color);
101 const int2 tiles_count = math::divide_ceil(input.domain().size, int2(32));
102 output.allocate_texture(Domain(tiles_count));
103 output.bind_as_image(shader, "output_img");
104
105 GPU_compute_dispatch(shader, tiles_count.x, tiles_count.y, 1);
106
108 input.unbind_as_texture();
109 output.unbind_as_image();
110
111 return output;
112 }
113
114 /* The max tile velocity image computes the maximum within 32x32 blocks, while the velocity can
115 * in fact extend beyond such a small block. So we dilate the max blocks by taking the maximum
116 * along the path of each of the max velocity tiles. Since the shader uses custom max atomics,
117 * the output will be an indirection buffer that points to a particular tile in the original max
118 * tile velocity image. This is done as a form of performance optimization, see the shader for
119 * more information. */
120 GPUStorageBuf *dilate_max_velocity(Result &max_tile_velocity)
121 {
122 GPUShader *shader = context().get_shader("compositor_motion_blur_max_velocity_dilate");
123 GPU_shader_bind(shader);
124
125 GPU_shader_uniform_1f(shader, "shutter_speed", node_storage(bnode()).fac);
126
127 max_tile_velocity.bind_as_texture(shader, "input_tx");
128
129 /* The shader assumes a maximum input size of 16k, and since the max tile velocity image is
130 * composed of blocks of 32, we get 16k / 32 = 512. So the table is 512x512, but we store two
131 * tables for the previous and next velocities, so we double that. */
132 const int size = sizeof(uint32_t) * 512 * 512 * 2;
133 GPUStorageBuf *tile_indirection_buffer = GPU_storagebuf_create_ex(
134 size, nullptr, GPU_USAGE_DEVICE_ONLY, __func__);
135 GPU_storagebuf_clear_to_zero(tile_indirection_buffer);
136 const int slot = GPU_shader_get_ssbo_binding(shader, "tile_indirection_buf");
137 GPU_storagebuf_bind(tile_indirection_buffer, slot);
138
139 compute_dispatch_threads_at_least(shader, max_tile_velocity.domain().size);
140
142 max_tile_velocity.unbind_as_texture();
143 GPU_storagebuf_unbind(tile_indirection_buffer);
144
145 return tile_indirection_buffer;
146 }
147
148 void compute_motion_blur(Result &max_tile_velocity, GPUStorageBuf *tile_indirection_buffer)
149 {
150 GPUShader *shader = context().get_shader("compositor_motion_blur");
151 GPU_shader_bind(shader);
152
153 GPU_shader_uniform_1i(shader, "samples_count", node_storage(bnode()).samples);
154 GPU_shader_uniform_1f(shader, "shutter_speed", node_storage(bnode()).fac);
155
156 Result &input = get_input("Image");
157 input.bind_as_texture(shader, "input_tx");
158
159 Result &depth = get_input("Z");
160 depth.bind_as_texture(shader, "depth_tx");
161
162 Result &velocity = get_input("Speed");
163 velocity.bind_as_texture(shader, "velocity_tx");
164
165 max_tile_velocity.bind_as_texture(shader, "max_velocity_tx");
166
168 const int slot = GPU_shader_get_ssbo_binding(shader, "tile_indirection_buf");
169 GPU_storagebuf_bind(tile_indirection_buffer, slot);
170
171 Result &output = get_result("Image");
172 const Domain domain = compute_domain();
173 output.allocate_texture(domain);
174 output.bind_as_image(shader, "output_img");
175
176 compute_dispatch_threads_at_least(shader, output.domain().size);
177
179 input.unbind_as_texture();
180 depth.unbind_as_texture();
181 velocity.unbind_as_texture();
182 max_tile_velocity.unbind_as_texture();
183 output.unbind_as_image();
184 }
185};
186
188{
189 return new VectorBlurOperation(context, node);
190}
191
192} // namespace blender::nodes::node_composite_vec_blur_cc
193
195{
197
198 static blender::bke::bNodeType ntype;
199
200 cmp_node_type_base(&ntype, CMP_NODE_VECBLUR, "Vector Blur", NODE_CLASS_OP_FILTER);
201 ntype.declare = file_ns::cmp_node_vec_blur_declare;
202 ntype.draw_buttons = file_ns::node_composit_buts_vecblur;
203 ntype.initfunc = file_ns::node_composit_init_vecblur;
206 ntype.get_compositor_operation = file_ns::get_compositor_operation;
207
209}
#define NODE_STORAGE_FUNCS(StorageT)
Definition BKE_node.hh:1799
#define NODE_CLASS_OP_FILTER
Definition BKE_node.hh:408
#define IFACE_(msgid)
void GPU_compute_dispatch(GPUShader *shader, uint groups_x_len, uint groups_y_len, uint groups_z_len)
void GPU_shader_uniform_1i(GPUShader *sh, const char *name, int value)
void GPU_shader_uniform_1f(GPUShader *sh, const char *name, float value)
int GPU_shader_get_ssbo_binding(GPUShader *shader, const char *name)
void GPU_shader_bind(GPUShader *shader)
void GPU_shader_uniform_1b(GPUShader *sh, const char *name, bool value)
void GPU_shader_unbind()
void GPU_memory_barrier(eGPUBarrier barrier)
Definition gpu_state.cc:374
@ GPU_BARRIER_SHADER_STORAGE
Definition GPU_state.hh:48
void GPU_storagebuf_bind(GPUStorageBuf *ssbo, int slot)
GPUStorageBuf * GPU_storagebuf_create_ex(size_t size, const void *data, GPUUsageType usage, const char *name)
void GPU_storagebuf_unbind(GPUStorageBuf *ssbo)
void GPU_storagebuf_clear_to_zero(GPUStorageBuf *ssbo)
void GPU_storagebuf_free(GPUStorageBuf *ssbo)
@ GPU_USAGE_DEVICE_ONLY
@ PROP_VELOCITY
Definition RNA_types.hh:166
uiLayout * uiLayoutColumn(uiLayout *layout, bool align)
void uiItemR(uiLayout *layout, PointerRNA *ptr, const char *propname, eUI_Item_Flag flag, const char *name, int icon)
@ UI_ITEM_R_SPLIT_EMPTY_NAME
struct GPUShader GPUShader
#define output
void compute_motion_blur(Result &max_tile_velocity, GPUStorageBuf *tile_indirection_buffer)
GPUShader * get_shader(const char *info_name, ResultPrecision precision)
Result create_result(ResultType type, ResultPrecision precision)
NodeOperation(Context &context, DNode node)
Result & get_input(StringRef identifier) const
Definition operation.cc:144
Result & get_result(StringRef identifier)
Definition operation.cc:46
const Domain & domain() const
Definition result.cc:712
void bind_as_texture(GPUShader *shader, const char *texture_name) const
Definition result.cc:253
local_group_size(16, 16) .push_constant(Type b
uint col
void node_type_storage(bNodeType *ntype, const char *storagename, void(*freefunc)(bNode *node), void(*copyfunc)(bNodeTree *dest_ntree, bNode *dest_node, const bNode *src_node))
Definition node.cc:4632
void node_register_type(bNodeType *ntype)
Definition node.cc:1708
VecBase< T, Size > divide_ceil(const VecBase< T, Size > &a, const VecBase< T, Size > &b)
static void node_composit_buts_vecblur(uiLayout *layout, bContext *, PointerRNA *ptr)
static NodeOperation * get_compositor_operation(Context &context, DNode node)
static void node_composit_init_vecblur(bNodeTree *, bNode *node)
static void cmp_node_vec_blur_declare(NodeDeclarationBuilder &b)
void compute_dispatch_threads_at_least(GPUShader *shader, int2 threads_range, int2 local_size=int2(16))
Definition utilities.cc:131
void cmp_node_type_base(blender::bke::bNodeType *ntype, int type, const char *name, short nclass)
void register_node_type_cmp_vecblur()
void node_free_standard_storage(bNode *node)
Definition node_util.cc:46
void node_copy_standard_storage(bNodeTree *, bNode *dest_node, const bNode *src_node)
Definition node_util.cc:58
#define min(a, b)
Definition sort.c:32
unsigned int uint32_t
Definition stdint.h:80
Defines a node type.
Definition BKE_node.hh:218
NodeGetCompositorOperationFunction get_compositor_operation
Definition BKE_node.hh:324
void(* initfunc)(bNodeTree *ntree, bNode *node)
Definition BKE_node.hh:267
void(* draw_buttons)(uiLayout *, bContext *C, PointerRNA *ptr)
Definition BKE_node.hh:238
NodeDeclareFunction declare
Definition BKE_node.hh:347
PointerRNA * ptr
Definition wm_files.cc:4126