Modifiers: Performance Simple Deformation

Use multiprocessing with simple deform modifiers.

Master 2.92 fps this patch 3.13 fps on Ryzen 1700X With Vega 64 GPU.

3970X: 2.85 fps -> 2.95 fps
3990X: 3.15 fps -> 3.41 fps
3995WX: 3.21 fps -> 3.38 fps

Reviewed By: jbakker

Differential Revision: https://developer.blender.org/D10609
This commit is contained in:
Jagannadhan Ravi 2021-04-23 10:06:46 +02:00 committed by Jeroen Bakker
parent cfa20ff03b
commit 425e19bc1f
3 changed files with 121 additions and 71 deletions

@ -1 +1 @@
Subproject commit 81815ea92c2071a08566dc66d4a871b6e2f5c868
Subproject commit 4cb833e84acfd2be5fa08ce75118ce9cb60643b8

@ -98,3 +98,10 @@
#else
# define ATTR_ALIGN(x) __attribute__((aligned(x)))
#endif
/* Alignment directive */
#ifdef _WIN64
# define ALIGN_STRUCT __declspec(align(64))
#else
# define ALIGN_STRUCT
#endif

@ -22,9 +22,8 @@
*/
#include "BLI_utildefines.h"
#include "BLI_math.h"
#include "BLI_task.h"
#include "BLT_translation.h"
#include "DNA_defaults.h"
@ -57,6 +56,21 @@
#define BEND_EPS 0.000001f
ALIGN_STRUCT struct DeformUserData {
bool invert_vgroup;
char mode;
char deform_axis;
int lock_axis;
int vgroup;
int limit_axis;
float weight;
float smd_factor;
float smd_limit[2];
float (*vertexCos)[3];
SpaceTransform *transf;
MDeformVert *dvert;
};
/* Re-maps the indices for X Y Z by shifting them up and wrapping, such that
* X = Y, Y = Z, Z = X (for X axis), and X = Z, Y = X, Z = Y (for Y axis). This
* exists because the deformations (excluding bend) are based on the Z axis.
@ -203,6 +217,86 @@ static void simpleDeform_bend(const float factor,
}
}
static void simple_helper(void *__restrict userdata,
const int iter,
const TaskParallelTLS *__restrict UNUSED(tls))
{
struct DeformUserData *curr_deform_data = userdata;
float weight = BKE_defvert_array_find_weight_safe(curr_deform_data->dvert, iter, curr_deform_data->vgroup);
const uint *axis_map = axis_map_table[(curr_deform_data->mode != MOD_SIMPLEDEFORM_MODE_BEND) ?
curr_deform_data->deform_axis :
2];
const float base_limit[2] = {0.0f, 0.0f};
if (curr_deform_data->invert_vgroup) {
weight = 1.0f - weight;
}
if (weight != 0.0f) {
float co[3], dcut[3] = {0.0f, 0.0f, 0.0f};
if (curr_deform_data->transf) {
BLI_space_transform_apply(curr_deform_data->transf, curr_deform_data->vertexCos[iter]);
}
copy_v3_v3(co, curr_deform_data->vertexCos[iter]);
/* Apply axis limits, and axis mappings */
if (curr_deform_data->lock_axis & MOD_SIMPLEDEFORM_LOCK_AXIS_X) {
axis_limit(0, base_limit, co, dcut);
}
if (curr_deform_data->lock_axis & MOD_SIMPLEDEFORM_LOCK_AXIS_Y) {
axis_limit(1, base_limit, co, dcut);
}
if (curr_deform_data->lock_axis & MOD_SIMPLEDEFORM_LOCK_AXIS_Z) {
axis_limit(2, base_limit, co, dcut);
}
axis_limit(curr_deform_data->limit_axis, curr_deform_data->smd_limit, co, dcut);
/* apply the deform to a mapped copy of the vertex, and then re-map it back. */
float co_remap[3];
float dcut_remap[3];
copy_v3_v3_map(co_remap, co, axis_map);
copy_v3_v3_map(dcut_remap, dcut, axis_map);
switch (curr_deform_data->mode) {
case MOD_SIMPLEDEFORM_MODE_TWIST:
simpleDeform_twist(curr_deform_data->smd_factor,
curr_deform_data->deform_axis,
dcut_remap,
co_remap); /* apply deform */
break;
case MOD_SIMPLEDEFORM_MODE_BEND:
simpleDeform_bend(curr_deform_data->smd_factor,
curr_deform_data->deform_axis,
dcut_remap,
co_remap); /* apply deform */
break;
case MOD_SIMPLEDEFORM_MODE_TAPER:
simpleDeform_taper(curr_deform_data->smd_factor,
curr_deform_data->deform_axis,
dcut_remap,
co_remap); /* apply deform */
break;
case MOD_SIMPLEDEFORM_MODE_STRETCH:
simpleDeform_stretch(curr_deform_data->smd_factor,
curr_deform_data->deform_axis,
dcut_remap,
co_remap); /* apply deform */
break;
default:
return; /* No simple-deform mode? */
}
copy_v3_v3_unmap(co, co_remap, axis_map);
/* Use vertex weight has coef of linear interpolation */
interp_v3_v3v3(curr_deform_data->vertexCos[iter], curr_deform_data->vertexCos[iter], co, weight);
if (curr_deform_data->transf) {
BLI_space_transform_invert(curr_deform_data->transf, curr_deform_data->vertexCos[iter]);
}
}
}
/* simple deform modifier */
static void SimpleDeformModifier_do(SimpleDeformModifierData *smd,
const ModifierEvalContext *UNUSED(ctx),
@ -211,14 +305,9 @@ static void SimpleDeformModifier_do(SimpleDeformModifierData *smd,
float (*vertexCos)[3],
int numVerts)
{
const float base_limit[2] = {0.0f, 0.0f};
int i;
float smd_limit[2], smd_factor;
SpaceTransform *transf = NULL, tmp_transf;
void (*simpleDeform_callback)(const float factor,
const int axis,
const float dcut[3],
float co[3]) = NULL; /* Mode callback */
int vgroup;
MDeformVert *dvert;
@ -300,23 +389,6 @@ static void SimpleDeformModifier_do(SimpleDeformModifierData *smd,
smd_factor = smd->factor / max_ff(FLT_EPSILON, smd_limit[1] - smd_limit[0]);
}
switch (smd->mode) {
case MOD_SIMPLEDEFORM_MODE_TWIST:
simpleDeform_callback = simpleDeform_twist;
break;
case MOD_SIMPLEDEFORM_MODE_BEND:
simpleDeform_callback = simpleDeform_bend;
break;
case MOD_SIMPLEDEFORM_MODE_TAPER:
simpleDeform_callback = simpleDeform_taper;
break;
case MOD_SIMPLEDEFORM_MODE_STRETCH:
simpleDeform_callback = simpleDeform_stretch;
break;
default:
return; /* No simple-deform mode? */
}
if (smd->mode == MOD_SIMPLEDEFORM_MODE_BEND) {
if (fabsf(smd_factor) < BEND_EPS) {
return;
@ -325,53 +397,24 @@ static void SimpleDeformModifier_do(SimpleDeformModifierData *smd,
MOD_get_vgroup(ob, mesh, smd->vgroup_name, &dvert, &vgroup);
const bool invert_vgroup = (smd->flag & MOD_SIMPLEDEFORM_FLAG_INVERT_VGROUP) != 0;
const uint *axis_map =
axis_map_table[(smd->mode != MOD_SIMPLEDEFORM_MODE_BEND) ? deform_axis : 2];
for (i = 0; i < numVerts; i++) {
float weight = BKE_defvert_array_find_weight_safe(dvert, i, vgroup);
if (invert_vgroup) {
weight = 1.0f - weight;
}
if (weight != 0.0f) {
float co[3], dcut[3] = {0.0f, 0.0f, 0.0f};
if (transf) {
BLI_space_transform_apply(transf, vertexCos[i]);
}
copy_v3_v3(co, vertexCos[i]);
/* Apply axis limits, and axis mappings */
if (lock_axis & MOD_SIMPLEDEFORM_LOCK_AXIS_X) {
axis_limit(0, base_limit, co, dcut);
}
if (lock_axis & MOD_SIMPLEDEFORM_LOCK_AXIS_Y) {
axis_limit(1, base_limit, co, dcut);
}
if (lock_axis & MOD_SIMPLEDEFORM_LOCK_AXIS_Z) {
axis_limit(2, base_limit, co, dcut);
}
axis_limit(limit_axis, smd_limit, co, dcut);
/* apply the deform to a mapped copy of the vertex, and then re-map it back. */
float co_remap[3];
float dcut_remap[3];
copy_v3_v3_map(co_remap, co, axis_map);
copy_v3_v3_map(dcut_remap, dcut, axis_map);
simpleDeform_callback(smd_factor, deform_axis, dcut_remap, co_remap); /* apply deform */
copy_v3_v3_unmap(co, co_remap, axis_map);
/* Use vertex weight has coef of linear interpolation */
interp_v3_v3v3(vertexCos[i], vertexCos[i], co, weight);
if (transf) {
BLI_space_transform_invert(transf, vertexCos[i]);
}
}
}
// build our data
struct DeformUserData deform_pool_data = {.mode = smd->mode,
.smd_factor = smd_factor,
.deform_axis = deform_axis,
.transf = transf,
.vertexCos = vertexCos,
.invert_vgroup = invert_vgroup,
.lock_axis = lock_axis,
.vgroup = vgroup,
.smd_limit[0] = smd_limit[0],
.smd_limit[1] = smd_limit[1],
.dvert = dvert,
.limit_axis = limit_axis};
/* Do deformation. */
TaskParallelSettings settings;
BLI_parallel_range_settings_defaults(&settings);
BLI_task_parallel_range(0, numVerts, &deform_pool_data, simple_helper, &settings);
}
/* SimpleDeform */