2023-08-16 00:20:26 +10:00
|
|
|
/* SPDX-FileCopyrightText: 2013 Blender Authors
|
2023-05-31 16:19:06 +02:00
|
|
|
*
|
|
|
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
2017-12-20 16:35:48 +01:00
|
|
|
|
2019-02-18 08:08:12 +11:00
|
|
|
/** \file
|
|
|
|
|
* \ingroup depsgraph
|
2017-12-20 16:35:48 +01:00
|
|
|
*/
|
|
|
|
|
|
2023-09-22 03:18:17 +02:00
|
|
|
#include "intern/node/deg_node_id.hh"
|
2017-12-20 16:35:48 +01:00
|
|
|
|
2020-12-04 11:28:09 +01:00
|
|
|
#include <cstdio>
|
2017-12-20 16:35:48 +01:00
|
|
|
#include <cstring> /* required for STREQ later on. */
|
|
|
|
|
|
2019-01-31 12:56:40 +01:00
|
|
|
#include "BLI_string.h"
|
2020-03-19 09:33:03 +01:00
|
|
|
#include "BLI_utildefines.h"
|
2017-12-20 16:35:48 +01:00
|
|
|
|
|
|
|
|
#include "DNA_ID.h"
|
|
|
|
|
#include "DNA_anim_types.h"
|
|
|
|
|
|
2024-01-15 12:44:04 -05:00
|
|
|
#include "BKE_lib_id.hh"
|
2017-12-20 16:35:48 +01:00
|
|
|
|
2023-09-22 03:18:17 +02:00
|
|
|
#include "DEG_depsgraph.hh"
|
2017-12-20 16:35:48 +01:00
|
|
|
|
2017-12-20 16:40:49 +01:00
|
|
|
#include "intern/eval/deg_eval_copy_on_write.h"
|
2023-09-22 03:18:17 +02:00
|
|
|
#include "intern/node/deg_node_component.hh"
|
|
|
|
|
#include "intern/node/deg_node_factory.hh"
|
|
|
|
|
#include "intern/node/deg_node_time.hh"
|
2017-12-20 16:35:48 +01:00
|
|
|
|
2020-11-07 18:17:12 +05:30
|
|
|
namespace blender::deg {
|
2017-12-20 16:35:48 +01:00
|
|
|
|
2019-01-31 12:56:40 +01:00
|
|
|
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";
|
|
|
|
|
}
|
2021-07-15 18:23:28 +10:00
|
|
|
BLI_assert_msg(0, "Unhandled linked state, should never happen.");
|
2019-08-01 13:53:25 +10:00
|
|
|
return "UNKNOWN";
|
2019-01-31 12:56:40 +01:00
|
|
|
}
|
|
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
IDNode::ComponentIDKey::ComponentIDKey(NodeType type, const char *name) : type(type), name(name) {}
|
2017-12-20 16:35:48 +01:00
|
|
|
|
2019-01-31 12:56:40 +01:00
|
|
|
bool IDNode::ComponentIDKey::operator==(const ComponentIDKey &other) const
|
2017-12-20 16:35:48 +01:00
|
|
|
{
|
2017-12-20 16:40:49 +01:00
|
|
|
return type == other.type && STREQ(name, other.name);
|
2017-12-20 16:35:48 +01:00
|
|
|
}
|
|
|
|
|
|
2020-07-20 12:16:20 +02:00
|
|
|
uint64_t IDNode::ComponentIDKey::hash() const
|
2020-06-09 10:10:56 +02:00
|
|
|
{
|
2022-09-25 18:30:50 +10:00
|
|
|
const int type_as_int = int(type);
|
2020-06-09 10:10:56 +02:00
|
|
|
return BLI_ghashutil_combine_hash(BLI_ghashutil_uinthash(type_as_int),
|
|
|
|
|
BLI_ghashutil_strhash_p(name));
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-03 17:37:25 -05:00
|
|
|
void IDNode::init(const ID *id, const char * /*subdata*/)
|
2017-12-20 16:35:48 +01:00
|
|
|
{
|
2020-01-28 14:50:13 +01:00
|
|
|
BLI_assert(id != nullptr);
|
2017-12-20 16:40:49 +01:00
|
|
|
/* Store ID-pointer. */
|
2020-03-11 17:25:17 +01:00
|
|
|
id_type = GS(id->name);
|
2017-12-20 16:40:49 +01:00
|
|
|
id_orig = (ID *)id;
|
2024-01-22 13:47:13 +01:00
|
|
|
id_orig_session_uid = id->session_uid;
|
2017-12-20 16:40:49 +01:00
|
|
|
eval_flags = 0;
|
2018-10-24 19:38:50 +03:00
|
|
|
previous_eval_flags = 0;
|
Refactor CDData masks, to have one mask per mesh elem type.
We already have different storages for cddata of verts, edges etc.,
'simply' do the same for the mask flags we use all around Blender code
to request some data, or limit some operation to some layers, etc.
Reason we need this is that some cddata types (like Normals) are
actually shared between verts/polys/loops, and we don’t want to generate
clnors everytime we request vnors!
As a side note, this also does final fix to T59338, which was the
trigger for this patch (need to request computed loop normals for
another mesh than evaluated one).
Reviewers: brecht, campbellbarton, sergey
Differential Revision: https://developer.blender.org/D4407
2019-03-07 11:13:40 +01:00
|
|
|
customdata_masks = DEGCustomDataMeshMasks();
|
|
|
|
|
previous_customdata_masks = DEGCustomDataMeshMasks();
|
2017-12-20 16:40:49 +01:00
|
|
|
linked_state = DEG_ID_LINKED_INDIRECTLY;
|
2022-07-20 10:04:02 +02:00
|
|
|
is_visible_on_build = true;
|
|
|
|
|
is_enabled_on_eval = true;
|
2018-11-14 16:50:59 +01:00
|
|
|
is_collection_fully_expanded = false;
|
2019-04-29 14:11:32 +02:00
|
|
|
has_base = false;
|
2019-06-04 11:33:41 +02:00
|
|
|
is_user_modified = false;
|
2021-04-19 19:38:05 +02:00
|
|
|
id_cow_recalc_backup = 0;
|
2018-09-19 15:46:03 +02:00
|
|
|
|
|
|
|
|
visible_components_mask = 0;
|
|
|
|
|
previously_visible_components_mask = 0;
|
2017-12-20 16:40:49 +01:00
|
|
|
}
|
2017-12-20 16:35:48 +01:00
|
|
|
|
Fix #119589: use-after-free when accessing not-fully-evaluated object geometry
While the evaluated result is not well defined, we expect Blender to not crash
when there are dependency cycles.
The evaluation of one object often takes the evaluated geometry of another
object into account. This works fine if the other object is already fully
evaluated. However, if there is a dependency cycle, the other object may not be
evaluated already. Currently, we have no way to check for this and were mostly
just relying on luck that the other objects geometry is in some valid state
(even if it's not the fully evaluated geometry).
This patch adds the ability to explicitly check if an objects geometry is fully
evaluated already, so that it can be accessed by other objects. If there are not
dependency cycles, this should always be true. If not, it may be false
sometimes, and in this case the other objects geometry should be ignored. The
same also applies to the object transforms and the geometry of a collection.
For that, new functions are added in `DEG_depsgraph_query.hh`. Those should be
used whenever accessing another objects or collections object during depsgraph
evaluation. More similar functions may be added in the future.
```
bool DEG_object_geometry_is_evaluated(const Object &object);
bool DEG_object_transform_is_evaluated(const Object &object);
bool DEG_collection_geometry_is_evaluated(const Collection &collection);
```
To determine if the these components are fully evaluated, a reference to the
corresponding depsgraph is needed. A possible solution to that is to pass the
depsgraph through the call stack to these functions. While possible, there are a
couple of annoyances. For one, the parameter would need to be added in many new
places. I don't have an exact number, but it's like 50 or so. Another
complication is that under some circumstances, multiple depsgraphs may have to
be passed around, for example when evaluating node tools (also see
`GeoNodesOperatorDepsgraphs`).
To simplify the patch and other code in the future, a different route is taken
where the depsgraph pointer is added to `ID_Runtime`, making it readily
accessible similar to the `ID.orig_id`. The depsgraph pointer is set in the same
place where the `orig_id` is set.
As a nice side benefit, this also improves the situation in simple cases like
having two cubes with a boolean modifier and they union each other.
Pull Request: https://projects.blender.org/blender/blender/pulls/123444
2024-06-20 15:24:38 +02:00
|
|
|
void IDNode::init_copy_on_write(Depsgraph &depsgraph, ID *id_cow_hint)
|
2017-12-20 16:40:49 +01:00
|
|
|
{
|
|
|
|
|
/* 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
|
2019-01-31 12:56:40 +01:00
|
|
|
* it is actually needed. */
|
2020-01-28 14:50:13 +01:00
|
|
|
if (id_cow_hint != nullptr) {
|
2024-02-19 15:54:08 +01:00
|
|
|
// BLI_assert(deg_eval_copy_is_needed(id_orig));
|
|
|
|
|
if (deg_eval_copy_is_needed(id_orig)) {
|
2017-12-20 16:40:49 +01:00
|
|
|
id_cow = id_cow_hint;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
id_cow = id_orig;
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-02-19 15:54:08 +01:00
|
|
|
else if (deg_eval_copy_is_needed(id_orig)) {
|
2017-12-20 16:40:49 +01:00
|
|
|
id_cow = (ID *)BKE_libblock_alloc_notest(GS(id_orig->name));
|
|
|
|
|
DEG_COW_PRINT(
|
|
|
|
|
"Create shallow copy for %s: id_orig=%p id_cow=%p\n", id_orig->name, id_orig, id_cow);
|
Fix #119589: use-after-free when accessing not-fully-evaluated object geometry
While the evaluated result is not well defined, we expect Blender to not crash
when there are dependency cycles.
The evaluation of one object often takes the evaluated geometry of another
object into account. This works fine if the other object is already fully
evaluated. However, if there is a dependency cycle, the other object may not be
evaluated already. Currently, we have no way to check for this and were mostly
just relying on luck that the other objects geometry is in some valid state
(even if it's not the fully evaluated geometry).
This patch adds the ability to explicitly check if an objects geometry is fully
evaluated already, so that it can be accessed by other objects. If there are not
dependency cycles, this should always be true. If not, it may be false
sometimes, and in this case the other objects geometry should be ignored. The
same also applies to the object transforms and the geometry of a collection.
For that, new functions are added in `DEG_depsgraph_query.hh`. Those should be
used whenever accessing another objects or collections object during depsgraph
evaluation. More similar functions may be added in the future.
```
bool DEG_object_geometry_is_evaluated(const Object &object);
bool DEG_object_transform_is_evaluated(const Object &object);
bool DEG_collection_geometry_is_evaluated(const Collection &collection);
```
To determine if the these components are fully evaluated, a reference to the
corresponding depsgraph is needed. A possible solution to that is to pass the
depsgraph through the call stack to these functions. While possible, there are a
couple of annoyances. For one, the parameter would need to be added in many new
places. I don't have an exact number, but it's like 50 or so. Another
complication is that under some circumstances, multiple depsgraphs may have to
be passed around, for example when evaluating node tools (also see
`GeoNodesOperatorDepsgraphs`).
To simplify the patch and other code in the future, a different route is taken
where the depsgraph pointer is added to `ID_Runtime`, making it readily
accessible similar to the `ID.orig_id`. The depsgraph pointer is set in the same
place where the `orig_id` is set.
As a nice side benefit, this also improves the situation in simple cases like
having two cubes with a boolean modifier and they union each other.
Pull Request: https://projects.blender.org/blender/blender/pulls/123444
2024-06-20 15:24:38 +02:00
|
|
|
deg_tag_eval_copy_id(depsgraph, id_cow, id_orig);
|
2017-12-20 16:40:49 +01:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
id_cow = id_orig;
|
|
|
|
|
}
|
2017-12-20 16:35:48 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Free 'id' node. */
|
2019-01-31 12:56:40 +01:00
|
|
|
IDNode::~IDNode()
|
2017-12-20 16:35:48 +01:00
|
|
|
{
|
2017-12-20 16:40:49 +01:00
|
|
|
destroy();
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-31 12:56:40 +01:00
|
|
|
void IDNode::destroy()
|
2017-12-20 16:40:49 +01:00
|
|
|
{
|
2020-01-28 14:50:13 +01:00
|
|
|
if (id_orig == nullptr) {
|
2017-12-20 16:40:49 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2024-02-19 15:54:08 +01:00
|
|
|
/* Free memory used by this evaluated ID. */
|
2020-11-06 12:30:59 +11:00
|
|
|
if (!ELEM(id_cow, id_orig, nullptr)) {
|
2024-02-19 15:54:08 +01:00
|
|
|
deg_free_eval_copy_datablock(id_cow);
|
2017-12-20 16:40:49 +01:00
|
|
|
MEM_freeN(id_cow);
|
2020-01-28 14:50:13 +01:00
|
|
|
id_cow = nullptr;
|
2024-02-19 15:54:08 +01:00
|
|
|
DEG_COW_PRINT(
|
|
|
|
|
"Destroy evaluated ID for %s: id_orig=%p id_cow=%p\n", id_orig->name, id_orig, id_cow);
|
2017-12-20 16:40:49 +01:00
|
|
|
}
|
|
|
|
|
|
2024-06-20 17:02:55 +02:00
|
|
|
for (ComponentNode *comp_node : components.values()) {
|
|
|
|
|
delete comp_node;
|
|
|
|
|
}
|
|
|
|
|
|
2017-12-20 16:40:49 +01:00
|
|
|
/* Tag that the node is freed. */
|
2020-01-28 14:50:13 +01:00
|
|
|
id_orig = nullptr;
|
2017-12-20 16:35:48 +01:00
|
|
|
}
|
|
|
|
|
|
2019-01-31 12:56:40 +01:00
|
|
|
string IDNode::identifier() const
|
2018-04-30 17:31:04 +02:00
|
|
|
{
|
|
|
|
|
char orig_ptr[24], cow_ptr[24];
|
2023-05-09 12:50:37 +10:00
|
|
|
SNPRINTF(orig_ptr, "%p", id_orig);
|
|
|
|
|
SNPRINTF(cow_ptr, "%p", id_cow);
|
2018-04-30 17:31:04 +02:00
|
|
|
return string(nodeTypeAsString(type)) + " : " + name + " (orig: " + orig_ptr +
|
2022-07-20 10:04:02 +02:00
|
|
|
", eval: " + cow_ptr + ", is_visible_on_build " +
|
|
|
|
|
(is_visible_on_build ? "true" : "false") + ")";
|
2018-04-30 17:31:04 +02:00
|
|
|
}
|
|
|
|
|
|
2019-02-15 16:00:54 +01:00
|
|
|
ComponentNode *IDNode::find_component(NodeType type, const char *name) const
|
2017-12-20 16:35:48 +01:00
|
|
|
{
|
|
|
|
|
ComponentIDKey key(type, name);
|
2020-04-28 12:49:52 +02:00
|
|
|
return components.lookup_default(key, nullptr);
|
2017-12-20 16:35:48 +01:00
|
|
|
}
|
|
|
|
|
|
2019-02-15 16:00:54 +01:00
|
|
|
ComponentNode *IDNode::add_component(NodeType type, const char *name)
|
2017-12-20 16:35:48 +01:00
|
|
|
{
|
2019-01-31 12:56:40 +01:00
|
|
|
ComponentNode *comp_node = find_component(type, name);
|
2017-12-20 16:35:48 +01:00
|
|
|
if (!comp_node) {
|
2019-01-31 12:56:40 +01:00
|
|
|
DepsNodeFactory *factory = type_get_factory(type);
|
2023-05-23 13:05:24 +02:00
|
|
|
BLI_assert(factory);
|
2019-01-31 12:56:40 +01:00
|
|
|
comp_node = (ComponentNode *)factory->create_node(this->id_orig, "", name);
|
2017-12-20 16:35:48 +01:00
|
|
|
|
|
|
|
|
/* Register. */
|
2023-04-07 15:46:19 +02:00
|
|
|
ComponentIDKey key(type, comp_node->name.c_str());
|
2020-04-28 12:49:52 +02:00
|
|
|
components.add_new(key, comp_node);
|
2017-12-20 16:35:48 +01:00
|
|
|
comp_node->owner = this;
|
|
|
|
|
}
|
|
|
|
|
return comp_node;
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-31 12:56:40 +01:00
|
|
|
void IDNode::tag_update(Depsgraph *graph, eUpdateSource source)
|
2017-12-20 16:35:48 +01:00
|
|
|
{
|
2020-04-28 12:49:52 +02:00
|
|
|
for (ComponentNode *comp_node : components.values()) {
|
2019-06-11 11:56:30 +02:00
|
|
|
/* 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;
|
|
|
|
|
}
|
2018-11-14 11:24:54 +01:00
|
|
|
comp_node->tag_update(graph, source);
|
2017-12-20 16:35:48 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-31 12:56:40 +01:00
|
|
|
void IDNode::finalize_build(Depsgraph *graph)
|
2017-12-20 16:35:48 +01:00
|
|
|
{
|
2017-12-20 16:40:49 +01:00
|
|
|
/* Finalize build of all components. */
|
2020-04-28 12:49:52 +02:00
|
|
|
for (ComponentNode *comp_node : components.values()) {
|
2017-12-20 16:40:49 +01:00
|
|
|
comp_node->finalize_build(graph);
|
2017-12-20 16:35:48 +01:00
|
|
|
}
|
2018-09-19 15:46:03 +02:00
|
|
|
visible_components_mask = get_visible_components_mask();
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-01-31 12:56:40 +01:00
|
|
|
IDComponentsMask IDNode::get_visible_components_mask() const
|
|
|
|
|
{
|
2018-09-19 15:46:03 +02:00
|
|
|
IDComponentsMask result = 0;
|
2020-04-28 12:49:52 +02:00
|
|
|
for (ComponentNode *comp_node : components.values()) {
|
2022-07-20 10:04:02 +02:00
|
|
|
if (comp_node->possibly_affects_visible_id) {
|
2022-09-25 18:30:50 +10:00
|
|
|
const int component_type_as_int = int(comp_node->type);
|
2019-01-31 12:56:40 +01:00
|
|
|
BLI_assert(component_type_as_int < 64);
|
|
|
|
|
result |= (1ULL << component_type_as_int);
|
2018-09-19 15:46:03 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return result;
|
2017-12-20 16:35:48 +01:00
|
|
|
}
|
|
|
|
|
|
2020-11-07 18:17:12 +05:30
|
|
|
} // namespace blender::deg
|