Blender V4.5
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_array.hh"
9#include "BLI_hash.hh"
10#include "BLI_index_range.hh"
11#include "BLI_math_vector.hh"
13
14#include "RE_pipeline.h"
15
16#include "GPU_texture.hh"
17
18#include "COM_context.hh"
19#include "COM_result.hh"
21
22namespace blender::compositor {
23
24/* --------------------------------------------------------------------
25 * Symmetric Blur Weights Key.
26 */
27
32
37
39{
40 return a.type == b.type && a.radius == b.radius;
41}
42
43/* --------------------------------------------------------------------
44 * Symmetric Blur Weights.
45 */
46
48 : result(context.create_result(ResultType::Float))
49{
50 /* The full size of filter is double the radius plus 1, but since the filter is symmetric, we
51 * only compute a single quadrant of it and so no doubling happens. We add 1 to make sure the
52 * filter size is always odd and there is a center weight. */
53 const float2 scale = math::safe_divide(float2(1.0f), radius);
54 const int2 size = int2(math::ceil(radius)) + int2(1);
55 weights_ = Array<float>(size.x * size.y);
56
57 float sum = 0.0f;
58
59 /* First, compute the center weight. */
60 const float center_weight = RE_filter_value(type, 0.0f);
61 weights_[0] = center_weight;
62 sum += center_weight;
63
64 /* Then, compute the weights along the positive x axis, making sure to add double the weight to
65 * the sum of weights because the filter is symmetric and we only loop over the positive half
66 * of the x axis. Skip the center weight already computed by dropping the front index. */
67 for (const int x : IndexRange(size.x).drop_front(1)) {
68 const float weight = RE_filter_value(type, x * scale.x);
69 weights_[x] = weight;
70 sum += weight * 2.0f;
71 }
72
73 /* Then, compute the weights along the positive y axis, making sure to add double the weight to
74 * the sum of weights because the filter is symmetric and we only loop over the positive half
75 * of the y axis. Skip the center weight already computed by dropping the front index. */
76 for (const int y : IndexRange(size.y).drop_front(1)) {
77 const float weight = RE_filter_value(type, y * scale.y);
78 weights_[size.x * y] = weight;
79 sum += weight * 2.0f;
80 }
81
82 /* Then, compute the other weights in the upper right quadrant, making sure to add quadruple
83 * the weight to the sum of weights because the filter is symmetric and we only loop over one
84 * quadrant of it. Skip the weights along the y and x axis already computed by dropping the
85 * front index. */
86 for (const int y : IndexRange(size.y).drop_front(1)) {
87 for (const int x : IndexRange(size.x).drop_front(1)) {
88 const float weight = RE_filter_value(type, math::length(float2(x, y) * scale));
89 weights_[size.x * y + x] = weight;
90 sum += weight * 4.0f;
91 }
92 }
93
94 /* Finally, normalize the weights. */
95 for (const int y : IndexRange(size.y)) {
96 for (const int x : IndexRange(size.x)) {
97 weights_[size.x * y + x] /= sum;
98 }
99 }
100
101 if (context.use_gpu()) {
102 this->result.allocate_texture(Domain(size), false);
103 GPU_texture_update(this->result, GPU_DATA_FLOAT, weights_.data());
104
105 /* CPU-side data no longer needed, so free it. */
106 weights_ = Array<float>();
107 }
108 else {
109 this->result.wrap_external(weights_.data(), size);
110 }
111}
112
117
118/* --------------------------------------------------------------------
119 * Symmetric Blur Weights Container.
120 */
121
123{
124 /* First, delete all resources that are no longer needed. */
125 map_.remove_if([](auto item) { return !item.value->needed; });
126
127 /* Second, reset the needed status of the remaining resources to false to ready them to track
128 * their needed status for the next evaluation. */
129 for (auto &value : map_.values()) {
130 value->needed = false;
131 }
132}
133
135{
136 const SymmetricBlurWeightsKey key(type, radius);
137
138 auto &weights = *map_.lookup_or_add_cb(
139 key, [&]() { return std::make_unique<SymmetricBlurWeights>(context, type, radius); });
140
141 weights.needed = true;
142 return weights.result;
143}
144
145} // namespace blender::compositor
@ GPU_DATA_FLOAT
void GPU_texture_update(GPUTexture *texture, eGPUDataFormat data_format, const void *data)
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