Depsgraph: Fix race condition writing drivers to array property

Animation system has separate fcurves for each of array elements and
dependency graph creates separate nodes for each of fcurve, This is
needed to keep granularity of updates, but causes issues because
animation system will actually write the whole array to property when
modifying single value (this is a limitation of RNA API).

Worked around by adding operation relation between array drivers
so we never write same array form multiple threads.
This commit is contained in:
Sergey Sharybin 2016-11-02 18:05:38 +01:00
parent e4164f31fc
commit 6514cbae6b
1 changed files with 49 additions and 0 deletions

View File

@ -842,6 +842,55 @@ void DepsgraphRelationBuilder::build_animdata(ID *id)
/* create the driver's relations to targets */
build_driver(id, fcu);
/* Special case for array drivers: we can not multithread them because
* of the way how they work internally: animation system will write the
* whole array back to RNA even when changing individual array value.
*
* Some tricky things here:
* - array_index is -1 for single channel drivers, meaning we only have
* to do some magic when array_index is not -1.
* - We do relation from next array index to a previous one, so we don't
* have to deal with array index 0.
*
* TODO(sergey): Avoid liner lookup somehow.
*/
if (fcu->array_index > 0) {
FCurve *fcu_prev = NULL;
for (FCurve *fcu_candidate = (FCurve *)adt->drivers.first;
fcu_candidate != NULL;
fcu_candidate = fcu_candidate->next)
{
/* Writing to different RNA paths is */
if (!STREQ(fcu_candidate->rna_path, fcu->rna_path)) {
continue;
}
/* We only do relation from previous fcurve to previous one. */
if (fcu_candidate->array_index >= fcu->array_index) {
continue;
}
/* Choose fcurve with highest possible array index. */
if (fcu_prev == NULL ||
fcu_candidate->array_index > fcu_prev->array_index)
{
fcu_prev = fcu_candidate;
}
}
if (fcu_prev != NULL) {
OperationKey prev_driver_key(id,
DEPSNODE_TYPE_PARAMETERS,
DEG_OPCODE_DRIVER,
deg_fcurve_id_name(fcu_prev));
OperationKey driver_key(id,
DEPSNODE_TYPE_PARAMETERS,
DEG_OPCODE_DRIVER,
deg_fcurve_id_name(fcu));
add_relation(prev_driver_key,
driver_key,
DEPSREL_TYPE_OPERATION,
"[Driver Order]");
}
}
/* prevent driver from occurring before own animation... */
if (adt->action || adt->nla_tracks.first) {
add_relation(adt_key, driver_key, DEPSREL_TYPE_OPERATION,