diff options
author | Campbell Barton <ideasman42@gmail.com> | 2021-06-29 09:18:26 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2021-06-30 09:53:55 +0300 |
commit | 2d4ec90497443dc28e342c539e65010c7f4a04bb (patch) | |
tree | 62d29a8c932d8b94f43fddf818c581432fb287a2 /source | |
parent | 501d2443d03cce18985fab3ffad5d23238748f3e (diff) |
Transform: support multi-threading for most modes
Multi-threading support for transform modes: bevel-weight, crease,
push-pull, rotate, shear, shrink-fatten, skin-resize, to-sphere,
trackball & translate.
This is done using a parallel loop over transform data.
From testing a 1.5million polygon mesh on a 32 core system
the overall performance gains were between ~20-28%
To ensure the code is thread-safe arguments to shared data are const.
Reviewed By: mano-wii
Diffstat (limited to 'source')
12 files changed, 934 insertions, 299 deletions
diff --git a/source/blender/editors/transform/transform_data.h b/source/blender/editors/transform/transform_data.h index 59b76c2eec5..606453e356b 100644 --- a/source/blender/editors/transform/transform_data.h +++ b/source/blender/editors/transform/transform_data.h @@ -149,6 +149,8 @@ typedef struct TransData { short protectflag; } TransData; +#define TRANSDATA_THREAD_LIMIT 1024 + /** #TransData.flag */ enum { TD_SELECTED = 1 << 0, diff --git a/source/blender/editors/transform/transform_mode_edge_bevelweight.c b/source/blender/editors/transform/transform_mode_edge_bevelweight.c index 3ce52ed3296..425bfec241e 100644 --- a/source/blender/editors/transform/transform_mode_edge_bevelweight.c +++ b/source/blender/editors/transform/transform_mode_edge_bevelweight.c @@ -25,6 +25,7 @@ #include "BLI_math.h" #include "BLI_string.h" +#include "BLI_task.h" #include "BKE_context.h" #include "BKE_unit.h" @@ -40,6 +41,50 @@ #include "transform_snap.h" /* -------------------------------------------------------------------- */ +/** \name Transform (Bevel Weight) Element + * \{ */ + +/** + * \note Small arrays / data-structures should be stored copied for faster memory access. + */ +struct TransDataArgs_BevelWeight { + const TransInfo *t; + const TransDataContainer *tc; + float weight; +}; + +static void transdata_elem_bevel_weight(const TransInfo *UNUSED(t), + const TransDataContainer *UNUSED(tc), + TransData *td, + const float weight) +{ + if (td->val == NULL) { + return; + } + *td->val = td->ival + weight * td->factor; + if (*td->val < 0.0f) { + *td->val = 0.0f; + } + if (*td->val > 1.0f) { + *td->val = 1.0f; + } +} + +static void transdata_elem_bevel_weight_fn(void *__restrict iter_data_v, + const int iter, + const TaskParallelTLS *__restrict UNUSED(tls)) +{ + struct TransDataArgs_BevelWeight *data = iter_data_v; + TransData *td = &data->tc->data[iter]; + if (td->flag & TD_SKIP) { + return; + } + transdata_elem_bevel_weight(data->t, data->tc, td, data->weight); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name Transform (Bevel Weight) * \{ */ @@ -83,18 +128,25 @@ static void applyBevelWeight(TransInfo *t, const int UNUSED(mval[2])) } FOREACH_TRANS_DATA_CONTAINER (t, tc) { - TransData *td = tc->data; - for (i = 0; i < tc->data_len; i++, td++) { - if (td->val) { - *td->val = td->ival + weight * td->factor; - if (*td->val < 0.0f) { - *td->val = 0.0f; - } - if (*td->val > 1.0f) { - *td->val = 1.0f; + if (tc->data_len < TRANSDATA_THREAD_LIMIT) { + TransData *td = tc->data; + for (i = 0; i < tc->data_len; i++, td++) { + if (td->flag & TD_SKIP) { + continue; } + transdata_elem_bevel_weight(t, tc, td, weight); } } + else { + struct TransDataArgs_BevelWeight data = { + .t = t, + .tc = tc, + .weight = weight, + }; + TaskParallelSettings settings; + BLI_parallel_range_settings_defaults(&settings); + BLI_task_parallel_range(0, tc->data_len, &data, transdata_elem_bevel_weight_fn, &settings); + } } recalcData(t); diff --git a/source/blender/editors/transform/transform_mode_edge_crease.c b/source/blender/editors/transform/transform_mode_edge_crease.c index 23fa20b68ff..91e2507e544 100644 --- a/source/blender/editors/transform/transform_mode_edge_crease.c +++ b/source/blender/editors/transform/transform_mode_edge_crease.c @@ -25,6 +25,7 @@ #include "BLI_math.h" #include "BLI_string.h" +#include "BLI_task.h" #include "BKE_context.h" #include "BKE_unit.h" @@ -40,6 +41,51 @@ #include "transform_snap.h" /* -------------------------------------------------------------------- */ +/** \name Transform (Crease) Element + * \{ */ + +/** + * \note Small arrays / data-structures should be stored copied for faster memory access. + */ +struct TransDataArgs_Crease { + const TransInfo *t; + const TransDataContainer *tc; + float crease; +}; + +static void transdata_elem_crease(const TransInfo *UNUSED(t), + const TransDataContainer *UNUSED(tc), + TransData *td, + const float crease) +{ + if (td->val == NULL) { + return; + } + + *td->val = td->ival + crease * td->factor; + if (*td->val < 0.0f) { + *td->val = 0.0f; + } + if (*td->val > 1.0f) { + *td->val = 1.0f; + } +} + +static void transdata_elem_crease_fn(void *__restrict iter_data_v, + const int iter, + const TaskParallelTLS *__restrict UNUSED(tls)) +{ + struct TransDataArgs_Crease *data = iter_data_v; + TransData *td = &data->tc->data[iter]; + if (td->flag & TD_SKIP) { + return; + } + transdata_elem_crease(data->t, data->tc, td, data->crease); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name Transform (Crease) * \{ */ @@ -83,22 +129,25 @@ static void applyCrease(TransInfo *t, const int UNUSED(mval[2])) } FOREACH_TRANS_DATA_CONTAINER (t, tc) { - TransData *td = tc->data; - for (i = 0; i < tc->data_len; i++, td++) { - if (td->flag & TD_SKIP) { - continue; - } - - if (td->val) { - *td->val = td->ival + crease * td->factor; - if (*td->val < 0.0f) { - *td->val = 0.0f; - } - if (*td->val > 1.0f) { - *td->val = 1.0f; + if (tc->data_len < TRANSDATA_THREAD_LIMIT) { + TransData *td = tc->data; + for (i = 0; i < tc->data_len; i++, td++) { + if (td->flag & TD_SKIP) { + continue; } + transdata_elem_crease(t, tc, td, crease); } } + else { + struct TransDataArgs_Crease data = { + .t = t, + .tc = tc, + .crease = crease, + }; + TaskParallelSettings settings; + BLI_parallel_range_settings_defaults(&settings); + BLI_task_parallel_range(0, tc->data_len, &data, transdata_elem_crease_fn, &settings); + } } recalcData(t); @@ -124,4 +173,5 @@ void initCrease(TransInfo *t) t->flag |= T_NO_CONSTRAINT | T_NO_PROJECT; } + /** \} */ diff --git a/source/blender/editors/transform/transform_mode_push_pull.c b/source/blender/editors/transform/transform_mode_push_pull.c index b08e479a3d0..098698b0e79 100644 --- a/source/blender/editors/transform/transform_mode_push_pull.c +++ b/source/blender/editors/transform/transform_mode_push_pull.c @@ -25,6 +25,7 @@ #include "BLI_math.h" #include "BLI_string.h" +#include "BLI_task.h" #include "BKE_context.h" #include "BKE_unit.h" @@ -41,12 +42,75 @@ #include "transform_snap.h" /* -------------------------------------------------------------------- */ +/** \name Transform (Push/Pull) Element + * \{ */ + +/** + * \note Small arrays / data-structures should be stored copied for faster memory access. + */ +struct TransDataArgs_PushPull { + const TransInfo *t; + const TransDataContainer *tc; + + float distance; + const float axis_global[3]; + bool is_data_space; +}; + +static void transdata_elem_push_pull(const TransInfo *t, + const TransDataContainer *tc, + TransData *td, + const float distance, + const float axis_global[3], + const bool is_data_space) +{ + float vec[3]; + sub_v3_v3v3(vec, tc->center_local, td->center); + if (t->con.applyRot && t->con.mode & CON_APPLY) { + float axis[3]; + copy_v3_v3(axis, axis_global); + t->con.applyRot(t, tc, td, axis, NULL); + + mul_m3_v3(td->smtx, axis); + if (isLockConstraint(t)) { + float dvec[3]; + project_v3_v3v3(dvec, vec, axis); + sub_v3_v3(vec, dvec); + } + else { + project_v3_v3v3(vec, vec, axis); + } + } + normalize_v3_length(vec, distance * td->factor); + if (is_data_space) { + mul_m3_v3(td->smtx, vec); + } + + add_v3_v3v3(td->loc, td->iloc, vec); +} + +static void transdata_elem_push_pull_fn(void *__restrict iter_data_v, + const int iter, + const TaskParallelTLS *__restrict UNUSED(tls)) +{ + struct TransDataArgs_PushPull *data = iter_data_v; + TransData *td = &data->tc->data[iter]; + if (td->flag & TD_SKIP) { + return; + } + transdata_elem_push_pull( + data->t, data->tc, td, data->distance, data->axis_global, data->is_data_space); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name Transform (Push/Pull) * \{ */ static void applyPushPull(TransInfo *t, const int UNUSED(mval[2])) { - float vec[3], axis_global[3]; + float axis_global[3]; float distance; int i; char str[UI_MAX_DRAW_STR]; @@ -80,34 +144,26 @@ static void applyPushPull(TransInfo *t, const int UNUSED(mval[2])) const bool is_data_space = (t->options & CTX_POSE_BONE) != 0; FOREACH_TRANS_DATA_CONTAINER (t, tc) { - TransData *td = tc->data; - for (i = 0; i < tc->data_len; i++, td++) { - if (td->flag & TD_SKIP) { - continue; - } - - sub_v3_v3v3(vec, tc->center_local, td->center); - if (t->con.applyRot && t->con.mode & CON_APPLY) { - float axis[3]; - copy_v3_v3(axis, axis_global); - t->con.applyRot(t, tc, td, axis, NULL); - - mul_m3_v3(td->smtx, axis); - if (isLockConstraint(t)) { - float dvec[3]; - project_v3_v3v3(dvec, vec, axis); - sub_v3_v3(vec, dvec); + if (tc->data_len < TRANSDATA_THREAD_LIMIT) { + TransData *td = tc->data; + for (i = 0; i < tc->data_len; i++, td++) { + if (td->flag & TD_SKIP) { + continue; } - else { - project_v3_v3v3(vec, vec, axis); - } - } - normalize_v3_length(vec, distance * td->factor); - if (is_data_space) { - mul_m3_v3(td->smtx, vec); - } - add_v3_v3v3(td->loc, td->iloc, vec); + transdata_elem_push_pull(t, tc, td, distance, axis_global, is_data_space); + } + } + else { + struct TransDataArgs_PushPull data = { + .t = t, + .tc = tc, + .axis_global = {UNPACK3(axis_global)}, + .is_data_space = is_data_space, + }; + TaskParallelSettings settings; + BLI_parallel_range_settings_defaults(&settings); + BLI_task_parallel_range(0, tc->data_len, &data, transdata_elem_push_pull_fn, &settings); } } diff --git a/source/blender/editors/transform/transform_mode_resize.c b/source/blender/editors/transform/transform_mode_resize.c index 6af16dee9b7..65f4623b3be 100644 --- a/source/blender/editors/transform/transform_mode_resize.c +++ b/source/blender/editors/transform/transform_mode_resize.c @@ -24,6 +24,7 @@ #include <stdlib.h> #include "BLI_math.h" +#include "BLI_task.h" #include "BKE_context.h" #include "BKE_unit.h" @@ -39,6 +40,30 @@ #include "transform_snap.h" /* -------------------------------------------------------------------- */ +/** \name Transform (Resize) Element + * \{ */ + +struct ElemResizeData { + const TransInfo *t; + const TransDataContainer *tc; + float mat[3][3]; +}; + +static void element_resize_fn(void *__restrict iter_data_v, + const int iter, + const TaskParallelTLS *__restrict UNUSED(tls)) +{ + struct ElemResizeData *data = iter_data_v; + TransData *td = &data->tc->data[iter]; + if (td->flag & TD_SKIP) { + return; + } + ElementResize(data->t, data->tc, td, data->mat); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name Transform (Resize) * \{ */ @@ -123,13 +148,27 @@ static void applyResize(TransInfo *t, const int UNUSED(mval[2])) copy_m3_m3(t->mat, mat); /* used in gizmo */ FOREACH_TRANS_DATA_CONTAINER (t, tc) { - TransData *td = tc->data; - for (i = 0; i < tc->data_len; i++, td++) { - if (td->flag & TD_SKIP) { - continue; - } - ElementResize(t, tc, td, mat); + if (tc->data_len < TRANSDATA_THREAD_LIMIT) { + TransData *td = tc->data; + for (i = 0; i < tc->data_len; i++, td++) { + if (td->flag & TD_SKIP) { + continue; + } + + ElementResize(t, tc, td, mat); + } + } + else { + struct ElemResizeData data = { + .t = t, + .tc = tc, + }; + copy_m3_m3(data.mat, mat); + + TaskParallelSettings settings; + BLI_parallel_range_settings_defaults(&settings); + BLI_task_parallel_range(0, tc->data_len, &data, element_resize_fn, &settings); } } diff --git a/source/blender/editors/transform/transform_mode_rotate.c b/source/blender/editors/transform/transform_mode_rotate.c index 066cdf20e93..44a29cfac45 100644 --- a/source/blender/editors/transform/transform_mode_rotate.c +++ b/source/blender/editors/transform/transform_mode_rotate.c @@ -24,6 +24,7 @@ #include <stdlib.h> #include "BLI_math.h" +#include "BLI_task.h" #include "BKE_context.h" #include "BKE_unit.h" @@ -37,6 +38,140 @@ #include "transform_snap.h" /* -------------------------------------------------------------------- */ +/** \name Transform (Rotation) Matrix Cache + * \{ */ + +struct RotateMatrixCache { + /** + * Counter for needed updates (when we need to update to non-default matrix, + * we also need another update on next iteration to go back to default matrix, + * hence the '2' value used here, instead of a mere boolean). + */ + short do_update_matrix; + float mat[3][3]; +}; + +static void rmat_cache_init(struct RotateMatrixCache *rmc, const float angle, const float axis[3]) +{ + axis_angle_normalized_to_mat3(rmc->mat, axis, angle); + rmc->do_update_matrix = 0; +} + +static void rmat_cache_reset(struct RotateMatrixCache *rmc) +{ + rmc->do_update_matrix = 2; +} + +static void rmat_cache_update(struct RotateMatrixCache *rmc, + const float axis[3], + const float angle) +{ + if (rmc->do_update_matrix > 0) { + axis_angle_normalized_to_mat3(rmc->mat, axis, angle); + rmc->do_update_matrix--; + } +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Transform (Rotation) Element + * \{ */ + +/** + * \note Small arrays / data-structures should be stored copied for faster memory access. + */ +struct TransDataArgs_Rotate { + const TransInfo *t; + const TransDataContainer *tc; + const float axis[3]; + float angle; + float angle_step; + bool is_large_rotation; +}; + +struct TransDataArgs_RotateTLS { + struct RotateMatrixCache rmc; +}; + +static void transdata_elem_rotate(const TransInfo *t, + const TransDataContainer *tc, + TransData *td, + const float axis[3], + const float angle, + const float angle_step, + const bool is_large_rotation, + struct RotateMatrixCache *rmc) +{ + float axis_buffer[3]; + const float *axis_final = axis; + + float angle_final = angle; + if (t->con.applyRot) { + copy_v3_v3(axis_buffer, axis); + axis_final = axis_buffer; + t->con.applyRot(t, tc, td, axis_buffer, NULL); + angle_final = angle * td->factor; + /* Even though final angle might be identical to orig value, + * we have to update the rotation matrix in that case... */ + rmat_cache_reset(rmc); + } + else if (t->flag & T_PROP_EDIT) { + angle_final = angle * td->factor; + } + + /* Rotation is very likely to be above 180°, we need to do rotation by steps. + * Note that this is only needed when doing 'absolute' rotation + * (i.e. from initial rotation again, typically when using numinput). + * regular incremental rotation (from mouse/widget/...) will be called often enough, + * hence steps are small enough to be properly handled without that complicated trick. + * Note that we can only do that kind of stepped rotation if we have initial rotation values + * (and access to some actual rotation value storage). + * Otherwise, just assume it's useless (e.g. in case of mesh/UV/etc. editing). + * Also need to be in Euler rotation mode, the others never allow more than one turn anyway. + */ + if (is_large_rotation && td->ext != NULL && td->ext->rotOrder == ROT_MODE_EUL) { + copy_v3_v3(td->ext->rot, td->ext->irot); + for (float angle_progress = angle_step; fabsf(angle_progress) < fabsf(angle_final); + angle_progress += angle_step) { + axis_angle_normalized_to_mat3(rmc->mat, axis_final, angle_progress); + ElementRotation(t, tc, td, rmc->mat, t->around); + } + rmat_cache_reset(rmc); + } + else if (angle_final != angle) { + rmat_cache_reset(rmc); + } + + rmat_cache_update(rmc, axis_final, angle_final); + + ElementRotation(t, tc, td, rmc->mat, t->around); +} + +static void transdata_elem_rotate_fn(void *__restrict iter_data_v, + const int iter, + const TaskParallelTLS *__restrict tls) +{ + struct TransDataArgs_Rotate *data = iter_data_v; + struct TransDataArgs_RotateTLS *tls_data = tls->userdata_chunk; + + TransData *td = &data->tc->data[iter]; + if (td->flag & TD_SKIP) { + return; + } + transdata_elem_rotate(data->t, + data->tc, + td, + data->axis, + data->angle, + data->angle_step, + data->is_large_rotation, + &tls_data->rmc); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name Transform (Rotation) * \{ */ @@ -115,12 +250,9 @@ static float large_rotation_limit(float angle) static void applyRotationValue(TransInfo *t, float angle, - float axis[3], + const float axis[3], const bool is_large_rotation) { - float mat[3][3]; - int i; - const float angle_sign = angle < 0.0f ? -1.0f : 1.0f; /* We cannot use something too close to 180°, or 'continuous' rotation may fail * due to computing error... */ @@ -132,60 +264,37 @@ static void applyRotationValue(TransInfo *t, angle = large_rotation_limit(angle); } - axis_angle_normalized_to_mat3(mat, axis, angle); - /* Counter for needed updates (when we need to update to non-default matrix, - * we also need another update on next iteration to go back to default matrix, - * hence the '2' value used here, instead of a mere boolean). */ - short do_update_matrix = 0; + struct RotateMatrixCache rmc = {0}; + rmat_cache_init(&rmc, angle, axis); FOREACH_TRANS_DATA_CONTAINER (t, tc) { - TransData *td = tc->data; - for (i = 0; i < tc->data_len; i++, td++) { - if (td->flag & TD_SKIP) { - continue; - } - - float angle_final = angle; - if (t->con.applyRot) { - t->con.applyRot(t, tc, td, axis, NULL); - angle_final = angle * td->factor; - /* Even though final angle might be identical to orig value, - * we have to update the rotation matrix in that case... */ - do_update_matrix = 2; - } - else if (t->flag & T_PROP_EDIT) { - angle_final = angle * td->factor; - } - - /* Rotation is very likely to be above 180°, we need to do rotation by steps. - * Note that this is only needed when doing 'absolute' rotation - * (i.e. from initial rotation again, typically when using numinput). - * regular incremental rotation (from mouse/widget/...) will be called often enough, - * hence steps are small enough to be properly handled without that complicated trick. - * Note that we can only do that kind of stepped rotation if we have initial rotation values - * (and access to some actual rotation value storage). - * Otherwise, just assume it's useless (e.g. in case of mesh/UV/etc. editing). - * Also need to be in Euler rotation mode, the others never allow more than one turn anyway. - */ - if (is_large_rotation && td->ext != NULL && td->ext->rotOrder == ROT_MODE_EUL) { - copy_v3_v3(td->ext->rot, td->ext->irot); - for (float angle_progress = angle_step; fabsf(angle_progress) < fabsf(angle_final); - angle_progress += angle_step) { - axis_angle_normalized_to_mat3(mat, axis, angle_progress); - ElementRotation(t, tc, td, mat, t->around); + if (tc->data_len < TRANSDATA_THREAD_LIMIT) { + TransData *td = tc->data; + for (int i = 0; i < tc->data_len; i++, td++) { + if (td->flag & TD_SKIP) { + continue; } - do_update_matrix = 2; + transdata_elem_rotate(t, tc, td, axis, angle, angle_step, is_large_rotation, &rmc); } - else if (angle_final != angle) { - do_update_matrix = 2; - } - - if (do_update_matrix > 0) { - axis_angle_normalized_to_mat3(mat, axis, angle_final); - do_update_matrix--; - } - - ElementRotation(t, tc, td, mat, t->around); + } + else { + struct TransDataArgs_Rotate data = { + .t = t, + .tc = tc, + .axis = {UNPACK3(axis)}, + .angle = angle, + .angle_step = angle_step, + .is_large_rotation = is_large_rotation, + }; + struct TransDataArgs_RotateTLS tls_data = { + .rmc = rmc, + }; + + TaskParallelSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.userdata_chunk = &tls_data; + settings.userdata_chunk_size = sizeof(tls_data); + BLI_task_parallel_range(0, tc->data_len, &data, transdata_elem_rotate_fn, &settings); } } } diff --git a/source/blender/editors/transform/transform_mode_shear.c b/source/blender/editors/transform/transform_mode_shear.c index 23ee55bf6c5..ab5dd11a926 100644 --- a/source/blender/editors/transform/transform_mode_shear.c +++ b/source/blender/editors/transform/transform_mode_shear.c @@ -27,6 +27,7 @@ #include "BLI_math.h" #include "BLI_string.h" +#include "BLI_task.h" #include "BKE_context.h" #include "BKE_unit.h" @@ -44,6 +45,79 @@ #include "transform_snap.h" /* -------------------------------------------------------------------- */ +/** \name Transform (Shear) Element + * \{ */ + +/** + * \note Small arrays / data-structures should be stored copied for faster memory access. + */ +struct TransDataArgs_Shear { + const TransInfo *t; + const TransDataContainer *tc; + float totmat[3][3]; + bool is_local_center; +}; + +static void transdata_elem_shear(const TransInfo *t, + const TransDataContainer *tc, + TransData *td, + const float totmat[3][3], + const bool is_local_center) +{ + float tmat[3][3]; + const float *center; + if (t->flag & T_EDIT) { + mul_m3_series(tmat, td->smtx, totmat, td->mtx); + } + else { + copy_m3_m3(tmat, totmat); + } + + if (is_local_center) { + center = td->center; + } + else { + center = tc->center_local; + } + + float vec[3]; + sub_v3_v3v3(vec, td->iloc, center); + mul_m3_v3(tmat, vec); + add_v3_v3(vec, center); + sub_v3_v3(vec, td->iloc); + + if (t->options & CTX_GPENCIL_STROKES) { + /* Grease pencil multi-frame falloff. */ + bGPDstroke *gps = (bGPDstroke *)td->extra; + if (gps != NULL) { + mul_v3_fl(vec, td->factor * gps->runtime.multi_frame_falloff); + } + else { + mul_v3_fl(vec, td->factor); + } + } + else { + mul_v3_fl(vec, td->factor); + } + + add_v3_v3v3(td->loc, td->iloc, vec); +} + +static void transdata_elem_shear_fn(void *__restrict iter_data_v, + const int iter, + const TaskParallelTLS *__restrict UNUSED(tls)) +{ + struct TransDataArgs_Shear *data = iter_data_v; + TransData *td = &data->tc->data[iter]; + if (td->flag & TD_SKIP) { + return; + } + transdata_elem_shear(data->t, data->tc, td, data->totmat, data->is_local_center); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name Transform (Shear) * \{ */ @@ -117,8 +191,7 @@ static eRedrawFlag handleEventShear(TransInfo *t, const wmEvent *event) static void applyShear(TransInfo *t, const int UNUSED(mval[2])) { - float vec[3]; - float smat[3][3], tmat[3][3], totmat[3][3], axismat[3][3], axismat_inv[3][3]; + float smat[3][3], totmat[3][3], axismat[3][3], axismat_inv[3][3]; float value; int i; char str[UI_MAX_DRAW_STR]; @@ -160,47 +233,26 @@ static void applyShear(TransInfo *t, const int UNUSED(mval[2])) mul_m3_series(totmat, axismat_inv, smat, axismat); FOREACH_TRANS_DATA_CONTAINER (t, tc) { - TransData *td = tc->data; - for (i = 0; i < tc->data_len; i++, td++) { - const float *center; - if (td->flag & TD_SKIP) { - continue; - } - - if (t->flag & T_EDIT) { - mul_m3_series(tmat, td->smtx, totmat, td->mtx); - } - else { - copy_m3_m3(tmat, totmat); - } - - if (is_local_center) { - center = td->center; - } - else { - center = tc->center_local; - } - - sub_v3_v3v3(vec, td->iloc, center); - mul_m3_v3(tmat, vec); - add_v3_v3(vec, center); - sub_v3_v3(vec, td->iloc); - - if (t->options & CTX_GPENCIL_STROKES) { - /* grease pencil multiframe falloff */ - bGPDstroke *gps = (bGPDstroke *)td->extra; - if (gps != NULL) { - mul_v3_fl(vec, td->factor * gps->runtime.multi_frame_falloff); - } - else { - mul_v3_fl(vec, td->factor); + if (tc->data_len < TRANSDATA_THREAD_LIMIT) { + TransData *td = tc->data; + for (i = 0; i < tc->data_len; i++, td++) { + if (td->flag & TD_SKIP) { + continue; } + transdata_elem_shear(t, tc, td, totmat, is_local_center); } - else { - mul_v3_fl(vec, td->factor); - } - - add_v3_v3v3(td->loc, td->iloc, vec); + } + else { + struct TransDataArgs_Shear data = { + .t = t, + .tc = tc, + .is_local_center = is_local_center, + }; + copy_m3_m3(data.totmat, totmat); + + TaskParallelSettings settings; + BLI_parallel_range_settings_defaults(&settings); + BLI_task_parallel_range(0, tc->data_len, &data, transdata_elem_shear_fn, &settings); } } diff --git a/source/blender/editors/transform/transform_mode_shrink_fatten.c b/source/blender/editors/transform/transform_mode_shrink_fatten.c index d2d73a14396..4cdaab599b4 100644 --- a/source/blender/editors/transform/transform_mode_shrink_fatten.c +++ b/source/blender/editors/transform/transform_mode_shrink_fatten.c @@ -25,6 +25,7 @@ #include "BLI_math.h" #include "BLI_string.h" +#include "BLI_task.h" #include "BKE_context.h" #include "BKE_unit.h" @@ -43,6 +44,47 @@ #include "transform_snap.h" /* -------------------------------------------------------------------- */ +/** \name Transform (Shrink-Fatten) Element + * \{ */ + +/** + * \note Small arrays / data-structures should be stored copied for faster memory access. + */ +struct TransDataArgs_ShrinkFatten { + const TransInfo *t; + const TransDataContainer *tc; + float distance; +}; + +static void transdata_elem_shrink_fatten(const TransInfo *t, + const TransDataContainer *UNUSED(tc), + TransData *td, + const float distance) +{ + /* Get the final offset. */ + float tdistance = distance * td->factor; + if (td->ext && (t->flag & T_ALT_TRANSFORM) != 0) { + tdistance *= td->ext->isize[0]; /* shell factor */ + } + + madd_v3_v3v3fl(td->loc, td->iloc, td->axismtx[2], tdistance); +} + +static void transdata_elem_shrink_fatten_fn(void *__restrict iter_data_v, + const int iter, + const TaskParallelTLS *__restrict UNUSED(tls)) +{ + struct TransDataArgs_ShrinkFatten *data = iter_data_v; + TransData *td = &data->tc->data[iter]; + if (td->flag & TD_SKIP) { + return; + } + transdata_elem_shrink_fatten(data->t, data->tc, td, data->distance); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name Transform (Shrink-Fatten) * \{ */ @@ -114,20 +156,24 @@ static void applyShrinkFatten(TransInfo *t, const int UNUSED(mval[2])) /* done with header string */ FOREACH_TRANS_DATA_CONTAINER (t, tc) { - TransData *td = tc->data; - for (i = 0; i < tc->data_len; i++, td++) { - float tdistance; /* temp dist */ - if (td->flag & TD_SKIP) { - continue; + if (tc->data_len < TRANSDATA_THREAD_LIMIT) { + TransData *td = tc->data; + for (i = 0; i < tc->data_len; i++, td++) { + if (td->flag & TD_SKIP) { + continue; + } + transdata_elem_shrink_fatten(t, tc, td, distance); } - - /* get the final offset */ - tdistance = distance * td->factor; - if (td->ext && (t->flag & T_ALT_TRANSFORM) != 0) { - tdistance *= td->ext->isize[0]; /* shell factor */ - } - - madd_v3_v3v3fl(td->loc, td->iloc, td->axismtx[2], tdistance); + } + else { + struct TransDataArgs_ShrinkFatten data = { + .t = t, + .tc = tc, + .distance = distance, + }; + TaskParallelSettings settings; + BLI_parallel_range_settings_defaults(&settings); + BLI_task_parallel_range(0, tc->data_len, &data, transdata_elem_shrink_fatten_fn, &settings); } } diff --git a/source/blender/editors/transform/transform_mode_skin_resize.c b/source/blender/editors/transform/transform_mode_skin_resize.c index 75ad83b0787..45336602c5a 100644 --- a/source/blender/editors/transform/transform_mode_skin_resize.c +++ b/source/blender/editors/transform/transform_mode_skin_resize.c @@ -24,6 +24,7 @@ #include <stdlib.h> #include "BLI_math.h" +#include "BLI_task.h" #include "BKE_context.h" #include "BKE_unit.h" @@ -38,6 +39,58 @@ #include "transform_snap.h" /* -------------------------------------------------------------------- */ +/** \name Transform (Skin) Element + * \{ */ + +/** + * \note Small arrays / data-structures should be stored copied for faster memory access. + */ +struct TransDataArgs_SkinResize { + const TransInfo *t; + const TransDataContainer *tc; + float mat[3][3]; +}; + +static void transdata_elem_skin_resize(const TransInfo *t, + const TransDataContainer *UNUSED(tc), + TransData *td, + const float mat[3][3]) +{ + float tmat[3][3], smat[3][3]; + float fsize[3]; + + if (t->flag & T_EDIT) { + mul_m3_m3m3(smat, mat, td->mtx); + mul_m3_m3m3(tmat, td->smtx, smat); + } + else { + copy_m3_m3(tmat, mat); + } + + if (t->con.applySize) { + t->con.applySize(t, NULL, NULL, tmat); + } + + mat3_to_size(fsize, tmat); + td->loc[0] = td->iloc[0] * (1 + (fsize[0] - 1) * td->factor); + td->loc[1] = td->iloc[1] * (1 + (fsize[1] - 1) * td->factor); +} + +static void transdata_elem_skin_resize_fn(void *__restrict iter_data_v, + const int iter, + const TaskParallelTLS *__restrict UNUSED(tls)) +{ + struct TransDataArgs_SkinResize *data = iter_data_v; + TransData *td = &data->tc->data[iter]; + if (td->flag & TD_SKIP) { + return; + } + transdata_elem_skin_resize(data->t, data->tc, td, data->mat); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name Transform (Skin) * \{ */ @@ -67,29 +120,24 @@ static void applySkinResize(TransInfo *t, const int UNUSED(mval[2])) headerResize(t, t->values_final, str, sizeof(str)); FOREACH_TRANS_DATA_CONTAINER (t, tc) { - TransData *td = tc->data; - for (i = 0; i < tc->data_len; i++, td++) { - float tmat[3][3], smat[3][3]; - float fsize[3]; - if (td->flag & TD_SKIP) { - continue; + if (tc->data_len < TRANSDATA_THREAD_LIMIT) { + TransData *td = tc->data; + for (i = 0; i < tc->data_len; i++, td++) { + if (td->flag & TD_SKIP) { + continue; + } + transdata_elem_skin_resize(t, tc, td, mat); } - - if (t->flag & T_EDIT) { - mul_m3_m3m3(smat, mat, td->mtx); - mul_m3_m3m3(tmat, td->smtx, smat); - } - else { - copy_m3_m3(tmat, mat); - } - - if (t->con.applySize) { - t->con.applySize(t, NULL, NULL, tmat); - } - - mat3_to_size(fsize, tmat); - td->loc[0] = td->iloc[0] * (1 + (fsize[0] - 1) * td->factor); - td->loc[1] = td->iloc[1] * (1 + (fsize[1] - 1) * td->factor); + } + else { + struct TransDataArgs_SkinResize data = { + .t = t, + .tc = tc, + }; + copy_m3_m3(data.mat, mat); + TaskParallelSettings settings; + BLI_parallel_range_settings_defaults(&settings); + BLI_task_parallel_range(0, tc->data_len, &data, transdata_elem_skin_resize_fn, &settings); } } diff --git a/source/blender/editors/transform/transform_mode_tosphere.c b/source/blender/editors/transform/transform_mode_tosphere.c index 9bca9b2e9e6..8587d5ae140 100644 --- a/source/blender/editors/transform/transform_mode_tosphere.c +++ b/source/blender/editors/transform/transform_mode_tosphere.c @@ -25,6 +25,7 @@ #include "BLI_math.h" #include "BLI_string.h" +#include "BLI_task.h" #include "MEM_guardedalloc.h" @@ -111,6 +112,74 @@ static void to_sphere_radius_update(TransInfo *t) /** \} */ /* -------------------------------------------------------------------- */ +/** \name Transform (ToSphere) Element + * \{ */ + +/** + * \note Small arrays / data-structures should be stored copied for faster memory access. + */ +struct TransDataArgs_ToSphere { + const TransInfo *t; + const TransDataContainer *tc; + float ratio; + const struct ToSphereInfo to_sphere_info; + bool is_local_center; + bool is_data_space; +}; + +static void transdata_elem_to_sphere(const TransInfo *UNUSED(t), + const TransDataContainer *tc, + TransData *td, + const float ratio, + const struct ToSphereInfo *to_sphere_info, + const bool is_local_center, + const bool is_data_space) +{ + float vec[3]; + const float *center = is_local_center ? td->center : tc->center_local; + if (is_data_space) { + copy_v3_v3(vec, td->center); + } + else { + copy_v3_v3(vec, td->iloc); + } + + sub_v3_v3(vec, center); + const float radius = normalize_v3(vec); + const float tratio = ratio * td->factor; + mul_v3_fl(vec, radius * (1.0f - tratio) + to_sphere_info->radius * tratio); + add_v3_v3(vec, center); + + if (is_data_space) { + sub_v3_v3(vec, td->center); + mul_m3_v3(td->smtx, vec); + add_v3_v3(vec, td->iloc); + } + + copy_v3_v3(td->loc, vec); +} + +static void transdata_elem_to_sphere_fn(void *__restrict iter_data_v, + const int iter, + const TaskParallelTLS *__restrict UNUSED(tls)) +{ + struct TransDataArgs_ToSphere *data = iter_data_v; + TransData *td = &data->tc->data[iter]; + if (td->flag & TD_SKIP) { + return; + } + transdata_elem_to_sphere(data->t, + data->tc, + td, + data->ratio, + &data->to_sphere_info, + data->is_local_center, + data->is_data_space); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name Transform (ToSphere) * \{ */ @@ -119,8 +188,7 @@ static void applyToSphere(TransInfo *t, const int UNUSED(mval[2])) const bool is_local_center = transdata_check_local_center(t, t->around); const bool is_data_space = (t->options & CTX_POSE_BONE) != 0; - float vec[3]; - float ratio, radius; + float ratio; int i; char str[UI_MAX_DRAW_STR]; @@ -147,40 +215,33 @@ static void applyToSphere(TransInfo *t, const int UNUSED(mval[2])) BLI_snprintf(str, sizeof(str), TIP_("To Sphere: %.4f %s"), ratio, t->proptext); } - const struct ToSphereInfo *data = t->custom.mode.data; - if (data->prop_size_prev != t->prop_size) { + const struct ToSphereInfo *to_sphere_info = t->custom.mode.data; + if (to_sphere_info->prop_size_prev != t->prop_size) { to_sphere_radius_update(t); } FOREACH_TRANS_DATA_CONTAINER (t, tc) { - TransData *td = tc->data; - for (i = 0; i < tc->data_len; i++, td++) { - float tratio; - if (td->flag & TD_SKIP) { - continue; - } - - const float *center = is_local_center ? td->center : tc->center_local; - if (is_data_space) { - copy_v3_v3(vec, td->center); - } - else { - copy_v3_v3(vec, td->iloc); - } - - sub_v3_v3(vec, center); - radius = normalize_v3(vec); - tratio = ratio * td->factor; - mul_v3_fl(vec, radius * (1.0f - tratio) + data->radius * tratio); - add_v3_v3(vec, center); - - if (is_data_space) { - sub_v3_v3(vec, td->center); - mul_m3_v3(td->smtx, vec); - add_v3_v3(vec, td->iloc); + if (tc->data_len < TRANSDATA_THREAD_LIMIT) { + TransData *td = tc->data; + for (i = 0; i < tc->data_len; i++, td++) { + if (td->flag & TD_SKIP) { + continue; + } + transdata_elem_to_sphere(t, tc, td, ratio, to_sphere_info, is_local_center, is_data_space); } - - copy_v3_v3(td->loc, vec); + } + else { + struct TransDataArgs_ToSphere data = { + .t = t, + .tc = tc, + .ratio = ratio, + .to_sphere_info = *to_sphere_info, + .is_local_center = is_local_center, + .is_data_space = is_data_space, + }; + TaskParallelSettings settings; + BLI_parallel_range_settings_defaults(&settings); + BLI_task_parallel_range(0, tc->data_len, &data, transdata_elem_to_sphere_fn, &settings); } } diff --git a/source/blender/editors/transform/transform_mode_trackball.c b/source/blender/editors/transform/transform_mode_trackball.c index d05077ef1ef..157283d08da 100644 --- a/source/blender/editors/transform/transform_mode_trackball.c +++ b/source/blender/editors/transform/transform_mode_trackball.c @@ -25,6 +25,7 @@ #include "BLI_math.h" #include "BLI_string.h" +#include "BLI_task.h" #include "BKE_context.h" #include "BKE_unit.h" @@ -40,6 +41,51 @@ #include "transform_snap.h" /* -------------------------------------------------------------------- */ +/** \name Transform (Rotation - Trackball) Element + * \{ */ + +/** + * \note Small arrays / data-structures should be stored copied for faster memory access. + */ +struct TransDataArgs_Trackball { + const TransInfo *t; + const TransDataContainer *tc; + const float axis[3]; + const float angle; + float mat[3][3]; +}; + +static void transdata_elem_trackball(const TransInfo *t, + const TransDataContainer *tc, + TransData *td, + const float axis[3], + const float angle, + const float mat[3][3]) +{ + float mat_buf[3][3]; + const float(*mat_final)[3] = mat; + if (t->flag & T_PROP_EDIT) { + axis_angle_normalized_to_mat3(mat_buf, axis, td->factor * angle); + mat_final = mat_buf; + } + ElementRotation(t, tc, td, mat_final, t->around); +} + +static void transdata_elem_trackball_fn(void *__restrict iter_data_v, + const int iter, + const TaskParallelTLS *__restrict UNUSED(tls)) +{ + struct TransDataArgs_Trackball *data = iter_data_v; + TransData *td = &data->tc->data[iter]; + if (td->flag & TD_SKIP) { + return; + } + transdata_elem_trackball(data->t, data->tc, td, data->axis, data->angle, data->mat); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name Transform (Rotation - Trackball) * \{ */ @@ -59,17 +105,27 @@ static void applyTrackballValue(TransInfo *t, axis_angle_normalized_to_mat3(mat, axis, angle); FOREACH_TRANS_DATA_CONTAINER (t, tc) { - TransData *td = tc->data; - for (i = 0; i < tc->data_len; i++, td++) { - if (td->flag & TD_SKIP) { - continue; + if (tc->data_len < TRANSDATA_THREAD_LIMIT) { + TransData *td = tc->data; + for (i = 0; i < tc->data_len; i++, td++) { + if (td->flag & TD_SKIP) { + continue; + } + transdata_elem_trackball(t, tc, td, axis, angle, mat); } - - if (t->flag & T_PROP_EDIT) { - axis_angle_normalized_to_mat3(mat, axis, td->factor * angle); - } - - ElementRotation(t, tc, td, mat, t->around); + } + else { + struct TransDataArgs_Trackball data = { + .t = t, + .tc = tc, + .axis = {UNPACK3(axis)}, + .angle = angle, + }; + copy_m3_m3(data.mat, mat); + + TaskParallelSettings settings; + BLI_parallel_range_settings_defaults(&settings); + BLI_task_parallel_range(0, tc->data_len, &data, transdata_elem_trackball_fn, &settings); } } } diff --git a/source/blender/editors/transform/transform_mode_translate.c b/source/blender/editors/transform/transform_mode_translate.c index 49afd7f0421..55bfedf26b8 100644 --- a/source/blender/editors/transform/transform_mode_translate.c +++ b/source/blender/editors/transform/transform_mode_translate.c @@ -29,6 +29,7 @@ #include "BLI_math.h" #include "BLI_string.h" +#include "BLI_task.h" #include "BKE_context.h" #include "BKE_report.h" @@ -49,6 +50,121 @@ #include "transform_snap.h" /* -------------------------------------------------------------------- */ +/** \name Transform (Translation) Element + * \{ */ + +/** + * \note Small arrays / data-structures should be stored copied for faster memory access. + */ +struct TransDataArgs_Translate { + const TransInfo *t; + const TransDataContainer *tc; + const float tc_pivot[3]; + const float vec[3]; + bool apply_snap_align_rotation; + bool is_valid_snapping_normal; +}; + +static void transdata_elem_translate(const TransInfo *t, + const TransDataContainer *tc, + TransData *td, + const float pivot[3], + const float vec[3], + const bool apply_snap_align_rotation, + const bool is_valid_snapping_normal) +{ + float rotate_offset[3] = {0}; + bool use_rotate_offset = false; + + /* Handle snapping rotation before doing the translation. */ + if (apply_snap_align_rotation) { + float mat[3][3]; + + if (is_valid_snapping_normal) { + const float *original_normal; + + /* In pose mode, we want to align normals with Y axis of bones. */ + if (t->options & CTX_POSE_BONE) { + original_normal = td->axismtx[1]; + } + else { + original_normal = td->axismtx[2]; + } + + rotation_between_vecs_to_mat3(mat, original_normal, t->tsnap.snapNormal); + } + else { + unit_m3(mat); + } + + ElementRotation_ex(t, tc, td, mat, pivot); + + if (td->loc) { + use_rotate_offset = true; + sub_v3_v3v3(rotate_offset, td->loc, td->iloc); + } + } + + float tvec[3]; + + if (t->con.applyVec) { + t->con.applyVec(t, tc, td, vec, tvec); + } + else { + copy_v3_v3(tvec, vec); + } + + mul_m3_v3(td->smtx, tvec); + + if (use_rotate_offset) { + add_v3_v3(tvec, rotate_offset); + } + + if (t->options & CTX_GPENCIL_STROKES) { + /* Grease pencil multi-frame falloff. */ + bGPDstroke *gps = (bGPDstroke *)td->extra; + if (gps != NULL) { + mul_v3_fl(tvec, td->factor * gps->runtime.multi_frame_falloff); + } + else { + mul_v3_fl(tvec, td->factor); + } + } + else { + /* Proportional editing falloff. */ + mul_v3_fl(tvec, td->factor); + } + + protectedTransBits(td->protectflag, tvec); + + if (td->loc) { + add_v3_v3v3(td->loc, td->iloc, tvec); + } + + constraintTransLim(t, td); +} + +static void transdata_elem_translate_fn(void *__restrict iter_data_v, + const int iter, + const TaskParallelTLS *__restrict UNUSED(tls)) +{ + struct TransDataArgs_Translate *data = iter_data_v; + TransData *td = &data->tc->data[iter]; + if (td->flag & TD_SKIP) { + return; + } + transdata_elem_translate(data->t, + data->tc, + td, + data->tc_pivot, + data->vec, + data->apply_snap_align_rotation, + data->is_valid_snapping_normal); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name Transform (Translation) * \{ */ @@ -242,14 +358,13 @@ static void ApplySnapTranslation(TransInfo *t, float vec[3]) static void applyTranslationValue(TransInfo *t, const float vec[3]) { const bool apply_snap_align_rotation = usingSnappingNormal(t); - float tvec[3]; + const bool is_valid_snapping_normal = apply_snap_align_rotation && validSnappingNormal(t); /* Ideally "apply_snap_align_rotation" would only be used when a snap point is found: * `t->tsnap.status & POINT_INIT` - perhaps this function isn't the best place to apply rotation. * However snapping rotation needs to be handled before doing the translation * (unless the pivot is also translated). */ FOREACH_TRANS_DATA_CONTAINER (t, tc) { - float pivot[3]; if (apply_snap_align_rotation) { copy_v3_v3(pivot, t->tsnap.snapTarget); @@ -259,79 +374,28 @@ static void applyTranslationValue(TransInfo *t, const float vec[3]) } } - TransData *td = tc->data; - for (int i = 0; i < tc->data_len; i++, td++) { - if (td->flag & TD_SKIP) { - continue; - } - - float rotate_offset[3] = {0}; - bool use_rotate_offset = false; - - /* Handle snapping rotation before doing the translation. */ - if (apply_snap_align_rotation) { - float mat[3][3]; - - if (validSnappingNormal(t)) { - const float *original_normal; - - /* In pose mode, we want to align normals with Y axis of bones. */ - if (t->options & CTX_POSE_BONE) { - original_normal = td->axismtx[1]; - } - else { - original_normal = td->axismtx[2]; - } - - rotation_between_vecs_to_mat3(mat, original_normal, t->tsnap.snapNormal); - } - else { - unit_m3(mat); - } - - ElementRotation_ex(t, tc, td, mat, pivot); - - if (td->loc) { - use_rotate_offset = true; - sub_v3_v3v3(rotate_offset, td->loc, td->iloc); + if (tc->data_len < TRANSDATA_THREAD_LIMIT) { + TransData *td = tc->data; + for (int i = 0; i < tc->data_len; i++, td++) { + if (td->flag & TD_SKIP) { + continue; } + transdata_elem_translate( + t, tc, td, pivot, vec, apply_snap_align_rotation, is_valid_snapping_normal); } - - if (t->con.applyVec) { - t->con.applyVec(t, tc, td, vec, tvec); - } - else { - copy_v3_v3(tvec, vec); - } - - mul_m3_v3(td->smtx, tvec); - - if (use_rotate_offset) { - add_v3_v3(tvec, rotate_offset); - } - - if (t->options & CTX_GPENCIL_STROKES) { - /* Grease pencil multi-frame falloff. */ - bGPDstroke *gps = (bGPDstroke *)td->extra; - if (gps != NULL) { - mul_v3_fl(tvec, td->factor * gps->runtime.multi_frame_falloff); - } - else { - mul_v3_fl(tvec, td->factor); - } - } - else { - /* Proportional editing falloff. */ - mul_v3_fl(tvec, td->factor); - } - - protectedTransBits(td->protectflag, tvec); - - if (td->loc) { - add_v3_v3v3(td->loc, td->iloc, tvec); - } - - constraintTransLim(t, td); + } + else { + struct TransDataArgs_Translate data = { + .t = t, + .tc = tc, + .tc_pivot = {UNPACK3(pivot)}, + .vec = {UNPACK3(vec)}, + .apply_snap_align_rotation = apply_snap_align_rotation, + .is_valid_snapping_normal = is_valid_snapping_normal, + }; + TaskParallelSettings settings; + BLI_parallel_range_settings_defaults(&settings); + BLI_task_parallel_range(0, tc->data_len, &data, transdata_elem_translate_fn, &settings); } } } |