Blender  V3.3
image_partial_update_test.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2020 Blender Foundation. */
3 #include "testing/testing.h"
4 
5 #include "CLG_log.h"
6 
7 #include "BKE_appdir.h"
8 #include "BKE_global.h"
9 #include "BKE_idtype.h"
10 #include "BKE_image.h"
12 #include "BKE_main.h"
13 
14 #include "IMB_imbuf.h"
15 #include "IMB_moviecache.h"
16 
17 #include "DNA_image_types.h"
18 
19 #include "MEM_guardedalloc.h"
20 
22 
23 constexpr float black_color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
24 
25 class ImagePartialUpdateTest : public testing::Test {
26  protected:
31  ImageUser image_user = {nullptr};
33  PartialUpdateUser *partial_update_user;
34 
35  private:
36  Image *create_test_image(int width, int height)
37  {
39  width,
40  height,
41  "Test Image",
42  32,
43  true,
46  false,
47  false,
48  false);
49  }
50 
51  protected:
52  void SetUp() override
53  {
54  CLG_init();
57  IMB_init();
58 
59  bmain = BKE_main_new();
60  /* Required by usage of #ID_BLEND_PATH_FROM_GLOBAL in #add_ibuf_for_tile. */
62  G_MAIN = bmain;
63  /* Creating an image generates a memory-leak during tests. */
64  image = create_test_image(1024, 1024);
66  image_buffer = BKE_image_acquire_ibuf(image, nullptr, nullptr);
67 
69  }
70 
71  void TearDown() override
72  {
75 
76  /* Restore original main in G_MAIN. */
79 
81  IMB_exit();
83  CLG_exit();
84  }
85 };
86 
87 TEST_F(ImagePartialUpdateTest, mark_full_update)
88 {
90  /* First tile should always return a full update. */
93  /* Second invoke should now detect no changes. */
96 
97  /* Mark full update */
99 
100  /* Validate need full update followed by no changes. */
101  result = BKE_image_partial_update_collect_changes(image, partial_update_user);
103  result = BKE_image_partial_update_collect_changes(image, partial_update_user);
105 }
106 
107 TEST_F(ImagePartialUpdateTest, mark_single_tile)
108 {
110  /* First tile should always return a full update. */
111  result = BKE_image_partial_update_collect_changes(image, partial_update_user);
113  /* Second invoke should now detect no changes. */
114  result = BKE_image_partial_update_collect_changes(image, partial_update_user);
116 
117  /* Mark region. */
118  rcti region;
119  BLI_rcti_init(&region, 10, 20, 40, 50);
120  BKE_image_partial_update_mark_region(image, image_tile, image_buffer, &region);
121 
122  /* Partial Update should be available. */
123  result = BKE_image_partial_update_collect_changes(image, partial_update_user);
125 
126  /* Check tiles. */
127  PartialUpdateRegion changed_region;
128  ePartialUpdateIterResult iter_result;
129  iter_result = BKE_image_partial_update_get_next_change(partial_update_user, &changed_region);
131  EXPECT_EQ(BLI_rcti_inside_rcti(&changed_region.region, &region), true);
132  iter_result = BKE_image_partial_update_get_next_change(partial_update_user, &changed_region);
134 
135  result = BKE_image_partial_update_collect_changes(image, partial_update_user);
137 }
138 
139 TEST_F(ImagePartialUpdateTest, mark_unconnected_tiles)
140 {
142  /* First tile should always return a full update. */
143  result = BKE_image_partial_update_collect_changes(image, partial_update_user);
145  /* Second invoke should now detect no changes. */
146  result = BKE_image_partial_update_collect_changes(image, partial_update_user);
148 
149  /* Mark region. */
150  rcti region_a;
151  BLI_rcti_init(&region_a, 10, 20, 40, 50);
152  BKE_image_partial_update_mark_region(image, image_tile, image_buffer, &region_a);
153  rcti region_b;
154  BLI_rcti_init(&region_b, 710, 720, 740, 750);
155  BKE_image_partial_update_mark_region(image, image_tile, image_buffer, &region_b);
156 
157  /* Partial Update should be available. */
158  result = BKE_image_partial_update_collect_changes(image, partial_update_user);
160 
161  /* Check tiles. */
162  PartialUpdateRegion changed_region;
163  ePartialUpdateIterResult iter_result;
164  iter_result = BKE_image_partial_update_get_next_change(partial_update_user, &changed_region);
166  EXPECT_EQ(BLI_rcti_inside_rcti(&changed_region.region, &region_b), true);
167  iter_result = BKE_image_partial_update_get_next_change(partial_update_user, &changed_region);
169  EXPECT_EQ(BLI_rcti_inside_rcti(&changed_region.region, &region_a), true);
170  iter_result = BKE_image_partial_update_get_next_change(partial_update_user, &changed_region);
172 
173  result = BKE_image_partial_update_collect_changes(image, partial_update_user);
175 }
176 
177 TEST_F(ImagePartialUpdateTest, donot_mark_outside_image)
178 {
180  /* First tile should always return a full update. */
181  result = BKE_image_partial_update_collect_changes(image, partial_update_user);
183  /* Second invoke should now detect no changes. */
184  result = BKE_image_partial_update_collect_changes(image, partial_update_user);
186 
187  /* Mark region. */
188  rcti region;
189  /* Axis. */
190  BLI_rcti_init(&region, -100, 0, 50, 100);
191  BKE_image_partial_update_mark_region(image, image_tile, image_buffer, &region);
192  result = BKE_image_partial_update_collect_changes(image, partial_update_user);
194 
195  BLI_rcti_init(&region, 1024, 1100, 50, 100);
196  BKE_image_partial_update_mark_region(image, image_tile, image_buffer, &region);
197  result = BKE_image_partial_update_collect_changes(image, partial_update_user);
199 
200  BLI_rcti_init(&region, 50, 100, -100, 0);
201  BKE_image_partial_update_mark_region(image, image_tile, image_buffer, &region);
202  result = BKE_image_partial_update_collect_changes(image, partial_update_user);
204 
205  BLI_rcti_init(&region, 50, 100, 1024, 1100);
206  BKE_image_partial_update_mark_region(image, image_tile, image_buffer, &region);
207  result = BKE_image_partial_update_collect_changes(image, partial_update_user);
209 
210  /* Diagonals. */
211  BLI_rcti_init(&region, -100, 0, -100, 0);
212  BKE_image_partial_update_mark_region(image, image_tile, image_buffer, &region);
213  result = BKE_image_partial_update_collect_changes(image, partial_update_user);
215 
216  BLI_rcti_init(&region, -100, 0, 1024, 1100);
217  BKE_image_partial_update_mark_region(image, image_tile, image_buffer, &region);
218  result = BKE_image_partial_update_collect_changes(image, partial_update_user);
220 
221  BLI_rcti_init(&region, 1024, 1100, -100, 0);
222  BKE_image_partial_update_mark_region(image, image_tile, image_buffer, &region);
223  result = BKE_image_partial_update_collect_changes(image, partial_update_user);
225 
226  BLI_rcti_init(&region, 1024, 1100, 1024, 1100);
227  BKE_image_partial_update_mark_region(image, image_tile, image_buffer, &region);
228  result = BKE_image_partial_update_collect_changes(image, partial_update_user);
230 }
231 
232 TEST_F(ImagePartialUpdateTest, mark_inside_image)
233 {
235  /* First tile should always return a full update. */
236  result = BKE_image_partial_update_collect_changes(image, partial_update_user);
238  /* Second invoke should now detect no changes. */
239  result = BKE_image_partial_update_collect_changes(image, partial_update_user);
241 
242  /* Mark region. */
243  rcti region;
244  BLI_rcti_init(&region, 0, 1, 0, 1);
245  BKE_image_partial_update_mark_region(image, image_tile, image_buffer, &region);
246  result = BKE_image_partial_update_collect_changes(image, partial_update_user);
248 
249  result = BKE_image_partial_update_collect_changes(image, partial_update_user);
251  BLI_rcti_init(&region, 1023, 1024, 0, 1);
252  BKE_image_partial_update_mark_region(image, image_tile, image_buffer, &region);
253  result = BKE_image_partial_update_collect_changes(image, partial_update_user);
255 
256  result = BKE_image_partial_update_collect_changes(image, partial_update_user);
258  BLI_rcti_init(&region, 1023, 1024, 1023, 1024);
259  BKE_image_partial_update_mark_region(image, image_tile, image_buffer, &region);
260  result = BKE_image_partial_update_collect_changes(image, partial_update_user);
262 
263  result = BKE_image_partial_update_collect_changes(image, partial_update_user);
265  BLI_rcti_init(&region, 1023, 1024, 0, 1);
266  BKE_image_partial_update_mark_region(image, image_tile, image_buffer, &region);
267  result = BKE_image_partial_update_collect_changes(image, partial_update_user);
269 }
270 
271 TEST_F(ImagePartialUpdateTest, sequential_mark_region)
272 {
274  /* First tile should always return a full update. */
275  result = BKE_image_partial_update_collect_changes(image, partial_update_user);
277  /* Second invoke should now detect no changes. */
278  result = BKE_image_partial_update_collect_changes(image, partial_update_user);
280 
281  {
282  /* Mark region. */
283  rcti region;
284  BLI_rcti_init(&region, 10, 20, 40, 50);
285  BKE_image_partial_update_mark_region(image, image_tile, image_buffer, &region);
286 
287  /* Partial Update should be available. */
288  result = BKE_image_partial_update_collect_changes(image, partial_update_user);
290 
291  /* Check tiles. */
292  PartialUpdateRegion changed_region;
293  ePartialUpdateIterResult iter_result;
294  iter_result = BKE_image_partial_update_get_next_change(partial_update_user, &changed_region);
296  EXPECT_EQ(BLI_rcti_inside_rcti(&changed_region.region, &region), true);
297  iter_result = BKE_image_partial_update_get_next_change(partial_update_user, &changed_region);
299 
300  result = BKE_image_partial_update_collect_changes(image, partial_update_user);
302  }
303 
304  {
305  /* Mark different region. */
306  rcti region;
307  BLI_rcti_init(&region, 710, 720, 740, 750);
308  BKE_image_partial_update_mark_region(image, image_tile, image_buffer, &region);
309 
310  /* Partial Update should be available. */
311  result = BKE_image_partial_update_collect_changes(image, partial_update_user);
313 
314  /* Check tiles. */
315  PartialUpdateRegion changed_region;
316  ePartialUpdateIterResult iter_result;
317  iter_result = BKE_image_partial_update_get_next_change(partial_update_user, &changed_region);
319  EXPECT_EQ(BLI_rcti_inside_rcti(&changed_region.region, &region), true);
320  iter_result = BKE_image_partial_update_get_next_change(partial_update_user, &changed_region);
322 
323  result = BKE_image_partial_update_collect_changes(image, partial_update_user);
325  }
326 }
327 
328 TEST_F(ImagePartialUpdateTest, mark_multiple_chunks)
329 {
331  /* First tile should always return a full update. */
332  result = BKE_image_partial_update_collect_changes(image, partial_update_user);
334  /* Second invoke should now detect no changes. */
335  result = BKE_image_partial_update_collect_changes(image, partial_update_user);
337 
338  /* Mark region. */
339  rcti region;
340  BLI_rcti_init(&region, 300, 700, 300, 700);
341  BKE_image_partial_update_mark_region(image, image_tile, image_buffer, &region);
342 
343  /* Partial Update should be available. */
344  result = BKE_image_partial_update_collect_changes(image, partial_update_user);
346 
347  /* Check tiles. */
348  PartialUpdateRegion changed_region;
349  int num_chunks_found = 0;
350  while (BKE_image_partial_update_get_next_change(partial_update_user, &changed_region) ==
352  BLI_rcti_isect(&changed_region.region, &region, nullptr);
353  num_chunks_found++;
354  }
355  EXPECT_EQ(num_chunks_found, 4);
356 }
357 
359 {
360  PartialUpdateChecker<NoTileData> checker(image, &image_user, partial_update_user);
361  /* First tile should always return a full update. */
364  /* Second invoke should now detect no changes. */
365  changes = checker.collect_changes();
367 
368  /* Mark region. */
369  rcti region;
370  BLI_rcti_init(&region, 300, 700, 300, 700);
371  BKE_image_partial_update_mark_region(image, image_tile, image_buffer, &region);
372 
373  /* Partial Update should be available. */
374  changes = checker.collect_changes();
376 
377  /* Check tiles. */
378  int num_tiles_found = 0;
380  BLI_rcti_isect(&changes.changed_region.region, &region, nullptr);
381  num_tiles_found++;
382  }
383  EXPECT_EQ(num_tiles_found, 4);
384 }
385 
386 } // namespace blender::bke::image::partial_update
void BKE_appdir_init(void)
Definition: appdir.c:88
void BKE_appdir_exit(void)
Definition: appdir.c:96
#define G_MAIN
Definition: BKE_global.h:267
void BKE_idtype_init(void)
Definition: idtype.c:106
void BKE_image_release_ibuf(struct Image *ima, struct ImBuf *ibuf, void *lock)
void BKE_image_partial_update_mark_region(struct Image *image, const struct ImageTile *image_tile, const struct ImBuf *image_buffer, const rcti *updated_region)
Mark a region of the image to update.
struct PartialUpdateUser * BKE_image_partial_update_create(const struct Image *image)
Create a new PartialUpdateUser. An Object that contains data to use partial updates.
struct ImBuf * BKE_image_acquire_ibuf(struct Image *ima, struct ImageUser *iuser, void **r_lock)
void BKE_image_partial_update_free(struct PartialUpdateUser *user)
free a partial update user.
struct Image * BKE_image_add_generated(struct 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)
void BKE_image_partial_update_mark_full_update(struct Image *image)
Mark the whole image to be updated.
struct Main * BKE_main_new(void)
Definition: main.c:32
void BKE_main_free(struct Main *mainvar)
Definition: main.c:40
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:417
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:197
void CLG_exit(void)
Definition: clog.c:703
void CLG_init(void)
Definition: clog.c:696
@ IMA_GENTYPE_BLANK
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei height
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei width
void IMB_init(void)
Definition: module.c:16
void IMB_exit(void)
Definition: module.c:25
void IMB_moviecache_destruct(void)
Definition: moviecache.cc:257
Read Guarded memory(de)allocation.
depth_tx normal_tx diffuse_light_tx specular_light_tx volume_light_tx environment_tx ambient_occlusion_tx aov_value_tx in_weight_img image(1, GPU_R32F, Qualifier::WRITE, ImageType::FLOAT_2D_ARRAY, "out_weight_img") .image(3
TEST_F(ImagePartialUpdateTest, mark_full_update)
ePartialUpdateCollectResult BKE_image_partial_update_collect_changes(struct Image *image, struct PartialUpdateUser *user)
collect the partial update since the last request.
ePartialUpdateIterResult BKE_image_partial_update_get_next_change(struct PartialUpdateUser *user, struct 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.
Definition: BKE_main.h:121
ePartialUpdateIterResult get_next_change()
Load the next changed region.
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.