WIP: Geometry Nodes: Smart static dependency building of modifier #106434

Closed
Iliya Katushenock wants to merge 3 commits from mod_moder:node_modifier_dependencies_fix into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
1 changed files with 130 additions and 59 deletions

View File

@ -12,6 +12,7 @@
#include "MEM_guardedalloc.h"
#include "BLI_array.hh"
#include "BLI_hash.hh"
#include "BLI_listbase.h"
#include "BLI_math_vector_types.hh"
#include "BLI_multi_value_map.hh"
@ -107,38 +108,65 @@ static void initData(ModifierData *md)
MEMCPY_STRUCT_AFTER(nmd, DNA_struct_default_get(NodesModifierData), modifier);
}
static void add_used_ids_from_sockets(const ListBase &sockets, Set<ID *> &ids)
enum eNodeModifierIDRelation : int8_t {
GEOMETRY = 1 << 0,
TRANSFORM = 1 << 1,
COLLECTION = 1 << 2,
CURVES = 1 << 3,
NOTHING = 0,
ALL = ~0,
};
inline eNodeModifierIDRelation &operator|=(eNodeModifierIDRelation &a, eNodeModifierIDRelation b)
{
return (eNodeModifierIDRelation &)((int8_t &)a |= (int8_t)b);
}
inline eNodeModifierIDRelation operator|(eNodeModifierIDRelation a, eNodeModifierIDRelation b)
{
return (eNodeModifierIDRelation)((int8_t)a | (int8_t)b);
}
inline eNodeModifierIDRelation operator&(eNodeModifierIDRelation a, eNodeModifierIDRelation b)
{
return (eNodeModifierIDRelation)((int8_t)a & (int8_t)b);
}
static void add_used_ids_from_sockets(const ListBase &sockets,
Map<ID *, eNodeModifierIDRelation> &ids)
{
LISTBASE_FOREACH (const bNodeSocket *, socket, &sockets) {
switch (socket->type) {
case SOCK_OBJECT: {
if (Object *object = ((bNodeSocketValueObject *)socket->default_value)->value) {
ids.add(&object->id);
ids.lookup_or_add(&object->id, NOTHING) |= ALL;
}
break;
}
case SOCK_COLLECTION: {
if (Collection *collection =
((bNodeSocketValueCollection *)socket->default_value)->value) {
ids.add(&collection->id);
ids.lookup_or_add(&collection->id, NOTHING) |= ALL;
}
break;
}
case SOCK_MATERIAL: {
if (Material *material = ((bNodeSocketValueMaterial *)socket->default_value)->value) {
ids.add(&material->id);
ids.lookup_or_add(&material->id, NOTHING) |= ALL;
}
break;
}
case SOCK_TEXTURE: {
if (Tex *texture = ((bNodeSocketValueTexture *)socket->default_value)->value) {
ids.add(&texture->id);
ids.lookup_or_add(&texture->id, NOTHING) |= ALL;
}
break;
}
case SOCK_IMAGE: {
if (Image *image = ((bNodeSocketValueImage *)socket->default_value)->value) {
ids.add(&image->id);
ids.lookup_or_add(&image->id, NOTHING) |= ALL;
}
break;
}
@ -152,34 +180,10 @@ static void add_used_ids_from_sockets(const ListBase &sockets, Set<ID *> &ids)
* more properties like whether the node is muted, but we would have to accept the cost of updating
* relations when those properties are changed.
*/
static bool node_needs_own_transform_relation(const bNode &node)
{
if (node.type == GEO_NODE_COLLECTION_INFO) {
const NodeGeometryCollectionInfo &storage = *static_cast<const NodeGeometryCollectionInfo *>(
node.storage);
return storage.transform_space == GEO_NODE_TRANSFORM_SPACE_RELATIVE;
}
if (node.type == GEO_NODE_OBJECT_INFO) {
const NodeGeometryObjectInfo &storage = *static_cast<const NodeGeometryObjectInfo *>(
node.storage);
return storage.transform_space == GEO_NODE_TRANSFORM_SPACE_RELATIVE;
}
if (node.type == GEO_NODE_SELF_OBJECT) {
return true;
}
if (node.type == GEO_NODE_DEFORM_CURVES_ON_SURFACE) {
return true;
}
return false;
}
static void process_nodes_for_depsgraph(const bNodeTree &tree,
Set<ID *> &ids,
bool &r_needs_own_transform_relation,
Set<const bNodeTree *> &checked_groups)
Map<ID *, eNodeModifierIDRelation> &ids,
Set<const bNodeTree *> &checked_groups,
bool &r_needs_own_transform_relation)
{
if (!checked_groups.add(&tree)) {
return;
@ -187,28 +191,81 @@ static void process_nodes_for_depsgraph(const bNodeTree &tree,
tree.ensure_topology_cache();
for (const bNode *node : tree.all_nodes()) {
add_used_ids_from_sockets(node->inputs, ids);
add_used_ids_from_sockets(node->outputs, ids);
r_needs_own_transform_relation |= node_needs_own_transform_relation(*node);
}
if (node->is_group()) {
const bNodeTree *group = reinterpret_cast<const bNodeTree *>(node->id);
if (group != nullptr) {
process_nodes_for_depsgraph(*group, ids, checked_groups, r_needs_own_transform_relation);
}
}
for (const bNode *node : tree.group_nodes()) {
if (const bNodeTree *sub_tree = reinterpret_cast<const bNodeTree *>(node->id)) {
process_nodes_for_depsgraph(*sub_tree, ids, r_needs_own_transform_relation, checked_groups);
switch (node->type) {
case (GEO_NODE_COLLECTION_INFO): {
const NodeGeometryCollectionInfo &storage =
*reinterpret_cast<const NodeGeometryCollectionInfo *>(node->storage);
const bool own_transform_relation = storage.transform_space ==
GEO_NODE_TRANSFORM_SPACE_RELATIVE;
bNodeSocket *collection_socket = nodeFindSocket(node, SOCK_IN, "Collection");
Collection *collection =
collection_socket->default_value_typed<bNodeSocketValueCollection>()->value;
if (collection == nullptr) {
break;
}
eNodeModifierIDRelation &id_relation = ids.lookup_or_add(&collection->id, NOTHING);
id_relation |= COLLECTION;
if (own_transform_relation) {
r_needs_own_transform_relation = true;
}
break;
}
case (GEO_NODE_OBJECT_INFO): {
const NodeGeometryObjectInfo &storage = *reinterpret_cast<const NodeGeometryObjectInfo *>(
node->storage);
const bool own_transform_relation = storage.transform_space ==
GEO_NODE_TRANSFORM_SPACE_RELATIVE;
bNodeSocket *object_socket = nodeFindSocket(node, SOCK_IN, "Object");
Object *object = object_socket->default_value_typed<bNodeSocketValueObject>()->value;
if (object == nullptr) {
break;
}
eNodeModifierIDRelation &id_relation = ids.lookup_or_add(&object->id, NOTHING);
id_relation |= GEOMETRY | TRANSFORM;
if (own_transform_relation) {
r_needs_own_transform_relation = true;
}
break;
}
case (GEO_NODE_SELF_OBJECT): {
r_needs_own_transform_relation = true;
add_used_ids_from_sockets(node->inputs, ids);
add_used_ids_from_sockets(node->outputs, ids);
break;
}
case (GEO_NODE_DEFORM_CURVES_ON_SURFACE): {
r_needs_own_transform_relation = true;
add_used_ids_from_sockets(node->inputs, ids);
add_used_ids_from_sockets(node->outputs, ids);
break;
}
default: {
add_used_ids_from_sockets(node->inputs, ids);
add_used_ids_from_sockets(node->outputs, ids);
break;
}
}
}
}
static void find_used_ids_from_settings(const NodesModifierSettings &settings, Set<ID *> &ids)
static void find_used_ids_from_settings(const NodesModifierSettings &settings,
Map<ID *, eNodeModifierIDRelation> &ids)
{
IDP_foreach_property(
settings.properties,
IDP_TYPE_FILTER_ID,
[](IDProperty *property, void *user_data) {
Set<ID *> *ids = (Set<ID *> *)user_data;
Map<ID *, eNodeModifierIDRelation> *ids = (Map<ID *, eNodeModifierIDRelation> *)user_data;
ID *id = IDP_Id(property);
if (id != nullptr) {
ids->add(id);
ids->lookup_or_add(id, NOTHING) |= ALL;
}
},
&ids);
@ -222,20 +279,36 @@ static const CustomData_MeshMasks dependency_data_mask{CD_MASK_PROP_ALL | CD_MAS
CD_MASK_PROP_ALL};
static void add_collection_relation(const ModifierUpdateDepsgraphContext *ctx,
Collection &collection)
const eNodeModifierIDRelation & /*relation*/,
ID *collection_id)
{
DEG_add_collection_geometry_relation(ctx->node, &collection, "Nodes Modifier");
DEG_add_collection_geometry_customdata_mask(ctx->node, &collection, &dependency_data_mask);
Collection *collection = reinterpret_cast<Collection *>(collection_id);
DEG_add_collection_geometry_relation(ctx->node, collection, "Nodes Modifier");
DEG_add_collection_geometry_customdata_mask(ctx->node, collection, &dependency_data_mask);
}
static void add_object_relation(const ModifierUpdateDepsgraphContext *ctx, Object &object)
static void add_object_relation(const ModifierUpdateDepsgraphContext *ctx,
const eNodeModifierIDRelation &relation,
ID *object_id)
{
DEG_add_object_relation(ctx->node, &object, DEG_OB_COMP_TRANSFORM, "Nodes Modifier");
if (&(ID &)object != &ctx->object->id) {
Object &object = *reinterpret_cast<Object *>(object_id);
if (object_id == &ctx->object->id) {
return;
}
if (relation & TRANSFORM) {
DEG_add_object_relation(ctx->node, &object, DEG_OB_COMP_TRANSFORM, "Nodes Modifier");
}
if (relation & COLLECTION) {
if (object.type == OB_EMPTY && object.instance_collection != nullptr) {
add_collection_relation(ctx, *object.instance_collection);
add_collection_relation(ctx, relation, reinterpret_cast<ID *>(object.instance_collection));
}
else if (DEG_object_has_geometry_component(&object)) {
}
if (relation & GEOMETRY) {
if (DEG_object_has_geometry_component(&object)) {
DEG_add_object_relation(ctx->node, &object, DEG_OB_COMP_GEOMETRY, "Nodes Modifier");
DEG_add_customdata_mask(ctx->node, &object, &dependency_data_mask);
}
@ -252,29 +325,27 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte
DEG_add_node_tree_output_relation(ctx->node, nmd->node_group, "Nodes Modifier");
bool needs_own_transform_relation = false;
Set<ID *> used_ids;
Map<ID *, eNodeModifierIDRelation> used_ids;
find_used_ids_from_settings(nmd->settings, used_ids);
Set<const bNodeTree *> checked_groups;
process_nodes_for_depsgraph(
*nmd->node_group, used_ids, needs_own_transform_relation, checked_groups);
*nmd->node_group, used_ids, checked_groups, needs_own_transform_relation);
if (ctx->object->type == OB_CURVES) {
Curves *curves_id = static_cast<Curves *>(ctx->object->data);
if (curves_id->surface != nullptr) {
used_ids.add(&curves_id->surface->id);
used_ids.lookup_or_add(&curves_id->surface->id, NOTHING) |= CURVES;
}
}
for (ID *id : used_ids) {
for (auto [id, relation] : used_ids.items()) {
switch ((ID_Type)GS(id->name)) {
case ID_OB: {
Object *object = reinterpret_cast<Object *>(id);
add_object_relation(ctx, *object);
add_object_relation(ctx, relation, id);
break;
}
case ID_GR: {
Collection *collection = reinterpret_cast<Collection *>(id);
add_collection_relation(ctx, *collection);
add_collection_relation(ctx, relation, id);
break;
}
case ID_IM: