Add Chromium-only Blender WebEngine parity work

This commit is contained in:
mes123456
2026-08-12 04:47:48 -04:00
commit 9fd26010f6
18225 changed files with 11622124 additions and 0 deletions

View File

@@ -0,0 +1,330 @@
/* SPDX-FileCopyrightText: 2013 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup depsgraph
*/
#include "intern/node/deg_node.hh"
#include "intern/depsgraph.hh"
#include "intern/depsgraph_relation.hh"
#include "intern/eval/deg_eval_copy_on_write.h"
#include "intern/node/deg_node_component.hh"
#include "intern/node/deg_node_factory.hh"
#include "intern/node/deg_node_id.hh"
#include "intern/node/deg_node_time.hh"
namespace blender::deg {
const char *nodeClassAsString(NodeClass node_class)
{
switch (node_class) {
case NodeClass::GENERIC:
return "GENERIC";
case NodeClass::COMPONENT:
return "COMPONENT";
case NodeClass::OPERATION:
return "OPERATION";
}
BLI_assert_msg(0, "Unhandled node class, should never happen.");
return "UNKNOWN";
}
const char *nodeTypeAsString(NodeType type)
{
switch (type) {
case NodeType::UNDEFINED:
return "UNDEFINED";
case NodeType::OPERATION:
return "OPERATION";
/* **** Generic Types **** */
case NodeType::TIMESOURCE:
return "TIMESOURCE";
case NodeType::ID_REF:
return "ID_REF";
/* **** Outer Types **** */
case NodeType::PARAMETERS:
return "PARAMETERS";
case NodeType::ANIMATION:
return "ANIMATION";
case NodeType::TRANSFORM:
return "TRANSFORM";
case NodeType::GEOMETRY:
return "GEOMETRY";
case NodeType::SEQUENCER:
return "SEQUENCER";
case NodeType::COMPOSITOR:
return "COMPOSITOR";
case NodeType::LAYER_COLLECTIONS:
return "LAYER_COLLECTIONS";
case NodeType::COPY_ON_EVAL:
return "COPY_ON_EVAL";
case NodeType::OBJECT_FROM_LAYER:
return "OBJECT_FROM_LAYER";
case NodeType::HIERARCHY:
return "HIERARCHY";
/* **** Evaluation-Related Outer Types (with Sub-data) **** */
case NodeType::EVAL_POSE:
return "EVAL_POSE";
case NodeType::BONE:
return "BONE";
case NodeType::PARTICLE_SYSTEM:
return "PARTICLE_SYSTEM";
case NodeType::PARTICLE_SETTINGS:
return "PARTICLE_SETTINGS";
case NodeType::SHADING:
return "SHADING";
case NodeType::CACHE:
return "CACHE";
case NodeType::POINT_CACHE:
return "POINT_CACHE";
case NodeType::IMAGE_ANIMATION:
return "IMAGE_ANIMATION";
case NodeType::BATCH_CACHE:
return "BATCH_CACHE";
case NodeType::INSTANCING:
return "INSTANCING";
case NodeType::SYNCHRONIZATION:
return "SYNCHRONIZATION";
case NodeType::AUDIO:
return "AUDIO";
case NodeType::ARMATURE:
return "ARMATURE";
case NodeType::GENERIC_DATABLOCK:
return "GENERIC_DATABLOCK";
case NodeType::SCENE:
return "SCENE";
case NodeType::VISIBILITY:
return "VISIBILITY";
case NodeType::NTREE_OUTPUT:
return "NTREE_OUTPUT";
case NodeType::NTREE_GEOMETRY_PREPROCESS:
return "NTREE_GEOMETRY_PREPROCESS";
/* Total number of meaningful node types. */
case NodeType::NUM_TYPES:
return "SpecialCase";
}
BLI_assert_msg(0, "Unhandled node type, should never happen.");
return "UNKNOWN";
}
NodeType nodeTypeFromSceneComponent(eDepsSceneComponentType component)
{
switch (component) {
case DEG_SCENE_COMP_PARAMETERS:
return NodeType::PARAMETERS;
case DEG_SCENE_COMP_ANIMATION:
return NodeType::ANIMATION;
case DEG_SCENE_COMP_SEQUENCER:
return NodeType::SEQUENCER;
case DEG_SCENE_COMP_COMPOSITOR:
return NodeType::COMPOSITOR;
}
return NodeType::UNDEFINED;
}
eDepsSceneComponentType nodeTypeToSceneComponent(NodeType type)
{
switch (type) {
case NodeType::PARAMETERS:
return DEG_SCENE_COMP_PARAMETERS;
case NodeType::ANIMATION:
return DEG_SCENE_COMP_ANIMATION;
case NodeType::SEQUENCER:
return DEG_SCENE_COMP_SEQUENCER;
case NodeType::COMPOSITOR:
return DEG_SCENE_COMP_COMPOSITOR;
case NodeType::OPERATION:
case NodeType::TIMESOURCE:
case NodeType::ID_REF:
case NodeType::LAYER_COLLECTIONS:
case NodeType::COPY_ON_EVAL:
case NodeType::OBJECT_FROM_LAYER:
case NodeType::HIERARCHY:
case NodeType::AUDIO:
case NodeType::ARMATURE:
case NodeType::GENERIC_DATABLOCK:
case NodeType::SCENE:
case NodeType::PARTICLE_SYSTEM:
case NodeType::PARTICLE_SETTINGS:
case NodeType::POINT_CACHE:
case NodeType::IMAGE_ANIMATION:
case NodeType::BATCH_CACHE:
case NodeType::INSTANCING:
case NodeType::SYNCHRONIZATION:
case NodeType::UNDEFINED:
case NodeType::NUM_TYPES:
case NodeType::TRANSFORM:
case NodeType::GEOMETRY:
case NodeType::EVAL_POSE:
case NodeType::BONE:
case NodeType::SHADING:
case NodeType::CACHE:
case NodeType::NTREE_OUTPUT:
case NodeType::NTREE_GEOMETRY_PREPROCESS:
return DEG_SCENE_COMP_PARAMETERS;
case NodeType::VISIBILITY:
BLI_assert_msg(0, "Visibility component is supposed to be only used internally.");
return DEG_SCENE_COMP_PARAMETERS;
}
BLI_assert_msg(0, "Unhandled node type, not supposed to happen.");
return DEG_SCENE_COMP_PARAMETERS;
}
NodeType nodeTypeFromObjectComponent(eDepsObjectComponentType component_type)
{
switch (component_type) {
case DEG_OB_COMP_ANY:
return NodeType::UNDEFINED;
case DEG_OB_COMP_PARAMETERS:
return NodeType::PARAMETERS;
case DEG_OB_COMP_ANIMATION:
return NodeType::ANIMATION;
case DEG_OB_COMP_TRANSFORM:
return NodeType::TRANSFORM;
case DEG_OB_COMP_GEOMETRY:
return NodeType::GEOMETRY;
case DEG_OB_COMP_EVAL_POSE:
return NodeType::EVAL_POSE;
case DEG_OB_COMP_BONE:
return NodeType::BONE;
case DEG_OB_COMP_SHADING:
return NodeType::SHADING;
case DEG_OB_COMP_CACHE:
return NodeType::CACHE;
}
return NodeType::UNDEFINED;
}
eDepsObjectComponentType nodeTypeToObjectComponent(NodeType type)
{
switch (type) {
case NodeType::PARAMETERS:
return DEG_OB_COMP_PARAMETERS;
case NodeType::ANIMATION:
return DEG_OB_COMP_ANIMATION;
case NodeType::TRANSFORM:
return DEG_OB_COMP_TRANSFORM;
case NodeType::GEOMETRY:
return DEG_OB_COMP_GEOMETRY;
case NodeType::EVAL_POSE:
return DEG_OB_COMP_EVAL_POSE;
case NodeType::BONE:
return DEG_OB_COMP_BONE;
case NodeType::SHADING:
return DEG_OB_COMP_SHADING;
case NodeType::CACHE:
return DEG_OB_COMP_CACHE;
case NodeType::OPERATION:
case NodeType::TIMESOURCE:
case NodeType::ID_REF:
case NodeType::SEQUENCER:
case NodeType::COMPOSITOR:
case NodeType::LAYER_COLLECTIONS:
case NodeType::COPY_ON_EVAL:
case NodeType::OBJECT_FROM_LAYER:
case NodeType::HIERARCHY:
case NodeType::AUDIO:
case NodeType::ARMATURE:
case NodeType::GENERIC_DATABLOCK:
case NodeType::SCENE:
case NodeType::PARTICLE_SYSTEM:
case NodeType::PARTICLE_SETTINGS:
case NodeType::POINT_CACHE:
case NodeType::IMAGE_ANIMATION:
case NodeType::BATCH_CACHE:
case NodeType::INSTANCING:
case NodeType::SYNCHRONIZATION:
case NodeType::NTREE_OUTPUT:
case NodeType::NTREE_GEOMETRY_PREPROCESS:
case NodeType::UNDEFINED:
case NodeType::NUM_TYPES:
return DEG_OB_COMP_PARAMETERS;
case NodeType::VISIBILITY:
BLI_assert_msg(0, "Visibility component is supposed to be only used internally.");
return DEG_OB_COMP_PARAMETERS;
}
BLI_assert_msg(0, "Unhandled node type, not supposed to happen.");
return DEG_OB_COMP_PARAMETERS;
}
/*******************************************************************************
* Type information.
*/
Node::TypeInfo::TypeInfo(NodeType type, const char *type_name, int id_recalc_tag)
: type(type), type_name(type_name), id_recalc_tag(id_recalc_tag)
{
}
/*******************************************************************************
* Evaluation statistics.
*/
Node::Stats::Stats()
{
reset();
}
void Node::Stats::reset()
{
current_time = 0.0;
}
void Node::Stats::reset_current()
{
current_time = 0.0;
}
/*******************************************************************************
* Node itself.
*/
Node::Node()
{
name = "";
}
Node::~Node() = default;
std::string Node::identifier() const
{
return std::string(nodeTypeAsString(type)) + " : " + name;
}
NodeClass Node::get_class() const
{
if (type == NodeType::OPERATION) {
return NodeClass::OPERATION;
}
if (type < NodeType::PARAMETERS) {
return NodeClass::GENERIC;
}
return NodeClass::COMPONENT;
}
/*******************************************************************************
* Generic nodes definition.
*/
DEG_DEPSNODE_DEFINE(TimeSourceNode, NodeType::TIMESOURCE, "Time Source");
static DepsNodeFactoryImpl<TimeSourceNode> DNTI_TIMESOURCE;
DEG_DEPSNODE_DEFINE(IDNode, NodeType::ID_REF, "ID Node");
static DepsNodeFactoryImpl<IDNode> DNTI_ID_REF;
void deg_register_base_depsnodes()
{
register_node_typeinfo(&DNTI_TIMESOURCE);
register_node_typeinfo(&DNTI_ID_REF);
}
} // namespace blender::deg

View File

@@ -0,0 +1,229 @@
/* SPDX-FileCopyrightText: 2013 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup depsgraph
*/
#pragma once
#include <string>
#include "MEM_guardedalloc.h"
#include "intern/depsgraph_type.hh"
#include "DEG_depsgraph_build.hh"
#include "BLI_vector.hh"
namespace blender {
struct ID;
struct Scene;
namespace deg {
struct Depsgraph;
struct OperationNode;
struct Relation;
/* Meta-type of Nodes - The general "level" in the graph structure
* the node serves. */
enum class NodeClass {
/* Types generally unassociated with user-visible entities,
* but needed for graph functioning. */
GENERIC = 0,
/* [Outer Node] An "aspect" of evaluating/updating an ID-Block, requiring
* certain types of evaluation behavior. */
COMPONENT = 1,
/* [Inner Node] A glorified function-pointer/callback for scheduling up
* evaluation operations for components, subject to relationship
* requirements. */
OPERATION = 2,
};
const char *nodeClassAsString(NodeClass node_class);
/* Types of Nodes */
enum class NodeType {
/* Fallback type for invalid return value */
UNDEFINED = 0,
/* Inner Node (Operation) */
OPERATION,
/* **** Generic Types **** */
/* Time-Source */
TIMESOURCE,
/* ID-Block reference - used as landmarks/collection point for components,
* but not usually part of main graph. */
ID_REF,
/* **** Outer Types **** */
/* Parameters Component - Default when nothing else fits
* (i.e. just SDNA property setting). */
PARAMETERS,
/* Animation Component */
ANIMATION,
/* Transform Component (Parenting/Constraints) */
TRANSFORM,
/* Geometry Component (#Mesh, #Curves, etc.) */
GEOMETRY,
/* Sequencer Component (Scene Only) */
SEQUENCER,
/* Compositor Component (Scene Only) */
COMPOSITOR,
/* Component which contains all operations needed for layer collections
* evaluation. */
LAYER_COLLECTIONS,
/* Entry component of majority of ID nodes: prepares evaluated pointers for
* execution. */
COPY_ON_EVAL,
/* Used by all operations which are updating object when something is
* changed in view layer. */
OBJECT_FROM_LAYER,
/* Hierarchy of objects and collections */
HIERARCHY,
/* Audio-related evaluation. */
AUDIO,
ARMATURE,
/* Un-interesting data-block, which is a part of dependency graph, but does
* not have very distinctive update procedure. */
GENERIC_DATABLOCK,
/* Scene evaluation, for dependencies to other evaluation which might require accumulated custom
* data masks. */
SCENE,
/* Component which is used to define visibility relation between IDs, on the ID level.
*
* Consider two ID nodes NodeA and NodeB, with the relation between visibility components going
* as NodeA -> NodeB. If NodeB is considered visible on screen, then the relation will ensure
* that NodeA is also visible. The way how relation is oriented could be seen as a inverted from
* visibility dependency point of view, but it follows the same direction as data dependency
* which simplifies common algorithms which are dealing with relations and visibility.
*
* The fact that the visibility operates on the ID level basically means that all components in
* the NodeA will be considered as affecting directly visible when NodeB's visibility is
* affecting directly visible ID.
*
* This is the way to ensure objects needed for visualization without any actual data dependency
* properly evaluated. Example of this is custom shapes for bones. */
VISIBILITY,
/* **** Evaluation-Related Outer Types (with Sub-data) **** */
/* Pose Component - Owner/Container of Bones Eval */
EVAL_POSE,
/* Bone Component - Child/Subcomponent of Pose */
BONE,
/* Particle Systems Component */
PARTICLE_SYSTEM,
PARTICLE_SETTINGS,
/* Material Shading Component */
SHADING,
/* Point cache Component */
POINT_CACHE,
/* Image Animation Component */
IMAGE_ANIMATION,
/* Cache Component */
/* TODO(sergey); Verify that we really need this. */
CACHE,
/* Batch Cache Component.
* TODO(dfelinto/sergey): rename to make it more generic. */
BATCH_CACHE,
/* Instancing system.
* Used to control visibility flags of dependencies. */
INSTANCING,
/* Synchronization back to original datablock. */
SYNCHRONIZATION,
/* Node tree output component. */
NTREE_OUTPUT,
/* Preprocessing for geometry node trees before they can be evaluated. */
NTREE_GEOMETRY_PREPROCESS,
/* Total number of meaningful node types. */
NUM_TYPES,
};
const char *nodeTypeAsString(NodeType type);
NodeType nodeTypeFromSceneComponent(eDepsSceneComponentType component_type);
eDepsSceneComponentType nodeTypeToSceneComponent(NodeType type);
NodeType nodeTypeFromObjectComponent(eDepsObjectComponentType component_type);
eDepsObjectComponentType nodeTypeToObjectComponent(NodeType type);
/* All nodes in Depsgraph are descended from this. */
struct Node {
/* Helper class for static typeinfo in subclasses. */
struct TypeInfo {
TypeInfo(NodeType type, const char *type_name, int id_recalc_tag = 0);
NodeType type;
const char *type_name;
int id_recalc_tag;
};
struct Stats {
Stats();
/* Reset all the counters. Including all stats needed for average
* evaluation time calculation. */
void reset();
/* Reset counters needed for the current graph evaluation, does not
* touch averaging accumulators. */
void reset_current();
/* Time spent on this node during current graph evaluation. */
double current_time;
};
/* Relationships between nodes
* The reason why all depsgraph nodes are descended from this type (apart
* from basic serialization benefits - from the typeinfo) is that we can
* have relationships between these nodes. */
using Relations = Vector<Relation *>;
std::string name; /* Identifier - mainly for debugging purposes. */
NodeType type; /* Structural type of node. */
Relations inlinks; /* Nodes which this one depends on. */
Relations outlinks; /* Nodes which depend on this one. */
Stats stats; /* Evaluation statistics. */
/* Generic tags for traversal algorithms and such.
*
* Actual meaning of values depends on a specific area. Every area is to
* clean this before use. */
int custom_flags;
/* Methods. */
Node();
virtual ~Node();
/** Generic identifier for Depsgraph Nodes. */
virtual std::string identifier() const;
virtual void init(const ID * /*id*/, const char * /*subdata*/) {}
virtual void tag_update(Depsgraph * /*graph*/, eUpdateSource /*source*/) {}
virtual OperationNode *get_entry_operation()
{
return nullptr;
}
virtual OperationNode *get_exit_operation()
{
return nullptr;
}
virtual NodeClass get_class() const;
MEM_CXX_CLASS_ALLOC_FUNCS("Node");
};
/* Macros for common static typeinfo. */
#define DEG_DEPSNODE_DECLARE static const Node::TypeInfo typeinfo
#define DEG_DEPSNODE_DEFINE(NodeType, type_, tname_) \
const Node::TypeInfo NodeType::typeinfo = Node::TypeInfo(type_, tname_)
void deg_register_base_depsnodes();
} // namespace deg
} // namespace blender

View File

@@ -0,0 +1,353 @@
/* SPDX-FileCopyrightText: 2013 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup depsgraph
*/
#include "intern/node/deg_node_component.hh"
#include <cstdio>
#include "DNA_object_types.h"
#include "BKE_action.hh"
#include "intern/node/deg_node_factory.hh"
#include "intern/node/deg_node_id.hh"
#include "intern/node/deg_node_operation.hh"
namespace blender::deg {
/* *********** */
/* Outer Nodes */
/* -------------------------------------------------------------------- */
/** \name Standard Component Methods
* \{ */
std::string ComponentNode::OperationIDKey::identifier() const
{
const std::string codebuf = std::to_string(int(opcode));
return "OperationIDKey(" + codebuf + ", " + name + ")";
}
ComponentNode::ComponentNode()
: entry_operation(nullptr),
exit_operation(nullptr),
possibly_affects_visible_id(false),
affects_visible_id(false)
{
operations_map = new Map<ComponentNode::OperationIDKey, OperationNode *>();
}
void ComponentNode::init(const ID * /*id*/, const char * /*subdata*/)
{
/* hook up eval context? */
/* XXX: maybe this needs a special API? */
}
/* Free 'component' node */
ComponentNode::~ComponentNode()
{
clear_operations();
delete operations_map;
}
std::string ComponentNode::identifier() const
{
const std::string type_name = type_get_factory(type)->type_name();
const std::string name_part = name[0] ? (std::string(" '") + name + "'") : "";
return "[" + type_name + "]" + name_part + " : " +
"(affects_visible_id: " + (affects_visible_id ? "true" : "false") + ")";
}
OperationNode *ComponentNode::find_operation(OperationIDKey key) const
{
OperationNode *node = nullptr;
if (operations_map != nullptr) {
node = operations_map->lookup_default(key, nullptr);
}
else {
for (OperationNode *op_node : operations) {
if (op_node->opcode == key.opcode && op_node->name_tag == key.name_tag &&
op_node->name == key.name)
{
node = op_node;
break;
}
}
}
return node;
}
OperationNode *ComponentNode::find_operation(OperationCode opcode,
const StringRef name,
int name_tag) const
{
OperationIDKey key(opcode, name, name_tag);
return find_operation(key);
}
OperationNode *ComponentNode::get_operation(OperationIDKey key) const
{
OperationNode *node = find_operation(key);
if (node == nullptr) {
fprintf(stderr,
"%s: find_operation(%s) failed\n",
this->identifier().c_str(),
key.identifier().c_str());
BLI_assert_msg(0, "Request for non-existing operation, should not happen");
return nullptr;
}
return node;
}
OperationNode *ComponentNode::get_operation(OperationCode opcode,
const StringRef name,
int name_tag) const
{
OperationIDKey key(opcode, name, name_tag);
return get_operation(key);
}
bool ComponentNode::has_operation(OperationIDKey key) const
{
return find_operation(key) != nullptr;
}
bool ComponentNode::has_operation(OperationCode opcode, const StringRef name, int name_tag) const
{
OperationIDKey key(opcode, name, name_tag);
return has_operation(key);
}
OperationNode *ComponentNode::add_operation(const DepsEvalOperationCb &op,
OperationCode opcode,
const StringRef name,
int name_tag)
{
OperationNode *op_node = find_operation(opcode, name, name_tag);
if (!op_node) {
DepsNodeFactory *factory = type_get_factory(NodeType::OPERATION);
op_node = static_cast<OperationNode *>(factory->create_node(this->owner->id_orig, "", name));
/* register opnode in this component's operation set */
OperationIDKey key(opcode, op_node->name, name_tag);
operations_map->add(key, op_node);
/* Set back-link. */
op_node->owner = this;
}
else {
fprintf(stderr,
"add_operation: Operation already exists - %s has %s at %p\n",
this->identifier().c_str(),
op_node->identifier().c_str(),
op_node);
BLI_assert_msg(0, "Should not happen!");
}
/* attach extra data */
op_node->evaluate = op;
op_node->opcode = opcode;
op_node->name = name;
op_node->name_tag = name_tag;
return op_node;
}
void ComponentNode::set_entry_operation(OperationNode *op_node)
{
BLI_assert(entry_operation == nullptr);
entry_operation = op_node;
}
void ComponentNode::set_exit_operation(OperationNode *op_node)
{
BLI_assert(exit_operation == nullptr);
exit_operation = op_node;
}
void ComponentNode::clear_operations()
{
if (operations_map != nullptr) {
for (OperationNode *op_node : operations_map->values()) {
delete op_node;
}
operations_map->clear();
}
for (OperationNode *op_node : operations) {
delete op_node;
}
operations.clear();
}
void ComponentNode::tag_update(Depsgraph *graph, eUpdateSource source)
{
/* Note that the node might already be tagged for an update due invisible state of the node
* during previous dependency evaluation. Here the node gets re-tagged, so we need to give
* the evaluated clues that evaluation needs to happen again. */
for (OperationNode *op_node : operations) {
op_node->tag_update(graph, source);
}
/* It is possible that tag happens before finalization. */
if (operations_map != nullptr) {
for (OperationNode *op_node : operations_map->values()) {
op_node->tag_update(graph, source);
}
}
}
OperationNode *ComponentNode::get_entry_operation()
{
if (entry_operation) {
return entry_operation;
}
if (operations_map != nullptr && operations_map->size() == 1) {
OperationNode *op_node = nullptr;
/* TODO(sergey): This is somewhat slow. */
for (OperationNode *tmp : operations_map->values()) {
op_node = tmp;
}
/* Cache for the subsequent usage. */
entry_operation = op_node;
return op_node;
}
if (operations.size() == 1) {
return operations[0];
}
return nullptr;
}
OperationNode *ComponentNode::get_exit_operation()
{
if (exit_operation) {
return exit_operation;
}
if (operations_map != nullptr && operations_map->size() == 1) {
OperationNode *op_node = nullptr;
/* TODO(sergey): This is somewhat slow. */
for (OperationNode *tmp : operations_map->values()) {
op_node = tmp;
}
/* Cache for the subsequent usage. */
exit_operation = op_node;
return op_node;
}
if (operations.size() == 1) {
return operations[0];
}
return nullptr;
}
void ComponentNode::finalize_build(Depsgraph * /*graph*/)
{
operations.reserve(operations_map->size());
for (OperationNode *op_node : operations_map->values()) {
operations.append(op_node);
}
delete operations_map;
operations_map = nullptr;
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Bone Component
* \{ */
void BoneComponentNode::init(const ID *id, const char *subdata)
{
/* generic component-node... */
ComponentNode::init(id, subdata);
/* name of component comes is bone name */
/* TODO(sergey): This sets name to an empty string because subdata is
* empty. Is it a bug? */
// this->name = subdata;
/* bone-specific node data */
Object *object = id_cast<Object *>(const_cast<ID *>(id));
this->pchan = BKE_pose_channel_find_name(object->pose, subdata);
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Register All Components
* \{ */
DEG_COMPONENT_NODE_DEFINE(Animation, ANIMATION, ID_RECALC_ANIMATION);
/* TODO(sergey): Is this a correct tag? */
DEG_COMPONENT_NODE_DEFINE(BatchCache, BATCH_CACHE, ID_RECALC_SHADING);
DEG_COMPONENT_NODE_DEFINE(Bone, BONE, ID_RECALC_GEOMETRY);
DEG_COMPONENT_NODE_DEFINE(Cache, CACHE, 0);
DEG_COMPONENT_NODE_DEFINE(CopyOnWrite, COPY_ON_EVAL, ID_RECALC_SYNC_TO_EVAL);
DEG_COMPONENT_NODE_DEFINE(ImageAnimation, IMAGE_ANIMATION, 0);
DEG_COMPONENT_NODE_DEFINE(Geometry, GEOMETRY, ID_RECALC_GEOMETRY);
DEG_COMPONENT_NODE_DEFINE(LayerCollections, LAYER_COLLECTIONS, 0);
DEG_COMPONENT_NODE_DEFINE(Parameters, PARAMETERS, ID_RECALC_PARAMETERS);
DEG_COMPONENT_NODE_DEFINE(Particles, PARTICLE_SYSTEM, ID_RECALC_GEOMETRY);
DEG_COMPONENT_NODE_DEFINE(ParticleSettings, PARTICLE_SETTINGS, 0);
DEG_COMPONENT_NODE_DEFINE(PointCache, POINT_CACHE, 0);
DEG_COMPONENT_NODE_DEFINE(Pose, EVAL_POSE, ID_RECALC_GEOMETRY);
DEG_COMPONENT_NODE_DEFINE(Sequencer, SEQUENCER, 0);
DEG_COMPONENT_NODE_DEFINE(Compositor, COMPOSITOR, 0);
DEG_COMPONENT_NODE_DEFINE(Shading, SHADING, ID_RECALC_SHADING);
DEG_COMPONENT_NODE_DEFINE(Transform, TRANSFORM, ID_RECALC_TRANSFORM);
DEG_COMPONENT_NODE_DEFINE(ObjectFromLayer, OBJECT_FROM_LAYER, 0);
DEG_COMPONENT_NODE_DEFINE(Hierarchy, HIERARCHY, 0);
DEG_COMPONENT_NODE_DEFINE(Instancing, INSTANCING, 0);
DEG_COMPONENT_NODE_DEFINE(Synchronization, SYNCHRONIZATION, 0);
DEG_COMPONENT_NODE_DEFINE(Audio, AUDIO, 0);
DEG_COMPONENT_NODE_DEFINE(Armature, ARMATURE, 0);
DEG_COMPONENT_NODE_DEFINE(GenericDatablock, GENERIC_DATABLOCK, 0);
DEG_COMPONENT_NODE_DEFINE(Scene, SCENE, 0);
DEG_COMPONENT_NODE_DEFINE(Visibility, VISIBILITY, 0);
DEG_COMPONENT_NODE_DEFINE(NTreeOutput, NTREE_OUTPUT, ID_RECALC_NTREE_OUTPUT);
DEG_COMPONENT_NODE_DEFINE(NTreeGeometryPreprocess, NTREE_GEOMETRY_PREPROCESS, 0);
/** \} */
/* -------------------------------------------------------------------- */
/** \name Node Types Register
* \{ */
void deg_register_component_depsnodes()
{
register_node_typeinfo(&DNTI_ANIMATION);
register_node_typeinfo(&DNTI_BONE);
register_node_typeinfo(&DNTI_CACHE);
register_node_typeinfo(&DNTI_BATCH_CACHE);
register_node_typeinfo(&DNTI_COPY_ON_EVAL);
register_node_typeinfo(&DNTI_GEOMETRY);
register_node_typeinfo(&DNTI_LAYER_COLLECTIONS);
register_node_typeinfo(&DNTI_PARAMETERS);
register_node_typeinfo(&DNTI_PARTICLE_SYSTEM);
register_node_typeinfo(&DNTI_PARTICLE_SETTINGS);
register_node_typeinfo(&DNTI_POINT_CACHE);
register_node_typeinfo(&DNTI_IMAGE_ANIMATION);
register_node_typeinfo(&DNTI_EVAL_POSE);
register_node_typeinfo(&DNTI_SEQUENCER);
register_node_typeinfo(&DNTI_COMPOSITOR);
register_node_typeinfo(&DNTI_SHADING);
register_node_typeinfo(&DNTI_TRANSFORM);
register_node_typeinfo(&DNTI_OBJECT_FROM_LAYER);
register_node_typeinfo(&DNTI_HIERARCHY);
register_node_typeinfo(&DNTI_INSTANCING);
register_node_typeinfo(&DNTI_SYNCHRONIZATION);
register_node_typeinfo(&DNTI_AUDIO);
register_node_typeinfo(&DNTI_ARMATURE);
register_node_typeinfo(&DNTI_GENERIC_DATABLOCK);
register_node_typeinfo(&DNTI_SCENE);
register_node_typeinfo(&DNTI_VISIBILITY);
register_node_typeinfo(&DNTI_NTREE_OUTPUT);
register_node_typeinfo(&DNTI_NTREE_GEOMETRY_PREPROCESS);
}
/** \} */
} // namespace blender::deg

View File

@@ -0,0 +1,261 @@
/* SPDX-FileCopyrightText: 2013 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup depsgraph
*/
#pragma once
#include "BLI_span.hh"
#include "BLI_string_ref.hh"
#include "intern/eval/deg_eval_copy_on_write.h"
#include "intern/node/deg_node.hh"
#include "intern/node/deg_node_id.hh"
#include "intern/node/deg_node_operation.hh"
#include "BLI_map.hh"
#include "BLI_vector.hh"
namespace blender {
struct ID;
struct bPoseChannel;
namespace deg {
struct Depsgraph;
struct IDNode;
struct OperationNode;
/* ID Component - Base type for all components */
struct ComponentNode : public Node {
/* Key used to look up operations within a component */
struct OperationIDKey {
OperationCode opcode = OperationCode::OPERATION;
int name_tag = -1;
StringRef name = "";
OperationIDKey() = default;
OperationIDKey(const OperationCode opcode) : opcode(opcode) {}
OperationIDKey(const OperationCode opcode, const StringRef name, const int name_tag)
: opcode(opcode), name_tag(name_tag), name(name)
{
}
std::string identifier() const;
friend bool operator==(const OperationIDKey &a, const OperationIDKey &b) = default;
uint64_t hash() const
{
return get_default_hash(opcode, name_tag, name);
}
};
/* Typedef for container of operations */
ComponentNode();
~ComponentNode() override;
/** Initialize 'component' node - from pointer data given. */
void init(const ID *id, const char *subdata) override;
std::string identifier() const override;
/* Find an existing operation, if requested operation does not exist nullptr will be returned.
* See #add_operation for the meaning and examples of #name and #name_tag.
*/
OperationNode *find_operation(OperationIDKey key) const;
OperationNode *find_operation(OperationCode opcode,
StringRef name = "",
int name_tag = -1) const;
/* Find an existing operation, will throw an assert() if it does not exist.
* See #add_operation for the meaning and examples of #name and #name_tag. */
OperationNode *get_operation(OperationIDKey key) const;
OperationNode *get_operation(OperationCode opcode, StringRef name = "", int name_tag = -1) const;
/* Check operation exists and return it. */
bool has_operation(OperationIDKey key) const;
bool has_operation(OperationCode opcode, StringRef name = "", int name_tag = -1) const;
/**
* Create a new node for representing an operation and add this to graph
*
* \warning If an existing node is found, it will be modified. This helps
* when node may have been partially created earlier (e.g. parent ref before
* parent item is added)
*
* \param opcode: The operation to perform.
* \param name: An optional identifier for operation. It will be used to tell operation nodes
* with the same code apart. For example, parameter operation code will have name
* set to the corresponding custom property name
* \param name_tag: An optional integer tag for the name. Is an additional way to tell operations
* apart. For example, RNA path to an array property will have the same opcode
* of PARAMETERS, name corresponding to the property name, and name tag
* corresponding to the array index within the property.
*/
OperationNode *add_operation(const DepsEvalOperationCb &op,
OperationCode opcode,
const StringRef name = "",
int name_tag = -1);
/* Entry/exit operations management.
*
* Use those instead of direct set since this will perform sanity checks. */
void set_entry_operation(OperationNode *op_node);
void set_exit_operation(OperationNode *op_node);
void clear_operations();
void tag_update(Depsgraph *graph, eUpdateSource source) override;
OperationNode *get_entry_operation() override;
OperationNode *get_exit_operation() override;
void finalize_build(Depsgraph *graph);
IDNode *owner;
/* ** Inner nodes for this component ** */
/* Operations stored as a hash map, for faster build.
* This hash map will be freed when graph is fully built. */
Map<ComponentNode::OperationIDKey, OperationNode *> *operations_map;
/* This is a "normal" list of operations, used by evaluation
* and other routines after construction. */
Vector<OperationNode *> operations;
OperationNode *entry_operation;
OperationNode *exit_operation;
virtual bool depends_on_cow()
{
return true;
}
/* Denotes whether copy-on-eval component is to be tagged when this component
* is tagged for update. */
virtual bool need_tag_cow_before_update(const IDRecalcFlag /*tag*/)
{
return true;
}
/* The component has (possibly indirect) effect on a data-block whose node has
* is_visible_on_build set to true.
*
* This field is ensured to be up-to-date prior to `IDNode::finalize_build()`. */
bool possibly_affects_visible_id;
/* Denotes whether this component actually affects (possibly indirectly) on a directly visible
* object. Includes possibly run-time visibility update of ID nodes.
*
* NOTE: Is only reliable after `deg_graph_flush_visibility()`. */
bool affects_visible_id;
};
/* ---------------------------------------- */
#define DEG_COMPONENT_NODE_DEFINE_TYPEINFO(NodeType, type_, type_name_, id_recalc_tag) \
const Node::TypeInfo NodeType::typeinfo = Node::TypeInfo(type_, type_name_, id_recalc_tag)
#define DEG_COMPONENT_NODE_DECLARE DEG_DEPSNODE_DECLARE
#define DEG_COMPONENT_NODE_DEFINE(name, NAME, id_recalc_tag) \
DEG_COMPONENT_NODE_DEFINE_TYPEINFO( \
name##ComponentNode, NodeType::NAME, #name " Component", id_recalc_tag); \
static DepsNodeFactoryImpl<name##ComponentNode> DNTI_##NAME
#define DEG_COMPONENT_NODE_DECLARE_GENERIC(name) \
struct name##ComponentNode : public ComponentNode { \
DEG_COMPONENT_NODE_DECLARE; \
}
#define DEG_COMPONENT_NODE_DECLARE_NO_COW_TAG_ON_UPDATE(name) \
struct name##ComponentNode : public ComponentNode { \
DEG_COMPONENT_NODE_DECLARE; \
virtual bool need_tag_cow_before_update(const IDRecalcFlag /*tag*/) \
{ \
return false; \
} \
}
#define DEG_COMPONENT_NODE_DECLARE_NO_COW(name) \
struct name##ComponentNode : public ComponentNode { \
DEG_COMPONENT_NODE_DECLARE; \
virtual bool depends_on_cow() \
{ \
return false; \
} \
}
DEG_COMPONENT_NODE_DECLARE_GENERIC(Animation);
DEG_COMPONENT_NODE_DECLARE_NO_COW_TAG_ON_UPDATE(BatchCache);
DEG_COMPONENT_NODE_DECLARE_GENERIC(Cache);
DEG_COMPONENT_NODE_DECLARE_GENERIC(CopyOnWrite);
DEG_COMPONENT_NODE_DECLARE_GENERIC(Geometry);
DEG_COMPONENT_NODE_DECLARE_GENERIC(ImageAnimation);
DEG_COMPONENT_NODE_DECLARE_GENERIC(LayerCollections);
DEG_COMPONENT_NODE_DECLARE_GENERIC(Particles);
DEG_COMPONENT_NODE_DECLARE_GENERIC(ParticleSettings);
DEG_COMPONENT_NODE_DECLARE_GENERIC(Pose);
DEG_COMPONENT_NODE_DECLARE_GENERIC(PointCache);
DEG_COMPONENT_NODE_DECLARE_GENERIC(Sequencer);
DEG_COMPONENT_NODE_DECLARE_GENERIC(Compositor);
DEG_COMPONENT_NODE_DECLARE_NO_COW_TAG_ON_UPDATE(Shading);
DEG_COMPONENT_NODE_DECLARE_GENERIC(ShadingParameters);
DEG_COMPONENT_NODE_DECLARE_GENERIC(Transform);
DEG_COMPONENT_NODE_DECLARE_NO_COW_TAG_ON_UPDATE(ObjectFromLayer);
DEG_COMPONENT_NODE_DECLARE_NO_COW_TAG_ON_UPDATE(Hierarchy);
DEG_COMPONENT_NODE_DECLARE_GENERIC(Instancing);
DEG_COMPONENT_NODE_DECLARE_GENERIC(Synchronization);
DEG_COMPONENT_NODE_DECLARE_GENERIC(Armature);
DEG_COMPONENT_NODE_DECLARE_GENERIC(GenericDatablock);
DEG_COMPONENT_NODE_DECLARE_GENERIC(Scene);
DEG_COMPONENT_NODE_DECLARE_NO_COW_TAG_ON_UPDATE(Visibility);
DEG_COMPONENT_NODE_DECLARE_GENERIC(Simulation);
DEG_COMPONENT_NODE_DECLARE_GENERIC(NTreeOutput);
DEG_COMPONENT_NODE_DECLARE_GENERIC(NTreeGeometryPreprocess);
/* Bone Component */
struct BoneComponentNode : public ComponentNode {
/** Initialize 'bone component' node - from pointer data given. */
void init(const ID *id, const char *subdata) override;
struct bPoseChannel *pchan; /* the bone that this component represents */
DEG_COMPONENT_NODE_DECLARE;
};
/* Eventually we would not tag parameters in all cases.
* Support for this each ID needs to be added on an individual basis. */
struct ParametersComponentNode : public ComponentNode {
bool need_tag_cow_before_update(const IDRecalcFlag /*tag*/) override
{
if (ID_TYPE_SUPPORTS_PARAMS_WITHOUT_COW(owner->id_type)) {
/* Disabled as this is not true for newly added objects, needs investigation. */
// BLI_assert(deg_eval_copy_is_expanded(owner->id_cow));
return false;
}
return true;
}
DEG_COMPONENT_NODE_DECLARE;
};
/* Audio component. */
struct AudioComponentNode : public ComponentNode {
bool need_tag_cow_before_update(const IDRecalcFlag tag) override
{
/* Frame change doesn't require a copy of the scene, doing so can be a heavy operation
* especially when the collection contains many objects, see #104798. */
return (tag != ID_RECALC_FRAME_CHANGE);
}
DEG_COMPONENT_NODE_DECLARE;
};
void deg_register_component_depsnodes();
} // namespace deg
} // namespace blender

View File

@@ -0,0 +1,30 @@
/* SPDX-FileCopyrightText: 2019 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup depsgraph
*/
#include "intern/node/deg_node_factory.hh"
namespace blender::deg {
/* Global type registry */
static DepsNodeFactory *node_typeinfo_registry[int(NodeType::NUM_TYPES)] = {nullptr};
void register_node_typeinfo(DepsNodeFactory *factory)
{
BLI_assert(factory != nullptr);
const int type_as_int = int(factory->type());
node_typeinfo_registry[type_as_int] = factory;
}
DepsNodeFactory *type_get_factory(const NodeType type)
{
/* Look up type - at worst, it doesn't exist in table yet, and we fail. */
const int type_as_int = int(type);
return node_typeinfo_registry[type_as_int];
}
} // namespace blender::deg

View File

@@ -0,0 +1,47 @@
/* SPDX-FileCopyrightText: 2019 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup depsgraph
*/
#pragma once
#include "BLI_string_ref.hh"
#include "intern/node/deg_node.hh"
namespace blender {
struct ID;
namespace deg {
struct DepsNodeFactory {
virtual NodeType type() const = 0;
virtual const char *type_name() const = 0;
virtual int id_recalc_tag() const = 0;
virtual Node *create_node(const ID *id, const char *subdata, StringRef name) const = 0;
};
template<class ModeObjectType> struct DepsNodeFactoryImpl : public DepsNodeFactory {
NodeType type() const override;
const char *type_name() const override;
int id_recalc_tag() const override;
Node *create_node(const ID *id, const char *subdata, StringRef name) const override;
};
/* Register typeinfo */
void register_node_typeinfo(DepsNodeFactory *factory);
/* Get typeinfo for specified type */
DepsNodeFactory *type_get_factory(NodeType type);
} // namespace deg
} // namespace blender
#include "intern/node/deg_node_factory_impl.hh"

View File

@@ -0,0 +1,47 @@
/* SPDX-FileCopyrightText: 2019 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup depsgraph
*/
#pragma once
#include "intern/node/deg_node_factory.hh"
namespace blender {
struct ID;
namespace deg {
template<class ModeObjectType> NodeType DepsNodeFactoryImpl<ModeObjectType>::type() const
{
return ModeObjectType::typeinfo.type;
}
template<class ModeObjectType> const char *DepsNodeFactoryImpl<ModeObjectType>::type_name() const
{
return ModeObjectType::typeinfo.type_name;
}
template<class ModeObjectType> int DepsNodeFactoryImpl<ModeObjectType>::id_recalc_tag() const
{
return ModeObjectType::typeinfo.id_recalc_tag;
}
template<class ModeObjectType>
Node *DepsNodeFactoryImpl<ModeObjectType>::create_node(const ID *id,
const char *subdata,
const StringRef name) const
{
Node *node = new ModeObjectType();
node->type = type();
node->name = name;
node->init(id, subdata);
return node;
}
} // namespace deg
} // namespace blender

View File

@@ -0,0 +1,189 @@
/* SPDX-FileCopyrightText: 2013 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup depsgraph
*/
#include "intern/node/deg_node_id.hh"
#include "BLI_string.h"
#include "BLI_utildefines.h"
#include "DNA_ID.h"
#include "BKE_lib_id.hh"
#include "intern/eval/deg_eval_copy_on_write.h"
#include "intern/node/deg_node_component.hh"
#include "intern/node/deg_node_factory.hh"
namespace blender::deg {
const char *linkedStateAsString(eDepsNode_LinkedState_Type linked_state)
{
switch (linked_state) {
case DEG_ID_LINKED_INDIRECTLY:
return "INDIRECTLY";
case DEG_ID_LINKED_VIA_SET:
return "VIA_SET";
case DEG_ID_LINKED_DIRECTLY:
return "DIRECTLY";
}
BLI_assert_msg(0, "Unhandled linked state, should never happen.");
return "UNKNOWN";
}
void IDNode::init(const ID *id, const char * /*subdata*/)
{
BLI_assert(id != nullptr);
/* Store ID-pointer. */
id_type = GS(id->name);
id_orig = const_cast<ID *>(id);
id_orig_session_uid = id->session_uid;
eval_flags = 0;
previous_eval_flags = 0;
customdata_masks = DEGCustomDataMeshMasks();
previous_customdata_masks = DEGCustomDataMeshMasks();
linked_state = DEG_ID_LINKED_INDIRECTLY;
is_visible_on_build = true;
is_enabled_on_eval = true;
is_collection_fully_expanded = false;
has_base = false;
is_user_modified = false;
id_cow_recalc_backup = 0;
visible_components_mask = 0;
previously_visible_components_mask = 0;
}
void IDNode::init_copy_on_write(ID *id_cow_hint)
{
/* Create pointer as early as possible, so we can use it for function
* bindings. Rest of data we'll be copying to the new datablock when
* it is actually needed. */
if (id_cow_hint != nullptr) {
// BLI_assert(deg_eval_copy_is_needed(id_orig));
if (deg_eval_copy_is_needed(id_orig)) {
id_cow = id_cow_hint;
/* While `id_cow->orig_id == id` should be `true` most of the time (a same 'orig' ID should
* keep a same pointer in most cases), in can happen that the same 'orig' ID got a new
* address, e.g. after being deleted and re-loaded from memfile undo, without any update of
* the depsgraph in-between (e.g. when the depsgraph belongs to an inactive viewlayer).
* Ref. #145848. */
id_cow->orig_id = this->id_orig;
}
else {
id_cow = id_orig;
}
}
else if (deg_eval_copy_is_needed(id_orig)) {
id_cow = BKE_libblock_alloc_notest(GS(id_orig->name));
/* No need to call #BKE_libblock_runtime_ensure here, this will be done by
* #BKE_libblock_copy_in_lib when #deg_expand_eval_copy_datablock is executed. */
DEG_COW_PRINT(
"Allocate memory for %s: id_orig=%p id_cow=%p\n", id_orig->name, id_orig, id_cow);
}
else {
id_cow = id_orig;
}
}
/* Free 'id' node. */
IDNode::~IDNode()
{
destroy();
}
void IDNode::destroy()
{
if (id_orig == nullptr) {
return;
}
/* Free memory used by this evaluated ID. */
if (!ELEM(id_cow, id_orig, nullptr)) {
deg_free_eval_copy_datablock(id_cow);
MEM_delete(id_cow);
id_cow = nullptr;
DEG_COW_PRINT(
"Destroy evaluated ID for %s: id_orig=%p id_cow=%p\n", id_orig->name, id_orig, id_cow);
}
for (ComponentNode *comp_node : components.values()) {
delete comp_node;
}
/* Tag that the node is freed. */
id_orig = nullptr;
}
std::string IDNode::identifier() const
{
char orig_ptr[24], cow_ptr[24];
SNPRINTF(orig_ptr, "%p", id_orig);
SNPRINTF(cow_ptr, "%p", id_cow);
return std::string(nodeTypeAsString(type)) + " : " + name + " (orig: " + orig_ptr +
", eval: " + cow_ptr + ", is_visible_on_build " +
(is_visible_on_build ? "true" : "false") + ")";
}
ComponentNode *IDNode::find_component(NodeType type, const StringRef name) const
{
ComponentIDKey key(type, name);
return components.lookup_default(key, nullptr);
}
ComponentNode *IDNode::add_component(NodeType type, const StringRef name)
{
ComponentNode *comp_node = find_component(type, name);
if (!comp_node) {
DepsNodeFactory *factory = type_get_factory(type);
BLI_assert(factory);
comp_node = static_cast<ComponentNode *>(factory->create_node(this->id_orig, "", name));
/* Register. */
ComponentIDKey key(type, comp_node->name);
components.add_new(key, comp_node);
comp_node->owner = this;
}
return comp_node;
}
void IDNode::tag_update(Depsgraph *graph, eUpdateSource source)
{
for (ComponentNode *comp_node : components.values()) {
/* Relations update does explicit animation update when needed. Here we ignore animation
* component to avoid loss of possible unkeyed changes. */
if (comp_node->type == NodeType::ANIMATION && source == DEG_UPDATE_SOURCE_RELATIONS) {
continue;
}
comp_node->tag_update(graph, source);
}
}
void IDNode::finalize_build(Depsgraph *graph)
{
/* Finalize build of all components. */
for (ComponentNode *comp_node : components.values()) {
comp_node->finalize_build(graph);
}
visible_components_mask = get_visible_components_mask();
}
IDComponentsMask IDNode::get_visible_components_mask() const
{
IDComponentsMask result = 0;
for (ComponentNode *comp_node : components.values()) {
if (comp_node->possibly_affects_visible_id) {
const int component_type_as_int = int(comp_node->type);
BLI_assert(component_type_as_int < 64);
result |= (1ULL << component_type_as_int);
}
}
return result;
}
} // namespace blender::deg

View File

@@ -0,0 +1,140 @@
/* SPDX-FileCopyrightText: 2013 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup depsgraph
*/
#pragma once
#include "intern/node/deg_node.hh"
#include "DNA_ID.h"
#include "BLI_map.hh"
#include "BLI_string_ref.hh"
#include "BLI_sys_types.h"
namespace blender::deg {
struct ComponentNode;
using IDComponentsMask = uint64_t;
/* NOTE: We use max comparison to mark an id node that is linked more than once
* So keep this enum ordered accordingly. */
enum eDepsNode_LinkedState_Type {
/* Generic indirectly linked id node. */
DEG_ID_LINKED_INDIRECTLY = 0,
/* Id node present in the set (background) only. */
DEG_ID_LINKED_VIA_SET = 1,
/* Id node directly linked via the SceneLayer. */
DEG_ID_LINKED_DIRECTLY = 2,
};
const char *linkedStateAsString(eDepsNode_LinkedState_Type linked_state);
/* ID-Block Reference */
struct IDNode : public Node {
struct ComponentIDKey {
NodeType type;
StringRef name;
ComponentIDKey(NodeType type, StringRef name = "") : type(type), name(name) {}
friend bool operator==(const ComponentIDKey &a, const ComponentIDKey &b) = default;
uint64_t hash() const
{
return get_default_hash(type, name);
}
};
/** Initialize 'id' node - from pointer data given. */
void init(const ID *id, const char *subdata) override;
void init_copy_on_write(ID *id_cow_hint = nullptr);
~IDNode() override;
void destroy();
std::string identifier() const override;
ComponentNode *find_component(NodeType type, StringRef name = "") const;
ComponentNode *add_component(NodeType type, StringRef name = "");
void tag_update(Depsgraph *graph, eUpdateSource source) override;
void finalize_build(Depsgraph *graph);
IDComponentsMask get_visible_components_mask() const;
/* Type of the ID stored separately, so it's possible to perform check whether evaluated copy is
* needed without de-referencing the id_cow (which is not safe when ID is NOT covered by
* copy-on-evaluation and has been deleted from the main database.) */
ID_Type id_type;
/* ID Block referenced. */
ID *id_orig;
/* Session-wide UUID of the id_orig.
* Is used on relations update to map evaluated state from old nodes to the new ones, without
* relying on pointers (which are not guaranteed to be unique) and without dereferencing id_orig
* which could be "stale" pointer. */
uint id_orig_session_uid;
/* Evaluated data-block.
* Will be covered by the copy-on-evaluation system if the ID Type needs it. */
ID *id_cow;
/* Hash to make it faster to look up components. */
Map<ComponentIDKey, ComponentNode *> components;
/* Additional flags needed for scene evaluation.
* TODO(sergey): Only needed for until really granular updates
* of all the entities. */
uint32_t eval_flags;
uint32_t previous_eval_flags;
/* Extra customdata mask which needs to be evaluated for the mesh object. */
DEGCustomDataMeshMasks customdata_masks;
DEGCustomDataMeshMasks previous_customdata_masks;
eDepsNode_LinkedState_Type linked_state;
/* Indicates the data-block is to be considered visible in the evaluated scene.
*
* This flag is set during dependency graph build where check for an actual visibility might not
* be available yet due to driven or animated restriction flags. So it is more of an intent or,
* in other words, plausibility of the data-block to be visible. */
bool is_visible_on_build;
/* Evaluated state of whether evaluation considered this data-block "enabled".
*
* For objects this is derived from the base restriction flags, which might be animated or
* driven. It is set to `BASE_ENABLED_<VIEWPORT, RENDER>` (depending on the graph mode) after
* the object's flags from layer were evaluated.
*
* For other data-types is currently always true. */
bool is_enabled_on_eval;
/* For the collection type of ID, denotes whether collection was fully
* recursed into. */
bool is_collection_fully_expanded;
/* Is used to figure out whether object came to the dependency graph via a base. */
bool has_base;
/* Accumulated flag from operation. Is initialized and used during updates flush. */
bool is_user_modified;
/* Copy-on-Write component has been explicitly tagged for update. */
bool is_cow_explicitly_tagged;
/* Accumulate recalc flags from multiple update passes. */
int id_cow_recalc_backup;
IDComponentsMask visible_components_mask;
IDComponentsMask previously_visible_components_mask;
DEG_DEPSNODE_DECLARE;
};
} // namespace blender::deg

View File

@@ -0,0 +1,286 @@
/* SPDX-FileCopyrightText: 2013 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup depsgraph
*/
#include "intern/node/deg_node_operation.hh"
#include "intern/depsgraph.hh"
#include "intern/node/deg_node_component.hh"
#include "intern/node/deg_node_factory.hh"
#include "intern/node/deg_node_id.hh"
namespace blender::deg {
const char *operationCodeAsString(OperationCode opcode)
{
switch (opcode) {
/* Generic Operations. */
case OperationCode::OPERATION:
return "OPERATION";
case OperationCode::ID_PROPERTY:
return "ID_PROPERTY";
case OperationCode::PARAMETERS_ENTRY:
return "PARAMETERS_ENTRY";
case OperationCode::PARAMETERS_EVAL:
return "PARAMETERS_EVAL";
case OperationCode::PARAMETERS_EXIT:
return "PARAMETERS_EXIT";
case OperationCode::VISIBILITY:
return "VISIBILITY";
/* Hierarchy. */
case OperationCode::HIERARCHY:
return "HIERARCHY";
/* Animation, Drivers, etc. */
case OperationCode::ANIMATION_ENTRY:
return "ANIMATION_ENTRY";
case OperationCode::ANIMATION_EVAL:
return "ANIMATION_EVAL";
case OperationCode::ANIMATION_EXIT:
return "ANIMATION_EXIT";
case OperationCode::DRIVER:
return "DRIVER";
case OperationCode::DRIVER_UNSHARE:
return "DRIVER_UNSHARE";
/* Scene related. */
case OperationCode::SCENE_EVAL:
return "SCENE_EVAL";
case OperationCode::AUDIO_ENTRY:
return "AUDIO_ENTRY";
case OperationCode::AUDIO_VOLUME:
return "AUDIO_VOLUME";
/* Object related. */
case OperationCode::OBJECT_FROM_LAYER_ENTRY:
return "OBJECT_FROM_LAYER_ENTRY";
case OperationCode::OBJECT_BASE_FLAGS:
return "OBJECT_BASE_FLAGS";
case OperationCode::OBJECT_FROM_LAYER_EXIT:
return "OBJECT_FROM_LAYER_EXIT";
case OperationCode::DIMENSIONS:
return "DIMENSIONS";
/* Transform. */
case OperationCode::TRANSFORM_INIT:
return "TRANSFORM_INIT";
case OperationCode::TRANSFORM_LOCAL:
return "TRANSFORM_LOCAL";
case OperationCode::TRANSFORM_PARENT:
return "TRANSFORM_PARENT";
case OperationCode::TRANSFORM_CONSTRAINTS:
return "TRANSFORM_CONSTRAINTS";
case OperationCode::TRANSFORM_FINAL:
return "TRANSFORM_FINAL";
case OperationCode::TRANSFORM_EVAL:
return "TRANSFORM_EVAL";
case OperationCode::TRANSFORM_SIMULATION_INIT:
return "TRANSFORM_SIMULATION_INIT";
/* Rigid body. */
case OperationCode::RIGIDBODY_REBUILD:
return "RIGIDBODY_REBUILD";
case OperationCode::RIGIDBODY_SIM:
return "RIGIDBODY_SIM";
case OperationCode::RIGIDBODY_TRANSFORM_COPY:
return "RIGIDBODY_TRANSFORM_COPY";
/* Geometry. */
case OperationCode::GEOMETRY_EVAL_INIT:
return "GEOMETRY_EVAL_INIT";
case OperationCode::MODIFIER:
return "MODIFIER";
case OperationCode::GEOMETRY_EVAL:
return "GEOMETRY_EVAL";
case OperationCode::GEOMETRY_EVAL_DONE:
return "GEOMETRY_EVAL_DONE";
case OperationCode::GEOMETRY_SHAPEKEY:
return "GEOMETRY_SHAPEKEY";
/* Object data. */
case OperationCode::LIGHT_PROBE_EVAL:
return "LIGHT_PROBE_EVAL";
case OperationCode::SPEAKER_EVAL:
return "SPEAKER_EVAL";
case OperationCode::SOUND_EVAL:
return "SOUND_EVAL";
case OperationCode::ARMATURE_EVAL:
return "ARMATURE_EVAL";
/* Pose. */
case OperationCode::POSE_INIT:
return "POSE_INIT";
case OperationCode::POSE_INIT_IK:
return "POSE_INIT_IK";
case OperationCode::POSE_CLEANUP:
return "POSE_CLEANUP";
case OperationCode::POSE_DONE:
return "POSE_DONE";
case OperationCode::POSE_IK_SOLVER:
return "POSE_IK_SOLVER";
case OperationCode::POSE_SPLINE_IK_SOLVER:
return "POSE_SPLINE_IK_SOLVER";
/* Bone. */
case OperationCode::BONE_LOCAL:
return "BONE_LOCAL";
case OperationCode::BONE_POSE_PARENT:
return "BONE_POSE_PARENT";
case OperationCode::BONE_CONSTRAINTS:
return "BONE_CONSTRAINTS";
case OperationCode::BONE_READY:
return "BONE_READY";
case OperationCode::BONE_DONE:
return "BONE_DONE";
case OperationCode::BONE_SEGMENTS:
return "BONE_SEGMENTS";
case OperationCode::BONE_VISIBILITY:
return "BONE_VISIBILITY";
/* Particle System. */
case OperationCode::PARTICLE_SYSTEM_INIT:
return "PARTICLE_SYSTEM_INIT";
case OperationCode::PARTICLE_SYSTEM_EVAL:
return "PARTICLE_SYSTEM_EVAL";
case OperationCode::PARTICLE_SYSTEM_DONE:
return "PARTICLE_SYSTEM_DONE";
/* Particles Settings. */
case OperationCode::PARTICLE_SETTINGS_INIT:
return "PARTICLE_SETTINGS_INIT";
case OperationCode::PARTICLE_SETTINGS_EVAL:
return "PARTICLE_SETTINGS_EVAL";
case OperationCode::PARTICLE_SETTINGS_RESET:
return "PARTICLE_SETTINGS_RESET";
/* Point Cache. */
case OperationCode::POINT_CACHE_RESET:
return "POINT_CACHE_RESET";
/* File cache. */
case OperationCode::FILE_CACHE_UPDATE:
return "FILE_CACHE_UPDATE";
/* Batch cache. */
case OperationCode::GEOMETRY_SELECT_UPDATE:
return "GEOMETRY_SELECT_UPDATE";
/* Masks. */
case OperationCode::MASK_ANIMATION:
return "MASK_ANIMATION";
case OperationCode::MASK_EVAL:
return "MASK_EVAL";
/* Collections. */
case OperationCode::VIEW_LAYER_EVAL:
return "VIEW_LAYER_EVAL";
/* Copy on eval. */
case OperationCode::COPY_ON_EVAL:
return "COPY_ON_EVAL";
/* Shading. */
case OperationCode::SHADING:
return "SHADING";
case OperationCode::SHADING_DONE:
return "SHADING_DONE";
case OperationCode::MATERIAL_UPDATE:
return "MATERIAL_UPDATE";
case OperationCode::LIGHT_UPDATE:
return "LIGHT_UPDATE";
case OperationCode::WORLD_UPDATE:
return "WORLD_UPDATE";
/* Light linking. */
case OperationCode::LIGHT_LINKING_UPDATE:
return "LIGHT_LINKING_UPDATE";
/* Node Tree. */
case OperationCode::NTREE_OUTPUT:
return "NTREE_OUTPUT";
case OperationCode::NTREE_GEOMETRY_PREPROCESS:
return "NTREE_GEOMETRY_PREPROCESS";
/* Movie clip. */
case OperationCode::MOVIECLIP_EVAL:
return "MOVIECLIP_EVAL";
/* Image. */
case OperationCode::IMAGE_ANIMATION:
return "IMAGE_ANIMATION";
/* Synchronization. */
case OperationCode::SYNCHRONIZE_TO_ORIGINAL:
return "SYNCHRONIZE_TO_ORIGINAL";
/* Generic datablock. */
case OperationCode::GENERIC_DATABLOCK_UPDATE:
return "GENERIC_DATABLOCK_UPDATE";
/* Sequencer. */
case OperationCode::SEQUENCES_EVAL:
return "SEQUENCES_EVAL";
case OperationCode::COMPOSITOR_EVAL:
return "COMPOSITOR_EVAL";
/* instancing. */
case OperationCode::INSTANCER:
return "INSTANCER";
case OperationCode::INSTANCE:
return "INSTANCE";
case OperationCode::INSTANCE_GEOMETRY:
return "INSTANCE_GEOMETRY";
}
BLI_assert_msg(0, "Unhandled operation code, should never happen.");
return "UNKNOWN";
}
OperationNode::OperationNode() : name_tag(-1), flag(0) {}
std::string OperationNode::identifier() const
{
return std::string(operationCodeAsString(opcode)) + "(" + name + ")";
}
std::string OperationNode::full_identifier() const
{
std::string owner_str = owner->owner->name;
if (owner->type == NodeType::BONE || !owner->name.empty()) {
owner_str += "/" + owner->name;
}
return owner_str + "/" + identifier();
}
void OperationNode::tag_update(Depsgraph *graph, eUpdateSource source)
{
/* Ensure that there is an entry tag for this update.
*
* Note that the node might already be tagged for an update due invisible state of the node
* during previous dependency evaluation. Here the node gets re-tagged, so we need to give
* the evaluated clues that evaluation needs to happen again. */
graph->add_entry_tag(this);
/* Enforce dynamic visibility code-path update.
* This ensures visibility flags are consistently propagated throughout the dependency graph when
* there is no animated visibility in the graph.
*
* For example this ensures that graph is updated properly when manually toggling non-animated
* modifier visibility. */
if (opcode == OperationCode::VISIBILITY) {
graph->need_update_nodes_visibility = true;
}
/* Tag for update, but also note that this was the source of an update. */
flag |= (DEPSOP_FLAG_NEEDS_UPDATE | DEPSOP_FLAG_DIRECTLY_MODIFIED);
switch (source) {
case DEG_UPDATE_SOURCE_TIME:
case DEG_UPDATE_SOURCE_RELATIONS:
case DEG_UPDATE_SOURCE_VISIBILITY:
case DEG_UPDATE_SOURCE_SIDE_EFFECT_REQUEST:
/* Currently nothing. */
break;
case DEG_UPDATE_SOURCE_USER_EDIT:
flag |= DEPSOP_FLAG_USER_MODIFIED;
break;
}
}
void OperationNode::set_as_entry()
{
BLI_assert(owner != nullptr);
owner->set_entry_operation(this);
}
void OperationNode::set_as_exit()
{
BLI_assert(owner != nullptr);
owner->set_exit_operation(this);
}
DEG_DEPSNODE_DEFINE(OperationNode, NodeType::OPERATION, "Operation");
static DepsNodeFactoryImpl<OperationNode> DNTI_OPERATION;
void deg_register_operation_depsnodes()
{
register_node_typeinfo(&DNTI_OPERATION);
}
} // namespace blender::deg

View File

@@ -0,0 +1,310 @@
/* SPDX-FileCopyrightText: 2013 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup depsgraph
*/
#pragma once
#include <functional>
#include <string>
#include "intern/node/deg_node.hh"
#include "intern/depsgraph_type.hh"
namespace blender {
struct Depsgraph;
namespace deg {
struct ComponentNode;
/* Evaluation Operation for atomic operation */
/* XXX: move this to another header that can be exposed? */
using DepsEvalOperationCb = std::function<void(blender::Depsgraph *)>;
/* Identifiers for common operations (as an enum). */
enum class OperationCode {
/* Generic Operations. -------------------------------------------------- */
/* Placeholder for operations which don't need special mention */
OPERATION = 0,
/* Generic parameters evaluation. --------------------------------------- */
ID_PROPERTY,
PARAMETERS_ENTRY,
PARAMETERS_EVAL,
PARAMETERS_EXIT,
VISIBILITY,
/* Hierarchy. ----------------------------------------------------------- */
HIERARCHY,
/* Animation, Drivers, etc. --------------------------------------------- */
/* NLA + Action */
ANIMATION_ENTRY,
ANIMATION_EVAL,
ANIMATION_EXIT,
/* Driver */
DRIVER,
/* Writes to RNA properties to ensure implicitly-shared data is un-shared. */
DRIVER_UNSHARE,
/* Scene related. ------------------------------------------------------- */
SCENE_EVAL,
AUDIO_ENTRY,
AUDIO_VOLUME,
/* Object related. ------------------------------------------------------ */
OBJECT_FROM_LAYER_ENTRY,
OBJECT_BASE_FLAGS,
OBJECT_FROM_LAYER_EXIT,
DIMENSIONS,
/* Transform. ----------------------------------------------------------- */
/* Transform entry point. */
TRANSFORM_INIT,
/* Local transforms only */
TRANSFORM_LOCAL,
/* Parenting */
TRANSFORM_PARENT,
/* Constraints */
TRANSFORM_CONSTRAINTS,
/* Handle object-level updates, mainly proxies hacks and recalc flags. */
TRANSFORM_EVAL,
/* Initializes transformation for simulation.
* For example, ensures point cache is properly reset before doing rigid
* body simulation. */
TRANSFORM_SIMULATION_INIT,
/* Transform exit point */
TRANSFORM_FINAL,
/* Rigid body. ---------------------------------------------------------- */
/* Perform Simulation */
RIGIDBODY_REBUILD,
RIGIDBODY_SIM,
/* Copy results to object */
RIGIDBODY_TRANSFORM_COPY,
/* Geometry. ------------------------------------------------------------ */
/* Initialize evaluation of the geometry. Is an entry operation of geometry
* component. */
GEOMETRY_EVAL_INIT,
/* Modifier. */
MODIFIER,
/* Evaluate the whole geometry, including modifiers. */
GEOMETRY_EVAL,
/* Evaluation of geometry is completely done. */
GEOMETRY_EVAL_DONE,
/* Evaluation of a shape key.
* NOTE: Currently only for object data data-blocks. */
GEOMETRY_SHAPEKEY,
/* Object data. --------------------------------------------------------- */
LIGHT_PROBE_EVAL,
SPEAKER_EVAL,
SOUND_EVAL,
ARMATURE_EVAL,
/* Pose. ---------------------------------------------------------------- */
/* Init pose, clear flags, etc. */
POSE_INIT,
/* Initialize IK solver related pose stuff. */
POSE_INIT_IK,
/* Pose is evaluated, and runtime data can be freed. */
POSE_CLEANUP,
/* Pose has been fully evaluated and ready to be used by others. */
POSE_DONE,
/* IK/Spline Solvers */
POSE_IK_SOLVER,
POSE_SPLINE_IK_SOLVER,
/* Bone. ---------------------------------------------------------------- */
/* Bone local transforms - entry point */
BONE_LOCAL,
/* Pose-space conversion (includes parent + rest-pose). */
BONE_POSE_PARENT,
/* Constraints */
BONE_CONSTRAINTS,
/* Bone transforms are ready
*
* - "READY" This (internal, noop) is used to signal that all pre-IK
* operations are done. Its role is to help mediate situations
* where cyclic relations may otherwise form (i.e. one bone in
* chain targeting another in same chain),
*
* - "DONE" This noop is used to signal that the bone's final pose
* transform can be read by others. */
/* TODO: deform mats could get calculated in the final_transform ops... */
BONE_READY,
BONE_DONE,
/* B-Bone segment shape computation (after DONE) */
BONE_SEGMENTS,
/* Getting the visibility doesn't need evaluation of the pose. */
BONE_VISIBILITY,
/* Particle System. ----------------------------------------------------- */
PARTICLE_SYSTEM_INIT,
PARTICLE_SYSTEM_EVAL,
PARTICLE_SYSTEM_DONE,
/* Particle Settings. --------------------------------------------------- */
PARTICLE_SETTINGS_INIT,
PARTICLE_SETTINGS_EVAL,
PARTICLE_SETTINGS_RESET,
/* Point Cache. --------------------------------------------------------- */
POINT_CACHE_RESET,
/* File cache. ---------------------------------------------------------- */
FILE_CACHE_UPDATE,
/* Collections. --------------------------------------------------------- */
VIEW_LAYER_EVAL,
/* Copy on Write. ------------------------------------------------------- */
COPY_ON_EVAL,
/* Shading. ------------------------------------------------------------- */
SHADING,
SHADING_DONE,
MATERIAL_UPDATE,
LIGHT_UPDATE,
WORLD_UPDATE,
/* Light linking. ------------------------------------------------------- */
LIGHT_LINKING_UPDATE,
/* Node Tree. ----------------------------------------------------------- */
NTREE_OUTPUT,
NTREE_GEOMETRY_PREPROCESS,
/* Batch caches. -------------------------------------------------------- */
GEOMETRY_SELECT_UPDATE,
/* Masks. --------------------------------------------------------------- */
MASK_ANIMATION,
MASK_EVAL,
/* Movie clips. --------------------------------------------------------- */
MOVIECLIP_EVAL,
/* Images. -------------------------------------------------------------- */
IMAGE_ANIMATION,
/* Synchronization. ----------------------------------------------------- */
SYNCHRONIZE_TO_ORIGINAL,
/* Generic data-block --------------------------------------------------- */
GENERIC_DATABLOCK_UPDATE,
/* Sequencer. ----------------------------------------------------------- */
SEQUENCES_EVAL,
/* Compositor. ---------------------------------------------------------- */
COMPOSITOR_EVAL,
/* instancing system. --------------------------------------------------- */
/* Operation on an instancer object. Relations from instanced objects go here. */
INSTANCER,
/* Operation on an object which is being instanced. */
INSTANCE,
INSTANCE_GEOMETRY,
};
const char *operationCodeAsString(OperationCode opcode);
/* Flags for Depsgraph Nodes.
* NOTE: IS a bit shifts to allow usage as an accumulated. bitmask.
*/
enum OperationFlag {
/* Node needs to be updated. */
DEPSOP_FLAG_NEEDS_UPDATE = (1 << 0),
/* Node was directly modified, causing need for update. */
DEPSOP_FLAG_DIRECTLY_MODIFIED = (1 << 1),
/* Node was updated due to user input. */
DEPSOP_FLAG_USER_MODIFIED = (1 << 2),
/* Node may not be removed, even when it has no evaluation callback and no outgoing relations.
* This is for NO-OP nodes that are purely used to indicate a relation between components/IDs,
* and not for connecting to an operation. */
DEPSOP_FLAG_PINNED = (1 << 3),
/* The operation directly or indirectly affects ID node visibility. */
DEPSOP_FLAG_AFFECTS_VISIBILITY = (1 << 4),
/* Evaluation of the node is temporarily disabled. */
DEPSOP_FLAG_MUTE = (1 << 5),
/* Set of flags which gets flushed along the relations. */
DEPSOP_FLAG_FLUSH = (DEPSOP_FLAG_USER_MODIFIED),
/* Set of flags which get cleared upon evaluation. */
DEPSOP_FLAG_CLEAR_ON_EVAL = (DEPSOP_FLAG_DIRECTLY_MODIFIED | DEPSOP_FLAG_NEEDS_UPDATE |
DEPSOP_FLAG_USER_MODIFIED),
};
/* Atomic Operation - Base type for all operations */
struct OperationNode : public Node {
OperationNode();
std::string identifier() const override;
/**
* Full node identifier, including owner name.
* used for logging and debug prints.
*/
std::string full_identifier() const;
void tag_update(Depsgraph *graph, eUpdateSource source) override;
bool is_noop() const
{
return bool(evaluate) == false;
}
OperationNode *get_entry_operation() override
{
return this;
}
OperationNode *get_exit_operation() override
{
return this;
}
/* Set this operation as component's entry/exit operation. */
void set_as_entry();
void set_as_exit();
/* Component that contains the operation. */
ComponentNode *owner;
/* Callback for operation. */
DepsEvalOperationCb evaluate;
/* How many inlinks are we still waiting on before we can be evaluated. */
uint32_t num_links_pending;
bool scheduled;
/* Identifier for the operation being performed. */
OperationCode opcode;
int name_tag;
/* (OperationFlag) extra settings affecting evaluation. */
int flag;
DEG_DEPSNODE_DECLARE;
};
void deg_register_operation_depsnodes();
} // namespace deg
} // namespace blender

View File

@@ -0,0 +1,32 @@
/* SPDX-FileCopyrightText: 2013 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup depsgraph
*/
#include "intern/node/deg_node_time.hh"
#include "intern/depsgraph.hh"
#include "intern/depsgraph_relation.hh"
namespace blender::deg {
void TimeSourceNode::tag_update(Depsgraph * /*graph*/, eUpdateSource /*source*/)
{
tagged_for_update = true;
}
void TimeSourceNode::flush_update_tag(Depsgraph *graph)
{
if (!tagged_for_update) {
return;
}
for (Relation *rel : outlinks) {
Node *node = rel->to;
node->tag_update(graph, DEG_UPDATE_SOURCE_TIME);
}
}
} // namespace blender::deg

View File

@@ -0,0 +1,28 @@
/* SPDX-FileCopyrightText: 2013 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup depsgraph
*/
#pragma once
#include "intern/node/deg_node.hh"
namespace blender::deg {
/* Time Source Node. */
struct TimeSourceNode : public Node {
bool tagged_for_update = false;
/* TODO: evaluate() operation needed */
void tag_update(Depsgraph *graph, eUpdateSource source) override;
void flush_update_tag(Depsgraph *graph);
DEG_DEPSNODE_DECLARE;
};
} // namespace blender::deg