Blender V5.0
symmetric_blur_weights.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 <cstdint>
6#include <memory>
7
8#include "BLI_hash.hh"
9#include "BLI_index_range.hh"
10#include "BLI_math_vector.hh"
12
13#include "RE_pipeline.h"
14
15#include "COM_context.hh"
16#include "COM_result.hh"
18
19namespace blender::compositor {
20
21/* --------------------------------------------------------------------
22 * Symmetric Blur Weights Key.
23 */
24
29
34
36{
37 return a.type == b.type && a.radius == b.radius;
38}
39
40/* --------------------------------------------------------------------
41 * Symmetric Blur Weights.
42 */
43
45 : result(context.create_result(ResultType::Float))
46{
47 /* The full size of filter is double the radius plus 1, but since the filter is symmetric, we
48 * only compute a single quadrant of it and so no doubling happens. We add 1 to make sure the
49 * filter size is always odd and there is a center weight. */
50 const float2 scale = math::safe_divide(float2(1.0f), radius);
51 const int2 size = int2(math::ceil(radius)) + int2(1);
52 this->result.allocate_texture(size, false, ResultStorageType::CPU);
53
54 float sum = 0.0f;
55
56 /* First, compute the center weight. */
57 const float center_weight = RE_filter_value(type, 0.0f);
58 this->result.store_pixel(int2(0, 0), center_weight);
59 sum += center_weight;
60
61 /* Then, compute the weights along the positive x axis, making sure to add double the weight to
62 * the sum of weights because the filter is symmetric and we only loop over the positive half
63 * of the x axis. Skip the center weight already computed by dropping the front index. */
64 for (const int x : IndexRange(size.x).drop_front(1)) {
65 const float weight = RE_filter_value(type, x * scale.x);
66 this->result.store_pixel(int2(x, 0), weight);
67 sum += weight * 2.0f;
68 }
69
70 /* Then, compute the weights along the positive y axis, making sure to add double the weight to
71 * the sum of weights because the filter is symmetric and we only loop over the positive half
72 * of the y axis. Skip the center weight already computed by dropping the front index. */
73 for (const int y : IndexRange(size.y).drop_front(1)) {
74 const float weight = RE_filter_value(type, y * scale.y);
75 this->result.store_pixel(int2(0, y), weight);
76 sum += weight * 2.0f;
77 }
78
79 /* Then, compute the other weights in the upper right quadrant, making sure to add quadruple
80 * the weight to the sum of weights because the filter is symmetric and we only loop over one
81 * quadrant of it. Skip the weights along the y and x axis already computed by dropping the
82 * front index. */
83 for (const int y : IndexRange(size.y).drop_front(1)) {
84 for (const int x : IndexRange(size.x).drop_front(1)) {
85 const float weight = RE_filter_value(type, math::length(float2(x, y) * scale));
86 this->result.store_pixel(int2(x, y), weight);
87 sum += weight * 4.0f;
88 }
89 }
90
91 /* Finally, normalize the weights. */
92 for (const int y : IndexRange(size.y)) {
93 for (const int x : IndexRange(size.x)) {
94 const int2 texel = int2(x, y);
95 this->result.store_pixel(texel, this->result.load_pixel<float>(texel) / sum);
96 }
97 }
98
99 if (context.use_gpu()) {
100 const Result gpu_result = this->result.upload_to_gpu(false);
101 this->result.release();
102 this->result = gpu_result;
103 }
104}
105
110
111/* --------------------------------------------------------------------
112 * Symmetric Blur Weights Container.
113 */
114
116{
117 /* First, delete all resources that are no longer needed. */
118 map_.remove_if([](auto item) { return !item.value->needed; });
119
120 /* Second, reset the needed status of the remaining resources to false to ready them to track
121 * their needed status for the next evaluation. */
122 for (auto &value : map_.values()) {
123 value->needed = false;
124 }
125}
126
128{
129 const SymmetricBlurWeightsKey key(type, radius);
130
131 auto &weights = *map_.lookup_or_add_cb(
132 key, [&]() { return std::make_unique<SymmetricBlurWeights>(context, type, radius); });
133
134 weights.needed = true;
135 return weights.result;
136}
137
138} // namespace blender::compositor
unsigned long long int uint64_t
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
static T sum(const btAlignedObjectArray< T > &items)
constexpr IndexRange drop_front(int64_t n) const
Result & get(Context &context, int type, float2 radius)
SymmetricBlurWeights(Context &context, int type, float2 radius)
float RE_filter_value(int type, float x)
bool operator==(const BokehKernelKey &a, const BokehKernelKey &b)
T safe_divide(const T &a, const T &b)
T length(const VecBase< T, Size > &a)
T ceil(const T &a)
uint64_t get_default_hash(const T &v, const Args &...args)
Definition BLI_hash.hh:233
VecBase< int32_t, 2 > int2
VecBase< float, 2 > float2