Blender V4.3
parallel_reduction.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_math_vector.hh"
7
8#include "MEM_guardedalloc.h"
9
10#include "GPU_compute.hh"
11#include "GPU_shader.hh"
12#include "GPU_texture.hh"
13
14#include "COM_context.hh"
15
17
19
20/* Reduces the given texture into a single value and returns it. The return value should be freed
21 * by a call to MEM_freeN. The return value is either a pointer to a float, or a pointer to an
22 * array of floats that represents a vector. This depends on the given format, which should be
23 * compatible with the reduction shader.
24 *
25 * The given reduction shader should be bound when calling the function and the shader is expected
26 * to be derived from the compositor_parallel_reduction.glsl shader, see that file for more
27 * information. Also see the compositor_parallel_reduction_info.hh file for example shader
28 * definitions. */
29static float *parallel_reduction_dispatch(Context &context,
30 GPUTexture *texture,
31 GPUShader *shader,
33{
34 GPU_shader_uniform_1b(shader, "is_initial_reduction", true);
35
36 GPUTexture *texture_to_reduce = texture;
37 int2 size_to_reduce = int2(GPU_texture_width(texture), GPU_texture_height(texture));
38
39 /* Dispatch the reduction shader until the texture reduces to a single pixel. */
40 while (size_to_reduce != int2(1)) {
41 const int2 reduced_size = math::divide_ceil(size_to_reduce, int2(16));
42 GPUTexture *reduced_texture = context.texture_pool().acquire(reduced_size, format);
43
45 const int texture_image_unit = GPU_shader_get_sampler_binding(shader, "input_tx");
46 GPU_texture_bind(texture_to_reduce, texture_image_unit);
47
48 const int image_unit = GPU_shader_get_sampler_binding(shader, "output_img");
49 GPU_texture_image_bind(reduced_texture, image_unit);
50
51 GPU_compute_dispatch(shader, reduced_size.x, reduced_size.y, 1);
52
53 GPU_texture_image_unbind(reduced_texture);
54 GPU_texture_unbind(texture_to_reduce);
55
56 /* Release the input texture only if it is not the source texture, since the source texture is
57 * not acquired or owned by the function. */
58 if (texture_to_reduce != texture) {
59 context.texture_pool().release(texture_to_reduce);
60 }
61
62 texture_to_reduce = reduced_texture;
63 size_to_reduce = reduced_size;
64
65 GPU_shader_uniform_1b(shader, "is_initial_reduction", false);
66 }
67
69 float *pixel = static_cast<float *>(GPU_texture_read(texture_to_reduce, GPU_DATA_FLOAT, 0));
70
71 /* Release the final texture only if it is not the source texture, since the source texture is
72 * not acquired or owned by the function. */
73 if (texture_to_reduce != texture) {
74 context.texture_pool().release(texture_to_reduce);
75 }
76
77 return pixel;
78}
79
80/* --------------------------------------------------------------------
81 * Sum Reductions.
82 */
83
84float sum_red(Context &context, GPUTexture *texture)
85{
86 GPUShader *shader = context.get_shader("compositor_sum_red", ResultPrecision::Full);
87 GPU_shader_bind(shader);
88
89 float *reduced_value = parallel_reduction_dispatch(
90 context,
91 texture,
92 shader,
94 const float sum = *reduced_value;
95 MEM_freeN(reduced_value);
97
98 return sum;
99}
100
101float sum_green(Context &context, GPUTexture *texture)
102{
103 GPUShader *shader = context.get_shader("compositor_sum_green", ResultPrecision::Full);
104 GPU_shader_bind(shader);
105
106 float *reduced_value = parallel_reduction_dispatch(
107 context,
108 texture,
109 shader,
111 const float sum = *reduced_value;
112 MEM_freeN(reduced_value);
114
115 return sum;
116}
117
118float sum_blue(Context &context, GPUTexture *texture)
119{
120 GPUShader *shader = context.get_shader("compositor_sum_blue", ResultPrecision::Full);
121 GPU_shader_bind(shader);
122
123 float *reduced_value = parallel_reduction_dispatch(
124 context,
125 texture,
126 shader,
128 const float sum = *reduced_value;
129 MEM_freeN(reduced_value);
131
132 return sum;
133}
134
135float sum_luminance(Context &context, GPUTexture *texture, float3 luminance_coefficients)
136{
137 GPUShader *shader = context.get_shader("compositor_sum_luminance", ResultPrecision::Full);
138 GPU_shader_bind(shader);
139
140 GPU_shader_uniform_3fv(shader, "luminance_coefficients", luminance_coefficients);
141
142 float *reduced_value = parallel_reduction_dispatch(
143 context,
144 texture,
145 shader,
147 const float sum = *reduced_value;
148 MEM_freeN(reduced_value);
150
151 return sum;
152}
153
154float sum_log_luminance(Context &context, GPUTexture *texture, float3 luminance_coefficients)
155{
156 GPUShader *shader = context.get_shader("compositor_sum_log_luminance", ResultPrecision::Full);
157 GPU_shader_bind(shader);
158
159 GPU_shader_uniform_3fv(shader, "luminance_coefficients", luminance_coefficients);
160
161 float *reduced_value = parallel_reduction_dispatch(
162 context,
163 texture,
164 shader,
166 const float sum = *reduced_value;
167 MEM_freeN(reduced_value);
169
170 return sum;
171}
172
173float4 sum_color(Context &context, GPUTexture *texture)
174{
175 GPUShader *shader = context.get_shader("compositor_sum_color", ResultPrecision::Full);
176 GPU_shader_bind(shader);
177
178 float *reduced_value = parallel_reduction_dispatch(
179 context,
180 texture,
181 shader,
183 const float4 sum = float4(reduced_value);
184 MEM_freeN(reduced_value);
186
187 return sum;
188}
189
190/* --------------------------------------------------------------------
191 * Sum Of Squared Difference Reductions.
192 */
193
194float sum_red_squared_difference(Context &context, GPUTexture *texture, float subtrahend)
195{
196 GPUShader *shader = context.get_shader("compositor_sum_red_squared_difference",
198 GPU_shader_bind(shader);
199
200 GPU_shader_uniform_1f(shader, "subtrahend", subtrahend);
201
202 float *reduced_value = parallel_reduction_dispatch(
203 context,
204 texture,
205 shader,
207 const float sum = *reduced_value;
208 MEM_freeN(reduced_value);
210
211 return sum;
212}
213
214float sum_green_squared_difference(Context &context, GPUTexture *texture, float subtrahend)
215{
216 GPUShader *shader = context.get_shader("compositor_sum_green_squared_difference",
218 GPU_shader_bind(shader);
219
220 GPU_shader_uniform_1f(shader, "subtrahend", subtrahend);
221
222 float *reduced_value = parallel_reduction_dispatch(
223 context,
224 texture,
225 shader,
227 const float sum = *reduced_value;
228 MEM_freeN(reduced_value);
230
231 return sum;
232}
233
234float sum_blue_squared_difference(Context &context, GPUTexture *texture, float subtrahend)
235{
236 GPUShader *shader = context.get_shader("compositor_sum_blue_squared_difference",
238 GPU_shader_bind(shader);
239
240 GPU_shader_uniform_1f(shader, "subtrahend", subtrahend);
241
242 float *reduced_value = parallel_reduction_dispatch(
243 context,
244 texture,
245 shader,
247 const float sum = *reduced_value;
248 MEM_freeN(reduced_value);
250
251 return sum;
252}
253
255 GPUTexture *texture,
256 float3 luminance_coefficients,
257 float subtrahend)
258{
259 GPUShader *shader = context.get_shader("compositor_sum_luminance_squared_difference",
261 GPU_shader_bind(shader);
262
263 GPU_shader_uniform_3fv(shader, "luminance_coefficients", luminance_coefficients);
264 GPU_shader_uniform_1f(shader, "subtrahend", subtrahend);
265
266 float *reduced_value = parallel_reduction_dispatch(
267 context,
268 texture,
269 shader,
271 const float sum = *reduced_value;
272 MEM_freeN(reduced_value);
274
275 return sum;
276}
277
278/* --------------------------------------------------------------------
279 * Maximum Reductions.
280 */
281
282float maximum_luminance(Context &context, GPUTexture *texture, float3 luminance_coefficients)
283{
284 GPUShader *shader = context.get_shader("compositor_maximum_luminance", ResultPrecision::Full);
285 GPU_shader_bind(shader);
286
287 GPU_shader_uniform_3fv(shader, "luminance_coefficients", luminance_coefficients);
288
289 float *reduced_value = parallel_reduction_dispatch(
290 context,
291 texture,
292 shader,
294 const float maximum = *reduced_value;
295 MEM_freeN(reduced_value);
297
298 return maximum;
299}
300
301float maximum_float(Context &context, GPUTexture *texture)
302{
303 GPUShader *shader = context.get_shader("compositor_maximum_float", ResultPrecision::Full);
304 GPU_shader_bind(shader);
305
306 float *reduced_value = parallel_reduction_dispatch(
307 context,
308 texture,
309 shader,
311 const float maximum = *reduced_value;
312 MEM_freeN(reduced_value);
314
315 return maximum;
316}
317
319 GPUTexture *texture,
320 float lower_bound,
321 float upper_bound)
322{
323 GPUShader *shader = context.get_shader("compositor_maximum_float_in_range",
325 GPU_shader_bind(shader);
326
327 GPU_shader_uniform_1f(shader, "lower_bound", lower_bound);
328 GPU_shader_uniform_1f(shader, "upper_bound", upper_bound);
329
330 float *reduced_value = parallel_reduction_dispatch(
331 context,
332 texture,
333 shader,
335 const float maximum = *reduced_value;
336 MEM_freeN(reduced_value);
338
339 return maximum;
340}
341
342/* --------------------------------------------------------------------
343 * Minimum Reductions.
344 */
345
346float minimum_luminance(Context &context, GPUTexture *texture, float3 luminance_coefficients)
347{
348 GPUShader *shader = context.get_shader("compositor_minimum_luminance", ResultPrecision::Full);
349 GPU_shader_bind(shader);
350
351 GPU_shader_uniform_3fv(shader, "luminance_coefficients", luminance_coefficients);
352
353 float *reduced_value = parallel_reduction_dispatch(
354 context,
355 texture,
356 shader,
358 const float minimum = *reduced_value;
359 MEM_freeN(reduced_value);
361
362 return minimum;
363}
364
365float minimum_float(Context &context, GPUTexture *texture)
366{
367 GPUShader *shader = context.get_shader("compositor_minimum_float", ResultPrecision::Full);
368 GPU_shader_bind(shader);
369
370 float *reduced_value = parallel_reduction_dispatch(
371 context,
372 texture,
373 shader,
375 const float minimum = *reduced_value;
376 MEM_freeN(reduced_value);
378
379 return minimum;
380}
381
383 GPUTexture *texture,
384 float lower_bound,
385 float upper_bound)
386{
387 GPUShader *shader = context.get_shader("compositor_minimum_float_in_range",
389 GPU_shader_bind(shader);
390
391 GPU_shader_uniform_1f(shader, "lower_bound", lower_bound);
392 GPU_shader_uniform_1f(shader, "upper_bound", upper_bound);
393
394 float *reduced_value = parallel_reduction_dispatch(
395 context,
396 texture,
397 shader,
399 const float minimum = *reduced_value;
400 MEM_freeN(reduced_value);
402
403 return minimum;
404}
405
406} // namespace blender::realtime_compositor
void GPU_compute_dispatch(GPUShader *shader, uint groups_x_len, uint groups_y_len, uint groups_z_len)
int GPU_shader_get_sampler_binding(GPUShader *shader, const char *name)
void GPU_shader_uniform_1f(GPUShader *sh, const char *name, float value)
void GPU_shader_uniform_3fv(GPUShader *sh, const char *name, const float data[3])
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_TEXTURE_FETCH
Definition GPU_state.hh:37
@ GPU_BARRIER_TEXTURE_UPDATE
Definition GPU_state.hh:39
int GPU_texture_height(const GPUTexture *texture)
void GPU_texture_bind(GPUTexture *texture, int unit)
int GPU_texture_width(const GPUTexture *texture)
void * GPU_texture_read(GPUTexture *texture, eGPUDataFormat data_format, int mip_level)
void GPU_texture_unbind(GPUTexture *texture)
@ GPU_DATA_FLOAT
void GPU_texture_image_unbind(GPUTexture *texture)
void GPU_texture_image_bind(GPUTexture *texture, int unit)
eGPUTextureFormat
Read Guarded memory(de)allocation.
struct GPUShader GPUShader
static T sum(const btAlignedObjectArray< T > &items)
static eGPUTextureFormat gpu_texture_format(ResultType type, ResultPrecision precision)
Definition result.cc:29
local_group_size(16, 16) .push_constant(Type texture
format
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
VecBase< T, Size > divide_ceil(const VecBase< T, Size > &a, const VecBase< T, Size > &b)
float sum_log_luminance(Context &context, GPUTexture *texture, float3 luminance_coefficients)
float sum_blue_squared_difference(Context &context, GPUTexture *texture, float subtrahend)
float maximum_float_in_range(Context &context, GPUTexture *texture, float lower_bound, float upper_bound)
float4 sum_color(Context &context, GPUTexture *texture)
float sum_luminance_squared_difference(Context &context, GPUTexture *texture, float3 luminance_coefficients, float subtrahend)
float minimum_float(Context &context, GPUTexture *texture)
float sum_blue(Context &context, GPUTexture *texture)
float sum_red_squared_difference(Context &context, GPUTexture *texture, float subtrahend)
float sum_luminance(Context &context, GPUTexture *texture, float3 luminance_coefficients)
float sum_red(Context &context, GPUTexture *texture)
float minimum_float_in_range(Context &context, GPUTexture *texture, float lower_bound, float upper_bound)
float maximum_luminance(Context &context, GPUTexture *texture, float3 luminance_coefficients)
float sum_green_squared_difference(Context &context, GPUTexture *texture, float subtrahend)
float sum_green(Context &context, GPUTexture *texture)
float minimum_luminance(Context &context, GPUTexture *texture, float3 luminance_coefficients)
static float * parallel_reduction_dispatch(Context &context, GPUTexture *texture, GPUShader *shader, eGPUTextureFormat format)
float maximum_float(Context &context, GPUTexture *texture)
VecBase< float, 4 > float4
VecBase< int32_t, 2 > int2