Fix T101004: Crash when invisible object becomes visible
A regression since ac20970bc2
The issue was caused by depsgraph clearing all id->recalc flags
wrongly assuming that all IDs are fully evaluated.
This change makes it so the depsgraph becomes aware of possibly
incompletely evaluated IDs.
Differential Revision: https://developer.blender.org/D15946
This commit is contained in:
@@ -155,12 +155,14 @@ IDNode *DepsgraphNodeBuilder::add_id_node(ID *id)
|
||||
IDComponentsMask previously_visible_components_mask = 0;
|
||||
uint32_t previous_eval_flags = 0;
|
||||
DEGCustomDataMeshMasks previous_customdata_masks;
|
||||
int id_invisible_recalc = 0;
|
||||
IDInfo *id_info = id_info_hash_.lookup_default(id->session_uuid, nullptr);
|
||||
if (id_info != nullptr) {
|
||||
id_cow = id_info->id_cow;
|
||||
previously_visible_components_mask = id_info->previously_visible_components_mask;
|
||||
previous_eval_flags = id_info->previous_eval_flags;
|
||||
previous_customdata_masks = id_info->previous_customdata_masks;
|
||||
id_invisible_recalc = id_info->id_invisible_recalc;
|
||||
/* Tag ID info to not free the CoW ID pointer. */
|
||||
id_info->id_cow = nullptr;
|
||||
}
|
||||
@@ -168,6 +170,7 @@ IDNode *DepsgraphNodeBuilder::add_id_node(ID *id)
|
||||
id_node->previously_visible_components_mask = previously_visible_components_mask;
|
||||
id_node->previous_eval_flags = previous_eval_flags;
|
||||
id_node->previous_customdata_masks = previous_customdata_masks;
|
||||
id_node->id_invisible_recalc = id_invisible_recalc;
|
||||
|
||||
/* NOTE: Zero number of components indicates that ID node was just created. */
|
||||
const bool is_newly_created = id_node->components.is_empty();
|
||||
@@ -366,6 +369,7 @@ void DepsgraphNodeBuilder::begin_build()
|
||||
id_info->previously_visible_components_mask = id_node->visible_components_mask;
|
||||
id_info->previous_eval_flags = id_node->eval_flags;
|
||||
id_info->previous_customdata_masks = id_node->customdata_masks;
|
||||
id_info->id_invisible_recalc = id_node->id_invisible_recalc;
|
||||
BLI_assert(!id_info_hash_.contains(id_node->id_orig_session_uuid));
|
||||
id_info_hash_.add_new(id_node->id_orig_session_uuid, id_info);
|
||||
id_node->id_cow = nullptr;
|
||||
|
||||
@@ -250,6 +250,8 @@ class DepsgraphNodeBuilder : public DepsgraphBuilder {
|
||||
IDComponentsMask previously_visible_components_mask;
|
||||
/* Special evaluation flag mask from the previous depsgraph. */
|
||||
uint32_t previous_eval_flags;
|
||||
/* Recalculation flags which were not evaluated for the ID in the previous depsgraph. */
|
||||
int id_invisible_recalc;
|
||||
/* Mesh CustomData mask from the previous depsgraph. */
|
||||
DEGCustomDataMeshMasks previous_customdata_masks;
|
||||
};
|
||||
|
||||
@@ -890,6 +890,13 @@ void DEG_ids_clear_recalc(Depsgraph *depsgraph, const bool backup)
|
||||
}
|
||||
/* Go over all ID nodes, clearing tags. */
|
||||
for (deg::IDNode *id_node : deg_graph->id_nodes) {
|
||||
if (!id_node->is_enabled_on_eval) {
|
||||
id_node->id_invisible_recalc |= id_node->id_cow->recalc;
|
||||
}
|
||||
else {
|
||||
id_node->id_invisible_recalc = 0;
|
||||
}
|
||||
|
||||
if (backup) {
|
||||
id_node->id_cow_recalc_backup |= id_node->id_cow->recalc;
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include "intern/debug/deg_debug.h"
|
||||
#include "intern/depsgraph.h"
|
||||
#include "intern/depsgraph_relation.h"
|
||||
#include "intern/depsgraph_tag.h"
|
||||
#include "intern/depsgraph_type.h"
|
||||
#include "intern/depsgraph_update.h"
|
||||
#include "intern/node/deg_node.h"
|
||||
@@ -99,6 +100,18 @@ inline void flush_prepare(Depsgraph *graph)
|
||||
|
||||
inline void flush_schedule_entrypoints(Depsgraph *graph, FlushQueue *queue)
|
||||
{
|
||||
/* Something changed in the scene, so re-tag IDs with flags which were previously ignored due to
|
||||
* ID being hidden. This will ensure the ID is properly evaluated when it becomes visible. */
|
||||
for (IDNode *node : graph->id_nodes) {
|
||||
if (node->id_invisible_recalc) {
|
||||
graph_id_tag_update(graph->bmain,
|
||||
graph,
|
||||
node->id_orig,
|
||||
node->id_invisible_recalc,
|
||||
DEG_UPDATE_SOURCE_VISIBILITY);
|
||||
}
|
||||
}
|
||||
|
||||
for (OperationNode *op_node : graph->entry_tags) {
|
||||
queue->push_back(op_node);
|
||||
op_node->scheduled = true;
|
||||
|
||||
@@ -75,6 +75,7 @@ void IDNode::init(const ID *id, const char *UNUSED(subdata))
|
||||
has_base = false;
|
||||
is_user_modified = false;
|
||||
id_cow_recalc_backup = 0;
|
||||
id_invisible_recalc = 0;
|
||||
|
||||
visible_components_mask = 0;
|
||||
previously_visible_components_mask = 0;
|
||||
|
||||
@@ -123,6 +123,9 @@ struct IDNode : public Node {
|
||||
/* Accumulate recalc flags from multiple update passes. */
|
||||
int id_cow_recalc_backup;
|
||||
|
||||
/* Flags which components were not evaluated due to ID being invisible. */
|
||||
int id_invisible_recalc;
|
||||
|
||||
IDComponentsMask visible_components_mask;
|
||||
IDComponentsMask previously_visible_components_mask;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user