Blender V4.3
cached_mask.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"
12#include "BLI_task.hh"
13
14#include "GPU_texture.hh"
15
16#include "BKE_lib_id.hh"
17#include "BKE_mask.h"
18
19#include "DNA_ID.h"
20#include "DNA_mask_types.h"
21
22#include "COM_cached_mask.hh"
23#include "COM_context.hh"
24#include "COM_result.hh"
25
27
28/* --------------------------------------------------------------------
29 * Cached Mask Key.
30 */
31
33 float aspect_ratio,
34 bool use_feather,
35 int motion_blur_samples,
36 float motion_blur_shutter)
37 : size(size),
38 aspect_ratio(aspect_ratio),
39 use_feather(use_feather),
40 motion_blur_samples(motion_blur_samples),
41 motion_blur_shutter(motion_blur_shutter)
42{
43}
44
50
52{
53 return a.size == b.size && a.aspect_ratio == b.aspect_ratio && a.use_feather == b.use_feather &&
54 a.motion_blur_samples == b.motion_blur_samples &&
55 a.motion_blur_shutter == b.motion_blur_shutter;
56}
57
58/* --------------------------------------------------------------------
59 * Cached Mask.
60 */
61
63 int2 size,
64 int current_frame,
65 bool use_feather,
66 int motion_blur_samples,
67 float motion_blur_shutter)
68{
70
71 if (!mask) {
72 return handles;
73 }
74
75 /* If motion blur samples are 1, that means motion blur is disabled, in that case, just return
76 * the currently evaluated raster handle. */
77 if (motion_blur_samples == 1) {
79 BKE_maskrasterize_handle_init(handle, mask, size.x, size.y, true, true, use_feather);
80 handles.append(handle);
81 return handles;
82 }
83
84 /* Otherwise, we have a number of motion blur samples, so make a copy of the Mask ID and evaluate
85 * it at the different motion blur frames to get the needed raster handles. */
86 Mask *evaluation_mask = reinterpret_cast<Mask *>(
87 BKE_id_copy_ex(nullptr, &mask->id, nullptr, LIB_ID_COPY_LOCALIZE | LIB_ID_COPY_NO_ANIMDATA));
88
89 /* We evaluate at the frames in the range [current_frame - shutter, current_frame + shutter]. */
90 const float start_frame = current_frame - motion_blur_shutter;
91 const float frame_step = (motion_blur_shutter * 2.0f) / motion_blur_samples;
92 for (int i = 0; i < motion_blur_samples; i++) {
94 BKE_mask_evaluate(evaluation_mask, start_frame + frame_step * i, true);
96 handle, evaluation_mask, size.x, size.y, true, true, use_feather);
97 handles.append(handle);
98 }
99
100 BKE_id_free(nullptr, &evaluation_mask->id);
101
102 return handles;
103}
104
106 Mask *mask,
107 int2 size,
108 int frame,
109 float aspect_ratio,
110 bool use_feather,
111 int motion_blur_samples,
112 float motion_blur_shutter)
113{
115 mask, size, frame, use_feather, motion_blur_samples, motion_blur_shutter);
116
117 Array<float> evaluated_mask(size.x * size.y);
118 threading::parallel_for(IndexRange(size.y), 1, [&](const IndexRange sub_y_range) {
119 for (const int64_t y : sub_y_range) {
120 for (const int64_t x : IndexRange(size.x)) {
121 /* Compute the coordinates in the [0, 1] range and add 0.5 to evaluate the mask at the
122 * center of pixels. */
123 float2 coordinates = (float2(x, y) + 0.5f) / float2(size);
124 /* Do aspect ratio correction around the center 0.5 point. */
125 coordinates = (coordinates - float2(0.5)) * float2(1.0, aspect_ratio) + float2(0.5);
126
127 float mask_value = 0.0f;
128 for (MaskRasterHandle *handle : handles) {
129 mask_value += BKE_maskrasterize_handle_sample(handle, coordinates);
130 }
131 evaluated_mask[y * size.x + x] = mask_value / handles.size();
132 }
133 }
134 });
135
136 for (MaskRasterHandle *handle : handles) {
138 }
139
140 texture_ = GPU_texture_create_2d(
141 "Cached Mask",
142 size.x,
143 size.y,
144 1,
145 Result::gpu_texture_format(ResultType::Float, context.get_precision()),
147 evaluated_mask.data());
148}
149
150CachedMask::~CachedMask()
151{
152 GPU_texture_free(texture_);
153}
154
155GPUTexture *CachedMask::texture()
156{
157 return texture_;
158}
159
160/* --------------------------------------------------------------------
161 * Cached Mask Container.
162 */
163
164void CachedMaskContainer::reset()
165{
166 /* First, delete all cached masks that are no longer needed. */
167 for (auto &cached_masks_for_id : map_.values()) {
168 cached_masks_for_id.remove_if([](auto item) { return !item.value->needed; });
169 }
170 map_.remove_if([](auto item) { return item.value.is_empty(); });
171
172 /* Second, reset the needed status of the remaining cached masks to false to ready them to track
173 * their needed status for the next evaluation. */
174 for (auto &cached_masks_for_id : map_.values()) {
175 for (auto &value : cached_masks_for_id.values()) {
176 value->needed = false;
177 }
178 }
179}
180
181CachedMask &CachedMaskContainer::get(Context &context,
182 Mask *mask,
183 int2 size,
184 float aspect_ratio,
185 bool use_feather,
186 int motion_blur_samples,
187 float motion_blur_shutter)
188{
189 const CachedMaskKey key(
190 size, aspect_ratio, use_feather, motion_blur_samples, motion_blur_shutter);
191
192 const std::string library_key = mask->id.lib ? mask->id.lib->id.name : "";
193 const std::string id_key = std::string(mask->id.name) + library_key;
194 auto &cached_masks_for_id = map_.lookup_or_add_default(id_key);
195
196 /* Invalidate the cache for that mask ID if it was changed and reset the recalculate flag. */
197 if (context.query_id_recalc_flag(reinterpret_cast<ID *>(mask)) & ID_RECALC_ALL) {
198 cached_masks_for_id.clear();
199 }
200
201 auto &cached_mask = *cached_masks_for_id.lookup_or_add_cb(key, [&]() {
202 return std::make_unique<CachedMask>(context,
203 mask,
204 size,
205 context.get_frame_number(),
206 aspect_ratio,
207 use_feather,
208 motion_blur_samples,
209 motion_blur_shutter);
210 });
211
212 cached_mask.needed = true;
213 return cached_mask;
214}
215
216} // namespace blender::realtime_compositor
@ LIB_ID_COPY_LOCALIZE
@ LIB_ID_COPY_NO_ANIMDATA
void BKE_id_free(Main *bmain, void *idv)
ID * BKE_id_copy_ex(Main *bmain, const ID *id, ID **new_id_p, int flag)
Definition lib_id.cc:760
void BKE_maskrasterize_handle_free(MaskRasterHandle *mr_handle)
MaskRasterHandle * BKE_maskrasterize_handle_new(void)
void BKE_mask_evaluate(struct Mask *mask, float ctime, bool do_newframe)
void BKE_maskrasterize_handle_init(MaskRasterHandle *mr_handle, struct Mask *mask, int width, int height, bool do_aspect_correct, bool do_mask_aa, bool do_feather)
ID and Library types, which are fundamental for SDNA.
@ ID_RECALC_ALL
Definition DNA_ID.h:1155
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)
@ GPU_TEXTURE_USAGE_SHADER_READ
CachedMaskKey(int2 size, float aspect_ratio, bool use_feather, int motion_blur_samples, float motion_blur_shutter)
CachedMask(Context &context, Mask *mask, int2 size, int frame, float aspect_ratio, bool use_feather, int motion_blur_samples, float motion_blur_shutter)
static eGPUTextureFormat gpu_texture_format(ResultType type, ResultPrecision precision)
Definition result.cc:29
local_group_size(16, 16) .push_constant(Type b
bool operator==(const BokehKernelKey &a, const BokehKernelKey &b)
static Vector< MaskRasterHandle * > get_mask_raster_handles(Mask *mask, int2 size, int current_frame, bool use_feather, int motion_blur_samples, float motion_blur_shutter)
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
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
Definition DNA_ID.h:413
ParamHandle ** handles