diff options
author | Falk David <falkdavid@gmx.de> | 2022-06-01 20:55:00 +0300 |
---|---|---|
committer | Falk David <falkdavid@gmx.de> | 2022-06-01 20:55:00 +0300 |
commit | 5db2001a737b77328bf770c39307cb3cb4e1826f (patch) | |
tree | 9c856d5a3d37042d83a9252e94748a4fdda10e29 | |
parent | 91cf6fdd8e49144853d3dfa3a54f02575eb73963 (diff) |
Multi-threaded copy/free/udapre runtime pointersfeature/multi-threaded-data-duplicate
-rw-r--r-- | source/blender/blenkernel/intern/gpencil.c | 309 |
1 files changed, 300 insertions, 9 deletions
diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c index 9842635a781..b916a4d1d63 100644 --- a/source/blender/blenkernel/intern/gpencil.c +++ b/source/blender/blenkernel/intern/gpencil.c @@ -51,19 +51,139 @@ #include "BLI_dlrbTree.h" #include "BLI_math_color.h" +#include "BLI_task.h" #include "DEG_depsgraph_query.h" #include "BLO_read_write.h" +#include "PIL_time_utildefines.h" + #include "BKE_gpencil.h" static CLG_LogRef LOG = {"bke.gpencil"}; -static void greasepencil_copy_data(Main *UNUSED(bmain), - ID *id_dst, - const ID *id_src, - const int UNUSED(flag)) +#define USE_MULTI_THREAD + +typedef struct tGPCopyUserData { + bGPDstroke **strokes_copy_array; + int strokes_num; +} tGPCopyUserData; + +static void parallel_copy_stroke_cb(void *__restrict userdata, + void *item, + int index, + const TaskParallelTLS *__restrict UNUSED(tls)) +{ + tGPCopyUserData *udata = (tGPCopyUserData *)userdata; + bGPDstroke *gps = (bGPDstroke *)item; + bGPDstroke *gps_copy = BKE_gpencil_stroke_duplicate(gps, true, true); + udata->strokes_copy_array[index] = gps_copy; +} + +static void greasepencil_copy_data_ex_new(Main *UNUSED(bmain), + ID *id_dst, + const ID *id_src, + const int UNUSED(flag)) +{ + bGPdata *gpd_dst = (bGPdata *)id_dst; + const bGPdata *gpd_src = (const bGPdata *)id_src; + + ListBase strokes = {0}; + int strokes_num = 0; + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd_src->layers) { + if (gpl->frames.first == NULL) { + continue; + } + + ListBase gpf_strokes = {0}; + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { + if (gpf->strokes.first == NULL) { + continue; + } + + strokes_num += BLI_listbase_count(&gpf->strokes); + + if (gpf_strokes.first == NULL) { + gpf_strokes.first = gpf->strokes.first; + gpf_strokes.last = gpf->strokes.last; + } + else { + ((bGPDstroke *)gpf_strokes.last)->next = gpf->strokes.first; + ((bGPDstroke *)gpf->strokes.first)->prev = gpf_strokes.last; + gpf_strokes.last = gpf->strokes.last; + } + } + + if (BLI_listbase_is_empty(&gpf_strokes)) { + continue; + } + + if (strokes.first == NULL) { + strokes.first = gpf_strokes.first; + strokes.last = gpf_strokes.last; + } + else { + ((bGPDstroke *)strokes.last)->next = gpf_strokes.first; + ((bGPDstroke *)gpf_strokes.first)->prev = strokes.last; + strokes.last = gpf_strokes.last; + } + } + + tGPCopyUserData userdata; + userdata.strokes_copy_array = MEM_callocN(sizeof(bGPDstroke *) * strokes_num, __func__); + userdata.strokes_num = strokes_num; + + TaskParallelSettings settings = {0}; + BLI_parallel_range_settings_defaults(&settings); + BLI_task_parallel_listbase(&strokes, &userdata, parallel_copy_stroke_cb, &settings); + + BLI_listbase_clear(&gpd_dst->layers); + int gps_idx = 0; + LISTBASE_FOREACH (bGPDlayer *, gpl_src, &gpd_src->layers) { + bGPDlayer *gpl_dst = MEM_dupallocN(gpl_src); + gpl_dst->prev = gpl_dst->next = NULL; + + BLI_listbase_clear(&gpl_dst->frames); + LISTBASE_FOREACH (bGPDframe *, gpf_src, &gpl_src->frames) { + bGPDframe *gpf_dst = MEM_dupallocN(gpf_src); + gpf_dst->prev = gpf_dst->next = NULL; + + if (!BLI_listbase_is_empty(&gpf_src->strokes)) { + /* Disconnect lists of strokes again. */ + ((bGPDstroke *)gpf_src->strokes.first)->prev = NULL; + ((bGPDstroke *)gpf_src->strokes.last)->next = NULL; + } + + BLI_listbase_clear(&gpf_dst->strokes); + LISTBASE_FOREACH (bGPDstroke *, gps_src, &gpf_src->strokes) { + BLI_addtail(&gpf_dst->strokes, userdata.strokes_copy_array[gps_idx]); + gps_idx++; + } + + if (gpf_src == gpl_dst->actframe) { + gpl_dst->actframe = gpf_dst; + } + BLI_addtail(&gpl_dst->frames, gpf_dst); + } + + BKE_gpencil_layer_mask_copy(gpl_src, gpl_dst); + BLI_addtail(&gpd_dst->layers, gpl_dst); + } + MEM_freeN(userdata.strokes_copy_array); + + /* duplicate material array */ + if (gpd_src->mat) { + gpd_dst->mat = MEM_dupallocN(gpd_src->mat); + } + + BKE_defgroup_copy_list(&gpd_dst->vertex_group_names, &gpd_src->vertex_group_names); +} + +static void greasepencil_copy_data_ex(Main *UNUSED(bmain), + ID *id_dst, + const ID *id_src, + const int UNUSED(flag)) { bGPdata *gpd_dst = (bGPdata *)id_dst; const bGPdata *gpd_src = (const bGPdata *)id_src; @@ -113,11 +233,77 @@ static void greasepencil_copy_data(Main *UNUSED(bmain), } } +static void greasepencil_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int flag) +{ + TIMEIT_START(greasepencil_copy_data); +#ifdef USE_MULTI_THREAD + greasepencil_copy_data_ex_new(bmain, id_dst, id_src, flag); +#else + greasepencil_copy_data_ex(bmain, id_dst, id_src, flag); +#endif + TIMEIT_END(greasepencil_copy_data); +} + +static void parallel_free_stroke_cb(void *__restrict UNUSED(userdata), + void *item, + int UNUSED(index), + const TaskParallelTLS *__restrict UNUSED(tls)) +{ + bGPDstroke *gps = (bGPDstroke *)item; + BKE_gpencil_free_stroke(gps); +} + +static void greasepencil_free_data_ex(ID *id) +{ + ListBase strokes = {0}; + bGPdata *gpd = (bGPdata *)id; + + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + if (gpl->frames.first == NULL) { + continue; + } + + ListBase gpf_strokes = {0}; + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { + if (gpf->strokes.first == NULL) { + continue; + } + + BLI_movelisttolist(&gpf_strokes, &gpf->strokes); + } + BLI_movelisttolist(&strokes, &gpf_strokes); + } + + TaskParallelSettings settings = {0}; + BLI_parallel_range_settings_defaults(&settings); + + BLI_task_parallel_listbase(&strokes, NULL, parallel_free_stroke_cb, &settings); + + LISTBASE_FOREACH_MUTABLE (bGPDlayer *, gpl, &gpd->layers) { + LISTBASE_FOREACH_MUTABLE (bGPDframe *, gpf, &gpl->frames) { + BLI_freelinkN(&gpl->frames, gpf); + // BLI_listbase_clear(&gpf->strokes); + } + BKE_gpencil_free_layer_masks(gpl); + BLI_freelinkN(&gpd->layers, gpl); + } + + MEM_SAFE_FREE(gpd->mat); + BLI_freelistN(&gpd->vertex_group_names); + BKE_gpencil_free_update_cache(gpd); +} + static void greasepencil_free_data(ID *id) { /* Really not ideal, but for now will do... In theory custom behaviors like not freeing cache * should be handled through specific API, and not be part of the generic one. */ + TIMEIT_START(greasepencil_free_data); +#ifdef USE_MULTI_THREAD + greasepencil_free_data_ex(id); +#else BKE_gpencil_free_data((bGPdata *)id, true); +#endif + TIMEIT_END(greasepencil_free_data); } static void greasepencil_foreach_id(ID *id, LibraryForeachIDData *data) @@ -2677,13 +2863,26 @@ void BKE_gpencil_layer_original_pointers_update(const struct bGPDlayer *gpl_orig } } -void BKE_gpencil_data_update_orig_pointers(const bGPdata *gpd_orig, const bGPdata *gpd_eval) +static void strokes_pointers_update_cb(void *UNUSED(userdata), + void *__restrict item, + int UNUSED(index), + const TaskParallelTLS *__restrict UNUSED(tls)) { - /* Assign pointers to the original stroke and points to the evaluated data. This must - * be done before applying any modifier because at this moment the structure is equals, - * so we can assume the layer index is the same in both data-blocks. - * This data will be used by operators. */ + bGPDstroke *gps_eval = (bGPDstroke *)item; + bGPDstroke *gps_orig = gps_eval->runtime.gps_orig; + /* Assign original point pointer. */ + bGPDspoint *pt_orig; + bGPDspoint *pt_eval; + for (int i = 0; i < gps_orig->totpoints; i++) { + pt_orig = &gps_orig->points[i]; + pt_eval = &gps_eval->points[i]; + pt_orig->runtime.idx_orig = pt_eval->runtime.idx_orig = i; + pt_eval->runtime.pt_orig = pt_orig; + } +} +void BKE_gpencil_data_update_orig_pointers_ex(const bGPdata *gpd_orig, const bGPdata *gpd_eval) +{ bGPDlayer *gpl_eval = gpd_eval->layers.first; LISTBASE_FOREACH (bGPDlayer *, gpl_orig, &gpd_orig->layers) { if (gpl_eval != NULL) { @@ -2695,6 +2894,98 @@ void BKE_gpencil_data_update_orig_pointers(const bGPdata *gpd_orig, const bGPdat } } +void BKE_gpencil_data_update_orig_pointers_ex_new(const bGPdata *gpd_orig, const bGPdata *gpd_eval) +{ + /* Assign pointers to the original stroke and points to the evaluated data. This must + * be done before applying any modifier because at this moment the structure is equals, + * so we can assume the layer index is the same in both data-blocks. + * This data will be used by operators. */ + + bGPDlayer *gpl_eval = gpd_eval->layers.first; + + ListBase strokes = {0}; + int strokes_num = 0; + LISTBASE_FOREACH (bGPDlayer *, gpl_orig, &gpd_orig->layers) { + gpl_eval->runtime.gpl_orig = gpl_orig; + + if (BLI_listbase_is_empty(&gpl_orig->frames)) { + gpl_eval = gpl_eval->next; + continue; + } + + bGPDframe *gpf_eval = gpl_eval->frames.first; + + ListBase gpf_strokes = {0}; + LISTBASE_FOREACH (bGPDframe *, gpf_orig, &gpl_orig->frames) { + gpf_eval->runtime.gpf_orig = gpf_orig; + if (BLI_listbase_is_empty(&gpf_orig->strokes)) { + gpf_eval = gpf_eval->next; + continue; + } + + bGPDstroke *gps_eval = gpf_eval->strokes.first; + LISTBASE_FOREACH (bGPDstroke *, gps_orig, &gpf_orig->strokes) { + gps_eval->runtime.gps_orig = gps_orig; + gps_eval = gps_eval->next; + } + + if (gpf_strokes.first == NULL) { + gpf_strokes.first = gpf_eval->strokes.first; + gpf_strokes.last = gpf_eval->strokes.last; + } + else { + ((bGPDstroke *)gpf_strokes.last)->next = gpf_eval->strokes.first; + ((bGPDstroke *)gpf_eval->strokes.first)->prev = gpf_strokes.last; + gpf_strokes.last = gpf_eval->strokes.last; + } + gpf_eval = gpf_eval->next; + } + + gpl_eval = gpl_eval->next; + + if (BLI_listbase_is_empty(&gpf_strokes)) { + continue; + } + + if (strokes.first == NULL) { + strokes.first = gpf_strokes.first; + strokes.last = gpf_strokes.last; + } + else { + ((bGPDstroke *)strokes.last)->next = gpf_strokes.first; + ((bGPDstroke *)gpf_strokes.first)->prev = strokes.last; + strokes.last = gpf_strokes.last; + } + } + + TaskParallelSettings settings = {0}; + settings.use_threading = true; + /* Update the runtime pointers of all the strokes in the layer in parallel. */ + BLI_task_parallel_listbase(&strokes, NULL, strokes_pointers_update_cb, &settings); + + LISTBASE_FOREACH (bGPDlayer *, gpl_eval_iter, &gpd_eval->layers) { + /* Disconnect the stroke lists in the frames again. */ + LISTBASE_FOREACH (bGPDframe *, gpf_eval_iter, &gpl_eval_iter->frames) { + if (!BLI_listbase_is_empty(&gpf_eval_iter->strokes)) { + /* Disconnect lists of strokes again. */ + ((bGPDstroke *)gpf_eval_iter->strokes.first)->prev = NULL; + ((bGPDstroke *)gpf_eval_iter->strokes.last)->next = NULL; + } + } + } +} + +void BKE_gpencil_data_update_orig_pointers(const bGPdata *gpd_orig, const bGPdata *gpd_eval) +{ + TIMEIT_START(BKE_gpencil_data_update_orig_pointers); +#ifdef USE_MULTI_THREAD + BKE_gpencil_data_update_orig_pointers_ex_new(gpd_orig, gpd_eval); +#else + BKE_gpencil_data_update_orig_pointers_ex(gpd_orig, gpd_eval); +#endif + TIMEIT_END(BKE_gpencil_data_update_orig_pointers); +} + /** * Update pointers of eval data to original data to keep references. * \param ob_orig: Original grease pencil object |