Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFalk David <falkdavid@gmx.de>2022-06-01 20:55:00 +0300
committerFalk David <falkdavid@gmx.de>2022-06-01 20:55:00 +0300
commit5db2001a737b77328bf770c39307cb3cb4e1826f (patch)
tree9c856d5a3d37042d83a9252e94748a4fdda10e29
parent91cf6fdd8e49144853d3dfa3a54f02575eb73963 (diff)
Multi-threaded copy/free/udapre runtime pointersfeature/multi-threaded-data-duplicate
-rw-r--r--source/blender/blenkernel/intern/gpencil.c309
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