Blender V4.3
COM_JumpFloodingAlgorithm.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2024 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include <limits>
6#include <utility>
7
8#include "BLI_array.hh"
9#include "BLI_math_base.h"
10#include "BLI_math_base.hh"
11#include "BLI_math_vector.hh"
12#include "BLI_span.hh"
13#include "BLI_task.hh"
14
16
17/* Exact copies of the functions in gpu_shader_compositor_jump_flooding_lib.glsl and
18 * jump_flooding.cc but adapted for CPU. See those files for more information. */
19
21
22int2 encode_jump_flooding_value(int2 closest_seed_texel, bool is_flooded)
23{
24 return is_flooded ? closest_seed_texel : JUMP_FLOODING_NON_FLOODED_VALUE;
25}
26
28{
29 return encode_jump_flooding_value(texel, is_seed);
30}
31
32static int2 load_jump_flooding(Span<int2> input, int2 texel, int2 size, int2 fallback)
33{
34 if (texel.x < 0 || texel.x >= size.x || texel.y < 0 || texel.y >= size.y) {
35 return fallback;
36 }
37 return input[size_t(texel.y) * size.x + texel.x];
38}
39
41 MutableSpan<int2> output,
42 int2 size,
43 int step_size)
44{
45 threading::parallel_for(IndexRange(size.y), 1, [&](const IndexRange sub_y_range) {
46 for (const int64_t y : sub_y_range) {
47 for (const int64_t x : IndexRange(size.x)) {
48 int2 texel = int2(x, y);
49
50 int2 closest_seed_texel = int2(0);
51 float minimum_squared_distance = std::numeric_limits<float>::max();
52 for (int j = -1; j <= 1; j++) {
53 for (int i = -1; i <= 1; i++) {
54 int2 offset = int2(i, j) * step_size;
55
56 int2 fallback = JUMP_FLOODING_NON_FLOODED_VALUE;
57 int2 jump_flooding_value = load_jump_flooding(input, texel + offset, size, fallback);
58
59 if (jump_flooding_value == JUMP_FLOODING_NON_FLOODED_VALUE) {
60 continue;
61 }
62
63 int2 closest_seed_texel_to_neighbor = jump_flooding_value;
64
65 float squared_distance = math::distance_squared(float2(closest_seed_texel_to_neighbor),
66 float2(texel));
67
68 if (squared_distance < minimum_squared_distance) {
69 minimum_squared_distance = squared_distance;
70 closest_seed_texel = closest_seed_texel_to_neighbor;
71 }
72 }
73 }
74
75 bool flooding_happened = minimum_squared_distance != std::numeric_limits<float>::max();
76 int2 jump_flooding_value = encode_jump_flooding_value(closest_seed_texel,
77 flooding_happened);
78
79 output[size_t(texel.y) * size.x + texel.x] = jump_flooding_value;
80 }
81 }
82 });
83}
84
86{
87 Array<int2> initial_flooded_result(size_t(size.x) * size.y);
88 jump_flooding_pass(input, initial_flooded_result, size, 1);
89
90 Array<int2> *result_to_flood = &initial_flooded_result;
91 Array<int2> intermediate_result(size_t(size.x) * size.y);
92 Array<int2> *result_after_flooding = &intermediate_result;
93
94 const int max_size = math::max(size.x, size.y);
95 int step_size = power_of_2_max_i(max_size) / 2;
96
97 while (step_size != 0) {
98 jump_flooding_pass(*result_to_flood, *result_after_flooding, size, step_size);
99 std::swap(result_to_flood, result_after_flooding);
100 step_size /= 2;
101 }
102
103 return *result_to_flood;
104}
105
106} // namespace blender::compositor
MINLINE int power_of_2_max_i(int n)
#define JUMP_FLOODING_NON_FLOODED_VALUE
static void jump_flooding_pass(Span< JFACoord > input, MutableSpan< JFACoord > output, int2 size, IndexRange x_range, IndexRange y_range, int step_size)
Definition effects.cc:2849
static int2 load_jump_flooding(Span< int2 > input, int2 texel, int2 size, int2 fallback)
Array< int2 > jump_flooding(Span< int2 > input, int2 size)
int2 initialize_jump_flooding_value(int2 texel, bool is_seed)
static void jump_flooding_pass(Span< int2 > input, MutableSpan< int2 > output, int2 size, int step_size)
int2 encode_jump_flooding_value(int2 closest_seed_texel, bool is_flooded)
T max(const T &a, const T &b)
void parallel_for(const IndexRange range, const int64_t grain_size, const Function &function, const TaskSizeHints &size_hints=detail::TaskSizeHints_Static(1))
Definition BLI_task.hh:95