diff --git a/source/blender/blenkernel/BKE_geometry_set.hh b/source/blender/blenkernel/BKE_geometry_set.hh index e9fd73bfdfd..e0f3b7a956a 100644 --- a/source/blender/blenkernel/BKE_geometry_set.hh +++ b/source/blender/blenkernel/BKE_geometry_set.hh @@ -168,6 +168,13 @@ struct GeometrySet { return static_cast(this->get_component_for_write(Component::static_type)); } + GeometryComponentPtr get_component_ptr(GeometryComponent::Type component_type) const; + template ImplicitSharingPtr get_component_ptr() const + { + BLI_STATIC_ASSERT(is_geometry_component_v, ""); + return static_cast>(components_(Component::static_type)); + } + /** * 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, * unlike #get_component_for_write. */ - GeometryComponent *get_component_ptr(GeometryComponent::Type type); - template Component *get_component_ptr() + GeometryComponent *get_component_for_write_ptr(GeometryComponent::Type type); + template Component *get_component_for_write_ptr() { BLI_STATIC_ASSERT(is_geometry_component_v, ""); - return static_cast(get_component_ptr(Component::static_type)); + return static_cast(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; }; +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 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 mesh_cage; +}; + /** * 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 @@ -696,6 +722,8 @@ class GeometryComponentEditData final : public GeometryComponent { */ std::unique_ptr grease_pencil_edit_hints_; + std::unique_ptr mesh_edit_hints_; + GeometryComponentEditData(); GeometryComponentPtr copy() const final; diff --git a/source/blender/blenkernel/BKE_object_types.hh b/source/blender/blenkernel/BKE_object_types.hh index 63d07c92efd..ad177d769f6 100644 --- a/source/blender/blenkernel/BKE_object_types.hh +++ b/source/blender/blenkernel/BKE_object_types.hh @@ -84,22 +84,6 @@ struct ObjectRuntime { */ 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 * to gpd_eval. diff --git a/source/blender/blenkernel/intern/geometry_set.cc b/source/blender/blenkernel/intern/geometry_set.cc index 4ec6078443a..87883f7b8cc 100644 --- a/source/blender/blenkernel/intern/geometry_set.cc +++ b/source/blender/blenkernel/intern/geometry_set.cc @@ -133,7 +133,7 @@ GeometryComponent &GeometrySet::get_component_for_write(GeometryComponent::Type return const_cast(*component_ptr); } -GeometryComponent *GeometrySet::get_component_ptr(GeometryComponent::Type type) +GeometryComponent *GeometrySet::get_component_for_write_ptr(GeometryComponent::Type type) { if (this->has(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() { - MeshComponent *component = this->get_component_ptr(); + MeshComponent *component = this->get_component_for_write_ptr(); return component == nullptr ? nullptr : component->get_for_write(); } PointCloud *GeometrySet::get_pointcloud_for_write() { - PointCloudComponent *component = this->get_component_ptr(); + PointCloudComponent *component = this->get_component_for_write_ptr(); return component == nullptr ? nullptr : component->get_for_write(); } Volume *GeometrySet::get_volume_for_write() { - VolumeComponent *component = this->get_component_ptr(); + VolumeComponent *component = this->get_component_for_write_ptr(); return component == nullptr ? nullptr : component->get_for_write(); } Curves *GeometrySet::get_curves_for_write() { - CurveComponent *component = this->get_component_ptr(); + CurveComponent *component = this->get_component_for_write_ptr(); return component == nullptr ? nullptr : component->get_for_write(); } Instances *GeometrySet::get_instances_for_write() { - InstancesComponent *component = this->get_component_ptr(); + InstancesComponent *component = this->get_component_for_write_ptr(); 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() { - GreasePencilComponent *component = this->get_component_ptr(); + GreasePencilComponent *component = this->get_component_for_write_ptr(); return component == nullptr ? nullptr : component->get_for_write(); } diff --git a/source/blender/blenkernel/intern/mesh_data_update.cc b/source/blender/blenkernel/intern/mesh_data_update.cc index 248ec5a394b..76241be34ec 100644 --- a/source/blender/blenkernel/intern/mesh_data_update.cc +++ b/source/blender/blenkernel/intern/mesh_data_update.cc @@ -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 * by modifiers to allow outputting non-mesh data from modifiers. */ -static Mesh *modifier_modify_mesh_and_geometry_set(ModifierData *md, - const ModifierEvalContext &mectx, - Mesh *input_mesh, - GeometrySet &geometry_set) +static void modifier_modify_mesh_and_geometry_set(ModifierData *md, + const ModifierEvalContext &mectx, + GeometrySet &geometry_set) { - Mesh *mesh_output = nullptr; const ModifierTypeInfo *mti = BKE_modifier_get_info((ModifierType)md->type); - if (mti->modify_geometry_set == nullptr) { - mesh_output = BKE_modifier_modify_mesh(md, &mectx, input_mesh); + if (mti->modify_geometry_set) { + if (Mesh *mesh = geometry_set.get_mesh_for_write()) { + BKE_mesh_wrapper_ensure_mdata(mesh); + } + mti->modify_geometry_set(md, &mectx, &geometry_set); } else { - /* For performance reasons, this should be called by the modifier and/or nodes themselves at - * some point. */ - 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 &mesh_component = geometry_set.get_component_for_write(); - 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); + if (Mesh *mesh = geometry_set.get_mesh_for_write()) { + geometry_set.replace_mesh(BKE_modifier_modify_mesh(md, &mectx, 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) @@ -305,30 +281,36 @@ static void set_rest_position(Mesh &mesh) } } -static void 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 bool allow_shared_mesh, - /* return args */ - Mesh **r_deform, - Mesh **r_final, - GeometrySet **r_geometry_set) +static MeshEditHints &geometry_mesh_edit_hints_ensure(GeometrySet &geometry) { - /* Input mesh shouldn't be modified. */ - Mesh &mesh_input = *static_cast(ob.data); - /* The final mesh is the result of calculating all enabled modifiers. */ - Mesh *mesh = nullptr; - /* The result of calculating all leading deform modifiers. */ - Mesh *mesh_deform = nullptr; - /* This geometry set contains the non-mesh data that might be generated by modifiers. */ - GeometrySet geometry_set_final; + auto &edit_data = geometry.get_component_for_write(); + if (!edit_data.mesh_edit_hints_) { + edit_data.mesh_edit_hints_ = std::make_unique(); + } + return *edit_data.mesh_edit_hints_; +} + +static void save_deform_mesh(GeometrySet &geometry) +{ + MeshEditHints &edit_data = geometry_mesh_edit_hints_ensure(geometry); + edit_data.mesh_deform = geometry.get_component_ptr(); +} + +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(ob.data); BLI_assert((mesh_input.id.tag & LIB_TAG_COPIED_ON_EVAL_FINAL_RESULT) == 0); + GeometrySet geometry_set = GeometrySet::from_mesh(const_cast(&mesh_input), + GeometryOwnershipType::ReadOnly); + /* Mesh with constructive modifiers but no deformation applied. Tracked * along with final mesh if undeformed / orco coordinates are requested * for texturing. */ @@ -371,11 +353,9 @@ static void mesh_calc_modifiers(Depsgraph &depsgraph, BKE_modifiers_clear_errors(&ob); if (ob.modifier_flag & OB_MODIFIER_FLAG_ADD_REST_POSITION) { - if (mesh == nullptr) { - mesh = BKE_mesh_copy_for_eval(mesh_input); - ASSERT_IS_VALID_MESH(mesh); + if (Mesh *mesh = geometry_set.get_mesh_for_write()) { + set_rest_position(*mesh); } - set_rest_position(*mesh); } /* Apply all leading deform modifiers. */ @@ -389,20 +369,17 @@ static void mesh_calc_modifiers(Depsgraph &depsgraph, if (mti->type == ModifierTypeType::OnlyDeform && !sculpt_dyntopo) { ScopedModifierTimer modifier_timer{*md}; - if (!mesh) { - mesh = BKE_mesh_copy_for_eval(mesh_input); - ASSERT_IS_VALID_MESH(mesh); - } - - if (mti->required_data_mask) { - CustomData_MeshMasks mask{}; - mti->required_data_mask(md, &mask); - if (mask.vmask & CD_MASK_ORCO) { - add_orco_mesh(ob, nullptr, *mesh, nullptr, CD_ORCO); + if (Mesh *mesh = geometry_set.get_mesh_for_write()) { + if (mti->required_data_mask) { + 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 { break; @@ -412,9 +389,7 @@ static void mesh_calc_modifiers(Depsgraph &depsgraph, /* Result of all leading deforming modifiers is cached for * places that wish to use the original mesh but with deformed * coordinates (like vertex paint). */ - if (r_deform) { - mesh_deform = BKE_mesh_copy_for_eval(mesh ? *mesh : mesh_input); - } + save_deform_mesh(geometry_set); } /* Apply all remaining constructive and deforming modifiers. */ @@ -475,42 +450,28 @@ static void mesh_calc_modifiers(Depsgraph &depsgraph, ScopedModifierTimer modifier_timer{*md}; /* Add orco mesh as layer if needed by this modifier. */ - if (mesh && mesh_orco && mti->required_data_mask) { - CustomData_MeshMasks mask = {0}; - mti->required_data_mask(md, &mask); - if (mask.vmask & CD_MASK_ORCO) { - add_orco_mesh(ob, nullptr, *mesh, mesh_orco, CD_ORCO); + if (Mesh *mesh = geometry_set.get_mesh_for_write()) { + if (mesh_orco && mti->required_data_mask) { + CustomData_MeshMasks mask = {0}; + mti->required_data_mask(md, &mask); + if (mask.vmask & CD_MASK_ORCO) { + add_orco_mesh(ob, nullptr, *mesh, mesh_orco, CD_ORCO); + } } } if (mti->type == ModifierTypeType::OnlyDeform) { - if (!mesh) { - mesh = BKE_mesh_copy_for_eval(mesh_input); - ASSERT_IS_VALID_MESH(mesh); + if (Mesh *mesh = geometry_set.get_mesh_for_write()) { + 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 { - 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; /* determine which data layers are needed by following modifiers */ 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 * constructive modifier. Modifiers will then do mapping mostly * automatic by copying them through CustomData_copy_data along @@ -541,45 +502,35 @@ static void mesh_calc_modifiers(Depsgraph &depsgraph, mesh->faces_num, 0); } - } - /* set the Mesh to only copy needed data */ - CustomData_MeshMasks mask = md_datamask->mask; - /* needMapping check here fixes bug #28112, otherwise it's - * possible that it won't be copied */ - CustomData_MeshMasks_update(&mask, &append_mask); - if (need_mapping) { - mask.vmask |= CD_MASK_ORIGINDEX; - mask.emask |= CD_MASK_ORIGINDEX; - mask.pmask |= CD_MASK_ORIGINDEX; - } - mesh_set_only_copy(mesh, &mask); + /* set the Mesh to only copy needed data */ + CustomData_MeshMasks mask = md_datamask->mask; + /* needMapping check here fixes bug #28112, otherwise it's + * possible that it won't be copied */ + CustomData_MeshMasks_update(&mask, &append_mask); + if (need_mapping) { + mask.vmask |= CD_MASK_ORIGINDEX; + mask.emask |= CD_MASK_ORIGINDEX; + mask.pmask |= CD_MASK_ORIGINDEX; + } + mesh_set_only_copy(mesh, &mask); - /* add cloth rest shape key if needed */ - if (mask.vmask & CD_MASK_CLOTH_ORCO) { - add_orco_mesh(ob, nullptr, *mesh, mesh_orco, CD_CLOTH_ORCO); - } + /* add cloth rest shape key if needed */ + if (mask.vmask & CD_MASK_CLOTH_ORCO) { + add_orco_mesh(ob, nullptr, *mesh, mesh_orco, CD_CLOTH_ORCO); + } - /* add an origspace layer if needed */ - if ((md_datamask->mask.lmask) & CD_MASK_ORIGSPACE_MLOOP) { - if (!CustomData_has_layer(&mesh->corner_data, CD_ORIGSPACE_MLOOP)) { - CustomData_add_layer( - &mesh->corner_data, CD_ORIGSPACE_MLOOP, CD_SET_DEFAULT, mesh->corners_num); - mesh_init_origspace(*mesh); + /* add an origspace layer if needed */ + if ((md_datamask->mask.lmask) & CD_MASK_ORIGSPACE_MLOOP) { + if (!CustomData_has_layer(&mesh->corner_data, CD_ORIGSPACE_MLOOP)) { + CustomData_add_layer( + &mesh->corner_data, CD_ORIGSPACE_MLOOP, CD_SET_DEFAULT, mesh->corners_num); + mesh_init_origspace(*mesh); + } } } - Mesh *mesh_next = modifier_modify_mesh_and_geometry_set(md, mectx, mesh, geometry_set_final); - 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; - } + modifier_modify_mesh_and_geometry_set(md, mectx, geometry_set); /* create an orco mesh in parallel */ if (nextmask.vmask & CD_MASK_ORCO) { @@ -600,17 +551,14 @@ static void mesh_calc_modifiers(Depsgraph &depsgraph, CustomData_MeshMasks_update(&temp_cddata_masks, &nextmask); mesh_set_only_copy(mesh_orco, &temp_cddata_masks); - mesh_next = BKE_modifier_modify_mesh(md, &mectx_orco, mesh_orco); - ASSERT_IS_VALID_MESH(mesh_next); - - if (mesh_next) { - /* if the modifier returned a new mesh, release the old one */ - if (mesh_orco != mesh_next) { - BLI_assert(mesh_orco != &mesh_input); + Mesh *mesh_orco_new = BKE_modifier_modify_mesh(md, &mectx_orco, mesh_orco); + ASSERT_IS_VALID_MESH(mesh_orco_new); + if (mesh_orco_new) { + if (mesh_orco != mesh_orco_new) { + BLI_assert(mesh_orco != mesh_input); BKE_id_free(nullptr, mesh_orco); } - - mesh_orco = mesh_next; + mesh_orco = mesh_orco_new; } } @@ -626,21 +574,23 @@ static void mesh_calc_modifiers(Depsgraph &depsgraph, nextmask.pmask |= CD_MASK_ORIGINDEX; mesh_set_only_copy(mesh_orco_cloth, &nextmask); - mesh_next = BKE_modifier_modify_mesh(md, &mectx_orco, mesh_orco_cloth); - ASSERT_IS_VALID_MESH(mesh_next); - - if (mesh_next) { - /* if the modifier returned a new mesh, release the old one */ - if (mesh_orco_cloth != mesh_next) { - BLI_assert(mesh_orco != &mesh_input); + Mesh *mesh_orco_cloth_new = BKE_modifier_modify_mesh(md, &mectx_orco, mesh_orco_cloth); + ASSERT_IS_VALID_MESH(mesh_orco_cloth_new); + if (mesh_orco_cloth_new) { + if (mesh_orco_cloth != mesh_orco_cloth_new) { + BLI_assert(mesh_orco != mesh_input); BKE_id_free(nullptr, mesh_orco_cloth); } - - mesh_orco_cloth = mesh_next; + mesh_orco_cloth = mesh_orco_cloth_new; } } - 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) { @@ -654,32 +604,6 @@ static void mesh_calc_modifiers(Depsgraph &depsgraph, 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) { 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. * 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); - - /* Compute normals. */ - if (is_own_mesh) { - 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; + if (const Mesh *mesh = geometry_set.get_mesh()) { + if (CustomData_has_layer(&mesh->vert_data, CD_CLOTH_ORCO)) { + Mesh *mesh_mut = geometry_set.get_mesh_for_write(); + CustomData_free_layers(&mesh_mut->vert_data, CD_CLOTH_ORCO, mesh_mut->verts_num); } } - /* Return final mesh */ - *r_final = mesh; - if (r_deform) { - *r_deform = mesh_deform; - } - if (r_geometry_set) { - *r_geometry_set = new GeometrySet(std::move(geometry_set_final)); - } + return geometry_set; } bool editbmesh_modifier_is_enabled(const Scene *scene, @@ -766,21 +660,19 @@ static MutableSpan mesh_wrapper_vert_coords_ensure_for_write(Mesh *mesh) return {}; } -static void editbmesh_calc_modifiers(Depsgraph &depsgraph, - const Scene &scene, - Object &ob, - const CustomData_MeshMasks &dataMask, - /* return args */ - Mesh **r_cage, - Mesh **r_final, - GeometrySet **r_geometry_set) +static void save_cage_mesh(GeometrySet &geometry) { - Mesh &mesh_input = *static_cast(ob.data); - BMEditMesh &em_input = *mesh_input.runtime->edit_mesh; + MeshEditHints &edit_data = geometry_mesh_edit_hints_ensure(geometry); + edit_data.mesh_cage = geometry.get_component_ptr(); +} - Mesh *mesh_cage = nullptr; - /* This geometry set contains the non-mesh data that might be generated by modifiers. */ - GeometrySet geometry_set_final; +static GeometrySet editbmesh_calc_modifiers(Depsgraph &depsgraph, + const Scene &scene, + Object &ob, + const CustomData_MeshMasks &dataMask) +{ + const Mesh &mesh_input = *static_cast(ob.data); + const BMEditMesh &em_input = *mesh_input.runtime->edit_mesh; /* Mesh with constructive modifiers but no deformation applied. Tracked * 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; CustomData_MeshMasks append_mask = CD_MASK_BAREMESH; - Mesh *mesh = BKE_mesh_wrapper_from_editmesh( - mesh_input.runtime->edit_mesh, &final_datamask, &mesh_input); + GeometrySet geometry_set = GeometrySet::from_mesh( + 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); - if (r_cage && cageIndex == -1) { - mesh_cage = mesh; + if (cageIndex == -1) { + save_cage_mesh(geometry_set); } /* 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); if (ob.modifier_flag & OB_MODIFIER_FLAG_ADD_REST_POSITION) { - BKE_mesh_wrapper_ensure_mdata(mesh); - set_rest_position(*mesh); + if (Mesh *mesh = geometry_set.get_mesh_for_write()) { + BKE_mesh_wrapper_ensure_mdata(mesh); + set_rest_position(*mesh); + } } bool non_deform_modifier_applied = false; @@ -840,6 +734,7 @@ static void editbmesh_calc_modifiers(Depsgraph &depsgraph, } ScopedModifierTimer modifier_timer{*md}; + Mesh *mesh = geometry_set.get_mesh_for_write(); /* Add an orco mesh as layer if needed by this modifier. */ 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( - *mesh_cage->runtime->edit_data); - } - } - } - if (mti->type == ModifierTypeType::OnlyDeform) { if (mti->deform_verts_EM) { BKE_modifier_deform_vertsEM( @@ -914,30 +794,25 @@ static void editbmesh_calc_modifiers(Depsgraph &depsgraph, mask.emask |= 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 (!CustomData_has_layer(&mesh->corner_data, CD_ORIGSPACE_MLOOP)) { - CustomData_add_layer( - &mesh->corner_data, CD_ORIGSPACE_MLOOP, CD_SET_DEFAULT, mesh->corners_num); - mesh_init_origspace(*mesh); + if (mask.lmask & CD_MASK_ORIGSPACE_MLOOP) { + if (!CustomData_has_layer(&mesh->corner_data, CD_ORIGSPACE_MLOOP)) { + CustomData_add_layer( + &mesh->corner_data, CD_ORIGSPACE_MLOOP, CD_SET_DEFAULT, mesh->corners_num); + mesh_init_origspace(*mesh); + } } + + mesh->runtime->deformed_only = false; } - Mesh *mesh_next = modifier_modify_mesh_and_geometry_set(md, mectx, mesh, geometry_set_final); - 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; + modifier_modify_mesh_and_geometry_set(md, mectx, geometry_set); } - if (r_cage && i == cageIndex) { - mesh_cage = mesh; + if (i == cageIndex) { + 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. */ if (final_datamask.vmask & CD_MASK_ORCO) { - /* 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); + if (Mesh *mesh = geometry_set.get_mesh_for_write()) { + /* 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); + } } if (mesh_orco) { BKE_id_free(nullptr, mesh_orco); } - /* Return final mesh. */ - *r_final = mesh; - if (r_cage) { - *r_cage = mesh_cage; - } - if (r_geometry_set) { - *r_geometry_set = new GeometrySet(std::move(geometry_set_final)); - } + return geometry_set; } 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 bool need_mapping) { -#if 0 /* XXX This is already taken care of in #mesh_calc_modifiers... */ - if (need_mapping) { - /* Also add the flag so that it is recorded in lastDataMask. */ - dataMask->vmask |= CD_MASK_ORIGINDEX; - dataMask->emask |= CD_MASK_ORIGINDEX; - dataMask->pmask |= CD_MASK_ORIGINDEX; - } -#endif + const Mesh &mesh_input = *static_cast(ob.data); + GeometrySet geometry_set = mesh_calc_modifiers( + depsgraph, scene, ob, true, need_mapping, dataMask, true); + const Mesh *mesh_eval = geometry_set.get_mesh(); - Mesh *mesh_eval = nullptr, *mesh_deform_eval = nullptr; - GeometrySet *geometry_set_eval = nullptr; - mesh_calc_modifiers(depsgraph, - scene, - ob, - true, - need_mapping, - dataMask, - true, - true, - &mesh_deform_eval, - &mesh_eval, - &geometry_set_eval); + BKE_object_eval_assign_data(&ob, &const_cast(mesh_eval->id), false); + ob.runtime->geometry_set_eval = new GeometrySet(std::move(geometry_set)); - /* 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(); - 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_need_mapping = need_mapping; /* Make sure that drivers can target shapekey properties. * Note that this causes a potential inconsistency, as the shapekey may have a * different topology than the evaluated mesh. */ - BLI_assert(mesh->key == nullptr || DEG_is_evaluated_id(&mesh->key->id)); - mesh_eval->key = mesh->key; + if (mesh_input.key) { + BLI_assert(DEG_is_evaluated_id(&mesh_input->key->id)); + if (mesh_eval != &mesh_input) { + const_cast(mesh_eval)->key = mesh_input.key; + } + } if ((ob.mode & OB_MODE_ALL_SCULPT) && ob.sculpt) { if (DEG_is_active(&depsgraph)) { @@ -1044,43 +886,50 @@ static void editbmesh_build_data(Depsgraph &depsgraph, Object &obedit, CustomData_MeshMasks &dataMask) { - Mesh *mesh = static_cast(obedit.data); - Mesh *me_cage; - Mesh *me_final; - GeometrySet *non_mesh_components; + const Mesh &mesh_input = *static_cast(obedit.data); - editbmesh_calc_modifiers( - 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; + GeometrySet geometry_set = editbmesh_calc_modifiers(depsgraph, scene, obedit, dataMask); /* Object has edit_mesh but is not in edit mode (object shares mesh datablock with another object * with is in edit mode). * Convert edit mesh to mesh until the draw manager can draw mesh wrapper which is not in the * edit mode. */ if (!(obedit.mode & OB_MODE_EDIT)) { - BKE_mesh_wrapper_ensure_mdata(me_final); - if (me_final != me_cage) { - BKE_mesh_wrapper_ensure_mdata(me_cage); + MeshEditHints &edit_hints = + *geometry_set.get_component_for_write().mesh_edit_hints_; + 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(copy); + } + Mesh *mesh_cage = const_cast(*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); - BKE_object_eval_assign_data(&obedit, &me_final->id, is_mesh_eval_owned); + Mesh *mesh_final = const_cast(geometry_set.get_mesh()); + + BKE_object_eval_assign_data(&obedit, &mesh_final->id, false); /* Make sure that drivers can target shapekey properties. * Note that this causes a potential inconsistency, as the shapekey may have a * different topology than the evaluated mesh. */ - BLI_assert(mesh->key == nullptr || DEG_is_evaluated_id(&mesh->key->id)); - me_final->key = mesh->key; + BLI_assert(mesh_input.key == nullptr || DEG_is_evaluated_id(&mesh_input.key->id)); + 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 = non_mesh_components; + obedit.runtime->geometry_set_eval = new GeometrySet(std::move(geometry_set)); obedit.runtime->last_data_mask = dataMask; } @@ -1202,7 +1051,7 @@ Mesh *mesh_get_eval_deform(Depsgraph *depsgraph, CustomData_MeshMasks cddata_masks = *dataMask; 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) || (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); } - return ob->runtime->mesh_deform_eval; + return const_cast(BKE_object_get_mesh_deform_eval(ob)); } Mesh *mesh_create_eval_final(Depsgraph *depsgraph, @@ -1219,10 +1068,10 @@ Mesh *mesh_create_eval_final(Depsgraph *depsgraph, Object *ob, const CustomData_MeshMasks *dataMask) { - Mesh *result; - mesh_calc_modifiers( - *depsgraph, *scene, *ob, true, false, *dataMask, false, false, nullptr, &result, nullptr); - return result; + GeometrySet geometry_set = mesh_calc_modifiers( + *depsgraph, *scene, *ob, true, false, *dataMask, false); + geometry_set.ensure_owns_direct_data(); + return geometry_set.get_component_for_write().release(); } Mesh *mesh_create_eval_no_deform(Depsgraph *depsgraph, @@ -1230,10 +1079,10 @@ Mesh *mesh_create_eval_no_deform(Depsgraph *depsgraph, Object *ob, const CustomData_MeshMasks *dataMask) { - Mesh *result; - mesh_calc_modifiers( - *depsgraph, *scene, *ob, false, false, *dataMask, false, false, nullptr, &result, nullptr); - return result; + GeometrySet geometry_set = mesh_calc_modifiers( + *depsgraph, *scene, *ob, false, false, *dataMask, false); + geometry_set.ensure_owns_direct_data(); + return geometry_set.get_component_for_write().release(); } Mesh *mesh_create_eval_no_deform_render(Depsgraph *depsgraph, @@ -1241,10 +1090,10 @@ Mesh *mesh_create_eval_no_deform_render(Depsgraph *depsgraph, Object *ob, const CustomData_MeshMasks *dataMask) { - Mesh *result; - mesh_calc_modifiers( - *depsgraph, *scene, *ob, false, false, *dataMask, false, false, nullptr, &result, nullptr); - return result; + GeometrySet geometry_set = mesh_calc_modifiers( + *depsgraph, *scene, *ob, false, false, *dataMask, false); + geometry_set.ensure_owns_direct_data(); + return geometry_set.get_component_for_write().release(); } 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); - 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)) { editbmesh_build_data(*depsgraph, *scene, *obedit, cddata_masks); } - return obedit->runtime->editmesh_eval_cage; + return const_cast(BKE_object_get_editmesh_eval_cage(obedit)); } Mesh *editbmesh_get_eval_cage_from_orig(Depsgraph *depsgraph, diff --git a/source/blender/blenkernel/intern/object.cc b/source/blender/blenkernel/intern/object.cc index 652daf9ca1f..a66270d2499 100644 --- a/source/blender/blenkernel/intern/object.cc +++ b/source/blender/blenkernel/intern/object.cc @@ -1640,13 +1640,6 @@ void BKE_object_free_derived_caches(Object *ob) object_update_from_subsurf_ccg(ob); - if (ob->runtime->editmesh_eval_cage && - ob->runtime->editmesh_eval_cage != reinterpret_cast(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->is_data_eval_owned) { ID *data_eval = ob->runtime->data_eval; @@ -1661,11 +1654,6 @@ void BKE_object_free_derived_caches(Object *ob) } 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 * 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; } - if (ob->runtime->geometry_set_eval != nullptr) { - delete ob->runtime->geometry_set_eval; - ob->runtime->geometry_set_eval = nullptr; - } + delete ob->runtime->geometry_set_eval; + ob->runtime->geometry_set_eval = nullptr; } 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 reinterpret_cast(object->runtime->data_eval); + return reinterpret_cast(object->runtime->data_eval); } 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(object->type == OB_MESH); const Mesh *mesh = static_cast(object->data); BLI_assert(mesh->runtime->edit_mesh != nullptr); UNUSED_VARS_NDEBUG(mesh); - - return object->runtime->editmesh_eval_cage; + const GeometrySet *geometry_set = object->runtime->geometry_set_eval; + if (!geometry_set) { + return nullptr; + } + const auto *component = geometry_set->get_component(); + 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) { + using namespace blender::bke; BLI_assert(!DEG_is_original_id(&object->id)); 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(); + 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) @@ -4879,7 +4898,6 @@ void BKE_object_runtime_reset_on_copy(Object *object, const int /*flag*/) blender::bke::ObjectRuntime *runtime = object->runtime; runtime->data_eval = nullptr; runtime->gpd_eval = nullptr; - runtime->mesh_deform_eval = nullptr; runtime->curve_cache = nullptr; runtime->object_as_temp_mesh = nullptr; runtime->pose_backup = nullptr; diff --git a/source/blender/blenlib/BLI_implicit_sharing_ptr.hh b/source/blender/blenlib/BLI_implicit_sharing_ptr.hh index ca73c0354ef..752d7c8afda 100644 --- a/source/blender/blenlib/BLI_implicit_sharing_ptr.hh +++ b/source/blender/blenlib/BLI_implicit_sharing_ptr.hh @@ -13,6 +13,7 @@ #include "BLI_implicit_sharing.hh" #include "BLI_struct_equality_utils.hh" +#include "BLI_utildefines.h" namespace blender { @@ -89,6 +90,12 @@ template class ImplicitSharingPtr { return data_ != nullptr; } + template))> + operator ImplicitSharingPtr() const + { + return ImplicitSharingPtr(static_cast(data_)); + } + const T *get() const { return data_;