Depsgraph: optimization of driver evaluation with many drivers.
This commit is contained in:
parent
e910765ad0
commit
e4afccf388
Notes:
blender-bot
2023-02-14 05:48:59 +01:00
Referenced by issue #55228, Performance regression of production file
|
@ -33,6 +33,7 @@
|
|||
|
||||
struct AnimData;
|
||||
struct AnimMapper;
|
||||
struct ChannelDriver;
|
||||
struct FCurve;
|
||||
struct ID;
|
||||
struct KS_Path;
|
||||
|
@ -202,7 +203,9 @@ void animsys_evaluate_action_group(struct PointerRNA *ptr, struct bAction *act,
|
|||
struct Depsgraph;
|
||||
|
||||
void BKE_animsys_eval_animdata(struct Depsgraph *depsgraph, struct ID *id);
|
||||
void BKE_animsys_eval_driver(struct Depsgraph *depsgraph, struct ID *id, struct FCurve *fcurve);
|
||||
void BKE_animsys_eval_driver(struct Depsgraph *depsgraph, struct ID *id, int driver_index, struct ChannelDriver *driver_orig);
|
||||
|
||||
void BKE_animsys_update_driver_array(struct ID *id);
|
||||
|
||||
/* ************************************* */
|
||||
|
||||
|
|
|
@ -250,6 +250,9 @@ void BKE_animdata_free(ID *id, const bool do_id_user)
|
|||
|
||||
/* free drivers - stored as a list of F-Curves */
|
||||
free_fcurves(&adt->drivers);
|
||||
|
||||
/* free driver array cache */
|
||||
MEM_SAFE_FREE(adt->driver_array);
|
||||
|
||||
/* free overrides */
|
||||
/* TODO... */
|
||||
|
@ -289,6 +292,7 @@ AnimData *BKE_animdata_copy(Main *bmain, AnimData *adt, const bool do_action, co
|
|||
|
||||
/* duplicate drivers (F-Curves) */
|
||||
copy_fcurves(&dadt->drivers, &adt->drivers);
|
||||
dadt->driver_array = NULL;
|
||||
|
||||
/* don't copy overrides */
|
||||
BLI_listbase_clear(&dadt->overrides);
|
||||
|
@ -2973,34 +2977,45 @@ void BKE_animsys_eval_animdata(Depsgraph *depsgraph, ID *id)
|
|||
BKE_animsys_evaluate_animdata(scene, id, adt, ctime, recalc);
|
||||
}
|
||||
|
||||
/* TODO(sergey): This is slow lookup of driver from CoW datablock.
|
||||
* Keep this for until we've got something smarter for depsgraph
|
||||
* building.\
|
||||
*/
|
||||
static FCurve *find_driver_from_evaluated_id(ID *id, FCurve *fcu)
|
||||
void BKE_animsys_update_driver_array(ID *id)
|
||||
{
|
||||
/* We've got non-CoW datablock, can use f-curve as-is. */
|
||||
if (id->orig_id == NULL) {
|
||||
return fcu;
|
||||
AnimData *adt = BKE_animdata_from_id(id);
|
||||
|
||||
/* Runtime driver map to avoid O(n^2) lookups in BKE_animsys_eval_driver.
|
||||
* Ideally the depsgraph could pass a pointer to the COW driver directly,
|
||||
* but this is difficult in the current design. */
|
||||
if (adt && adt->drivers.first) {
|
||||
BLI_assert(!adt->driver_array);
|
||||
|
||||
int num_drivers = BLI_listbase_count(&adt->drivers);
|
||||
adt->driver_array = MEM_mallocN(sizeof(FCurve*) * num_drivers, "adt->driver_array");
|
||||
|
||||
int driver_index = 0;
|
||||
for (FCurve *fcu = adt->drivers.first; fcu; fcu = fcu->next) {
|
||||
adt->driver_array[driver_index++] = fcu;
|
||||
}
|
||||
}
|
||||
/*const*/ ID *id_orig = id->orig_id;
|
||||
const AnimData *adt_orig = BKE_animdata_from_id(id_orig);
|
||||
const AnimData *adt_cow = BKE_animdata_from_id(id);
|
||||
const int fcu_index = BLI_findindex(&adt_orig->drivers, fcu);
|
||||
BLI_assert(fcu_index != -1);
|
||||
return BLI_findlink(&adt_cow->drivers, fcu_index);
|
||||
}
|
||||
|
||||
void BKE_animsys_eval_driver(Depsgraph *depsgraph,
|
||||
ID *id,
|
||||
FCurve *fcu)
|
||||
int driver_index,
|
||||
ChannelDriver *driver_orig)
|
||||
{
|
||||
/* TODO(sergey): De-duplicate with BKE animsys. */
|
||||
ChannelDriver *driver = fcu->driver;
|
||||
PointerRNA id_ptr;
|
||||
bool ok = false;
|
||||
|
||||
fcu = find_driver_from_evaluated_id(id, fcu);
|
||||
/* Lookup driver, accelerated with driver array map. */
|
||||
const AnimData *adt = BKE_animdata_from_id(id);
|
||||
FCurve* fcu;
|
||||
|
||||
if (adt->driver_array) {
|
||||
fcu = adt->driver_array[driver_index];
|
||||
}
|
||||
else {
|
||||
fcu = BLI_findlink(&adt->drivers, driver_index);
|
||||
}
|
||||
|
||||
DEG_debug_print_eval_subdata_index(
|
||||
depsgraph, __func__, id->name, id, "fcu", fcu->rna_path, fcu, fcu->array_index);
|
||||
|
@ -3011,7 +3026,7 @@ void BKE_animsys_eval_driver(Depsgraph *depsgraph,
|
|||
if ((fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED)) == 0) {
|
||||
/* check if driver itself is tagged for recalculation */
|
||||
/* XXX driver recalc flag is not set yet by depsgraph! */
|
||||
if ((driver) && !(driver->flag & DRIVER_FLAG_INVALID) /*&& (driver->flag & DRIVER_FLAG_RECALC)*/) {
|
||||
if ((driver_orig) && !(driver_orig->flag & DRIVER_FLAG_INVALID) /*&& (driver_orig->flag & DRIVER_FLAG_RECALC)*/) {
|
||||
/* evaluate this using values set already in other places
|
||||
* NOTE: for 'layering' option later on, we should check if we should remove old value before adding
|
||||
* new to only be done when drivers only changed */
|
||||
|
@ -3027,12 +3042,12 @@ void BKE_animsys_eval_driver(Depsgraph *depsgraph,
|
|||
//printf("\tnew val = %f\n", fcu->curval);
|
||||
|
||||
/* clear recalc flag */
|
||||
driver->flag &= ~DRIVER_FLAG_RECALC;
|
||||
driver_orig->flag &= ~DRIVER_FLAG_RECALC;
|
||||
|
||||
/* set error-flag if evaluation failed */
|
||||
if (ok == 0) {
|
||||
printf("invalid driver - %s[%d]\n", fcu->rna_path, fcu->array_index);
|
||||
driver->flag |= DRIVER_FLAG_INVALID;
|
||||
driver_orig->flag |= DRIVER_FLAG_INVALID;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2819,6 +2819,7 @@ static void direct_link_animdata(FileData *fd, AnimData *adt)
|
|||
/* link drivers */
|
||||
link_list(fd, &adt->drivers);
|
||||
direct_link_fcurves(fd, &adt->drivers);
|
||||
adt->driver_array = NULL;
|
||||
|
||||
/* link overrides */
|
||||
// TODO...
|
||||
|
|
|
@ -704,9 +704,10 @@ void DepsgraphNodeBuilder::build_animdata(ID *id)
|
|||
}
|
||||
|
||||
/* drivers */
|
||||
int driver_index = 0;
|
||||
LISTBASE_FOREACH (FCurve *, fcu, &adt->drivers) {
|
||||
/* create driver */
|
||||
build_driver(id, fcu);
|
||||
build_driver(id, fcu, driver_index++);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -715,16 +716,21 @@ void DepsgraphNodeBuilder::build_animdata(ID *id)
|
|||
* Build graph node(s) for Driver
|
||||
* \param id: ID-Block that driver is attached to
|
||||
* \param fcu: Driver-FCurve
|
||||
* \param driver_index: Index in animation data drivers list
|
||||
*/
|
||||
void DepsgraphNodeBuilder::build_driver(ID *id, FCurve *fcurve)
|
||||
void DepsgraphNodeBuilder::build_driver(ID *id, FCurve *fcurve, int driver_index)
|
||||
{
|
||||
ID *id_cow = get_cow_id(id);
|
||||
|
||||
/* Create data node for this driver */
|
||||
/* TODO(sergey): Shall we use COW of fcu itself here? */
|
||||
ID *id_cow = get_cow_id(id);
|
||||
ChannelDriver *driver_orig = fcurve->driver;
|
||||
|
||||
/* TODO(sergey): ideally we could pass the COW of fcu, but since it
|
||||
* has not yet been allocated at this point we can't. As a workaround
|
||||
* the animation systems allocates an array so we can do a fast lookup
|
||||
* with the driver index. */
|
||||
ensure_operation_node(id,
|
||||
DEG_NODE_TYPE_PARAMETERS,
|
||||
function_bind(BKE_animsys_eval_driver, _1, id_cow, fcurve),
|
||||
function_bind(BKE_animsys_eval_driver, _1, id_cow, driver_index, driver_orig),
|
||||
DEG_OPCODE_DRIVER,
|
||||
fcurve->rna_path ? fcurve->rna_path : "",
|
||||
fcurve->array_index);
|
||||
|
|
|
@ -178,7 +178,7 @@ struct DepsgraphNodeBuilder {
|
|||
void build_particle_settings(ParticleSettings *part);
|
||||
void build_cloth(Object *object);
|
||||
void build_animdata(ID *id);
|
||||
void build_driver(ID *id, FCurve *fcurve);
|
||||
void build_driver(ID *id, FCurve *fcurve, int driver_index);
|
||||
void build_driver_variables(ID *id, FCurve *fcurve);
|
||||
void build_driver_id_property(ID *id, const char *rna_path);
|
||||
void build_ik_pose(Object *object,
|
||||
|
|
|
@ -542,6 +542,7 @@ void update_special_pointers(const Depsgraph *depsgraph,
|
|||
break;
|
||||
}
|
||||
update_edit_mode_pointers(depsgraph, id_orig, id_cow);
|
||||
BKE_animsys_update_driver_array(id_cow);
|
||||
}
|
||||
|
||||
/* This callback is used to validate that all nested ID datablocks are
|
||||
|
|
|
@ -917,6 +917,8 @@ typedef struct AnimData {
|
|||
ListBase drivers; /* standard user-created Drivers/Expressions (used as part of a rig) */
|
||||
ListBase overrides; /* temp storage (AnimOverride) of values for settings that are animated (but the value hasn't been keyframed) */
|
||||
|
||||
FCurve **driver_array; /* runtime data, for depsgraph evaluation */
|
||||
|
||||
/* settings for animation evaluation */
|
||||
int flag; /* user-defined settings */
|
||||
int recalc; /* depsgraph recalculation flags */
|
||||
|
|
Loading…
Reference in New Issue