Blender V4.3
jump_flooding.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 <utility>
6
7#include "BLI_assert.h"
8#include "BLI_math_base.h"
9#include "BLI_math_base.hh"
10
11#include "GPU_shader.hh"
12
13#include "COM_context.hh"
14#include "COM_result.hh"
15#include "COM_utilities.hh"
16
18
20
21static void jump_flooding_pass(Context &context, Result &input, Result &output, int step_size)
22{
23 GPUShader *shader = context.get_shader("compositor_jump_flooding", ResultPrecision::Half);
24 GPU_shader_bind(shader);
25
26 GPU_shader_uniform_1i(shader, "step_size", step_size);
27
28 input.bind_as_texture(shader, "input_tx");
29 output.bind_as_image(shader, "output_img");
30
31 compute_dispatch_threads_at_least(shader, input.domain().size);
32
34 input.unbind_as_texture();
35 output.unbind_as_image();
36}
37
38void jump_flooding(Context &context, Result &input, Result &output)
39{
40 BLI_assert(input.type() == ResultType::Int2);
41 BLI_assert(output.type() == ResultType::Int2);
42
43 /* First, run a jump flooding pass with a step size of 1. This initial pass is proposed by the
44 * 1+FJA variant to improve accuracy. */
45 Result initial_flooded_result = context.create_result(ResultType::Int2, ResultPrecision::Half);
46 initial_flooded_result.allocate_texture(input.domain());
47 jump_flooding_pass(context, input, initial_flooded_result, 1);
48
49 /* We compute the result using a ping-pong buffer, so create an intermediate result. */
50 Result *result_to_flood = &initial_flooded_result;
51 Result intermediate_result = context.create_result(ResultType::Int2, ResultPrecision::Half);
52 intermediate_result.allocate_texture(input.domain());
53 Result *result_after_flooding = &intermediate_result;
54
55 /* The algorithm starts with a step size that is half the size of the image. However, the
56 * algorithm assumes a square image that is a power of two in width without loss of generality.
57 * To generalize that, we use half the next power of two of the maximum dimension. */
58 const int max_size = math::max(input.domain().size.x, input.domain().size.y);
59 int step_size = power_of_2_max_i(max_size) / 2;
60
61 /* Successively apply a jump flooding pass, halving the step size every time and swapping the
62 * ping-pong buffers. */
63 while (step_size != 0) {
64 jump_flooding_pass(context, *result_to_flood, *result_after_flooding, step_size);
65 std::swap(result_to_flood, result_after_flooding);
66 step_size /= 2;
67 }
68
69 /* Notice that the output of the last pass is stored in result_to_flood due to the last swap, so
70 * steal the data from it and release the other buffer. */
71 result_after_flooding->release();
72 output.steal_data(*result_to_flood);
73}
74
75} // namespace blender::realtime_compositor
#define BLI_assert(a)
Definition BLI_assert.h:50
MINLINE int power_of_2_max_i(int n)
void GPU_shader_uniform_1i(GPUShader *sh, const char *name, int value)
void GPU_shader_bind(GPUShader *shader)
void GPU_shader_unbind()
struct GPUShader GPUShader
void allocate_texture(Domain domain, bool from_pool=true)
Definition result.cc:204
T max(const T &a, const T &b)
void jump_flooding(Context &context, Result &input, Result &output)
static void jump_flooding_pass(Context &context, Result &input, Result &output, int step_size)
void compute_dispatch_threads_at_least(GPUShader *shader, int2 threads_range, int2 local_size=int2(16))
Definition utilities.cc:131