WIP: Mesh: Improve and simplify modifier evaluation logic #119968

Draft
Hans Goudey wants to merge 28 commits from HooglyBoogly/blender:fix-modifier-eval-geometry-set-improve into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
6 changed files with 287 additions and 401 deletions

View File

@ -168,6 +168,13 @@ struct GeometrySet {
return static_cast<Component &>(this->get_component_for_write(Component::static_type)); return static_cast<Component &>(this->get_component_for_write(Component::static_type));
} }
GeometryComponentPtr get_component_ptr(GeometryComponent::Type component_type) const;
template<typename Component> ImplicitSharingPtr<Component> get_component_ptr() const
{
BLI_STATIC_ASSERT(is_geometry_component_v<Component>, "");
return static_cast<ImplicitSharingPtr<Component>>(components_(Component::static_type));
}
/** /**
* Get the component of the given type. Might return null if the component does not exist yet. * Get the component of the given type. Might return null if the component does not exist yet.
*/ */
@ -428,11 +435,11 @@ struct GeometrySet {
* Retrieve the pointer to a component without creating it if it does not exist, * Retrieve the pointer to a component without creating it if it does not exist,
* unlike #get_component_for_write. * unlike #get_component_for_write.
*/ */
GeometryComponent *get_component_ptr(GeometryComponent::Type type); GeometryComponent *get_component_for_write_ptr(GeometryComponent::Type type);
template<typename Component> Component *get_component_ptr() template<typename Component> Component *get_component_for_write_ptr()
{ {
BLI_STATIC_ASSERT(is_geometry_component_v<Component>, ""); BLI_STATIC_ASSERT(is_geometry_component_v<Component>, "");
return static_cast<Component *>(get_component_ptr(Component::static_type)); return static_cast<Component *>(get_component_for_write_ptr(Component::static_type));
} }
}; };
@ -675,6 +682,25 @@ class VolumeComponent : public GeometryComponent {
static constexpr inline GeometryComponent::Type static_type = Type::Volume; static constexpr inline GeometryComponent::Type static_type = Type::Volume;
}; };
struct MeshEditHints {
/**
* Mesh created by object evaluation. It only has leading deformation modifiers applied.
*
* \todo This should use a similar system to #CurvesEditHints storing just an array for the
* deformed positions, but for historical reasons we copy the whole mesh.
*/
ImplicitSharingPtr<MeshComponent> mesh_deform;
/**
* Evaluated mesh cage in edit mode.
*
* \note When the mesh's `runtime->deformed_only` is true, its vertex positions and other
* geometry arrays will be aligned the edit-mesh. Otherwise the #CD_ORIGINDEX custom-data should
* be used to map the cage geometry back to the original indices, see
* #eModifierTypeFlag_SupportsMapping.
*/
ImplicitSharingPtr<MeshComponent> mesh_cage;
};
/** /**
* When the original data is in some edit mode, we want to propagate some additional information * When the original data is in some edit mode, we want to propagate some additional information
* through object evaluation. This information can be used by edit modes to support working on * through object evaluation. This information can be used by edit modes to support working on
@ -696,6 +722,8 @@ class GeometryComponentEditData final : public GeometryComponent {
*/ */
std::unique_ptr<GreasePencilEditHints> grease_pencil_edit_hints_; std::unique_ptr<GreasePencilEditHints> grease_pencil_edit_hints_;
std::unique_ptr<MeshEditHints> mesh_edit_hints_;
GeometryComponentEditData(); GeometryComponentEditData();
GeometryComponentPtr copy() const final; GeometryComponentPtr copy() const final;

View File

@ -84,22 +84,6 @@ struct ObjectRuntime {
*/ */
GeometrySet *geometry_set_eval = nullptr; GeometrySet *geometry_set_eval = nullptr;
/**
* Mesh structure created during object evaluation.
* It has deformation only modifiers applied on it.
*/
Mesh *mesh_deform_eval = nullptr;
/**
* Evaluated mesh cage in edit mode.
*
* \note When the mesh's `runtime->deformed_only` is true, the meshes vertex positions
* and other geometry arrays will be aligned the edit-mesh. Otherwise the #CD_ORIGINDEX
* custom-data should be used to map the cage geometry back to the original indices, see
* #eModifierTypeFlag_SupportsMapping.
*/
Mesh *editmesh_eval_cage = nullptr;
/** /**
* Original grease pencil bGPdata pointer, before object->data was changed to point * Original grease pencil bGPdata pointer, before object->data was changed to point
* to gpd_eval. * to gpd_eval.

View File

@ -133,7 +133,7 @@ GeometryComponent &GeometrySet::get_component_for_write(GeometryComponent::Type
return const_cast<GeometryComponent &>(*component_ptr); return const_cast<GeometryComponent &>(*component_ptr);
} }
GeometryComponent *GeometrySet::get_component_ptr(GeometryComponent::Type type) GeometryComponent *GeometrySet::get_component_for_write_ptr(GeometryComponent::Type type)
{ {
if (this->has(type)) { if (this->has(type)) {
return &this->get_component_for_write(type); return &this->get_component_for_write(type);
@ -529,31 +529,31 @@ void GeometrySet::replace_grease_pencil(GreasePencil *grease_pencil,
Mesh *GeometrySet::get_mesh_for_write() Mesh *GeometrySet::get_mesh_for_write()
{ {
MeshComponent *component = this->get_component_ptr<MeshComponent>(); MeshComponent *component = this->get_component_for_write_ptr<MeshComponent>();
return component == nullptr ? nullptr : component->get_for_write(); return component == nullptr ? nullptr : component->get_for_write();
} }
PointCloud *GeometrySet::get_pointcloud_for_write() PointCloud *GeometrySet::get_pointcloud_for_write()
{ {
PointCloudComponent *component = this->get_component_ptr<PointCloudComponent>(); PointCloudComponent *component = this->get_component_for_write_ptr<PointCloudComponent>();
return component == nullptr ? nullptr : component->get_for_write(); return component == nullptr ? nullptr : component->get_for_write();
} }
Volume *GeometrySet::get_volume_for_write() Volume *GeometrySet::get_volume_for_write()
{ {
VolumeComponent *component = this->get_component_ptr<VolumeComponent>(); VolumeComponent *component = this->get_component_for_write_ptr<VolumeComponent>();
return component == nullptr ? nullptr : component->get_for_write(); return component == nullptr ? nullptr : component->get_for_write();
} }
Curves *GeometrySet::get_curves_for_write() Curves *GeometrySet::get_curves_for_write()
{ {
CurveComponent *component = this->get_component_ptr<CurveComponent>(); CurveComponent *component = this->get_component_for_write_ptr<CurveComponent>();
return component == nullptr ? nullptr : component->get_for_write(); return component == nullptr ? nullptr : component->get_for_write();
} }
Instances *GeometrySet::get_instances_for_write() Instances *GeometrySet::get_instances_for_write()
{ {
InstancesComponent *component = this->get_component_ptr<InstancesComponent>(); InstancesComponent *component = this->get_component_for_write_ptr<InstancesComponent>();
return component == nullptr ? nullptr : component->get_for_write(); return component == nullptr ? nullptr : component->get_for_write();
} }
@ -569,7 +569,7 @@ CurvesEditHints *GeometrySet::get_curve_edit_hints_for_write()
GreasePencil *GeometrySet::get_grease_pencil_for_write() GreasePencil *GeometrySet::get_grease_pencil_for_write()
{ {
GreasePencilComponent *component = this->get_component_ptr<GreasePencilComponent>(); GreasePencilComponent *component = this->get_component_for_write_ptr<GreasePencilComponent>();
return component == nullptr ? nullptr : component->get_for_write(); return component == nullptr ? nullptr : component->get_for_write();
} }

View File

@ -240,50 +240,26 @@ static void mesh_calc_finalize(const Mesh &mesh_input, Mesh &mesh_eval)
* The purpose of the geometry set is to store all geometry components that are generated * The purpose of the geometry set is to store all geometry components that are generated
* by modifiers to allow outputting non-mesh data from modifiers. * by modifiers to allow outputting non-mesh data from modifiers.
*/ */
static Mesh *modifier_modify_mesh_and_geometry_set(ModifierData *md, static void modifier_modify_mesh_and_geometry_set(ModifierData *md,
const ModifierEvalContext &mectx, const ModifierEvalContext &mectx,
Mesh *input_mesh, GeometrySet &geometry_set)
GeometrySet &geometry_set)
{ {
Mesh *mesh_output = nullptr;
const ModifierTypeInfo *mti = BKE_modifier_get_info((ModifierType)md->type); const ModifierTypeInfo *mti = BKE_modifier_get_info((ModifierType)md->type);
if (mti->modify_geometry_set == nullptr) { if (mti->modify_geometry_set) {
mesh_output = BKE_modifier_modify_mesh(md, &mectx, input_mesh); if (Mesh *mesh = geometry_set.get_mesh_for_write()) {
BKE_mesh_wrapper_ensure_mdata(mesh);
}
mti->modify_geometry_set(md, &mectx, &geometry_set);
} }
else { else {
/* For performance reasons, this should be called by the modifier and/or nodes themselves at if (Mesh *mesh = geometry_set.get_mesh_for_write()) {
* some point. */ geometry_set.replace_mesh(BKE_modifier_modify_mesh(md, &mectx, mesh));
BKE_mesh_wrapper_ensure_mdata(input_mesh);
/* Replace only the mesh rather than the whole component, because the entire #MeshComponent
* might have been replaced by data from a different object in the node tree, which means the
* component contains vertex group name data for that object that should not be removed. */
geometry_set.replace_mesh(input_mesh, GeometryOwnershipType::Editable);
/* Let the modifier change the geometry set. */
mti->modify_geometry_set(md, &mectx, &geometry_set);
/* Release the mesh from the geometry set again. */
if (geometry_set.has<MeshComponent>()) {
MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>();
if (mesh_component.get() != input_mesh) {
/* Make sure the mesh component actually owns the mesh before taking over ownership. */
mesh_component.ensure_owns_direct_data();
}
mesh_output = mesh_component.release();
}
/* Need to ensure that non-mesh data is also owned by the geometry set. Otherwise it might be
* freed while there is still a reference to it in the geometry. */
geometry_set.ensure_owns_direct_data();
/* Return an empty mesh instead of null. */
if (mesh_output == nullptr) {
mesh_output = BKE_mesh_new_nomain(0, 0, 0, 0);
BKE_mesh_copy_parameters_for_eval(mesh_output, input_mesh);
} }
} }
return mesh_output; if (!geometry_set.has_mesh()) {
geometry_set.replace_mesh(BKE_mesh_new_nomain(0, 0, 0, 0));
}
} }
static void set_rest_position(Mesh &mesh) static void set_rest_position(Mesh &mesh)
@ -305,30 +281,36 @@ static void set_rest_position(Mesh &mesh)
} }
} }
static void mesh_calc_modifiers(Depsgraph &depsgraph, static MeshEditHints &geometry_mesh_edit_hints_ensure(GeometrySet &geometry)
const Scene &scene,
Object &ob,
const bool use_deform,
const bool need_mapping,
const CustomData_MeshMasks &dataMask,
const bool use_cache,
const bool allow_shared_mesh,
/* return args */
Mesh **r_deform,
Mesh **r_final,
GeometrySet **r_geometry_set)
{ {
/* Input mesh shouldn't be modified. */ auto &edit_data = geometry.get_component_for_write<GeometryComponentEditData>();
Mesh &mesh_input = *static_cast<Mesh *>(ob.data); if (!edit_data.mesh_edit_hints_) {
/* The final mesh is the result of calculating all enabled modifiers. */ edit_data.mesh_edit_hints_ = std::make_unique<MeshEditHints>();
Mesh *mesh = nullptr; }
/* The result of calculating all leading deform modifiers. */ return *edit_data.mesh_edit_hints_;
Mesh *mesh_deform = nullptr; }
/* This geometry set contains the non-mesh data that might be generated by modifiers. */
GeometrySet geometry_set_final; static void save_deform_mesh(GeometrySet &geometry)
{
MeshEditHints &edit_data = geometry_mesh_edit_hints_ensure(geometry);
edit_data.mesh_deform = geometry.get_component_ptr<MeshComponent>();
}
static GeometrySet mesh_calc_modifiers(Depsgraph &depsgraph,
const Scene &scene,
Object &ob,
const bool use_deform,
const bool need_mapping,
const CustomData_MeshMasks &dataMask,
const bool use_cache)
{
const Mesh &mesh_input = *static_cast<const Mesh *>(ob.data);
BLI_assert((mesh_input.id.tag & LIB_TAG_COPIED_ON_EVAL_FINAL_RESULT) == 0); BLI_assert((mesh_input.id.tag & LIB_TAG_COPIED_ON_EVAL_FINAL_RESULT) == 0);
GeometrySet geometry_set = GeometrySet::from_mesh(const_cast<Mesh *>(&mesh_input),
GeometryOwnershipType::ReadOnly);
/* Mesh with constructive modifiers but no deformation applied. Tracked /* Mesh with constructive modifiers but no deformation applied. Tracked
* along with final mesh if undeformed / orco coordinates are requested * along with final mesh if undeformed / orco coordinates are requested
* for texturing. */ * for texturing. */
@ -371,11 +353,9 @@ static void mesh_calc_modifiers(Depsgraph &depsgraph,
BKE_modifiers_clear_errors(&ob); BKE_modifiers_clear_errors(&ob);
if (ob.modifier_flag & OB_MODIFIER_FLAG_ADD_REST_POSITION) { if (ob.modifier_flag & OB_MODIFIER_FLAG_ADD_REST_POSITION) {
if (mesh == nullptr) { if (Mesh *mesh = geometry_set.get_mesh_for_write()) {
mesh = BKE_mesh_copy_for_eval(mesh_input); set_rest_position(*mesh);
ASSERT_IS_VALID_MESH(mesh);
} }
set_rest_position(*mesh);
} }
/* Apply all leading deform modifiers. */ /* Apply all leading deform modifiers. */
@ -389,20 +369,17 @@ static void mesh_calc_modifiers(Depsgraph &depsgraph,
if (mti->type == ModifierTypeType::OnlyDeform && !sculpt_dyntopo) { if (mti->type == ModifierTypeType::OnlyDeform && !sculpt_dyntopo) {
ScopedModifierTimer modifier_timer{*md}; ScopedModifierTimer modifier_timer{*md};
if (!mesh) { if (Mesh *mesh = geometry_set.get_mesh_for_write()) {
mesh = BKE_mesh_copy_for_eval(mesh_input); if (mti->required_data_mask) {
ASSERT_IS_VALID_MESH(mesh); CustomData_MeshMasks mask{};
} mti->required_data_mask(md, &mask);
if (mask.vmask & CD_MASK_ORCO) {
if (mti->required_data_mask) { add_orco_mesh(ob, nullptr, *mesh, nullptr, CD_ORCO);
CustomData_MeshMasks mask{}; }
mti->required_data_mask(md, &mask);
if (mask.vmask & CD_MASK_ORCO) {
add_orco_mesh(ob, nullptr, *mesh, nullptr, CD_ORCO);
} }
}
BKE_modifier_deform_verts(md, &mectx, mesh, mesh->vert_positions_for_write()); BKE_modifier_deform_verts(md, &mectx, mesh, mesh->vert_positions_for_write());
}
} }
else { else {
break; break;
@ -412,9 +389,7 @@ static void mesh_calc_modifiers(Depsgraph &depsgraph,
/* Result of all leading deforming modifiers is cached for /* Result of all leading deforming modifiers is cached for
* places that wish to use the original mesh but with deformed * places that wish to use the original mesh but with deformed
* coordinates (like vertex paint). */ * coordinates (like vertex paint). */
if (r_deform) { save_deform_mesh(geometry_set);
mesh_deform = BKE_mesh_copy_for_eval(mesh ? *mesh : mesh_input);
}
} }
/* Apply all remaining constructive and deforming modifiers. */ /* Apply all remaining constructive and deforming modifiers. */
@ -475,42 +450,28 @@ static void mesh_calc_modifiers(Depsgraph &depsgraph,
ScopedModifierTimer modifier_timer{*md}; ScopedModifierTimer modifier_timer{*md};
/* Add orco mesh as layer if needed by this modifier. */ /* Add orco mesh as layer if needed by this modifier. */
if (mesh && mesh_orco && mti->required_data_mask) { if (Mesh *mesh = geometry_set.get_mesh_for_write()) {
CustomData_MeshMasks mask = {0}; if (mesh_orco && mti->required_data_mask) {
mti->required_data_mask(md, &mask); CustomData_MeshMasks mask = {0};
if (mask.vmask & CD_MASK_ORCO) { mti->required_data_mask(md, &mask);
add_orco_mesh(ob, nullptr, *mesh, mesh_orco, CD_ORCO); if (mask.vmask & CD_MASK_ORCO) {
add_orco_mesh(ob, nullptr, *mesh, mesh_orco, CD_ORCO);
}
} }
} }
if (mti->type == ModifierTypeType::OnlyDeform) { if (mti->type == ModifierTypeType::OnlyDeform) {
if (!mesh) { if (Mesh *mesh = geometry_set.get_mesh_for_write()) {
mesh = BKE_mesh_copy_for_eval(mesh_input); BKE_modifier_deform_verts(md, &mectx, mesh, mesh->vert_positions_for_write());
ASSERT_IS_VALID_MESH(mesh);
} }
BKE_modifier_deform_verts(md, &mectx, mesh, mesh->vert_positions_for_write());
} }
else { else {
bool check_for_needs_mapping = false;
if (mesh != nullptr) {
if (have_non_onlydeform_modifiers_applied == false) {
/* If we only deformed, we won't have initialized #CD_ORIGINDEX.
* as this is the only part of the function that initializes mapping. */
check_for_needs_mapping = true;
}
}
else {
mesh = BKE_mesh_copy_for_eval(mesh_input);
ASSERT_IS_VALID_MESH(mesh);
check_for_needs_mapping = true;
}
have_non_onlydeform_modifiers_applied = true; have_non_onlydeform_modifiers_applied = true;
/* determine which data layers are needed by following modifiers */ /* determine which data layers are needed by following modifiers */
CustomData_MeshMasks nextmask = md_datamask->next ? md_datamask->next->mask : final_datamask; CustomData_MeshMasks nextmask = md_datamask->next ? md_datamask->next->mask : final_datamask;
if (check_for_needs_mapping) { if (Mesh *mesh = geometry_set.get_mesh_for_write()) {
/* Initialize original indices the first time we evaluate a /* Initialize original indices the first time we evaluate a
* constructive modifier. Modifiers will then do mapping mostly * constructive modifier. Modifiers will then do mapping mostly
* automatic by copying them through CustomData_copy_data along * automatic by copying them through CustomData_copy_data along
@ -541,45 +502,35 @@ static void mesh_calc_modifiers(Depsgraph &depsgraph,
mesh->faces_num, mesh->faces_num,
0); 0);
} }
}
/* set the Mesh to only copy needed data */ /* set the Mesh to only copy needed data */
CustomData_MeshMasks mask = md_datamask->mask; CustomData_MeshMasks mask = md_datamask->mask;
/* needMapping check here fixes bug #28112, otherwise it's /* needMapping check here fixes bug #28112, otherwise it's
* possible that it won't be copied */ * possible that it won't be copied */
CustomData_MeshMasks_update(&mask, &append_mask); CustomData_MeshMasks_update(&mask, &append_mask);
if (need_mapping) { if (need_mapping) {
mask.vmask |= CD_MASK_ORIGINDEX; mask.vmask |= CD_MASK_ORIGINDEX;
mask.emask |= CD_MASK_ORIGINDEX; mask.emask |= CD_MASK_ORIGINDEX;
mask.pmask |= CD_MASK_ORIGINDEX; mask.pmask |= CD_MASK_ORIGINDEX;
} }
mesh_set_only_copy(mesh, &mask); mesh_set_only_copy(mesh, &mask);
/* add cloth rest shape key if needed */ /* add cloth rest shape key if needed */
if (mask.vmask & CD_MASK_CLOTH_ORCO) { if (mask.vmask & CD_MASK_CLOTH_ORCO) {
add_orco_mesh(ob, nullptr, *mesh, mesh_orco, CD_CLOTH_ORCO); add_orco_mesh(ob, nullptr, *mesh, mesh_orco, CD_CLOTH_ORCO);
} }
/* add an origspace layer if needed */ /* add an origspace layer if needed */
if ((md_datamask->mask.lmask) & CD_MASK_ORIGSPACE_MLOOP) { if ((md_datamask->mask.lmask) & CD_MASK_ORIGSPACE_MLOOP) {
if (!CustomData_has_layer(&mesh->corner_data, CD_ORIGSPACE_MLOOP)) { if (!CustomData_has_layer(&mesh->corner_data, CD_ORIGSPACE_MLOOP)) {
CustomData_add_layer( CustomData_add_layer(
&mesh->corner_data, CD_ORIGSPACE_MLOOP, CD_SET_DEFAULT, mesh->corners_num); &mesh->corner_data, CD_ORIGSPACE_MLOOP, CD_SET_DEFAULT, mesh->corners_num);
mesh_init_origspace(*mesh); mesh_init_origspace(*mesh);
}
} }
} }
Mesh *mesh_next = modifier_modify_mesh_and_geometry_set(md, mectx, mesh, geometry_set_final); modifier_modify_mesh_and_geometry_set(md, mectx, geometry_set);
ASSERT_IS_VALID_MESH(mesh_next);
if (mesh_next) {
/* if the modifier returned a new mesh, release the old one */
if (mesh != mesh_next) {
BLI_assert(mesh != &mesh_input);
BKE_id_free(nullptr, mesh);
}
mesh = mesh_next;
}
/* create an orco mesh in parallel */ /* create an orco mesh in parallel */
if (nextmask.vmask & CD_MASK_ORCO) { if (nextmask.vmask & CD_MASK_ORCO) {
@ -600,17 +551,14 @@ static void mesh_calc_modifiers(Depsgraph &depsgraph,
CustomData_MeshMasks_update(&temp_cddata_masks, &nextmask); CustomData_MeshMasks_update(&temp_cddata_masks, &nextmask);
mesh_set_only_copy(mesh_orco, &temp_cddata_masks); mesh_set_only_copy(mesh_orco, &temp_cddata_masks);
mesh_next = BKE_modifier_modify_mesh(md, &mectx_orco, mesh_orco); Mesh *mesh_orco_new = BKE_modifier_modify_mesh(md, &mectx_orco, mesh_orco);
ASSERT_IS_VALID_MESH(mesh_next); ASSERT_IS_VALID_MESH(mesh_orco_new);
if (mesh_orco_new) {
if (mesh_next) { if (mesh_orco != mesh_orco_new) {
/* if the modifier returned a new mesh, release the old one */ BLI_assert(mesh_orco != mesh_input);
if (mesh_orco != mesh_next) {
BLI_assert(mesh_orco != &mesh_input);
BKE_id_free(nullptr, mesh_orco); BKE_id_free(nullptr, mesh_orco);
} }
mesh_orco = mesh_orco_new;
mesh_orco = mesh_next;
} }
} }
@ -626,21 +574,23 @@ static void mesh_calc_modifiers(Depsgraph &depsgraph,
nextmask.pmask |= CD_MASK_ORIGINDEX; nextmask.pmask |= CD_MASK_ORIGINDEX;
mesh_set_only_copy(mesh_orco_cloth, &nextmask); mesh_set_only_copy(mesh_orco_cloth, &nextmask);
mesh_next = BKE_modifier_modify_mesh(md, &mectx_orco, mesh_orco_cloth); Mesh *mesh_orco_cloth_new = BKE_modifier_modify_mesh(md, &mectx_orco, mesh_orco_cloth);
ASSERT_IS_VALID_MESH(mesh_next); ASSERT_IS_VALID_MESH(mesh_orco_cloth_new);
if (mesh_orco_cloth_new) {
if (mesh_next) { if (mesh_orco_cloth != mesh_orco_cloth_new) {
/* if the modifier returned a new mesh, release the old one */ BLI_assert(mesh_orco != mesh_input);
if (mesh_orco_cloth != mesh_next) {
BLI_assert(mesh_orco != &mesh_input);
BKE_id_free(nullptr, mesh_orco_cloth); BKE_id_free(nullptr, mesh_orco_cloth);
} }
mesh_orco_cloth = mesh_orco_cloth_new;
mesh_orco_cloth = mesh_next;
} }
} }
mesh->runtime->deformed_only = false; if (const Mesh *mesh = geometry_set.get_mesh()) {
if (mesh->runtime->deformed_only) {
Mesh *mesh_mut = geometry_set.get_mesh_for_write();
mesh_mut->runtime->deformed_only = false;
}
}
} }
if (sculpt_mode && md->type == eModifierType_Multires) { if (sculpt_mode && md->type == eModifierType_Multires) {
@ -654,32 +604,6 @@ static void mesh_calc_modifiers(Depsgraph &depsgraph,
BKE_modifier_free_temporary_data(md); BKE_modifier_free_temporary_data(md);
} }
if (mesh == nullptr) {
if (allow_shared_mesh) {
mesh = &mesh_input;
}
else {
mesh = BKE_mesh_copy_for_eval(mesh_input);
}
}
/* Denotes whether the object which the modifier stack came from owns the mesh or whether the
* mesh is shared across multiple objects since there are no effective modifiers. */
const bool is_own_mesh = (mesh != &mesh_input);
/* Add orco coordinates to final and deformed mesh if requested. */
if (final_datamask.vmask & CD_MASK_ORCO) {
/* No need in ORCO layer if the mesh was not deformed or modified: undeformed mesh in this case
* matches input mesh. */
if (is_own_mesh) {
add_orco_mesh(ob, nullptr, *mesh, mesh_orco, CD_ORCO);
}
if (mesh_deform) {
add_orco_mesh(ob, nullptr, *mesh_deform, nullptr, CD_ORCO);
}
}
if (mesh_orco) { if (mesh_orco) {
BKE_id_free(nullptr, mesh_orco); BKE_id_free(nullptr, mesh_orco);
} }
@ -689,44 +613,14 @@ static void mesh_calc_modifiers(Depsgraph &depsgraph,
/* Remove temporary data layer only needed for modifier evaluation. /* Remove temporary data layer only needed for modifier evaluation.
* Save some memory, and ensure GPU subdivision does not need to deal with this. */ * Save some memory, and ensure GPU subdivision does not need to deal with this. */
CustomData_free_layers(&mesh->vert_data, CD_CLOTH_ORCO, mesh->verts_num); if (const Mesh *mesh = geometry_set.get_mesh()) {
if (CustomData_has_layer(&mesh->vert_data, CD_CLOTH_ORCO)) {
/* Compute normals. */ Mesh *mesh_mut = geometry_set.get_mesh_for_write();
if (is_own_mesh) { CustomData_free_layers(&mesh_mut->vert_data, CD_CLOTH_ORCO, mesh_mut->verts_num);
mesh_calc_finalize(mesh_input, *mesh);
}
else {
MeshRuntime *runtime = mesh_input.runtime;
if (runtime->mesh_eval == nullptr) {
std::lock_guard lock{mesh_input.runtime->eval_mutex};
if (runtime->mesh_eval == nullptr) {
/* Not yet finalized by any instance, do it now
* Isolate since computing normals is multithreaded and we are holding a lock. */
threading::isolate_task([&] {
mesh = BKE_mesh_copy_for_eval(mesh_input);
mesh_calc_finalize(mesh_input, *mesh);
runtime->mesh_eval = mesh;
});
}
else {
/* Already finalized by another instance, reuse. */
mesh = runtime->mesh_eval;
}
}
else {
/* Already finalized by another instance, reuse. */
mesh = runtime->mesh_eval;
} }
} }
/* Return final mesh */ return geometry_set;
*r_final = mesh;
if (r_deform) {
*r_deform = mesh_deform;
}
if (r_geometry_set) {
*r_geometry_set = new GeometrySet(std::move(geometry_set_final));
}
} }
bool editbmesh_modifier_is_enabled(const Scene *scene, bool editbmesh_modifier_is_enabled(const Scene *scene,
@ -766,21 +660,19 @@ static MutableSpan<float3> mesh_wrapper_vert_coords_ensure_for_write(Mesh *mesh)
return {}; return {};
} }
static void editbmesh_calc_modifiers(Depsgraph &depsgraph, static void save_cage_mesh(GeometrySet &geometry)
const Scene &scene,
Object &ob,
const CustomData_MeshMasks &dataMask,
/* return args */
Mesh **r_cage,
Mesh **r_final,
GeometrySet **r_geometry_set)
{ {
Mesh &mesh_input = *static_cast<Mesh *>(ob.data); MeshEditHints &edit_data = geometry_mesh_edit_hints_ensure(geometry);
BMEditMesh &em_input = *mesh_input.runtime->edit_mesh; edit_data.mesh_cage = geometry.get_component_ptr<MeshComponent>();
}
Mesh *mesh_cage = nullptr; static GeometrySet editbmesh_calc_modifiers(Depsgraph &depsgraph,
/* This geometry set contains the non-mesh data that might be generated by modifiers. */ const Scene &scene,
GeometrySet geometry_set_final; Object &ob,
const CustomData_MeshMasks &dataMask)
{
const Mesh &mesh_input = *static_cast<const Mesh *>(ob.data);
const BMEditMesh &em_input = *mesh_input.runtime->edit_mesh;
/* Mesh with constructive modifiers but no deformation applied. Tracked /* Mesh with constructive modifiers but no deformation applied. Tracked
* along with final mesh if undeformed / orco coordinates are requested * along with final mesh if undeformed / orco coordinates are requested
@ -810,12 +702,12 @@ static void editbmesh_calc_modifiers(Depsgraph &depsgraph,
CDMaskLink *md_datamask = datamasks; CDMaskLink *md_datamask = datamasks;
CustomData_MeshMasks append_mask = CD_MASK_BAREMESH; CustomData_MeshMasks append_mask = CD_MASK_BAREMESH;
Mesh *mesh = BKE_mesh_wrapper_from_editmesh( GeometrySet geometry_set = GeometrySet::from_mesh(
mesh_input.runtime->edit_mesh, &final_datamask, &mesh_input); BKE_mesh_wrapper_from_editmesh(mesh_input.runtime->edit_mesh, &final_datamask, &mesh_input));
int cageIndex = BKE_modifiers_get_cage_index(&scene, &ob, nullptr, true); int cageIndex = BKE_modifiers_get_cage_index(&scene, &ob, nullptr, true);
if (r_cage && cageIndex == -1) { if (cageIndex == -1) {
mesh_cage = mesh; save_cage_mesh(geometry_set);
} }
/* The mesh from edit mode should not have any original index layers already, since those /* The mesh from edit mode should not have any original index layers already, since those
@ -828,8 +720,10 @@ static void editbmesh_calc_modifiers(Depsgraph &depsgraph,
BKE_modifiers_clear_errors(&ob); BKE_modifiers_clear_errors(&ob);
if (ob.modifier_flag & OB_MODIFIER_FLAG_ADD_REST_POSITION) { if (ob.modifier_flag & OB_MODIFIER_FLAG_ADD_REST_POSITION) {
BKE_mesh_wrapper_ensure_mdata(mesh); if (Mesh *mesh = geometry_set.get_mesh_for_write()) {
set_rest_position(*mesh); BKE_mesh_wrapper_ensure_mdata(mesh);
set_rest_position(*mesh);
}
} }
bool non_deform_modifier_applied = false; bool non_deform_modifier_applied = false;
@ -840,6 +734,7 @@ static void editbmesh_calc_modifiers(Depsgraph &depsgraph,
} }
ScopedModifierTimer modifier_timer{*md}; ScopedModifierTimer modifier_timer{*md};
Mesh *mesh = geometry_set.get_mesh_for_write();
/* Add an orco mesh as layer if needed by this modifier. */ /* Add an orco mesh as layer if needed by this modifier. */
if (mesh_orco && mti->required_data_mask) { if (mesh_orco && mti->required_data_mask) {
@ -850,21 +745,6 @@ static void editbmesh_calc_modifiers(Depsgraph &depsgraph,
} }
} }
if (mesh == mesh_cage) {
/* If the cage mesh has already been assigned, we have passed the cage index in the modifier
* list. If the cage and final meshes are still the same, duplicate the final mesh so the
* cage mesh isn't modified anymore. */
mesh = BKE_mesh_copy_for_eval(*mesh);
if (mesh_cage->runtime->edit_mesh) {
mesh->runtime->edit_mesh = mesh_cage->runtime->edit_mesh;
mesh->runtime->is_original_bmesh = true;
if (mesh_cage->runtime->edit_data) {
mesh->runtime->edit_data = std::make_unique<EditMeshData>(
*mesh_cage->runtime->edit_data);
}
}
}
if (mti->type == ModifierTypeType::OnlyDeform) { if (mti->type == ModifierTypeType::OnlyDeform) {
if (mti->deform_verts_EM) { if (mti->deform_verts_EM) {
BKE_modifier_deform_vertsEM( BKE_modifier_deform_vertsEM(
@ -914,30 +794,25 @@ static void editbmesh_calc_modifiers(Depsgraph &depsgraph,
mask.emask |= CD_MASK_ORIGINDEX; mask.emask |= CD_MASK_ORIGINDEX;
mask.pmask |= CD_MASK_ORIGINDEX; mask.pmask |= CD_MASK_ORIGINDEX;
mesh_set_only_copy(mesh, &mask); if (Mesh *mesh = geometry_set.get_mesh_for_write()) {
mesh_set_only_copy(mesh, &mask);
if (mask.lmask & CD_MASK_ORIGSPACE_MLOOP) { if (mask.lmask & CD_MASK_ORIGSPACE_MLOOP) {
if (!CustomData_has_layer(&mesh->corner_data, CD_ORIGSPACE_MLOOP)) { if (!CustomData_has_layer(&mesh->corner_data, CD_ORIGSPACE_MLOOP)) {
CustomData_add_layer( CustomData_add_layer(
&mesh->corner_data, CD_ORIGSPACE_MLOOP, CD_SET_DEFAULT, mesh->corners_num); &mesh->corner_data, CD_ORIGSPACE_MLOOP, CD_SET_DEFAULT, mesh->corners_num);
mesh_init_origspace(*mesh); mesh_init_origspace(*mesh);
}
} }
mesh->runtime->deformed_only = false;
} }
Mesh *mesh_next = modifier_modify_mesh_and_geometry_set(md, mectx, mesh, geometry_set_final); modifier_modify_mesh_and_geometry_set(md, mectx, geometry_set);
ASSERT_IS_VALID_MESH(mesh_next);
if (mesh_next) {
if (mesh != mesh_next) {
BKE_id_free(nullptr, mesh);
}
mesh = mesh_next;
}
mesh->runtime->deformed_only = false;
} }
if (r_cage && i == cageIndex) { if (i == cageIndex) {
mesh_cage = mesh; blender::bke::save_cage_mesh(geometry_set);
} }
} }
@ -945,24 +820,18 @@ static void editbmesh_calc_modifiers(Depsgraph &depsgraph,
/* Add orco coordinates to final and deformed mesh if requested. */ /* Add orco coordinates to final and deformed mesh if requested. */
if (final_datamask.vmask & CD_MASK_ORCO) { if (final_datamask.vmask & CD_MASK_ORCO) {
/* FIXME(@ideasman42): avoid the need to convert to mesh data just to add an orco layer. */ if (Mesh *mesh = geometry_set.get_mesh_for_write()) {
BKE_mesh_wrapper_ensure_mdata(mesh); /* FIXME(@ideasman42): avoid the need to convert to mesh data just to add an orco layer. */
BKE_mesh_wrapper_ensure_mdata(mesh);
add_orco_mesh(ob, &em_input, *mesh, mesh_orco, CD_ORCO); add_orco_mesh(ob, &em_input, *mesh, mesh_orco, CD_ORCO);
}
} }
if (mesh_orco) { if (mesh_orco) {
BKE_id_free(nullptr, mesh_orco); BKE_id_free(nullptr, mesh_orco);
} }
/* Return final mesh. */ return geometry_set;
*r_final = mesh;
if (r_cage) {
*r_cage = mesh_cage;
}
if (r_geometry_set) {
*r_geometry_set = new GeometrySet(std::move(geometry_set_final));
}
} }
static void mesh_build_extra_data(const Depsgraph &depsgraph, static void mesh_build_extra_data(const Depsgraph &depsgraph,
@ -982,53 +851,26 @@ static void mesh_build_data(Depsgraph &depsgraph,
const CustomData_MeshMasks &dataMask, const CustomData_MeshMasks &dataMask,
const bool need_mapping) const bool need_mapping)
{ {
#if 0 /* XXX This is already taken care of in #mesh_calc_modifiers... */ const Mesh &mesh_input = *static_cast<const Mesh *>(ob.data);
if (need_mapping) { GeometrySet geometry_set = mesh_calc_modifiers(
/* Also add the flag so that it is recorded in lastDataMask. */ depsgraph, scene, ob, true, need_mapping, dataMask, true);
dataMask->vmask |= CD_MASK_ORIGINDEX; const Mesh *mesh_eval = geometry_set.get_mesh();
dataMask->emask |= CD_MASK_ORIGINDEX;
dataMask->pmask |= CD_MASK_ORIGINDEX;
}
#endif
Mesh *mesh_eval = nullptr, *mesh_deform_eval = nullptr; BKE_object_eval_assign_data(&ob, &const_cast<ID &>(mesh_eval->id), false);
GeometrySet *geometry_set_eval = nullptr; ob.runtime->geometry_set_eval = new GeometrySet(std::move(geometry_set));
mesh_calc_modifiers(depsgraph,
scene,
ob,
true,
need_mapping,
dataMask,
true,
true,
&mesh_deform_eval,
&mesh_eval,
&geometry_set_eval);
/* The modifier stack evaluation is storing result in mesh->runtime.mesh_eval, but this result
* is not guaranteed to be owned by object.
*
* Check ownership now, since later on we can not go to a mesh owned by someone else via
* object's runtime: this could cause access freed data on depsgraph destruction (mesh who owns
* the final result might be freed prior to object). */
Mesh *mesh = (Mesh *)ob.data;
const bool is_mesh_eval_owned = (mesh_eval != mesh->runtime->mesh_eval);
BKE_object_eval_assign_data(&ob, &mesh_eval->id, is_mesh_eval_owned);
/* Add the final mesh as a non-owning component to the geometry set. */
MeshComponent &mesh_component = geometry_set_eval->get_component_for_write<MeshComponent>();
mesh_component.replace(mesh_eval, GeometryOwnershipType::Editable);
ob.runtime->geometry_set_eval = geometry_set_eval;
ob.runtime->mesh_deform_eval = mesh_deform_eval;
ob.runtime->last_data_mask = dataMask; ob.runtime->last_data_mask = dataMask;
ob.runtime->last_need_mapping = need_mapping; ob.runtime->last_need_mapping = need_mapping;
/* Make sure that drivers can target shapekey properties. /* Make sure that drivers can target shapekey properties.
* Note that this causes a potential inconsistency, as the shapekey may have a * Note that this causes a potential inconsistency, as the shapekey may have a
* different topology than the evaluated mesh. */ * different topology than the evaluated mesh. */
BLI_assert(mesh->key == nullptr || DEG_is_evaluated_id(&mesh->key->id)); if (mesh_input.key) {
mesh_eval->key = mesh->key; BLI_assert(DEG_is_evaluated_id(&mesh_input->key->id));
if (mesh_eval != &mesh_input) {
const_cast<Mesh *>(mesh_eval)->key = mesh_input.key;
}
}
if ((ob.mode & OB_MODE_ALL_SCULPT) && ob.sculpt) { if ((ob.mode & OB_MODE_ALL_SCULPT) && ob.sculpt) {
if (DEG_is_active(&depsgraph)) { if (DEG_is_active(&depsgraph)) {
@ -1044,43 +886,50 @@ static void editbmesh_build_data(Depsgraph &depsgraph,
Object &obedit, Object &obedit,
CustomData_MeshMasks &dataMask) CustomData_MeshMasks &dataMask)
{ {
Mesh *mesh = static_cast<Mesh *>(obedit.data); const Mesh &mesh_input = *static_cast<const Mesh *>(obedit.data);
Mesh *me_cage;
Mesh *me_final;
GeometrySet *non_mesh_components;
editbmesh_calc_modifiers( GeometrySet geometry_set = editbmesh_calc_modifiers(depsgraph, scene, obedit, dataMask);
depsgraph, scene, obedit, dataMask, &me_cage, &me_final, &non_mesh_components);
/* The modifier stack result is expected to share edit mesh pointer with the input.
* This is similar `mesh_calc_finalize()`. */
BKE_mesh_free_editmesh(me_final);
BKE_mesh_free_editmesh(me_cage);
me_final->runtime->edit_mesh = me_cage->runtime->edit_mesh = mesh->runtime->edit_mesh;
/* Object has edit_mesh but is not in edit mode (object shares mesh datablock with another object /* Object has edit_mesh but is not in edit mode (object shares mesh datablock with another object
* with is in edit mode). * with is in edit mode).
* Convert edit mesh to mesh until the draw manager can draw mesh wrapper which is not in the * Convert edit mesh to mesh until the draw manager can draw mesh wrapper which is not in the
* edit mode. */ * edit mode. */
if (!(obedit.mode & OB_MODE_EDIT)) { if (!(obedit.mode & OB_MODE_EDIT)) {
BKE_mesh_wrapper_ensure_mdata(me_final); MeshEditHints &edit_hints =
if (me_final != me_cage) { *geometry_set.get_component_for_write<GeometryComponentEditData>().mesh_edit_hints_;
BKE_mesh_wrapper_ensure_mdata(me_cage); const bool cage_mesh_shared = edit_hints.mesh_cage->get() == geometry_set.get_mesh();
Mesh *mesh = geometry_set.get_mesh_for_write();
BKE_mesh_wrapper_ensure_mdata(mesh);
if (cage_mesh_shared) {
save_cage_mesh(geometry_set);
}
else {
if (edit_hints.mesh_cage->is_mutable()) {
edit_hints.mesh_cage->tag_ensured_mutable();
}
else {
Mesh *mesh_copy = BKE_mesh_copy_for_eval(*edit_hints.mesh_cage->get());
MeshComponent *copy = new MeshComponent(mesh_copy);
edit_hints.mesh_cage = ImplicitSharingPtr<MeshComponent>(copy);
}
Mesh *mesh_cage = const_cast<MeshComponent &>(*edit_hints.mesh_cage).get_for_write();
BKE_mesh_wrapper_ensure_mdata(mesh_cage);
} }
} }
const bool is_mesh_eval_owned = (me_final != mesh->runtime->mesh_eval); Mesh *mesh_final = const_cast<Mesh *>(geometry_set.get_mesh());
BKE_object_eval_assign_data(&obedit, &me_final->id, is_mesh_eval_owned);
BKE_object_eval_assign_data(&obedit, &mesh_final->id, false);
/* Make sure that drivers can target shapekey properties. /* Make sure that drivers can target shapekey properties.
* Note that this causes a potential inconsistency, as the shapekey may have a * Note that this causes a potential inconsistency, as the shapekey may have a
* different topology than the evaluated mesh. */ * different topology than the evaluated mesh. */
BLI_assert(mesh->key == nullptr || DEG_is_evaluated_id(&mesh->key->id)); BLI_assert(mesh_input.key == nullptr || DEG_is_evaluated_id(&mesh_input.key->id));
me_final->key = mesh->key; if (mesh_input.key && !mesh_final->key) {
mesh_final->key = mesh_input.key;
}
obedit.runtime->editmesh_eval_cage = me_cage; obedit.runtime->geometry_set_eval = new GeometrySet(std::move(geometry_set));
obedit.runtime->geometry_set_eval = non_mesh_components;
obedit.runtime->last_data_mask = dataMask; obedit.runtime->last_data_mask = dataMask;
} }
@ -1202,7 +1051,7 @@ Mesh *mesh_get_eval_deform(Depsgraph *depsgraph,
CustomData_MeshMasks cddata_masks = *dataMask; CustomData_MeshMasks cddata_masks = *dataMask;
object_get_datamask(*depsgraph, *ob, cddata_masks, &need_mapping); object_get_datamask(*depsgraph, *ob, cddata_masks, &need_mapping);
if (!ob->runtime->mesh_deform_eval || if (!BKE_object_get_mesh_deform_eval(ob) ||
!CustomData_MeshMasks_are_matching(&(ob->runtime->last_data_mask), &cddata_masks) || !CustomData_MeshMasks_are_matching(&(ob->runtime->last_data_mask), &cddata_masks) ||
(need_mapping && !ob->runtime->last_need_mapping)) (need_mapping && !ob->runtime->last_need_mapping))
{ {
@ -1211,7 +1060,7 @@ Mesh *mesh_get_eval_deform(Depsgraph *depsgraph,
*depsgraph, *scene, *ob, cddata_masks, need_mapping || ob->runtime->last_need_mapping); *depsgraph, *scene, *ob, cddata_masks, need_mapping || ob->runtime->last_need_mapping);
} }
return ob->runtime->mesh_deform_eval; return const_cast<Mesh *>(BKE_object_get_mesh_deform_eval(ob));
} }
Mesh *mesh_create_eval_final(Depsgraph *depsgraph, Mesh *mesh_create_eval_final(Depsgraph *depsgraph,
@ -1219,10 +1068,10 @@ Mesh *mesh_create_eval_final(Depsgraph *depsgraph,
Object *ob, Object *ob,
const CustomData_MeshMasks *dataMask) const CustomData_MeshMasks *dataMask)
{ {
Mesh *result; GeometrySet geometry_set = mesh_calc_modifiers(
mesh_calc_modifiers( *depsgraph, *scene, *ob, true, false, *dataMask, false);
*depsgraph, *scene, *ob, true, false, *dataMask, false, false, nullptr, &result, nullptr); geometry_set.ensure_owns_direct_data();
return result; return geometry_set.get_component_for_write<MeshComponent>().release();
} }
Mesh *mesh_create_eval_no_deform(Depsgraph *depsgraph, Mesh *mesh_create_eval_no_deform(Depsgraph *depsgraph,
@ -1230,10 +1079,10 @@ Mesh *mesh_create_eval_no_deform(Depsgraph *depsgraph,
Object *ob, Object *ob,
const CustomData_MeshMasks *dataMask) const CustomData_MeshMasks *dataMask)
{ {
Mesh *result; GeometrySet geometry_set = mesh_calc_modifiers(
mesh_calc_modifiers( *depsgraph, *scene, *ob, false, false, *dataMask, false);
*depsgraph, *scene, *ob, false, false, *dataMask, false, false, nullptr, &result, nullptr); geometry_set.ensure_owns_direct_data();
return result; return geometry_set.get_component_for_write<MeshComponent>().release();
} }
Mesh *mesh_create_eval_no_deform_render(Depsgraph *depsgraph, Mesh *mesh_create_eval_no_deform_render(Depsgraph *depsgraph,
@ -1241,10 +1090,10 @@ Mesh *mesh_create_eval_no_deform_render(Depsgraph *depsgraph,
Object *ob, Object *ob,
const CustomData_MeshMasks *dataMask) const CustomData_MeshMasks *dataMask)
{ {
Mesh *result; GeometrySet geometry_set = mesh_calc_modifiers(
mesh_calc_modifiers( *depsgraph, *scene, *ob, false, false, *dataMask, false);
*depsgraph, *scene, *ob, false, false, *dataMask, false, false, nullptr, &result, nullptr); geometry_set.ensure_owns_direct_data();
return result; return geometry_set.get_component_for_write<MeshComponent>().release();
} }
Mesh *editbmesh_get_eval_cage(Depsgraph *depsgraph, Mesh *editbmesh_get_eval_cage(Depsgraph *depsgraph,
@ -1260,13 +1109,13 @@ Mesh *editbmesh_get_eval_cage(Depsgraph *depsgraph,
*/ */
object_get_datamask(*depsgraph, *obedit, cddata_masks, nullptr); object_get_datamask(*depsgraph, *obedit, cddata_masks, nullptr);
if (!obedit->runtime->editmesh_eval_cage || if (!BKE_object_get_editmesh_eval_cage(obedit) ||
!CustomData_MeshMasks_are_matching(&(obedit->runtime->last_data_mask), &cddata_masks)) !CustomData_MeshMasks_are_matching(&(obedit->runtime->last_data_mask), &cddata_masks))
{ {
editbmesh_build_data(*depsgraph, *scene, *obedit, cddata_masks); editbmesh_build_data(*depsgraph, *scene, *obedit, cddata_masks);
} }
return obedit->runtime->editmesh_eval_cage; return const_cast<Mesh *>(BKE_object_get_editmesh_eval_cage(obedit));
} }
Mesh *editbmesh_get_eval_cage_from_orig(Depsgraph *depsgraph, Mesh *editbmesh_get_eval_cage_from_orig(Depsgraph *depsgraph,

View File

@ -1640,13 +1640,6 @@ void BKE_object_free_derived_caches(Object *ob)
object_update_from_subsurf_ccg(ob); object_update_from_subsurf_ccg(ob);
if (ob->runtime->editmesh_eval_cage &&
ob->runtime->editmesh_eval_cage != reinterpret_cast<Mesh *>(ob->runtime->data_eval))
{
BKE_id_free(nullptr, ob->runtime->editmesh_eval_cage);
}
ob->runtime->editmesh_eval_cage = nullptr;
if (ob->runtime->data_eval != nullptr) { if (ob->runtime->data_eval != nullptr) {
if (ob->runtime->is_data_eval_owned) { if (ob->runtime->is_data_eval_owned) {
ID *data_eval = ob->runtime->data_eval; ID *data_eval = ob->runtime->data_eval;
@ -1661,11 +1654,6 @@ void BKE_object_free_derived_caches(Object *ob)
} }
ob->runtime->data_eval = nullptr; ob->runtime->data_eval = nullptr;
} }
if (ob->runtime->mesh_deform_eval != nullptr) {
Mesh *mesh_deform_eval = ob->runtime->mesh_deform_eval;
BKE_id_free(nullptr, mesh_deform_eval);
ob->runtime->mesh_deform_eval = nullptr;
}
/* Restore initial pointer for copy-on-evaluation data-blocks, object->data /* Restore initial pointer for copy-on-evaluation data-blocks, object->data
* might be pointing to an evaluated data-block data was just freed above. */ * might be pointing to an evaluated data-block data was just freed above. */
@ -1686,10 +1674,8 @@ void BKE_object_free_derived_caches(Object *ob)
ob->runtime->gpd_eval = nullptr; ob->runtime->gpd_eval = nullptr;
} }
if (ob->runtime->geometry_set_eval != nullptr) { delete ob->runtime->geometry_set_eval;
delete ob->runtime->geometry_set_eval; ob->runtime->geometry_set_eval = nullptr;
ob->runtime->geometry_set_eval = nullptr;
}
} }
void BKE_object_free_caches(Object *object) void BKE_object_free_caches(Object *object)
@ -4221,26 +4207,59 @@ const Mesh *BKE_object_get_editmesh_eval_final(const Object *object)
return nullptr; return nullptr;
} }
return reinterpret_cast<Mesh *>(object->runtime->data_eval); return reinterpret_cast<const Mesh *>(object->runtime->data_eval);
} }
const Mesh *BKE_object_get_editmesh_eval_cage(const Object *object) const Mesh *BKE_object_get_editmesh_eval_cage(const Object *object)
{ {
using namespace blender::bke;
BLI_assert(!DEG_is_original_id(&object->id)); BLI_assert(!DEG_is_original_id(&object->id));
BLI_assert(object->type == OB_MESH); BLI_assert(object->type == OB_MESH);
const Mesh *mesh = static_cast<const Mesh *>(object->data); const Mesh *mesh = static_cast<const Mesh *>(object->data);
BLI_assert(mesh->runtime->edit_mesh != nullptr); BLI_assert(mesh->runtime->edit_mesh != nullptr);
UNUSED_VARS_NDEBUG(mesh); UNUSED_VARS_NDEBUG(mesh);
const GeometrySet *geometry_set = object->runtime->geometry_set_eval;
return object->runtime->editmesh_eval_cage; if (!geometry_set) {
return nullptr;
}
const auto *component = geometry_set->get_component<GeometryComponentEditData>();
if (!component) {
return nullptr;
}
const MeshEditHints *edit_hints = component->mesh_edit_hints_.get();
if (!edit_hints) {
return nullptr;
}
const MeshComponent *mesh_component = edit_hints->mesh_cage.get();
if (!mesh_component) {
return nullptr;
}
return mesh_component->get();
} }
const Mesh *BKE_object_get_mesh_deform_eval(const Object *object) const Mesh *BKE_object_get_mesh_deform_eval(const Object *object)
{ {
using namespace blender::bke;
BLI_assert(!DEG_is_original_id(&object->id)); BLI_assert(!DEG_is_original_id(&object->id));
BLI_assert(object->type == OB_MESH); BLI_assert(object->type == OB_MESH);
return object->runtime->mesh_deform_eval; const GeometrySet *geometry_set = object->runtime->geometry_set_eval;
if (!geometry_set) {
return nullptr;
}
const auto *component = geometry_set->get_component<GeometryComponentEditData>();
if (!component) {
return nullptr;
}
const MeshEditHints *edit_hints = component->mesh_edit_hints_.get();
if (!edit_hints) {
return nullptr;
}
const MeshComponent *mesh_component = edit_hints->mesh_deform.get();
if (!mesh_component) {
return nullptr;
}
return mesh_component->get();
} }
Lattice *BKE_object_get_lattice(const Object *object) Lattice *BKE_object_get_lattice(const Object *object)
@ -4879,7 +4898,6 @@ void BKE_object_runtime_reset_on_copy(Object *object, const int /*flag*/)
blender::bke::ObjectRuntime *runtime = object->runtime; blender::bke::ObjectRuntime *runtime = object->runtime;
runtime->data_eval = nullptr; runtime->data_eval = nullptr;
runtime->gpd_eval = nullptr; runtime->gpd_eval = nullptr;
runtime->mesh_deform_eval = nullptr;
runtime->curve_cache = nullptr; runtime->curve_cache = nullptr;
runtime->object_as_temp_mesh = nullptr; runtime->object_as_temp_mesh = nullptr;
runtime->pose_backup = nullptr; runtime->pose_backup = nullptr;

View File

@ -13,6 +13,7 @@
#include "BLI_implicit_sharing.hh" #include "BLI_implicit_sharing.hh"
#include "BLI_struct_equality_utils.hh" #include "BLI_struct_equality_utils.hh"
#include "BLI_utildefines.h"
namespace blender { namespace blender {
@ -89,6 +90,12 @@ template<typename T> class ImplicitSharingPtr {
return data_ != nullptr; return data_ != nullptr;
} }
template<typename U, BLI_ENABLE_IF((std::is_convertible_v<T, U>))>
operator ImplicitSharingPtr<U>() const
{
return ImplicitSharingPtr<U>(static_cast<U *>(data_));
}
const T *get() const const T *get() const
{ {
return data_; return data_;