Blender V4.3
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_shader.hh"
17#include "GPU_texture.hh"
18
19#include "COM_context.hh"
20#include "COM_result.hh"
22
24
25/* --------------------------------------------------------------------
26 * Symmetric Blur Weights Key.
27 */
28
30 : type(type), radius(radius)
31{
32}
33
35{
36 return get_default_hash(type, radius.x, radius.y);
37}
38
40{
41 return a.type == b.type && a.radius == b.radius;
42}
43
44/* --------------------------------------------------------------------
45 * Symmetric Blur Weights.
46 */
47
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 Array<float> weights(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 texture_ = GPU_texture_create_2d(
102 "Weights",
103 size.x,
104 size.y,
105 1,
106 Result::gpu_texture_format(ResultType::Float, context.get_precision()),
108 weights.data());
109}
110
115
116void SymmetricBlurWeights::bind_as_texture(GPUShader *shader, const char *texture_name) const
117{
118 const int texture_image_unit = GPU_shader_get_sampler_binding(shader, texture_name);
119 GPU_texture_bind(texture_, texture_image_unit);
120}
121
126
127/* --------------------------------------------------------------------
128 * Symmetric Blur Weights Container.
129 */
130
132{
133 /* First, delete all resources that are no longer needed. */
134 map_.remove_if([](auto item) { return !item.value->needed; });
135
136 /* Second, reset the needed status of the remaining resources to false to ready them to track
137 * their needed status for the next evaluation. */
138 for (auto &value : map_.values()) {
139 value->needed = false;
140 }
141}
142
144{
145 const SymmetricBlurWeightsKey key(type, radius);
146
147 auto &weights = *map_.lookup_or_add_cb(
148 key, [&]() { return std::make_unique<SymmetricBlurWeights>(context, type, radius); });
149
150 weights.needed = true;
151 return weights;
152}
153
154} // namespace blender::realtime_compositor
int GPU_shader_get_sampler_binding(GPUShader *shader, const char *name)
void GPU_texture_bind(GPUTexture *texture, int unit)
GPUTexture * GPU_texture_create_2d(const char *name, int width, int height, int mip_len, eGPUTextureFormat format, eGPUTextureUsage usage, const float *data)
void GPU_texture_free(GPUTexture *texture)
void GPU_texture_unbind(GPUTexture *texture)
@ GPU_TEXTURE_USAGE_GENERAL
struct GPUShader GPUShader
static T sum(const btAlignedObjectArray< T > &items)
const T * data() const
Definition BLI_array.hh:301
constexpr IndexRange drop_front(int64_t n) const
static eGPUTextureFormat gpu_texture_format(ResultType type, ResultPrecision precision)
Definition result.cc:29
SymmetricBlurWeights & get(Context &context, int type, float2 radius)
SymmetricBlurWeights(Context &context, int type, float2 radius)
void bind_as_texture(GPUShader *shader, const char *texture_name) const
local_group_size(16, 16) .push_constant(Type b
float RE_filter_value(int type, float x)
T safe_divide(const T &a, const T &b)
T length(const VecBase< T, Size > &a)
T ceil(const T &a)
bool operator==(const BokehKernelKey &a, const BokehKernelKey &b)
VecBase< int32_t, 2 > int2
VecBase< float, 2 > float2
uint64_t get_default_hash(const T &v)
Definition BLI_hash.hh:219
unsigned __int64 uint64_t
Definition stdint.h:90