Depsgraph: support flushing parameters without a full COW update
Avoid computationally expensive copying operations when only some settings have been modified. This is done by adding support for updating parameters without tagging for copy-on-write. Currently only mesh data blocks are supported, other data-blocks can be added individually. This prepares for changing values such as edit-mesh auto-smooth angle in edit-mode without duplicating all mesh-data. The benefit will only be seen when the user interface no longer tags all ID's for copy on write updates. ID_RECALC_GEOMETRY_ALL_MODES has been added to support situations where non edit-mode geometry is modified in edit-mode. While this isn't something user are likely to do, Python scripts may change the underlying mesh. Reviewed By: sergey Ref D11377
This commit is contained in:
parent
67b352f9c5
commit
27da305a40
Notes:
blender-bot
2023-02-14 09:24:53 +01:00
Referenced by commitcbdddc5648
, Workaround for assert from27da305a40
Referenced by issue #90476, Intermittent failure of cycles texture_space_mesh_modifier test Referenced by issue #88550, Mesh Optimization Project Progress
|
@ -315,6 +315,9 @@ void BKE_id_blend_write(struct BlendWriter *writer, struct ID *id);
|
|||
|
||||
#define IS_TAGGED(_id) ((_id) && (((ID *)_id)->tag & LIB_TAG_DOIT))
|
||||
|
||||
/* lib_id_eval.c */
|
||||
void BKE_id_eval_properties_copy(struct ID *id_cow, struct ID *id);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -165,6 +165,7 @@ set(SRC
|
|||
intern/layer_utils.c
|
||||
intern/lib_id.c
|
||||
intern/lib_id_delete.c
|
||||
intern/lib_id_eval.c
|
||||
intern/lib_override.c
|
||||
intern/lib_query.c
|
||||
intern/lib_remap.c
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \ingroup bke
|
||||
*
|
||||
* Contains management of ID's and libraries
|
||||
* allocate and free of all library data
|
||||
*/
|
||||
|
||||
#include "DNA_ID.h"
|
||||
#include "DNA_mesh_types.h"
|
||||
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "BKE_lib_id.h"
|
||||
#include "BKE_mesh.h"
|
||||
|
||||
/**
|
||||
* Copy relatives parameters, from `id` to `id_cow`.
|
||||
* Use handle the #ID_RECALC_PARAMETERS tag.
|
||||
* \note Keep in sync with #ID_TYPE_SUPPORTS_PARAMS_WITHOUT_COW.
|
||||
*/
|
||||
void BKE_id_eval_properties_copy(ID *id_cow, ID *id)
|
||||
{
|
||||
const ID_Type id_type = GS(id->name);
|
||||
BLI_assert((id_cow->tag & LIB_TAG_COPIED_ON_WRITE) && !(id->tag & LIB_TAG_COPIED_ON_WRITE));
|
||||
BLI_assert(ID_TYPE_SUPPORTS_PARAMS_WITHOUT_COW(id_type));
|
||||
if (id_type == ID_ME) {
|
||||
BKE_mesh_copy_parameters((Mesh *)id_cow, (const Mesh *)id);
|
||||
}
|
||||
else {
|
||||
BLI_assert_unreachable();
|
||||
}
|
||||
}
|
|
@ -1105,7 +1105,7 @@ bool BKE_mesh_validate(Mesh *me, const bool do_verbose, const bool cddata_check_
|
|||
&changed);
|
||||
|
||||
if (changed) {
|
||||
DEG_id_tag_update(&me->id, ID_RECALC_GEOMETRY);
|
||||
DEG_id_tag_update(&me->id, ID_RECALC_GEOMETRY_ALL_MODES);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1183,7 +1183,7 @@ bool BKE_mesh_validate_material_indices(Mesh *me)
|
|||
}
|
||||
|
||||
if (!is_valid) {
|
||||
DEG_id_tag_update(&me->id, ID_RECALC_GEOMETRY);
|
||||
DEG_id_tag_update(&me->id, ID_RECALC_GEOMETRY_ALL_MODES);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -1810,7 +1810,7 @@ void BKE_sculpt_color_layer_create_if_needed(struct Object *object)
|
|||
|
||||
CustomData_add_layer(&orig_me->vdata, CD_PROP_COLOR, CD_DEFAULT, NULL, orig_me->totvert);
|
||||
BKE_mesh_update_customdata_pointers(orig_me, true);
|
||||
DEG_id_tag_update(&orig_me->id, ID_RECALC_GEOMETRY);
|
||||
DEG_id_tag_update(&orig_me->id, ID_RECALC_GEOMETRY_ALL_MODES);
|
||||
}
|
||||
|
||||
/** \warning Expects a fully evaluated depsgraph. */
|
||||
|
|
|
@ -1215,7 +1215,19 @@ void DepsgraphNodeBuilder::build_parameters(ID *id)
|
|||
op_node = add_operation_node(id, NodeType::PARAMETERS, OperationCode::PARAMETERS_ENTRY);
|
||||
op_node->set_as_entry();
|
||||
/* Generic evaluation node. */
|
||||
add_operation_node(id, NodeType::PARAMETERS, OperationCode::PARAMETERS_EVAL);
|
||||
|
||||
if (ID_TYPE_SUPPORTS_PARAMS_WITHOUT_COW(GS(id->name))) {
|
||||
ID *id_cow = get_cow_id(id);
|
||||
add_operation_node(
|
||||
id,
|
||||
NodeType::PARAMETERS,
|
||||
OperationCode::PARAMETERS_EVAL,
|
||||
[id_cow, id](::Depsgraph * /*depsgraph*/) { BKE_id_eval_properties_copy(id_cow, id); });
|
||||
}
|
||||
else {
|
||||
add_operation_node(id, NodeType::PARAMETERS, OperationCode::PARAMETERS_EVAL);
|
||||
}
|
||||
|
||||
/* Explicit exit operation. */
|
||||
op_node = add_operation_node(id, NodeType::PARAMETERS, OperationCode::PARAMETERS_EXIT);
|
||||
op_node->set_as_exit();
|
||||
|
|
|
@ -230,6 +230,7 @@ void depsgraph_tag_to_component_opcode(const ID *id,
|
|||
case ID_RECALC_SOURCE:
|
||||
*component_type = NodeType::PARAMETERS;
|
||||
break;
|
||||
case ID_RECALC_GEOMETRY_ALL_MODES:
|
||||
case ID_RECALC_ALL:
|
||||
case ID_RECALC_PSYS_ALL:
|
||||
BLI_assert(!"Should not happen");
|
||||
|
@ -705,6 +706,8 @@ const char *DEG_update_tag_as_string(IDRecalcFlag flag)
|
|||
return "TRANSFORM";
|
||||
case ID_RECALC_GEOMETRY:
|
||||
return "GEOMETRY";
|
||||
case ID_RECALC_GEOMETRY_ALL_MODES:
|
||||
return "GEOMETRY_ALL_MODES";
|
||||
case ID_RECALC_ANIMATION:
|
||||
return "ANIMATION";
|
||||
case ID_RECALC_PSYS_REDO:
|
||||
|
|
|
@ -23,7 +23,9 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "intern/eval/deg_eval_copy_on_write.h"
|
||||
#include "intern/node/deg_node.h"
|
||||
#include "intern/node/deg_node_id.h"
|
||||
#include "intern/node/deg_node_operation.h"
|
||||
|
||||
#include "BLI_string.h"
|
||||
|
@ -172,7 +174,6 @@ 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(Parameters);
|
||||
DEG_COMPONENT_NODE_DECLARE_GENERIC(Particles);
|
||||
DEG_COMPONENT_NODE_DECLARE_GENERIC(ParticleSettings);
|
||||
DEG_COMPONENT_NODE_DECLARE_GENERIC(Pose);
|
||||
|
@ -199,6 +200,21 @@ struct BoneComponentNode : public ComponentNode {
|
|||
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 {
|
||||
virtual bool need_tag_cow_before_update() override
|
||||
{
|
||||
if (ID_TYPE_SUPPORTS_PARAMS_WITHOUT_COW(owner->id_type)) {
|
||||
BLI_assert(deg_copy_on_write_is_expanded(owner->id_cow));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
DEG_COMPONENT_NODE_DECLARE;
|
||||
};
|
||||
|
||||
void deg_register_component_depsnodes();
|
||||
|
||||
} // namespace deg
|
||||
|
|
|
@ -4753,7 +4753,7 @@ static int edbm_separate_exec(bContext *C, wmOperator *op)
|
|||
.calc_object_remap = true,
|
||||
}));
|
||||
|
||||
DEG_id_tag_update(&me->id, ID_RECALC_GEOMETRY);
|
||||
DEG_id_tag_update(&me->id, ID_RECALC_GEOMETRY_ALL_MODES);
|
||||
WM_event_add_notifier(C, NC_GEOM | ND_DATA, me);
|
||||
}
|
||||
|
||||
|
|
|
@ -454,6 +454,10 @@ typedef struct PreviewImage {
|
|||
#define ID_TYPE_IS_COW(_id_type) \
|
||||
(!ELEM(_id_type, ID_LI, ID_IP, ID_SCR, ID_VF, ID_BR, ID_WM, ID_PAL, ID_PC, ID_WS, ID_IM))
|
||||
|
||||
/* Check whether data-block type requires copy-on-write from #ID_RECALC_PARAMETERS.
|
||||
* Keep in sync with #BKE_id_eval_properties_copy. */
|
||||
#define ID_TYPE_SUPPORTS_PARAMS_WITHOUT_COW(id_type) ELEM(id_type, ID_ME)
|
||||
|
||||
#ifdef GS
|
||||
# undef GS
|
||||
#endif
|
||||
|
@ -602,10 +606,18 @@ typedef enum IDRecalcFlag {
|
|||
*
|
||||
* When object of armature type gets tagged with this flag, its pose is
|
||||
* re-evaluated.
|
||||
*
|
||||
* When object of other type is tagged with this flag it makes the modifier
|
||||
* stack to be re-evaluated.
|
||||
*
|
||||
* When object data type (mesh, curve, ...) gets tagged with this flag it
|
||||
* makes all objects which shares this data-block to be updated.
|
||||
*
|
||||
* Note that the evaluation depends on the object-mode.
|
||||
* So edit-mesh data for example only reevaluate with the updated edit-mesh.
|
||||
* When geometry in the original ID has been modified #ID_RECALC_GEOMETRY_ALL_MODES
|
||||
* must be used instead.
|
||||
*
|
||||
* When a collection gets tagged with this flag, all objects depending on the geometry and
|
||||
* transforms on any of the objects in the collection are updated. */
|
||||
ID_RECALC_GEOMETRY = (1 << 1),
|
||||
|
@ -665,6 +677,10 @@ typedef enum IDRecalcFlag {
|
|||
|
||||
ID_RECALC_AUDIO = (1 << 20),
|
||||
|
||||
/* NOTE: This triggers copy on write for types that require it.
|
||||
* Exceptions to this can be added using #ID_TYPE_SUPPORTS_PARAMS_WITHOUT_COW,
|
||||
* this has the advantage that large arrays stored in the idea data don't
|
||||
* have to be copied on every update. */
|
||||
ID_RECALC_PARAMETERS = (1 << 21),
|
||||
|
||||
/* Input has changed and datablock is to be reload from disk.
|
||||
|
@ -689,6 +705,11 @@ typedef enum IDRecalcFlag {
|
|||
* all dependent objects. */
|
||||
ID_RECALC_ANIMATION_NO_FLUSH = ID_RECALC_COPY_ON_WRITE,
|
||||
|
||||
/* Ensure geometry of object and edit modes are both up-to-date in the evaluated data-block.
|
||||
* Example usage is when mesh validation modifies the non-edit-mode data,
|
||||
* which we want to be copied over to the evaluated data-block. */
|
||||
ID_RECALC_GEOMETRY_ALL_MODES = ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE,
|
||||
|
||||
/***************************************************************************
|
||||
* Aggregate flags, use only for checks on runtime.
|
||||
* Do NOT use those for tagging. */
|
||||
|
|
|
@ -239,6 +239,19 @@ static void rna_Mesh_update_data_legacy_deg_tag_all(Main *UNUSED(bmain),
|
|||
WM_main_add_notifier(NC_GEOM | ND_DATA, id);
|
||||
}
|
||||
|
||||
static void rna_Mesh_update_geom_and_params(Main *UNUSED(bmain),
|
||||
Scene *UNUSED(scene),
|
||||
PointerRNA *ptr)
|
||||
{
|
||||
ID *id = ptr->owner_id;
|
||||
if (id->us <= 0) { /* See note in section heading. */
|
||||
return;
|
||||
}
|
||||
|
||||
DEG_id_tag_update(id, ID_RECALC_GEOMETRY | ID_RECALC_PARAMETERS);
|
||||
WM_main_add_notifier(NC_GEOM | ND_DATA, id);
|
||||
}
|
||||
|
||||
static void rna_Mesh_update_data_edit_weight(Main *bmain, Scene *scene, PointerRNA *ptr)
|
||||
{
|
||||
BKE_mesh_batch_cache_dirty_tag(rna_mesh(ptr), BKE_MESH_BATCH_DIRTY_ALL);
|
||||
|
@ -3333,7 +3346,7 @@ static void rna_def_mesh(BlenderRNA *brna)
|
|||
"Auto Smooth",
|
||||
"Auto smooth (based on smooth/sharp faces/edges and angle between faces), "
|
||||
"or use custom split normals data if available");
|
||||
RNA_def_property_update(prop, 0, "rna_Mesh_update_data_legacy_deg_tag_all");
|
||||
RNA_def_property_update(prop, 0, "rna_Mesh_update_geom_and_params");
|
||||
|
||||
prop = RNA_def_property(srna, "auto_smooth_angle", PROP_FLOAT, PROP_ANGLE);
|
||||
RNA_def_property_float_sdna(prop, NULL, "smoothresh");
|
||||
|
@ -3342,7 +3355,7 @@ static void rna_def_mesh(BlenderRNA *brna)
|
|||
"Auto Smooth Angle",
|
||||
"Maximum angle between face normals that will be considered as smooth "
|
||||
"(unused if custom split normals data are available)");
|
||||
RNA_def_property_update(prop, 0, "rna_Mesh_update_data_legacy_deg_tag_all");
|
||||
RNA_def_property_update(prop, 0, "rna_Mesh_update_geom_and_params");
|
||||
|
||||
RNA_define_verify_sdna(false);
|
||||
prop = RNA_def_property(srna, "has_custom_normals", PROP_BOOLEAN, PROP_NONE);
|
||||
|
@ -3373,7 +3386,7 @@ static void rna_def_mesh(BlenderRNA *brna)
|
|||
prop,
|
||||
"Auto Texture Space",
|
||||
"Adjust active object's texture space automatically when transforming object");
|
||||
RNA_def_property_update(prop, 0, "rna_Mesh_update_data_legacy_deg_tag_all");
|
||||
RNA_def_property_update(prop, 0, "rna_Mesh_update_geom_and_params");
|
||||
|
||||
# if 0
|
||||
prop = RNA_def_property(srna, "texspace_location", PROP_FLOAT, PROP_TRANSLATION);
|
||||
|
|
|
@ -208,7 +208,7 @@ static void rna_Mesh_clear_geometry(Mesh *mesh)
|
|||
{
|
||||
BKE_mesh_clear_geometry(mesh);
|
||||
|
||||
DEG_id_tag_update(&mesh->id, ID_RECALC_GEOMETRY);
|
||||
DEG_id_tag_update(&mesh->id, ID_RECALC_GEOMETRY_ALL_MODES);
|
||||
WM_main_add_notifier(NC_GEOM | ND_DATA, mesh);
|
||||
}
|
||||
|
||||
|
|
|
@ -1060,7 +1060,7 @@ static PyObject *bpy_bmesh_to_mesh(BPy_BMesh *self, PyObject *args)
|
|||
|
||||
/* we could have the user do this but if they forget blender can easy crash
|
||||
* since the references arrays for the objects derived meshes are now invalid */
|
||||
DEG_id_tag_update(&me->id, ID_RECALC_GEOMETRY);
|
||||
DEG_id_tag_update(&me->id, ID_RECALC_GEOMETRY_ALL_MODES);
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue