Blender  V3.3
gpencil_update_cache.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2022 Blender Foundation. */
3 
8 #include <stdio.h>
9 
11 
12 #include "BLI_dlrbTree.h"
13 #include "BLI_listbase.h"
14 
15 #include "BKE_gpencil.h"
16 
17 #include "DNA_gpencil_types.h"
18 #include "DNA_userdef_types.h"
19 
20 #include "MEM_guardedalloc.h"
21 
22 static GPencilUpdateCache *update_cache_alloc(int index, int flag, void *data)
23 {
24  GPencilUpdateCache *new_cache = MEM_callocN(sizeof(GPencilUpdateCache), __func__);
25  new_cache->children = BLI_dlrbTree_new();
26  new_cache->flag = flag;
27  new_cache->index = index;
28  new_cache->data = data;
29 
30  return new_cache;
31 }
32 
33 static short cache_node_compare(void *node, void *data)
34 {
35  int index_a = ((GPencilUpdateCacheNode *)node)->cache->index;
36  int index_b = ((GPencilUpdateCache *)data)->index;
37  if (index_a == index_b) {
38  return 0;
39  }
40  return index_a < index_b ? 1 : -1;
41 }
42 
44 {
45  GPencilUpdateCacheNode *new_node = MEM_callocN(sizeof(GPencilUpdateCacheNode), __func__);
46  new_node->cache = ((GPencilUpdateCache *)data);
47  return (DLRBT_Node *)new_node;
48 }
49 
50 static void cache_node_free(void *node);
51 
53 {
55  MEM_SAFE_FREE(cache->children);
56  MEM_freeN(cache);
57 }
58 
59 static void cache_node_free(void *node)
60 {
61  GPencilUpdateCache *cache = ((GPencilUpdateCacheNode *)node)->cache;
62  if (cache != NULL) {
63  update_cache_free(cache);
64  }
65  MEM_freeN(node);
66 }
67 
68 static void cache_node_update(void *node, void *data)
69 {
70  GPencilUpdateCache *update_cache = ((GPencilUpdateCacheNode *)node)->cache;
71  GPencilUpdateCache *new_update_cache = (GPencilUpdateCache *)data;
72 
73  /* If the new cache is already "covered" by the current cache, just free it and return. */
74  if (new_update_cache->flag <= update_cache->flag) {
75  update_cache_free(new_update_cache);
76  return;
77  }
78 
79  update_cache->data = new_update_cache->data;
80  update_cache->flag = new_update_cache->flag;
81 
82  /* In case the new cache does a full update, remove its children since they will be all
83  * updated by this cache. */
84  if (new_update_cache->flag == GP_UPDATE_NODE_FULL_COPY) {
86  }
87 
88  update_cache_free(new_update_cache);
89 }
90 
92  void *data,
93  int gpl_index,
94  int gpf_index,
95  int gps_index,
96  bool full_copy)
97 {
98  if (root_cache->flag == GP_UPDATE_NODE_FULL_COPY) {
99  /* Entire data-block has to be recalculated, e.g. nothing else needs to be added to the cache.
100  */
101  return;
102  }
103 
104  const int node_flag = full_copy ? GP_UPDATE_NODE_FULL_COPY : GP_UPDATE_NODE_LIGHT_COPY;
105 
106  if (gpl_index == -1) {
107  root_cache->data = (bGPdata *)data;
108  root_cache->flag = node_flag;
109  if (full_copy) {
110  /* Entire data-block has to be recalculated, remove all caches of "lower" elements. */
112  }
113  return;
114  }
115 
116  const bool is_layer_update_node = (gpf_index == -1);
117  /* If the data pointer in #GPencilUpdateCache is NULL, this element is not actually cached
118  * and does not need to be updated, but we do need the index to find elements that are in
119  * levels below. E.g. if a stroke needs to be updated, the frame it is in would not hold a
120  * pointer to it's data. */
122  gpl_index,
123  is_layer_update_node ? node_flag : GP_UPDATE_NODE_NO_COPY,
124  is_layer_update_node ? (bGPDlayer *)data : NULL);
127 
129  if (gpl_node->cache->flag == GP_UPDATE_NODE_FULL_COPY || is_layer_update_node) {
130  return;
131  }
132 
133  const bool is_frame_update_node = (gps_index == -1);
135  gpf_index,
136  is_frame_update_node ? node_flag : GP_UPDATE_NODE_NO_COPY,
137  is_frame_update_node ? (bGPDframe *)data : NULL);
139  gpl_node->cache->children,
143  gpf_cache);
144 
146  if (gpf_node->cache->flag == GP_UPDATE_NODE_FULL_COPY || is_frame_update_node) {
147  return;
148  }
149 
150  GPencilUpdateCache *gps_cache = update_cache_alloc(gps_index, node_flag, (bGPDstroke *)data);
151  BLI_dlrbTree_add(gpf_node->cache->children,
155  gps_cache);
156 
158 }
159 
161  bGPdata *gpd, bGPDlayer *gpl, bGPDframe *gpf, bGPDstroke *gps, bool full_copy)
162 {
163  if (gpd == NULL) {
164  return;
165  }
166 
167  GPencilUpdateCache *root_cache = gpd->runtime.update_cache;
168  if (root_cache == NULL) {
170  root_cache = gpd->runtime.update_cache;
171  }
172 
173  if (root_cache->flag == GP_UPDATE_NODE_FULL_COPY) {
174  /* Entire data-block has to be recalculated, e.g. nothing else needs to be added to the cache.
175  */
176  return;
177  }
178 
179  const int gpl_index = (gpl != NULL) ? BLI_findindex(&gpd->layers, gpl) : -1;
180  const int gpf_index = (gpl != NULL && gpf != NULL) ? BLI_findindex(&gpl->frames, gpf) : -1;
181  const int gps_index = (gpf != NULL && gps != NULL) ? BLI_findindex(&gpf->strokes, gps) : -1;
182 
183  void *data = gps;
184  if (!data) {
185  data = gpf;
186  }
187  if (!data) {
188  data = gpl;
189  }
190  if (!data) {
191  data = gpd;
192  }
193 
194  update_cache_node_create_ex(root_cache, data, gpl_index, gpf_index, gps_index, full_copy);
195 }
196 
199  int depth,
200  void *user_data)
201 {
202  if (BLI_listbase_is_empty((ListBase *)parent_cache->children)) {
203  return;
204  }
205 
206  LISTBASE_FOREACH (GPencilUpdateCacheNode *, cache_node, parent_cache->children) {
207  GPencilUpdateCache *cache = cache_node->cache;
208 
210  if (cb != NULL) {
211  bool skip = cb(cache, user_data);
212  if (skip) {
213  continue;
214  }
215  }
216 
217  gpencil_traverse_update_cache_ex(cache, ts, depth + 1, user_data);
218  }
219 }
220 
221 /* -------------------------------------------------------------------- */
227 {
228  return update_cache_alloc(
230 }
231 
234  void *user_data)
235 {
237 }
238 
240 {
241  update_cache_node_create(gpd, gpl, gpf, gps, true);
242 }
243 
245 {
246  update_cache_node_create(gpd, gpl, gpf, gps, false);
247 }
248 
250 {
251  GPencilUpdateCache *gpd_cache = gpd->runtime.update_cache;
252  if (gpd_cache) {
253  update_cache_free(gpd_cache);
254  gpd->runtime.update_cache = NULL;
255  }
256 }
257 
@ GP_UPDATE_NODE_NO_COPY
@ GP_UPDATE_NODE_LIGHT_COPY
@ GP_UPDATE_NODE_FULL_COPY
bool(* GPencilUpdateCacheIter_Cb)(GPencilUpdateCache *cache, void *user_data)
DLRBT_Tree * BLI_dlrbTree_new(void)
Definition: DLRB_tree.c:16
DLRBT_Node * BLI_dlrbTree_add(DLRBT_Tree *tree, DLRBT_Comparator_FP cmp_cb, DLRBT_NAlloc_FP new_cb, DLRBT_NUpdate_FP update_cb, void *data)
Definition: DLRB_tree.c:526
void BLI_dlrbTree_linkedlist_sync(DLRBT_Tree *tree)
Definition: DLRB_tree.c:103
void BLI_dlrbTree_free(DLRBT_Tree *tree, DLRBT_NFree_FP free_cb)
Definition: DLRB_tree.c:49
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
Definition: BLI_listbase.h:269
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:336
int BLI_findindex(const struct ListBase *listbase, const void *vlink) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
OperationNode * node
void * user_data
static DLRBT_Node * cache_node_alloc(void *data)
void BKE_gpencil_tag_light_update(bGPdata *gpd, bGPDlayer *gpl, bGPDframe *gpf, bGPDstroke *gps)
static void gpencil_traverse_update_cache_ex(GPencilUpdateCache *parent_cache, GPencilUpdateCacheTraverseSettings *ts, int depth, void *user_data)
static void cache_node_free(void *node)
static void update_cache_node_create(bGPdata *gpd, bGPDlayer *gpl, bGPDframe *gpf, bGPDstroke *gps, bool full_copy)
GPencilUpdateCache * BKE_gpencil_create_update_cache(void *data, bool full_copy)
void BKE_gpencil_free_update_cache(bGPdata *gpd)
static void cache_node_update(void *node, void *data)
static void update_cache_node_create_ex(GPencilUpdateCache *root_cache, void *data, int gpl_index, int gpf_index, int gps_index, bool full_copy)
void BKE_gpencil_traverse_update_cache(GPencilUpdateCache *cache, GPencilUpdateCacheTraverseSettings *ts, void *user_data)
void BKE_gpencil_tag_full_update(bGPdata *gpd, bGPDlayer *gpl, bGPDframe *gpf, bGPDstroke *gps)
static short cache_node_compare(void *node, void *data)
static void update_cache_free(GPencilUpdateCache *cache)
static GPencilUpdateCache * update_cache_alloc(int index, int flag, void *data)
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:31
GPencilUpdateCacheIter_Cb update_cache_cb[3]
struct DLRBT_Tree * children
ListBase strokes
ListBase frames
struct GPencilUpdateCache * update_cache
ListBase layers
bGPdata_Runtime runtime