Blender V4.3
image_partial_update_test.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2020 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4#include "testing/testing.h"
5
6#include "CLG_log.h"
7
8#include "GHOST_Path-api.hh"
9
10#include "BKE_appdir.hh"
11#include "BKE_global.hh"
12#include "BKE_idtype.hh"
13#include "BKE_image.hh"
15#include "BKE_main.hh"
16
17#include "IMB_imbuf.hh"
18#include "IMB_moviecache.hh"
19
20#include "DNA_image_types.h"
21
22#include "MEM_guardedalloc.h"
23
25
26constexpr float black_color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
27
28class ImagePartialUpdateTest : public testing::Test {
29 protected:
34 ImageUser image_user = {nullptr};
36 PartialUpdateUser *partial_update_user;
37
38 private:
39 Image *create_test_image(int width, int height)
40 {
42 width,
43 height,
44 "Test Image",
45 32,
46 true,
49 false,
50 false,
51 false);
52 }
53
54 protected:
55 void SetUp() override
56 {
57 CLG_init();
60 IMB_init();
61
63 /* Required by usage of #ID_BLEND_PATH_FROM_GLOBAL in #add_ibuf_for_tile. */
65 G_MAIN = bmain;
66 /* Creating an image generates a memory-leak during tests. */
67 image = create_test_image(1024, 1024);
69 image_buffer = BKE_image_acquire_ibuf(image, nullptr, nullptr);
70
72 }
73
74 void TearDown() override
75 {
76 BKE_image_release_ibuf(image, image_buffer, nullptr);
78
79 /* Restore original main in G_MAIN. */
82
84 IMB_exit();
87 CLG_exit();
88 }
89};
90
92{
94 /* First tile should always return a full update. */
95 result = BKE_image_partial_update_collect_changes(image, partial_update_user);
97 /* Second invoke should now detect no changes. */
98 result = BKE_image_partial_update_collect_changes(image, partial_update_user);
100
101 /* Mark full update */
103
104 /* Validate need full update followed by no changes. */
105 result = BKE_image_partial_update_collect_changes(image, partial_update_user);
107 result = BKE_image_partial_update_collect_changes(image, partial_update_user);
109}
110
112{
114 /* First tile should always return a full update. */
115 result = BKE_image_partial_update_collect_changes(image, partial_update_user);
117 /* Second invoke should now detect no changes. */
118 result = BKE_image_partial_update_collect_changes(image, partial_update_user);
120
121 /* Mark region. */
122 rcti region;
123 BLI_rcti_init(&region, 10, 20, 40, 50);
124 BKE_image_partial_update_mark_region(image, image_tile, image_buffer, &region);
125
126 /* Partial Update should be available. */
127 result = BKE_image_partial_update_collect_changes(image, partial_update_user);
129
130 /* Check tiles. */
131 PartialUpdateRegion changed_region;
132 ePartialUpdateIterResult iter_result;
133 iter_result = BKE_image_partial_update_get_next_change(partial_update_user, &changed_region);
135 EXPECT_EQ(BLI_rcti_inside_rcti(&changed_region.region, &region), true);
136 iter_result = BKE_image_partial_update_get_next_change(partial_update_user, &changed_region);
138
139 result = BKE_image_partial_update_collect_changes(image, partial_update_user);
141}
142
143TEST_F(ImagePartialUpdateTest, mark_unconnected_tiles)
144{
146 /* First tile should always return a full update. */
147 result = BKE_image_partial_update_collect_changes(image, partial_update_user);
149 /* Second invoke should now detect no changes. */
150 result = BKE_image_partial_update_collect_changes(image, partial_update_user);
152
153 /* Mark region. */
154 rcti region_a;
155 BLI_rcti_init(&region_a, 10, 20, 40, 50);
156 BKE_image_partial_update_mark_region(image, image_tile, image_buffer, &region_a);
157 rcti region_b;
158 BLI_rcti_init(&region_b, 710, 720, 740, 750);
159 BKE_image_partial_update_mark_region(image, image_tile, image_buffer, &region_b);
160
161 /* Partial Update should be available. */
162 result = BKE_image_partial_update_collect_changes(image, partial_update_user);
164
165 /* Check tiles. */
166 PartialUpdateRegion changed_region;
167 ePartialUpdateIterResult iter_result;
168 iter_result = BKE_image_partial_update_get_next_change(partial_update_user, &changed_region);
170 EXPECT_EQ(BLI_rcti_inside_rcti(&changed_region.region, &region_b), true);
171 iter_result = BKE_image_partial_update_get_next_change(partial_update_user, &changed_region);
173 EXPECT_EQ(BLI_rcti_inside_rcti(&changed_region.region, &region_a), true);
174 iter_result = BKE_image_partial_update_get_next_change(partial_update_user, &changed_region);
176
177 result = BKE_image_partial_update_collect_changes(image, partial_update_user);
179}
180
181TEST_F(ImagePartialUpdateTest, donot_mark_outside_image)
182{
184 /* First tile should always return a full update. */
185 result = BKE_image_partial_update_collect_changes(image, partial_update_user);
187 /* Second invoke should now detect no changes. */
188 result = BKE_image_partial_update_collect_changes(image, partial_update_user);
190
191 /* Mark region. */
192 rcti region;
193 /* Axis. */
194 BLI_rcti_init(&region, -100, 0, 50, 100);
195 BKE_image_partial_update_mark_region(image, image_tile, image_buffer, &region);
196 result = BKE_image_partial_update_collect_changes(image, partial_update_user);
198
199 BLI_rcti_init(&region, 1024, 1100, 50, 100);
200 BKE_image_partial_update_mark_region(image, image_tile, image_buffer, &region);
201 result = BKE_image_partial_update_collect_changes(image, partial_update_user);
203
204 BLI_rcti_init(&region, 50, 100, -100, 0);
205 BKE_image_partial_update_mark_region(image, image_tile, image_buffer, &region);
206 result = BKE_image_partial_update_collect_changes(image, partial_update_user);
208
209 BLI_rcti_init(&region, 50, 100, 1024, 1100);
210 BKE_image_partial_update_mark_region(image, image_tile, image_buffer, &region);
211 result = BKE_image_partial_update_collect_changes(image, partial_update_user);
213
214 /* Diagonals. */
215 BLI_rcti_init(&region, -100, 0, -100, 0);
216 BKE_image_partial_update_mark_region(image, image_tile, image_buffer, &region);
217 result = BKE_image_partial_update_collect_changes(image, partial_update_user);
219
220 BLI_rcti_init(&region, -100, 0, 1024, 1100);
221 BKE_image_partial_update_mark_region(image, image_tile, image_buffer, &region);
222 result = BKE_image_partial_update_collect_changes(image, partial_update_user);
224
225 BLI_rcti_init(&region, 1024, 1100, -100, 0);
226 BKE_image_partial_update_mark_region(image, image_tile, image_buffer, &region);
227 result = BKE_image_partial_update_collect_changes(image, partial_update_user);
229
230 BLI_rcti_init(&region, 1024, 1100, 1024, 1100);
231 BKE_image_partial_update_mark_region(image, image_tile, image_buffer, &region);
232 result = BKE_image_partial_update_collect_changes(image, partial_update_user);
234}
235
237{
239 /* First tile should always return a full update. */
240 result = BKE_image_partial_update_collect_changes(image, partial_update_user);
242 /* Second invoke should now detect no changes. */
243 result = BKE_image_partial_update_collect_changes(image, partial_update_user);
245
246 /* Mark region. */
247 rcti region;
248 BLI_rcti_init(&region, 0, 1, 0, 1);
249 BKE_image_partial_update_mark_region(image, image_tile, image_buffer, &region);
250 result = BKE_image_partial_update_collect_changes(image, partial_update_user);
252
253 result = BKE_image_partial_update_collect_changes(image, partial_update_user);
255 BLI_rcti_init(&region, 1023, 1024, 0, 1);
256 BKE_image_partial_update_mark_region(image, image_tile, image_buffer, &region);
257 result = BKE_image_partial_update_collect_changes(image, partial_update_user);
259
260 result = BKE_image_partial_update_collect_changes(image, partial_update_user);
262 BLI_rcti_init(&region, 1023, 1024, 1023, 1024);
263 BKE_image_partial_update_mark_region(image, image_tile, image_buffer, &region);
264 result = BKE_image_partial_update_collect_changes(image, partial_update_user);
266
267 result = BKE_image_partial_update_collect_changes(image, partial_update_user);
269 BLI_rcti_init(&region, 1023, 1024, 0, 1);
270 BKE_image_partial_update_mark_region(image, image_tile, image_buffer, &region);
271 result = BKE_image_partial_update_collect_changes(image, partial_update_user);
273}
274
275TEST_F(ImagePartialUpdateTest, sequential_mark_region)
276{
278 /* First tile should always return a full update. */
279 result = BKE_image_partial_update_collect_changes(image, partial_update_user);
281 /* Second invoke should now detect no changes. */
282 result = BKE_image_partial_update_collect_changes(image, partial_update_user);
284
285 {
286 /* Mark region. */
287 rcti region;
288 BLI_rcti_init(&region, 10, 20, 40, 50);
289 BKE_image_partial_update_mark_region(image, image_tile, image_buffer, &region);
290
291 /* Partial Update should be available. */
292 result = BKE_image_partial_update_collect_changes(image, partial_update_user);
294
295 /* Check tiles. */
296 PartialUpdateRegion changed_region;
297 ePartialUpdateIterResult iter_result;
298 iter_result = BKE_image_partial_update_get_next_change(partial_update_user, &changed_region);
300 EXPECT_EQ(BLI_rcti_inside_rcti(&changed_region.region, &region), true);
301 iter_result = BKE_image_partial_update_get_next_change(partial_update_user, &changed_region);
303
304 result = BKE_image_partial_update_collect_changes(image, partial_update_user);
306 }
307
308 {
309 /* Mark different region. */
310 rcti region;
311 BLI_rcti_init(&region, 710, 720, 740, 750);
312 BKE_image_partial_update_mark_region(image, image_tile, image_buffer, &region);
313
314 /* Partial Update should be available. */
315 result = BKE_image_partial_update_collect_changes(image, partial_update_user);
317
318 /* Check tiles. */
319 PartialUpdateRegion changed_region;
320 ePartialUpdateIterResult iter_result;
321 iter_result = BKE_image_partial_update_get_next_change(partial_update_user, &changed_region);
323 EXPECT_EQ(BLI_rcti_inside_rcti(&changed_region.region, &region), true);
324 iter_result = BKE_image_partial_update_get_next_change(partial_update_user, &changed_region);
326
327 result = BKE_image_partial_update_collect_changes(image, partial_update_user);
329 }
330}
331
332TEST_F(ImagePartialUpdateTest, mark_multiple_chunks)
333{
335 /* First tile should always return a full update. */
336 result = BKE_image_partial_update_collect_changes(image, partial_update_user);
338 /* Second invoke should now detect no changes. */
339 result = BKE_image_partial_update_collect_changes(image, partial_update_user);
341
342 /* Mark region. */
343 rcti region;
344 BLI_rcti_init(&region, 300, 700, 300, 700);
345 BKE_image_partial_update_mark_region(image, image_tile, image_buffer, &region);
346
347 /* Partial Update should be available. */
348 result = BKE_image_partial_update_collect_changes(image, partial_update_user);
350
351 /* Check tiles. */
352 PartialUpdateRegion changed_region;
353 int num_chunks_found = 0;
354 while (BKE_image_partial_update_get_next_change(partial_update_user, &changed_region) ==
356 {
357 BLI_rcti_isect(&changed_region.region, &region, nullptr);
358 num_chunks_found++;
359 }
360 EXPECT_EQ(num_chunks_found, 4);
361}
362
364{
365 PartialUpdateChecker<NoTileData> checker(image, &image_user, partial_update_user);
366 /* First tile should always return a full update. */
369 /* Second invoke should now detect no changes. */
370 changes = checker.collect_changes();
372
373 /* Mark region. */
374 rcti region;
375 BLI_rcti_init(&region, 300, 700, 300, 700);
376 BKE_image_partial_update_mark_region(image, image_tile, image_buffer, &region);
377
378 /* Partial Update should be available. */
379 changes = checker.collect_changes();
381
382 /* Check tiles. */
383 int num_tiles_found = 0;
384 while (changes.get_next_change() == ePartialUpdateIterResult::ChangeAvailable) {
385 BLI_rcti_isect(&changes.changed_region.region, &region, nullptr);
386 num_tiles_found++;
387 }
388 EXPECT_EQ(num_tiles_found, 4);
389}
390
391} // namespace blender::bke::image::partial_update
void BKE_appdir_init()
Definition appdir.cc:93
void BKE_appdir_exit()
Definition appdir.cc:101
#define G_MAIN
void BKE_idtype_init()
Definition idtype.cc:127
ImBuf * BKE_image_acquire_ibuf(Image *ima, ImageUser *iuser, void **r_lock)
void BKE_image_partial_update_mark_region(Image *image, const ImageTile *image_tile, const ImBuf *image_buffer, const rcti *updated_region)
Mark a region of the image to update.
void BKE_image_release_ibuf(Image *ima, ImBuf *ibuf, void *lock)
void BKE_image_partial_update_free(PartialUpdateUser *user)
free a partial update user.
PartialUpdateUser * BKE_image_partial_update_create(const Image *image)
Create a new PartialUpdateUser. An Object that contains data to use partial updates.
void BKE_image_partial_update_mark_full_update(Image *image)
Mark the whole image to be updated.
Image * BKE_image_add_generated(Main *bmain, unsigned int width, unsigned int height, const char *name, int depth, int floatbuf, short gen_type, const float color[4], bool stereo3d, bool is_data, bool tiled)
Main * BKE_main_new(void)
Definition main.cc:45
void BKE_main_free(Main *bmain)
Definition main.cc:175
EXPECT_EQ(BLI_expr_pylike_eval(expr, nullptr, 0, &result), EXPR_PYLIKE_INVALID)
void BLI_rcti_init(struct rcti *rect, int xmin, int xmax, int ymin, int ymax)
Definition rct.c:418
bool BLI_rcti_isect(const struct rcti *src1, const struct rcti *src2, struct rcti *dest)
bool BLI_rcti_inside_rcti(const rcti *rct_a, const rcti *rct_b)
Definition rct.c:198
void CLG_exit(void)
Definition clog.c:706
void CLG_init(void)
Definition clog.c:699
@ IMA_GENTYPE_BLANK
GHOST_TSuccess GHOST_DisposeSystemPaths()
void IMB_exit()
Definition module.cc:26
void IMB_init()
Definition module.cc:18
void IMB_moviecache_destruct()
Read Guarded memory(de)allocation.
ePartialUpdateCollectResult BKE_image_partial_update_collect_changes(Image *image, PartialUpdateUser *user)
collect the partial update since the last request.
TEST_F(ImagePartialUpdateTest, mark_full_update)
ePartialUpdateIterResult BKE_image_partial_update_get_next_change(PartialUpdateUser *user, PartialUpdateRegion *r_region)
ePartialUpdateCollectResult
Result codes of BKE_image_partial_update_collect_changes.
@ PartialChangesDetected
Changes detected since the last time requested.
@ FullUpdateNeeded
Unable to construct partial updates. Caller should perform a full update.
@ NoChangesDetected
No changes detected since the last time requested.
ePartialUpdateIterResult
Return codes of BKE_image_partial_update_get_next_change.
@ Finished
no tiles left when iterating over tiles.
@ ChangeAvailable
a chunk was available and has been loaded.
CollectResult collect_changes()
Check for new changes since the last time this method was invoked for this user.
struct rcti region
region of the image that has been updated. Region can be bigger than actual changes.
void * BKE_image_get_tile
Definition stubs.c:36