Anim: run bezier handle calculation in parallel #119388

Merged
Christoph Lendenfeld merged 21 commits from ChrisLend/blender:thread_recalc_handles into main 2024-05-07 10:43:03 +02:00
1 changed files with 42 additions and 45 deletions

View File

@ -28,6 +28,7 @@
#include "BLI_math_vector_types.hh"
#include "BLI_sort_utils.h"
#include "BLI_string_utils.hh"
#include "BLI_task.hh"
#include "BLT_translation.hh"
@ -1245,6 +1246,7 @@ static BezTriple *cycle_offset_triple(
void BKE_fcurve_handles_recalc_ex(FCurve *fcu, eBezTriple_Flag handle_sel_flag)
{

If fcu->totvert == 2 then prev could be the same as bezt. The old code didn't have that, as it used prev = bezt at the end of the loop (unless I'm missing something, which is entirely possible).

The same goes for next below, that'll also be the same as bezt when bezt is the last key and totvert == 2. That was already the case in the old code, though.

Also (in the old code) the negative counting in a but the positive order of visiting the keys makes my head hurt. I'm glad you're resolving this.

If `fcu->totvert == 2` then `prev` could be the same as `bezt`. The old code didn't have that, as it used `prev = bezt` at the end of the loop (unless I'm missing something, which is entirely possible). The same goes for `next` below, that'll also be the same as `bezt` when `bezt` is the last key and `totvert == 2`. That was already the case in the old code, though. Also (in the old code) the negative counting in `a` but the positive order of visiting the keys makes my head hurt. I'm glad you're resolving this.
using namespace blender;
/* Error checking:
* - Need at least two points.
* - Need bezier keys.
@ -1257,60 +1259,55 @@ void BKE_fcurve_handles_recalc_ex(FCurve *fcu, eBezTriple_Flag handle_sel_flag)
}
/* If the first modifier is Cycles, smooth the curve through the cycle. */
BezTriple *first = &fcu->bezt[0], *last = &fcu->bezt[fcu->totvert - 1];
BezTriple tmp;
BezTriple *first = &fcu->bezt[0];
BezTriple *last = &fcu->bezt[fcu->totvert - 1];
const bool cycle = BKE_fcurve_is_cyclic(fcu) && BEZT_IS_AUTOH(first) && BEZT_IS_AUTOH(last);
/* Get initial pointers. */
BezTriple *bezt = fcu->bezt;
BezTriple *prev = cycle_offset_triple(cycle, &tmp, &fcu->bezt[fcu->totvert - 2], last, first);
BezTriple *next = (bezt + 1);
threading::parallel_for(IndexRange(fcu->totvert), 256, [&](const IndexRange range) {
BezTriple tmp;

I'd just write threading::parallel_for(IndexRange(fcu->totvert),

I'd just write `threading::parallel_for(IndexRange(fcu->totvert), `
for (const int i : range) {
BezTriple *bezt = &fcu->bezt[i];
BezTriple *prev = nullptr;
BezTriple *next = nullptr;
if (i > 0) {
prev = (bezt - 1);
}
else {
prev = cycle_offset_triple(cycle, &tmp, &fcu->bezt[fcu->totvert - 2], last, first);
}
if (i < fcu->totvert - 1) {
next = (bezt + 1);
}

This can be replaced with CLAMP_MAX(bezt->vec[0][0], bezt->vec[1][0]);, and the below case with CLAMP_MIN().

This can be replaced with `CLAMP_MAX(bezt->vec[0][0], bezt->vec[1][0]);`, and the below case with `CLAMP_MIN()`.
else {
next = cycle_offset_triple(cycle, &tmp, &fcu->bezt[1], first, last);
}
/* Loop over all beztriples, adjusting handles. */
int a = fcu->totvert;
while (a--) {
/* Clamp timing of handles to be on either side of beztriple. */
if (bezt->vec[0][0] > bezt->vec[1][0]) {
bezt->vec[0][0] = bezt->vec[1][0];
}
if (bezt->vec[2][0] < bezt->vec[1][0]) {
bezt->vec[2][0] = bezt->vec[1][0];
}
/* Clamp timing of handles to be on either side of beztriple. */
CLAMP_MAX(bezt->vec[0][0], bezt->vec[1][0]);
CLAMP_MIN(bezt->vec[2][0], bezt->vec[1][0]);
/* Calculate auto-handles. */
BKE_nurb_handle_calc_ex(bezt, prev, next, handle_sel_flag, true, fcu->auto_smoothing);
/* Calculate auto-handles. */
BKE_nurb_handle_calc_ex(bezt, prev, next, handle_sel_flag, true, fcu->auto_smoothing);
/* For automatic ease in and out. */
if (BEZT_IS_AUTOH(bezt) && !cycle) {
/* Only do this on first or last beztriple. */
if (ELEM(a, 0, fcu->totvert - 1)) {
/* Set both handles to have same horizontal value as keyframe. */
if (fcu->extend == FCURVE_EXTRAPOLATE_CONSTANT) {
bezt->vec[0][1] = bezt->vec[2][1] = bezt->vec[1][1];
/* Remember that these keyframes are special, they don't need to be adjusted. */
bezt->auto_handle_type = HD_AUTOTYPE_LOCKED_FINAL;
/* For automatic ease in and out. */
if (BEZT_IS_AUTOH(bezt) && !cycle) {
/* Only do this on first or last beztriple. */
if (ELEM(i, 0, fcu->totvert - 1)) {
/* Set both handles to have same horizontal value as keyframe. */
if (fcu->extend == FCURVE_EXTRAPOLATE_CONSTANT) {
bezt->vec[0][1] = bezt->vec[2][1] = bezt->vec[1][1];
/* Remember that these keyframes are special, they don't need to be adjusted. */
bezt->auto_handle_type = HD_AUTOTYPE_LOCKED_FINAL;
}
}
}
}
/* Avoid total smoothing failure on duplicate keyframes (can happen during grab). */
if (prev && prev->vec[1][0] >= bezt->vec[1][0]) {
prev->auto_handle_type = bezt->auto_handle_type = HD_AUTOTYPE_LOCKED_FINAL;
/* Avoid total smoothing failure on duplicate keyframes (can happen during grab). */
if (prev && prev->vec[1][0] >= bezt->vec[1][0]) {
prev->auto_handle_type = bezt->auto_handle_type = HD_AUTOTYPE_LOCKED_FINAL;
}
}
/* Advance pointers for next iteration. */
prev = bezt;
if (a == 1) {
next = cycle_offset_triple(cycle, &tmp, &fcu->bezt[1], first, last);
}
else if (next != nullptr) {
next++;
}
bezt++;
}
});

If this is relatively cheap, you can take look at TaskSizeHints.

If this is relatively cheap, you can take look at `TaskSizeHints`.
/* If cyclic extrapolation and Auto Clamp has triggered, ensure it is symmetric. */
if (cycle && (first->auto_handle_type != HD_AUTOTYPE_NORMAL ||