From 0caab0ee83ed0240211a0d490085e045fd14d60f Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Tue, 28 Mar 2023 14:34:09 +0200 Subject: [PATCH 01/46] Squashed commit of the following: commit 33be282c3b415656a4577586dd70999702589a65 Author: Jacques Lucke Date: Wed Mar 22 12:42:53 2023 +0100 fix after merg commit 4b9d973bc6c564104e35a641bb64ec7b5c08c5f8 Merge: 2318d0a5086 69ba34fa217 Author: Jacques Lucke Date: Wed Mar 22 12:40:23 2023 +0100 Merge branch 'main' into temp-copy-on-write commit 2318d0a50868f5fb6fccccca8bd118adbfb81682 Author: Jacques Lucke Date: Tue Mar 14 20:34:55 2023 +0100 fix Fixed this in the past at some point, but a merge conflict reverted it.. commit ff134afff8feb42e6de031a6354b118375a1c27d Merge: 3400e55ba96 99506b3d733 Author: Jacques Lucke Date: Tue Mar 14 20:17:06 2023 +0100 Merge branch 'main' into temp-copy-on-write commit 3400e55ba96873084db846967d2166b0a1722127 Author: Jacques Lucke Date: Tue Mar 14 20:10:36 2023 +0100 cleanup name commit 36a18db75a41975a30961a58ab9d3258f9a53cbc Author: Jacques Lucke Date: Tue Mar 14 19:29:24 2023 +0100 rename commit 5f4ca0ca2cd02baf2c016126b5f034ad6da141d4 Author: Jacques Lucke Date: Tue Mar 14 19:24:23 2023 +0100 cleanup commit 73aa98c62f0e716a247480bea70aaf557e12d06d Author: Jacques Lucke Date: Tue Mar 14 19:11:28 2023 +0100 cleanup commit 27061b704b08564f79387fce2dbe07a42e0d60c2 Author: Jacques Lucke Date: Tue Mar 14 18:52:30 2023 +0100 cleanup commit 39d770fae48b859a9ce775b503d2b08b3b3229ba Author: Jacques Lucke Date: Tue Mar 14 18:21:57 2023 +0100 cleanup commit 0f9e2af3b069015c75bd338f1b86789756652a02 Author: Jacques Lucke Date: Tue Mar 14 17:49:22 2023 +0100 fix double free in edit-mesh-undo commit 657b0dc433774d6c3f6534b817bb5df1b354ab11 Author: Jacques Lucke Date: Tue Mar 14 17:47:18 2023 +0100 make destructor virtual commit f890130a6c22aa382066e40e338238937a78d947 Author: Jacques Lucke Date: Tue Mar 14 17:04:15 2023 +0100 remove rna integration commit 195e9c335bc31650779daf668a09bcad568144dc Author: Jacques Lucke Date: Tue Mar 14 17:00:38 2023 +0100 fix merge error commit 28faa89077de7a8c193ae1fe445b640cc3a00d2a Author: Jacques Lucke Date: Tue Mar 14 16:30:14 2023 +0100 cleanup commit 7ce2820c051836a2f3058882fe3b5228f67dbec9 Author: Jacques Lucke Date: Tue Mar 14 15:54:16 2023 +0100 cleanup commit 14905927b35e9b4c5f53f94a618850291f3532f8 Merge: 80f34eaa4de 92b607d6866 Author: Jacques Lucke Date: Tue Mar 14 15:53:35 2023 +0100 Merge branch 'main' into temp-copy-on-write commit 80f34eaa4de8b86781b9caf22780936c19bacf6e Merge: 06e1b3f9f69 01480229b1c Author: Jacques Lucke Date: Fri Feb 10 17:01:07 2023 +0100 Merge branch 'main' into temp-copy-on-write commit 06e1b3f9f69f96182d7a81fb3332e1033cc1b842 Merge: 82ffc03449f 43f308f2167 Author: Jacques Lucke Date: Wed Feb 8 14:48:47 2023 +0100 Merge branch 'main' into temp-copy-on-write-customdata commit 82ffc03449fee664632e818b3c20d168db26e7ae Author: Jacques Lucke Date: Tue Feb 7 19:50:58 2023 +0100 fix commit ce4657910876d0790860fef41688e18072012585 Merge: e71021db062 f5552d759cc Author: Jacques Lucke Date: Tue Feb 7 19:50:54 2023 +0100 Merge branch 'main' into temp-copy-on-write-customdata commit e71021db06272109e48093a0bb8c950ca05d2ab2 Merge: ff6f1a0a706 b642dc7bc7d Author: Jacques Lucke Date: Mon Feb 6 00:27:06 2023 +0100 Merge branch 'master' into temp-copy-on-write-customdata commit ff6f1a0a706b5840b98e3bd44e6bbccf62dd9533 Author: Jacques Lucke Date: Sun Feb 5 23:36:06 2023 +0100 simplify embedding cow commit 9c51e093a31673eceeef88b84789dd254b1eba35 Author: Jacques Lucke Date: Sun Feb 5 23:17:32 2023 +0100 partial fix commit 1284bdc24c3abc95fe8b61ec0ba354c4ee7a8b1e Author: Jacques Lucke Date: Sun Feb 5 22:31:05 2023 +0100 removing support for saving undo step as actual file commit a59b848992fd7168c99c97b2052c4d355a47d6ef Author: Jacques Lucke Date: Sun Feb 5 22:22:23 2023 +0100 fix commit 4d67393e7ed399169f508d6743e5e65d90605534 Merge: 2e9fcdc6001 3d6ceb737d8 Author: Jacques Lucke Date: Sun Feb 5 22:19:52 2023 +0100 Merge branch 'master' into temp-copy-on-write-customdata commit 2e9fcdc6001a1af82a9a23edae303af442e25e05 Author: Jacques Lucke Date: Tue Jan 31 22:42:05 2023 +0100 disable array store for editmesh undo commit b4ac85084cb9b8733dcded84a1f9d88b69e7a9b3 Author: Jacques Lucke Date: Tue Jan 31 22:41:40 2023 +0100 improve rna api commit 6f4772d1706d5a0fdd528209ff7dbead9db57713 Author: Jacques Lucke Date: Tue Jan 31 21:53:57 2023 +0100 cleanup file structure commit b703fc76c8f5d85c7d5d85fd47a8ac5903b55076 Author: Jacques Lucke Date: Tue Jan 31 21:47:48 2023 +0100 cleanup commit 60612b84dceb152b52a96f62c7f7383aa535f08a Author: Jacques Lucke Date: Tue Jan 31 21:46:45 2023 +0100 cleanup commit a16a60f60032d5d82fc812c5dcefa18f8a82937a Author: Jacques Lucke Date: Tue Jan 31 21:45:35 2023 +0100 cleanup commit 6065a378cfb0fe5d6291b45461b48749f88cf3bc Author: Jacques Lucke Date: Tue Jan 31 21:43:04 2023 +0100 use virtual class commit 53178b94e012d1089d8eae37c2a336a5008a318b Author: Jacques Lucke Date: Tue Jan 31 19:55:17 2023 +0100 initial rna integration commit ee675db8f669f7e4e2d7cea8aeaca4d42d8371f2 Author: Jacques Lucke Date: Sun Jan 29 02:16:59 2023 +0100 store destructor in cow type commit 8f6b51ac1542cd3b5695ccfb5caf6b373a87c26d Author: Jacques Lucke Date: Sun Jan 29 00:20:36 2023 +0100 cleanup commit c9477aac6a1fdff210353d5b21e6547688eb0ce0 Merge: c678fe09e47 e497da5fda3 Author: Jacques Lucke Date: Sun Jan 29 00:15:55 2023 +0100 Merge branch 'master' into temp-copy-on-write-customdata commit c678fe09e472c9e92022f84d2b6c81a0952c9d11 Author: Jacques Lucke Date: Mon Jan 23 01:48:20 2023 +0100 cleanup commit 097c085a4e11f50c7a37d1a63222e06e4be84bea Author: Jacques Lucke Date: Mon Jan 23 01:47:04 2023 +0100 Support copy-on-write in undo system commit ef1f42865e7fa723ac52184f8ae14c7b4634a8a9 Merge: 2b71cf4b313 93a840360a0 Author: Jacques Lucke Date: Mon Jan 23 00:55:37 2023 +0100 Merge branch 'master' into temp-copy-on-write-customdata commit 2b71cf4b313c012f521f10347ad6410b2945e017 Merge: d4ec435d4fe 3a2899cc317 Author: Jacques Lucke Date: Sun Jan 22 20:44:29 2023 +0100 Merge branch 'master' into temp-copy-on-write-customdata commit d4ec435d4fe2acd25713aee6ce2f4c0f460d8fd4 Author: Jacques Lucke Date: Sat Jan 21 18:14:36 2023 +0100 compile fixes commit ba33242d9a0062ceb17af06a7be73fdf7bcf2e0c Author: Jacques Lucke Date: Sat Jan 21 16:35:33 2023 +0100 progress commit 66b4840d900231d298b8cf668eea48bf2ad0520d Author: Jacques Lucke Date: Sat Jan 21 16:32:06 2023 +0100 fix freeing commit 8cff18da913115259292e30e912ed17e1cc1bde4 Author: Jacques Lucke Date: Sat Jan 21 15:24:49 2023 +0100 progress commit b45b522d2220c7fb1e2b27cb3b01822c31e05bbc Author: Jacques Lucke Date: Sat Jan 21 15:02:06 2023 +0100 progress commit b592d76a8edcdd952c920e7af7f24daf1f5f2068 Author: Jacques Lucke Date: Sat Jan 21 14:32:56 2023 +0100 remove CD_FLAG_NOFREE commit be0fe0433db7fa2d760498f781ba404551e45798 Author: Jacques Lucke Date: Sat Jan 21 14:21:54 2023 +0100 cleanup commit 3530c63611553a1dd2f1d40221ed5a3a624064a6 Author: Jacques Lucke Date: Sat Jan 21 14:11:36 2023 +0100 progress commit c1d1665a79e5c1ce59f374053c6cfba72ebd3d0b Author: Jacques Lucke Date: Sat Jan 21 14:01:47 2023 +0100 progress commit 3f2293353443e83e24ed06d653d3ab72b543dce1 Author: Jacques Lucke Date: Sat Jan 21 13:47:35 2023 +0100 progress commit c4c9a43072f2a78f54cd4f7ebf7e88c2867b2077 Author: Jacques Lucke Date: Sat Jan 21 13:42:06 2023 +0100 progress commit e3779d12d5de0e0cc24d5b1cf4a375ac6ef032f8 Author: Jacques Lucke Date: Sat Jan 21 13:28:31 2023 +0100 progress commit 3ed5d00f7eab7152f1fe88bfc1397ab5522d57d2 Author: Jacques Lucke Date: Sat Jan 21 13:01:10 2023 +0100 fix commit 5329d5803ecd7df829884091a9cd3aecf4e3735c Author: Jacques Lucke Date: Sat Jan 21 12:50:29 2023 +0100 progress commit 51388d401c60c50f326f0dbb18e32bed5b79e4e9 Merge: 5a3c8a1b124 ced00214985 Author: Jacques Lucke Date: Sat Jan 21 11:41:08 2023 +0100 Merge branch 'temp-copy-on-write' into temp-copy-on-write-customdata commit ced00214985e2443e2e30552a13bbd752a7ee008 Merge: 0b7155b5c5e 6aa29549e88 Author: Jacques Lucke Date: Sat Jan 21 11:40:42 2023 +0100 Merge branch 'master' into temp-copy-on-write commit 5a3c8a1b124d3e20df4bb1b60725e2680b1b43d3 Author: Jacques Lucke Date: Fri Jan 20 23:45:03 2023 +0100 change custom data api for cow commit 0b7155b5c5ef9c3c8fa6a3ab4dda68703469992c Author: Jacques Lucke Date: Fri Jan 20 21:59:07 2023 +0100 fix commit d76e6862f0c6398be8f5bd441fab54d6e0fbd96a Author: Jacques Lucke Date: Fri Jan 20 21:57:15 2023 +0100 fix commit 6b1028d49278a0488eddd6c5d4057716f225e6ea Author: Jacques Lucke Date: Fri Jan 20 21:52:16 2023 +0100 fix commit dd8af7b46a6cb765b1ee22b485947c06825b7a00 Merge: ac439c7eedf 244c87dd680 Author: Jacques Lucke Date: Fri Jan 20 21:45:15 2023 +0100 Merge branch 'master' into temp-copy-on-write commit ac439c7eedfab6db7ae86ef37b98d4564cf72af6 Merge: 3f3adef4a07 c99d1d5d0db Author: Jacques Lucke Date: Thu Feb 17 17:23:52 2022 +0100 Use new copy-on-write system for sharing geometry components. Differential Revision: https://developer.blender.org/D14139 commit 3f3adef4a07df05fe92e0b948d4e2bc48f5ec3fc Merge: c5b55a84f58 b2867d43658 Author: Jacques Lucke Date: Tue Jan 4 13:38:02 2022 +0100 Merge branch 'master' into temp-copy-on-write commit c5b55a84f58aebc302de66fff13816d4beda38ee Author: Jacques Lucke Date: Mon Jan 3 16:57:15 2022 +0100 cleanup commit 1713a780c56b1c2fc1ba3e1b02fc6f860cd2604b Author: Jacques Lucke Date: Mon Jan 3 16:55:45 2022 +0100 progress commit e0ac932156b9b44190d5638f2c38d17af7770594 Author: Jacques Lucke Date: Mon Jan 3 15:29:23 2022 +0100 initial data structure --- source/blender/blenkernel/BKE_attribute.hh | 1 - source/blender/blenkernel/BKE_customdata.h | 73 +- .../blender/blenkernel/intern/DerivedMesh.cc | 10 +- .../blenkernel/intern/attribute_access.cc | 51 +- .../blenkernel/intern/cdderivedmesh.cc | 15 +- source/blender/blenkernel/intern/curves.cc | 7 +- .../blenkernel/intern/curves_geometry.cc | 4 +- .../blender/blenkernel/intern/curves_utils.cc | 7 +- .../blender/blenkernel/intern/customdata.cc | 655 ++++++++++-------- source/blender/blenkernel/intern/mesh.cc | 23 +- .../blenkernel/intern/mesh_boolean_convert.cc | 8 +- .../blenkernel/intern/mesh_calc_edges.cc | 2 +- .../blender/blenkernel/intern/mesh_convert.cc | 21 +- .../blenkernel/intern/mesh_legacy_convert.cc | 30 +- .../blender/blenkernel/intern/pointcloud.cc | 30 +- .../blender/blenkernel/intern/subdiv_mesh.cc | 20 +- source/blender/blenlib/CMakeLists.txt | 2 + source/blender/blenloader/BLO_read_write.h | 15 + source/blender/blenloader/BLO_undofile.h | 21 +- source/blender/blenloader/intern/readfile.cc | 16 + source/blender/blenloader/intern/undofile.cc | 67 +- .../blenloader/intern/versioning_legacy.c | 10 +- source/blender/blenloader/intern/writefile.cc | 16 + source/blender/bmesh/intern/bmesh_construct.c | 24 +- .../bmesh/intern/bmesh_mesh_convert.cc | 40 +- source/blender/editors/mesh/editmesh_undo.cc | 9 + source/blender/editors/mesh/mesh_data.cc | 11 +- source/blender/editors/mesh/meshtools.cc | 8 +- .../blender/editors/object/object_modifier.cc | 2 +- .../editors/sculpt_paint/sculpt_dyntopo.cc | 12 +- .../editors/sculpt_paint/sculpt_undo.cc | 20 +- .../geometry/intern/mesh_split_edges.cc | 3 +- source/blender/io/collada/MeshImporter.cpp | 2 +- .../blender/makesdna/DNA_customdata_types.h | 10 +- .../blender/windowmanager/intern/wm_files.cc | 29 +- .../windowmanager/intern/wm_init_exit.cc | 29 +- source/creator/creator_signals.c | 28 - 37 files changed, 680 insertions(+), 651 deletions(-) diff --git a/source/blender/blenkernel/BKE_attribute.hh b/source/blender/blenkernel/BKE_attribute.hh index afa9f1fba23..75fcd99fbec 100644 --- a/source/blender/blenkernel/BKE_attribute.hh +++ b/source/blender/blenkernel/BKE_attribute.hh @@ -812,7 +812,6 @@ class CustomDataAttributes { std::optional get_for_write(const AttributeIDRef &attribute_id); bool create(const AttributeIDRef &attribute_id, eCustomDataType data_type); - bool create_by_move(const AttributeIDRef &attribute_id, eCustomDataType data_type, void *buffer); bool remove(const AttributeIDRef &attribute_id); bool foreach_attribute(const AttributeForeachCallback callback, eAttrDomain domain) const; diff --git a/source/blender/blenkernel/BKE_customdata.h b/source/blender/blenkernel/BKE_customdata.h index 53e21f3c660..013863a0822 100644 --- a/source/blender/blenkernel/BKE_customdata.h +++ b/source/blender/blenkernel/BKE_customdata.h @@ -74,14 +74,10 @@ extern const CustomData_MeshMasks CD_MASK_EVERYTHING; /** Add/copy/merge allocation types. */ typedef enum eCDAllocType { - /** Use the data pointer. */ + /** Use the data pointer. This is only used internally. */ CD_ASSIGN = 0, /** Allocate and set to default, which is usually just zeroed memory. */ CD_SET_DEFAULT = 2, - /** Use data pointers, set layer flag NOFREE. */ - CD_REFERENCE = 3, - /** Do a full copy of all layers, only allowed if source has same number of elements. */ - CD_DUPLICATE = 4, /** * Default construct new layer values. Does nothing for trivial types. This should be used * if all layer values will be set by the caller after creating the layer. @@ -158,15 +154,23 @@ void CustomData_data_multiply(int type, void *data, float fac); void CustomData_data_add(int type, void *data1, const void *data2); /** - * Initializes a CustomData object with the same layer setup as source. - * mask is a bit-field where `(mask & (1 << (layer type)))` indicates - * if a layer should be copied or not. alloctype must be one of the above. + * Initializes a CustomData object with the same layer setup as source. `mask` is a bit-field where + * `(mask & (1 << (layer type)))` indicates if a layer should be copied or not. The data layers + * will be shared or copied depending on whether the layer uses COW. */ void CustomData_copy(const struct CustomData *source, struct CustomData *dest, eCustomDataMask mask, - eCDAllocType alloctype, int totelem); +/** + * Initializes a CustomData object with the same layers as source. The data is not copied from the + * source. Instead, the new layers are initialized using the given `alloctype`. + */ +void CustomData_copy_new(const struct CustomData *source, + struct CustomData *dest, + eCustomDataMask mask, + eCDAllocType alloctype, + int totelem); /* BMESH_TODO, not really a public function but readfile.c needs it */ void CustomData_update_typemap(struct CustomData *data); @@ -178,8 +182,12 @@ void CustomData_update_typemap(struct CustomData *data); bool CustomData_merge(const struct CustomData *source, struct CustomData *dest, eCustomDataMask mask, - eCDAllocType alloctype, int totelem); +bool CustomData_merge_new(const struct CustomData *source, + struct CustomData *dest, + eCustomDataMask mask, + eCDAllocType alloctype, + int totelem); /** * Reallocate custom data to a new element count. If the new size is larger, the new values use @@ -193,12 +201,12 @@ void CustomData_realloc(struct CustomData *data, int old_size, int new_size); * then goes through the mesh and makes sure all the custom-data blocks are * consistent with the new layout. */ -bool CustomData_bmesh_merge(const struct CustomData *source, - struct CustomData *dest, - eCustomDataMask mask, - eCDAllocType alloctype, - struct BMesh *bm, - char htype); +bool CustomData_bmesh_merge_new(const struct CustomData *source, + struct CustomData *dest, + eCustomDataMask mask, + eCDAllocType alloctype, + struct BMesh *bm, + char htype); /** * Remove layers that aren't stored in BMesh or are stored as flags on BMesh. @@ -229,18 +237,23 @@ void CustomData_free_typemask(struct CustomData *data, int totelem, eCustomDataM void CustomData_free_temporary(struct CustomData *data, int totelem); /** - * Adds a data layer of the given type to the #CustomData object, optionally - * backed by an external data array. the different allocation types are - * defined above. returns the data of the layer. + * Adds a layer of the given type to the #CustomData object. The new layer is initialized based on + * the given alloctype. \return The layer data. */ void *CustomData_add_layer(struct CustomData *data, eCustomDataType type, eCDAllocType alloctype, int totelem); + +/** + * Adds a layer of the given type to the #CustomData object. The new layer takes ownership of the + * passed in `layer_data`. If a #bCopyOnWrite is passed in, it's user count is increased. + */ const void *CustomData_add_layer_with_data(struct CustomData *data, eCustomDataType type, void *layer_data, - int totelem); + int totelem, + const struct bCopyOnWrite *cow); /** * Same as above but accepts a name. @@ -250,17 +263,26 @@ void *CustomData_add_layer_named(struct CustomData *data, eCDAllocType alloctype, int totelem, const char *name); + const void *CustomData_add_layer_named_with_data(struct CustomData *data, eCustomDataType type, void *layer_data, int totelem, - const char *name); + const char *name, + const struct bCopyOnWrite *cow); + void *CustomData_add_layer_anonymous(struct CustomData *data, - int type, + eCustomDataType type, eCDAllocType alloctype, - void *layer, int totelem, const AnonymousAttributeIDHandle *anonymous_id); +const void *CustomData_add_layer_anonymous_with_data( + struct CustomData *data, + eCustomDataType type, + const AnonymousAttributeIDHandle *anonymous_id, + int totelem, + void *layer_data, + const struct bCopyOnWrite *cow); /** * Frees the active or first data layer with the give type. @@ -296,11 +318,6 @@ int CustomData_number_of_layers(const struct CustomData *data, int type); int CustomData_number_of_anonymous_layers(const struct CustomData *data, int type); int CustomData_number_of_layers_typemask(const struct CustomData *data, eCustomDataMask mask); -/** - * Duplicate all the layers with flag NOFREE, and remove the flag from duplicated layers. - */ -void CustomData_duplicate_referenced_layers(CustomData *data, int totelem); - /** * Set the #CD_FLAG_NOCOPY flag in custom data layers where the mask is * zero for the layer type, so only layer types specified by the mask will be copied diff --git a/source/blender/blenkernel/intern/DerivedMesh.cc b/source/blender/blenkernel/intern/DerivedMesh.cc index f6fcd4278a0..44a1bb18bdc 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.cc +++ b/source/blender/blenkernel/intern/DerivedMesh.cc @@ -253,11 +253,11 @@ void DM_from_template(DerivedMesh *dm, int numPolys) { const CustomData_MeshMasks *mask = &CD_MASK_DERIVEDMESH; - CustomData_copy(&source->vertData, &dm->vertData, mask->vmask, CD_SET_DEFAULT, numVerts); - CustomData_copy(&source->edgeData, &dm->edgeData, mask->emask, CD_SET_DEFAULT, numEdges); - CustomData_copy(&source->faceData, &dm->faceData, mask->fmask, CD_SET_DEFAULT, numTessFaces); - CustomData_copy(&source->loopData, &dm->loopData, mask->lmask, CD_SET_DEFAULT, numLoops); - CustomData_copy(&source->polyData, &dm->polyData, mask->pmask, CD_SET_DEFAULT, numPolys); + CustomData_copy_new(&source->vertData, &dm->vertData, mask->vmask, CD_SET_DEFAULT, numVerts); + CustomData_copy_new(&source->edgeData, &dm->edgeData, mask->emask, CD_SET_DEFAULT, numEdges); + CustomData_copy_new(&source->faceData, &dm->faceData, mask->fmask, CD_SET_DEFAULT, numTessFaces); + CustomData_copy_new(&source->loopData, &dm->loopData, mask->lmask, CD_SET_DEFAULT, numLoops); + CustomData_copy_new(&source->polyData, &dm->polyData, mask->pmask, CD_SET_DEFAULT, numPolys); dm->type = type; dm->numVertData = numVerts; diff --git a/source/blender/blenkernel/intern/attribute_access.cc b/source/blender/blenkernel/intern/attribute_access.cc index 564918ec245..c92da85f8b4 100644 --- a/source/blender/blenkernel/intern/attribute_access.cc +++ b/source/blender/blenkernel/intern/attribute_access.cc @@ -201,13 +201,16 @@ static bool add_builtin_type_custom_data_layer_from_init(CustomData &custom_data return true; } case AttributeInit::Type::MoveArray: { - void *source_data = static_cast(initializer).data; - const void *data = CustomData_add_layer_with_data( - &custom_data, data_type, source_data, domain_num); - if (data == nullptr) { - MEM_freeN(source_data); + void *src_data = static_cast(initializer).data; + const void *stored_data = CustomData_add_layer_with_data( + &custom_data, data_type, src_data, domain_num, nullptr); + if (stored_data == nullptr) { return false; } + if (stored_data != src_data) { + MEM_freeN(src_data); + return true; + } return true; } } @@ -230,25 +233,26 @@ static void *add_generic_custom_data_layer(CustomData &custom_data, } const AnonymousAttributeID &anonymous_id = attribute_id.anonymous_id(); return CustomData_add_layer_anonymous( - &custom_data, data_type, alloctype, nullptr, domain_size, &anonymous_id); + &custom_data, data_type, alloctype, domain_size, &anonymous_id); } static const void *add_generic_custom_data_layer_with_existing_data( CustomData &custom_data, const eCustomDataType data_type, - void *layer_data, + const AttributeIDRef &attribute_id, const int domain_size, - const AttributeIDRef &attribute_id) + void *layer_data, + const bCopyOnWrite *cow) { - if (!attribute_id.is_anonymous()) { - char attribute_name_c[MAX_CUSTOMDATA_LAYER_NAME]; - attribute_id.name().copy(attribute_name_c); - return CustomData_add_layer_named_with_data( - &custom_data, data_type, layer_data, domain_size, attribute_name_c); + if (attribute_id.is_anonymous()) { + const AnonymousAttributeID &anonymous_id = attribute_id.anonymous_id(); + return CustomData_add_layer_anonymous_with_data( + &custom_data, data_type, &anonymous_id, domain_size, layer_data, cow); } - const AnonymousAttributeID &anonymous_id = attribute_id.anonymous_id(); - return CustomData_add_layer_anonymous( - &custom_data, data_type, CD_ASSIGN, layer_data, domain_size, &anonymous_id); + char attribute_name_c[MAX_CUSTOMDATA_LAYER_NAME]; + attribute_id.name().copy(attribute_name_c); + return CustomData_add_layer_named_with_data( + &custom_data, data_type, layer_data, domain_size, attribute_name_c, cow); } static bool add_custom_data_layer_from_attribute_init(const AttributeIDRef &attribute_id, @@ -279,9 +283,9 @@ static bool add_custom_data_layer_from_attribute_init(const AttributeIDRef &attr break; } case AttributeInit::Type::MoveArray: { - void *source_data = static_cast(initializer).data; + void *data = static_cast(initializer).data; add_generic_custom_data_layer_with_existing_data( - custom_data, data_type, source_data, domain_num, attribute_id); + custom_data, data_type, attribute_id, domain_num, data, nullptr); break; } } @@ -570,7 +574,7 @@ CustomDataAttributes::~CustomDataAttributes() CustomDataAttributes::CustomDataAttributes(const CustomDataAttributes &other) { size_ = other.size_; - CustomData_copy(&other.data, &data, CD_MASK_ALL, CD_DUPLICATE, size_); + CustomData_copy(&other.data, &data, CD_MASK_ALL, size_); } CustomDataAttributes::CustomDataAttributes(CustomDataAttributes &&other) @@ -654,15 +658,6 @@ bool CustomDataAttributes::create(const AttributeIDRef &attribute_id, return result != nullptr; } -bool CustomDataAttributes::create_by_move(const AttributeIDRef &attribute_id, - const eCustomDataType data_type, - void *buffer) -{ - const void *result = add_generic_custom_data_layer_with_existing_data( - data, data_type, buffer, size_, attribute_id); - return result != nullptr; -} - bool CustomDataAttributes::remove(const AttributeIDRef &attribute_id) { for (const int i : IndexRange(data.totlayer)) { diff --git a/source/blender/blenkernel/intern/cdderivedmesh.cc b/source/blender/blenkernel/intern/cdderivedmesh.cc index fa7273314a2..183780cd462 100644 --- a/source/blender/blenkernel/intern/cdderivedmesh.cc +++ b/source/blender/blenkernel/intern/cdderivedmesh.cc @@ -190,9 +190,7 @@ static CDDerivedMesh *cdDM_create(const char *desc) return cddm; } -static DerivedMesh *cdDM_from_mesh_ex(Mesh *mesh, - eCDAllocType alloctype, - const CustomData_MeshMasks *mask) +static DerivedMesh *cdDM_from_mesh_ex(Mesh *mesh, const CustomData_MeshMasks *mask) { CDDerivedMesh *cddm = cdDM_create(__func__); DerivedMesh *dm = &cddm->dm; @@ -215,15 +213,14 @@ static DerivedMesh *cdDM_from_mesh_ex(Mesh *mesh, * (which isn't generally the case). */ dm->deformedOnly = 1; - CustomData_merge(&mesh->vdata, &dm->vertData, cddata_masks.vmask, alloctype, mesh->totvert); - CustomData_merge(&mesh->edata, &dm->edgeData, cddata_masks.emask, alloctype, mesh->totedge); + CustomData_merge(&mesh->vdata, &dm->vertData, cddata_masks.vmask, mesh->totvert); + CustomData_merge(&mesh->edata, &dm->edgeData, cddata_masks.emask, mesh->totedge); CustomData_merge(&mesh->fdata, &dm->faceData, cddata_masks.fmask | CD_MASK_ORIGINDEX, - alloctype, 0 /* `mesh->totface` */); - CustomData_merge(&mesh->ldata, &dm->loopData, cddata_masks.lmask, alloctype, mesh->totloop); - CustomData_merge(&mesh->pdata, &dm->polyData, cddata_masks.pmask, alloctype, mesh->totpoly); + CustomData_merge(&mesh->ldata, &dm->loopData, cddata_masks.lmask, mesh->totloop); + CustomData_merge(&mesh->pdata, &dm->polyData, cddata_masks.pmask, mesh->totpoly); cddm->vert_positions = static_cast(CustomData_get_layer_named_for_write( &dm->vertData, CD_PROP_FLOAT3, "position", mesh->totvert)); @@ -255,5 +252,5 @@ static DerivedMesh *cdDM_from_mesh_ex(Mesh *mesh, DerivedMesh *CDDM_from_mesh(Mesh *mesh) { - return cdDM_from_mesh_ex(mesh, CD_REFERENCE, &CD_MASK_MESH); + return cdDM_from_mesh_ex(mesh, &CD_MASK_MESH); } diff --git a/source/blender/blenkernel/intern/curves.cc b/source/blender/blenkernel/intern/curves.cc index 0dbdbaf0a57..c4d1cc10f8a 100644 --- a/source/blender/blenkernel/intern/curves.cc +++ b/source/blender/blenkernel/intern/curves.cc @@ -62,7 +62,7 @@ static void curves_init_data(ID *id) new (&curves->geometry) blender::bke::CurvesGeometry(); } -static void curves_copy_data(Main * /*bmain*/, ID *id_dst, const ID *id_src, const int flag) +static void curves_copy_data(Main * /*bmain*/, ID *id_dst, const ID *id_src, const int /*flag*/) { using namespace blender; @@ -80,9 +80,8 @@ static void curves_copy_data(Main * /*bmain*/, ID *id_dst, const ID *id_src, con dst.point_num = src.point_num; dst.curve_num = src.curve_num; - const eCDAllocType alloc_type = (flag & LIB_ID_COPY_CD_REFERENCE) ? CD_REFERENCE : CD_DUPLICATE; - CustomData_copy(&src.point_data, &dst.point_data, CD_MASK_ALL, alloc_type, dst.point_num); - CustomData_copy(&src.curve_data, &dst.curve_data, CD_MASK_ALL, alloc_type, dst.curve_num); + CustomData_copy(&src.point_data, &dst.point_data, CD_MASK_ALL, dst.point_num); + CustomData_copy(&src.curve_data, &dst.curve_data, CD_MASK_ALL, dst.curve_num); dst.curve_offsets = static_cast(MEM_dupallocN(src.curve_offsets)); diff --git a/source/blender/blenkernel/intern/curves_geometry.cc b/source/blender/blenkernel/intern/curves_geometry.cc index 108841b0bcc..6e6b8d7d72a 100644 --- a/source/blender/blenkernel/intern/curves_geometry.cc +++ b/source/blender/blenkernel/intern/curves_geometry.cc @@ -82,8 +82,8 @@ static void copy_curves_geometry(CurvesGeometry &dst, const CurvesGeometry &src) CustomData_free(&dst.curve_data, dst.curve_num); dst.point_num = src.point_num; dst.curve_num = src.curve_num; - CustomData_copy(&src.point_data, &dst.point_data, CD_MASK_ALL, CD_DUPLICATE, dst.point_num); - CustomData_copy(&src.curve_data, &dst.curve_data, CD_MASK_ALL, CD_DUPLICATE, dst.curve_num); + CustomData_copy(&src.point_data, &dst.point_data, CD_MASK_ALL, dst.point_num); + CustomData_copy(&src.curve_data, &dst.curve_data, CD_MASK_ALL, dst.curve_num); MEM_SAFE_FREE(dst.curve_offsets); dst.curve_offsets = (int *)MEM_malloc_arrayN(dst.point_num + 1, sizeof(int), __func__); diff --git a/source/blender/blenkernel/intern/curves_utils.cc b/source/blender/blenkernel/intern/curves_utils.cc index 9785928cf0c..8a58699dd59 100644 --- a/source/blender/blenkernel/intern/curves_utils.cc +++ b/source/blender/blenkernel/intern/curves_utils.cc @@ -101,11 +101,8 @@ void fill_points(const OffsetIndices points_by_curve, bke::CurvesGeometry copy_only_curve_domain(const bke::CurvesGeometry &src_curves) { bke::CurvesGeometry dst_curves(0, src_curves.curves_num()); - CustomData_copy(&src_curves.curve_data, - &dst_curves.curve_data, - CD_MASK_ALL, - CD_DUPLICATE, - src_curves.curves_num()); + CustomData_copy( + &src_curves.curve_data, &dst_curves.curve_data, CD_MASK_ALL, src_curves.curves_num()); dst_curves.runtime->type_counts = src_curves.runtime->type_counts; return dst_curves; } diff --git a/source/blender/blenkernel/intern/customdata.cc b/source/blender/blenkernel/intern/customdata.cc index 72636e2176c..d7f5b7365b4 100644 --- a/source/blender/blenkernel/intern/customdata.cc +++ b/source/blender/blenkernel/intern/customdata.cc @@ -2159,9 +2159,10 @@ void customData_mask_layers__print(const CustomData_MeshMasks *mask) static void customData_update_offsets(CustomData *data); static CustomDataLayer *customData_add_layer__internal(CustomData *data, - int type, + eCustomDataType type, eCDAllocType alloctype, - void *layerdata, + void *layer_data_to_assign, + const bCopyOnWrite *cow_to_assign, int totelem, const char *name); @@ -2192,93 +2193,108 @@ static bool customdata_typemap_is_valid(const CustomData *data) } #endif -bool CustomData_merge(const CustomData *source, - CustomData *dest, - eCustomDataMask mask, - eCDAllocType alloctype, - int totelem) +static void *copy_layer_data(const eCustomDataType type, const void *data, const int totelem) +{ + const LayerTypeInfo &type_info = *layerType_getInfo(type); + if (type_info.copy) { + void *new_data = MEM_malloc_arrayN(size_t(totelem), type_info.size, __func__); + type_info.copy(data, new_data, totelem); + return new_data; + } + return MEM_dupallocN(data); +} + +static void free_layer_data(const eCustomDataType type, const void *data, const int totelem) +{ + const LayerTypeInfo &type_info = *layerType_getInfo(type); + if (type_info.free) { + type_info.free(const_cast(data), totelem, type_info.size); + } + MEM_freeN(const_cast(data)); +} + +static bool customdata_merge_internal(const CustomData *source, + CustomData *dest, + const eCustomDataMask mask, + const eCDAllocType alloctype, + const int totelem) { - // const LayerTypeInfo *typeInfo; - CustomDataLayer *layer, *newlayer; - int lasttype = -1, lastactive = 0, lastrender = 0, lastclone = 0, lastmask = 0; - int number = 0, maxnumber = -1; bool changed = false; + int last_type = -1; + int last_active = 0; + int last_render = 0; + int last_clone = 0; + int last_mask = 0; + int current_type_layer_count = 0; + int max_current_type_layer_count = -1; + for (int i = 0; i < source->totlayer; i++) { - layer = &source->layers[i]; - // typeInfo = layerType_getInfo(layer->type); /* UNUSED */ + const CustomDataLayer &src_layer = source->layers[i]; + const eCustomDataType type = eCustomDataType(src_layer.type); + const int src_layer_flag = src_layer.flag; - int type = layer->type; - int flag = layer->flag; - - if (type != lasttype) { - number = 0; - maxnumber = CustomData_layertype_layers_max(type); - lastactive = layer->active; - lastrender = layer->active_rnd; - lastclone = layer->active_clone; - lastmask = layer->active_mask; - lasttype = type; + if (type != last_type) { + current_type_layer_count = 0; + max_current_type_layer_count = CustomData_layertype_layers_max(type); + last_active = src_layer.active; + last_render = src_layer.active_rnd; + last_clone = src_layer.active_clone; + last_mask = src_layer.active_mask; + last_type = type; } else { - number++; + current_type_layer_count++; } - if (flag & CD_FLAG_NOCOPY) { + if (src_layer_flag & CD_FLAG_NOCOPY) { + /* Don't merge this layer because it's not supposed to leave the source data. */ continue; } if (!(mask & CD_TYPE_AS_MASK(type))) { + /* Don't merge this layer because it does not match the type mask. */ continue; } - if ((maxnumber != -1) && (number >= maxnumber)) { + if ((max_current_type_layer_count != -1) && + (current_type_layer_count >= max_current_type_layer_count)) { + /* Don't merge this layer because the maximum amount of layers of this type is reached. */ continue; } - if (CustomData_get_named_layer_index(dest, type, layer->name) != -1) { + if (CustomData_get_named_layer_index(dest, type, src_layer.name) != -1) { + /* Don't merge this layer because it exists in the destination already. */ continue; } - void *data; - switch (alloctype) { - case CD_ASSIGN: - case CD_REFERENCE: - case CD_DUPLICATE: - data = layer->data; - break; - default: - data = nullptr; - break; - } - - if ((alloctype == CD_ASSIGN) && (flag & CD_FLAG_NOFREE)) { - newlayer = customData_add_layer__internal( - dest, type, CD_REFERENCE, data, totelem, layer->name); - } - else { - newlayer = customData_add_layer__internal(dest, type, alloctype, data, totelem, layer->name); - } - - if (newlayer) { - newlayer->uid = layer->uid; - - newlayer->active = lastactive; - newlayer->active_rnd = lastrender; - newlayer->active_clone = lastclone; - newlayer->active_mask = lastmask; - newlayer->flag |= flag & (CD_FLAG_EXTERNAL | CD_FLAG_IN_MEMORY); - changed = true; - - if (layer->anonymous_id != nullptr) { - newlayer->anonymous_id = layer->anonymous_id; - if (alloctype == CD_ASSIGN) { - layer->anonymous_id = nullptr; + void *layer_data_to_assign = nullptr; + const bCopyOnWrite *cow_to_assign = nullptr; + if (alloctype == CD_ASSIGN) { + if (src_layer.data != nullptr) { + if (src_layer.cow == nullptr) { + /* Can't share the layer, duplicate it instead. */ + layer_data_to_assign = copy_layer_data(type, src_layer.data, totelem); } else { - layer->anonymous_id->add_user(); + /* Share the layer. */ + layer_data_to_assign = src_layer.data; + cow_to_assign = src_layer.cow; } } - if (alloctype == CD_ASSIGN) { - layer->data = nullptr; - } + } + + CustomDataLayer *new_layer = customData_add_layer__internal( + dest, type, alloctype, layer_data_to_assign, cow_to_assign, totelem, src_layer.name); + + new_layer->uid = src_layer.uid; + new_layer->flag |= src_layer_flag & (CD_FLAG_EXTERNAL | CD_FLAG_IN_MEMORY); + new_layer->active = last_active; + new_layer->active_rnd = last_render; + new_layer->active_clone = last_clone; + new_layer->active_mask = last_mask; + changed = true; + + if (src_layer.anonymous_id != nullptr) { + new_layer->anonymous_id = src_layer.anonymous_id; + new_layer->anonymous_id->add_user(); } } @@ -2286,6 +2302,23 @@ bool CustomData_merge(const CustomData *source, return changed; } +bool CustomData_merge(const CustomData *source, + CustomData *dest, + eCustomDataMask mask, + int totelem) +{ + return customdata_merge_internal(source, dest, mask, CD_ASSIGN, totelem); +} + +bool CustomData_merge_new(const CustomData *source, + CustomData *dest, + const eCustomDataMask mask, + const eCDAllocType alloctype, + const int totelem) +{ + return customdata_merge_internal(source, dest, mask, alloctype, totelem); +} + CustomData CustomData_shallow_copy_remove_non_bmesh_attributes(const CustomData *src, const eCustomDataMask mask) { @@ -2311,28 +2344,85 @@ CustomData CustomData_shallow_copy_remove_non_bmesh_attributes(const CustomData return dst; } +/** + * A #bCopyOnWrite that knows how to free the entire referenced custom data layer (including + * potentially separately allocated chunks like for vertex groups). + */ +class CustomDataLayerCOW : public bCopyOnWrite { + private: + const void *data_; + const int totelem_; + const eCustomDataType type_; + + public: + CustomDataLayerCOW(const void *data, const int totelem, const eCustomDataType type) + : bCopyOnWrite(1), data_(data), totelem_(totelem), type_(type) + { + } + + private: + void delete_self_with_data() override + { + free_layer_data(type_, data_, totelem_); + MEM_delete(this); + } +}; + +/** Create a #bCopyOnWrite that takes ownership of the data. */ +static bCopyOnWrite *make_cow_for_array(const eCustomDataType type, + const void *data, + const int totelem) +{ + return MEM_new(__func__, data, totelem, type); +} + +/** + * If the layer data is currently shared (hence it is immutable), create a copy that can be edited. + */ +static void ensure_layer_data_is_mutable(CustomDataLayer &layer, const int totelem) +{ + if (layer.data == nullptr) { + return; + } + if (layer.cow == nullptr) { + /* Can not be shared without cow data. */ + return; + } + if (layer.cow->is_shared()) { + const eCustomDataType type = eCustomDataType(layer.type); + const void *old_data = layer.data; + layer.data = copy_layer_data(type, old_data, totelem); + layer.cow->remove_user_and_delete_if_last(); + layer.cow = make_cow_for_array(type, layer.data, totelem); + } +} + void CustomData_realloc(CustomData *data, const int old_size, const int new_size) { BLI_assert(new_size >= 0); for (int i = 0; i < data->totlayer; i++) { CustomDataLayer *layer = &data->layers[i]; const LayerTypeInfo *typeInfo = layerType_getInfo(layer->type); - const int64_t old_size_in_bytes = int64_t(old_size) * typeInfo->size; const int64_t new_size_in_bytes = int64_t(new_size) * typeInfo->size; - if (layer->flag & CD_FLAG_NOFREE) { - const void *old_data = layer->data; - layer->data = MEM_malloc_arrayN(new_size, typeInfo->size, __func__); - if (typeInfo->copy) { - typeInfo->copy(old_data, layer->data, std::min(old_size, new_size)); - } - else { - std::memcpy(layer->data, old_data, std::min(old_size_in_bytes, new_size_in_bytes)); - } - layer->flag &= ~CD_FLAG_NOFREE; + + void *new_layer_data = MEM_mallocN(new_size_in_bytes, __func__); + /* Copy or relocate data to new array. */ + if (typeInfo->copy) { + typeInfo->copy(layer->data, new_layer_data, std::min(old_size, new_size)); } else { - layer->data = MEM_reallocN(layer->data, new_size_in_bytes); + memcpy(new_layer_data, layer->data, std::min(old_size_in_bytes, new_size_in_bytes)); + } + /* Remove ownership of old array */ + if (layer->cow) { + layer->cow->remove_user_and_delete_if_last(); + layer->cow = nullptr; + } + /* Take ownership of new array. */ + layer->data = new_layer_data; + if (layer->data) { + layer->cow = make_cow_for_array(eCustomDataType(layer->type), layer->data, new_size); } if (new_size > old_size) { @@ -2345,11 +2435,7 @@ void CustomData_realloc(CustomData *data, const int old_size, const int new_size } } -void CustomData_copy(const CustomData *source, - CustomData *dest, - eCustomDataMask mask, - eCDAllocType alloctype, - int totelem) +void CustomData_copy(const CustomData *source, CustomData *dest, eCustomDataMask mask, int totelem) { CustomData_reset(dest); @@ -2357,28 +2443,39 @@ void CustomData_copy(const CustomData *source, dest->external = static_cast(MEM_dupallocN(source->external)); } - CustomData_merge(source, dest, mask, alloctype, totelem); + CustomData_merge(source, dest, mask, totelem); +} + +void CustomData_copy_new(const struct CustomData *source, + struct CustomData *dest, + eCustomDataMask mask, + eCDAllocType alloctype, + int totelem) +{ + CustomData_reset(dest); + + if (source->external) { + dest->external = static_cast(MEM_dupallocN(source->external)); + } + + CustomData_merge_new(source, dest, mask, alloctype, totelem); } static void customData_free_layer__internal(CustomDataLayer *layer, const int totelem) { - const LayerTypeInfo *typeInfo; - if (layer->anonymous_id != nullptr) { layer->anonymous_id->remove_user_and_delete_if_last(); layer->anonymous_id = nullptr; } - if (!(layer->flag & CD_FLAG_NOFREE) && layer->data) { - typeInfo = layerType_getInfo(layer->type); - - if (typeInfo->free) { - typeInfo->free(layer->data, totelem, typeInfo->size); - } - + const eCustomDataType type = eCustomDataType(layer->type); + if (layer->cow == nullptr) { if (layer->data) { - MEM_freeN(layer->data); + free_layer_data(type, layer->data, totelem); } } + else { + layer->cow->remove_user_and_delete_if_last(); + } } static void CustomData_external_free(CustomData *data) @@ -2726,107 +2823,40 @@ bool CustomData_layer_is_anonymous(const struct CustomData *data, int type, int return data->layers[layer_index].anonymous_id != nullptr; } -static bool customData_resize(CustomData *data, const int amount) +static void customData_resize(CustomData *data, const int grow_amount) { - CustomDataLayer *tmp = static_cast( - MEM_calloc_arrayN((data->maxlayer + amount), sizeof(*tmp), __func__)); - if (!tmp) { - return false; - } - - data->maxlayer += amount; - if (data->layers) { - memcpy(tmp, data->layers, sizeof(*tmp) * data->totlayer); - MEM_freeN(data->layers); - } - data->layers = tmp; - - return true; + data->layers = static_cast( + MEM_reallocN(data->layers, (data->maxlayer + grow_amount) * sizeof(CustomDataLayer))); + data->maxlayer += grow_amount; } static CustomDataLayer *customData_add_layer__internal(CustomData *data, - const int type, + const eCustomDataType type, const eCDAllocType alloctype, - void *layerdata, + void *layer_data_to_assign, + const bCopyOnWrite *cow_to_assign, const int totelem, const char *name) { - const LayerTypeInfo *typeInfo = layerType_getInfo(type); + const LayerTypeInfo &type_info = *layerType_getInfo(type); int flag = 0; /* Some layer types only support a single layer. */ - if (!typeInfo->defaultname && CustomData_has_layer(data, type)) { + if (!type_info.defaultname && CustomData_has_layer(data, type)) { /* This function doesn't support dealing with existing layer data for these layer types when * the layer already exists. */ - BLI_assert(layerdata == nullptr); + BLI_assert(layer_data_to_assign == nullptr); return &data->layers[CustomData_get_layer_index(data, type)]; } - void *newlayerdata = nullptr; - switch (alloctype) { - case CD_SET_DEFAULT: - if (totelem > 0) { - if (typeInfo->set_default_value) { - newlayerdata = MEM_malloc_arrayN(totelem, typeInfo->size, layerType_getName(type)); - typeInfo->set_default_value(newlayerdata, totelem); - } - else { - newlayerdata = MEM_calloc_arrayN(totelem, typeInfo->size, layerType_getName(type)); - } - } - break; - case CD_CONSTRUCT: - if (totelem > 0) { - newlayerdata = MEM_malloc_arrayN(totelem, typeInfo->size, layerType_getName(type)); - if (typeInfo->construct) { - typeInfo->construct(newlayerdata, totelem); - } - } - break; - case CD_ASSIGN: - if (totelem > 0) { - BLI_assert(layerdata != nullptr); - newlayerdata = layerdata; - } - else { - MEM_SAFE_FREE(layerdata); - } - break; - case CD_REFERENCE: - if (totelem > 0) { - BLI_assert(layerdata != nullptr); - newlayerdata = layerdata; - flag |= CD_FLAG_NOFREE; - } - break; - case CD_DUPLICATE: - if (totelem > 0) { - newlayerdata = MEM_malloc_arrayN(totelem, typeInfo->size, layerType_getName(type)); - if (typeInfo->copy) { - typeInfo->copy(layerdata, newlayerdata, totelem); - } - else { - BLI_assert(layerdata != nullptr); - BLI_assert(newlayerdata != nullptr); - memcpy(newlayerdata, layerdata, totelem * typeInfo->size); - } - } - break; - } - int index = data->totlayer; if (index >= data->maxlayer) { - if (!customData_resize(data, CUSTOMDATA_GROW)) { - if (newlayerdata != layerdata) { - MEM_freeN(newlayerdata); - } - return nullptr; - } + customData_resize(data, CUSTOMDATA_GROW); } data->totlayer++; - /* keep layers ordered by type */ + /* Keep layers ordered by type. */ for (; index > 0 && data->layers[index - 1].type > type; index--) { data->layers[index] = data->layers[index - 1]; } @@ -2838,15 +2868,56 @@ static CustomDataLayer *customData_add_layer__internal(CustomData *data, * leaks into the new layer. */ memset(&new_layer, 0, sizeof(CustomDataLayer)); + switch (alloctype) { + case CD_SET_DEFAULT: { + if (totelem > 0) { + if (type_info.set_default_value) { + new_layer.data = MEM_malloc_arrayN(totelem, type_info.size, layerType_getName(type)); + type_info.set_default_value(new_layer.data, totelem); + } + else { + new_layer.data = MEM_calloc_arrayN(totelem, type_info.size, layerType_getName(type)); + } + } + break; + } + case CD_CONSTRUCT: { + if (totelem > 0) { + new_layer.data = MEM_malloc_arrayN(totelem, type_info.size, layerType_getName(type)); + if (type_info.construct) { + type_info.construct(new_layer.data, totelem); + } + } + break; + } + case CD_ASSIGN: { + if (totelem == 0 && cow_to_assign == nullptr) { + MEM_SAFE_FREE(layer_data_to_assign); + } + else { + new_layer.data = layer_data_to_assign; + new_layer.cow = cow_to_assign; + if (new_layer.cow) { + new_layer.cow->add_user(); + } + } + break; + } + } + + if (new_layer.data != nullptr && new_layer.cow == nullptr) { + /* Make layer data shareable. */ + new_layer.cow = make_cow_for_array(type, new_layer.data, totelem); + } + new_layer.type = type; new_layer.flag = flag; - new_layer.data = newlayerdata; /* Set default name if none exists. Note we only call DATA_() once * we know there is a default name, to avoid overhead of locale lookups * in the depsgraph. */ - if (!name && typeInfo->defaultname) { - name = DATA_(typeInfo->defaultname); + if (!name && type_info.defaultname) { + name = DATA_(type_info.defaultname); } if (name) { @@ -2875,13 +2946,15 @@ static CustomDataLayer *customData_add_layer__internal(CustomData *data, return &data->layers[index]; } -static void *customdata_add_layer( - CustomData *data, const int type, eCDAllocType alloctype, void *layerdata, const int totelem) +void *CustomData_add_layer(CustomData *data, + const eCustomDataType type, + eCDAllocType alloctype, + const int totelem) { const LayerTypeInfo *typeInfo = layerType_getInfo(type); CustomDataLayer *layer = customData_add_layer__internal( - data, type, alloctype, layerdata, totelem, typeInfo->defaultname); + data, type, alloctype, nullptr, nullptr, totelem, typeInfo->defaultname); CustomData_update_typemap(data); if (layer) { @@ -2891,31 +2964,16 @@ static void *customdata_add_layer( return nullptr; } -void *CustomData_add_layer(CustomData *data, - const eCustomDataType type, - const eCDAllocType alloctype, - const int totelem) -{ - return customdata_add_layer(data, type, alloctype, nullptr, totelem); -} - const void *CustomData_add_layer_with_data(CustomData *data, const eCustomDataType type, void *layer_data, - const int totelem) + const int totelem, + const bCopyOnWrite *cow) { - return customdata_add_layer(data, type, CD_ASSIGN, layer_data, totelem); -} + const LayerTypeInfo *typeInfo = layerType_getInfo(type); -static void *customdata_add_layer_named(CustomData *data, - const eCustomDataType type, - const eCDAllocType alloctype, - void *layerdata, - const int totelem, - const char *name) -{ CustomDataLayer *layer = customData_add_layer__internal( - data, type, alloctype, layerdata, totelem, name); + data, type, CD_ASSIGN, layer_data, cow, totelem, typeInfo->defaultname); CustomData_update_typemap(data); if (layer) { @@ -2931,25 +2989,42 @@ void *CustomData_add_layer_named(CustomData *data, const int totelem, const char *name) { - return customdata_add_layer_named(data, type, alloctype, nullptr, totelem, name); + CustomDataLayer *layer = customData_add_layer__internal( + data, type, alloctype, nullptr, nullptr, totelem, name); + CustomData_update_typemap(data); + + if (layer) { + return layer->data; + } + return nullptr; } -const void *CustomData_add_layer_named_with_data( - CustomData *data, const eCustomDataType type, void *layer_data, int totelem, const char *name) +const void *CustomData_add_layer_named_with_data(CustomData *data, + eCustomDataType type, + void *layer_data, + int totelem, + const char *name, + const bCopyOnWrite *cow) { - return customdata_add_layer_named(data, type, CD_ASSIGN, layer_data, totelem, name); + CustomDataLayer *layer = customData_add_layer__internal( + data, type, CD_ASSIGN, layer_data, cow, totelem, name); + CustomData_update_typemap(data); + + if (layer) { + return layer->data; + } + return nullptr; } void *CustomData_add_layer_anonymous(CustomData *data, - const int type, + const eCustomDataType type, const eCDAllocType alloctype, - void *layerdata, const int totelem, const AnonymousAttributeIDHandle *anonymous_id) { const char *name = anonymous_id->name().c_str(); CustomDataLayer *layer = customData_add_layer__internal( - data, type, alloctype, layerdata, totelem, name); + data, type, alloctype, nullptr, nullptr, totelem, name); CustomData_update_typemap(data); if (layer == nullptr) { @@ -2961,6 +3036,27 @@ void *CustomData_add_layer_anonymous(CustomData *data, return layer->data; } +const void *CustomData_add_layer_anonymous_with_data( + CustomData *data, + const eCustomDataType type, + const AnonymousAttributeIDHandle *anonymous_id, + const int totelem, + void *layer_data, + const bCopyOnWrite *cow) +{ + const char *name = anonymous_id->name().c_str(); + CustomDataLayer *layer = customData_add_layer__internal( + data, type, CD_ASSIGN, layer_data, cow, totelem, name); + CustomData_update_typemap(data); + + if (layer == nullptr) { + return nullptr; + } + anonymous_id->add_user(); + layer->anonymous_id = anonymous_id; + return layer->data; +} + bool CustomData_free_layer(CustomData *data, const int type, const int totelem, const int index) { const int index_first = CustomData_get_layer_index(data, type); @@ -3086,47 +3182,6 @@ int CustomData_number_of_layers_typemask(const CustomData *data, const eCustomDa return number; } -static void *customData_duplicate_referenced_layer_index(CustomData *data, - const int layer_index, - const int totelem) -{ - if (layer_index == -1) { - return nullptr; - } - - CustomDataLayer *layer = &data->layers[layer_index]; - - if (layer->flag & CD_FLAG_NOFREE) { - /* MEM_dupallocN won't work in case of complex layers, like e.g. - * CD_MDEFORMVERT, which has pointers to allocated data... - * So in case a custom copy function is defined, use it! - */ - const LayerTypeInfo *typeInfo = layerType_getInfo(layer->type); - - if (typeInfo->copy) { - void *dst_data = MEM_malloc_arrayN( - size_t(totelem), typeInfo->size, "CD duplicate ref layer"); - typeInfo->copy(layer->data, dst_data, totelem); - layer->data = dst_data; - } - else { - layer->data = MEM_dupallocN(layer->data); - } - - layer->flag &= ~CD_FLAG_NOFREE; - } - - return layer->data; -} - -void CustomData_duplicate_referenced_layers(CustomData *data, const int totelem) -{ - for (int i = 0; i < data->totlayer; i++) { - CustomDataLayer *layer = &data->layers[i]; - layer->data = customData_duplicate_referenced_layer_index(data, i, totelem); - } -} - void CustomData_free_temporary(CustomData *data, const int totelem) { int i, j; @@ -3304,14 +3359,12 @@ void CustomData_copy_layer_type_data(const CustomData *source, void CustomData_free_elem(CustomData *data, const int index, const int count) { for (int i = 0; i < data->totlayer; i++) { - if (!(data->layers[i].flag & CD_FLAG_NOFREE)) { - const LayerTypeInfo *typeInfo = layerType_getInfo(data->layers[i].type); + const LayerTypeInfo *typeInfo = layerType_getInfo(data->layers[i].type); - if (typeInfo->free) { - size_t offset = size_t(index) * typeInfo->size; + if (typeInfo->free) { + size_t offset = size_t(index) * typeInfo->size; - typeInfo->free(POINTER_OFFSET(data->layers[i].data, offset), count, typeInfo->size); - } + typeInfo->free(POINTER_OFFSET(data->layers[i].data, offset), count, typeInfo->size); } } } @@ -3476,7 +3529,12 @@ const void *CustomData_get_layer(const CustomData *data, const int type) void *CustomData_get_layer_for_write(CustomData *data, const int type, const int totelem) { const int layer_index = CustomData_get_active_layer_index(data, type); - return customData_duplicate_referenced_layer_index(data, layer_index, totelem); + if (layer_index == -1) { + return nullptr; + } + CustomDataLayer &layer = data->layers[layer_index]; + ensure_layer_data_is_mutable(layer, totelem); + return layer.data; } const void *CustomData_get_layer_n(const CustomData *data, const int type, const int n) @@ -3485,7 +3543,6 @@ const void *CustomData_get_layer_n(const CustomData *data, const int type, const if (layer_index == -1) { return nullptr; } - return data->layers[layer_index].data; } @@ -3495,7 +3552,12 @@ void *CustomData_get_layer_n_for_write(CustomData *data, const int totelem) { const int layer_index = CustomData_get_layer_index_n(data, type, n); - return customData_duplicate_referenced_layer_index(data, layer_index, totelem); + if (layer_index == -1) { + return nullptr; + } + CustomDataLayer &layer = data->layers[layer_index]; + ensure_layer_data_is_mutable(layer, totelem); + return layer.data; } const void *CustomData_get_layer_named(const CustomData *data, const int type, const char *name) @@ -3504,7 +3566,6 @@ const void *CustomData_get_layer_named(const CustomData *data, const int type, c if (layer_index == -1) { return nullptr; } - return data->layers[layer_index].data; } @@ -3514,7 +3575,12 @@ void *CustomData_get_layer_named_for_write(CustomData *data, const int totelem) { const int layer_index = CustomData_get_named_layer_index(data, type, name); - return customData_duplicate_referenced_layer_index(data, layer_index, totelem); + if (layer_index == -1) { + return nullptr; + } + CustomDataLayer &layer = data->layers[layer_index]; + ensure_layer_data_is_mutable(layer, totelem); + return layer.data; } int CustomData_get_offset(const CustomData *data, const int type) @@ -3523,7 +3589,6 @@ int CustomData_get_offset(const CustomData *data, const int type) if (layer_index == -1) { return -1; } - return data->layers[layer_index].offset; } @@ -3601,12 +3666,12 @@ void CustomData_bmesh_init_pool(CustomData *data, const int totelem, const char } } -bool CustomData_bmesh_merge(const CustomData *source, - CustomData *dest, - eCustomDataMask mask, - eCDAllocType alloctype, - BMesh *bm, - const char htype) +bool CustomData_bmesh_merge_new(const CustomData *source, + CustomData *dest, + eCustomDataMask mask, + eCDAllocType alloctype, + BMesh *bm, + const char htype) { if (CustomData_number_of_layers_typemask(source, mask) == 0) { @@ -3620,7 +3685,7 @@ bool CustomData_bmesh_merge(const CustomData *source, destold.layers = static_cast(MEM_dupallocN(destold.layers)); } - if (CustomData_merge(source, dest, mask, alloctype, 0) == false) { + if (CustomData_merge_new(source, dest, mask, alloctype, 0) == false) { if (destold.layers) { MEM_freeN(destold.layers); } @@ -3700,13 +3765,11 @@ void CustomData_bmesh_free_block(CustomData *data, void **block) } for (int i = 0; i < data->totlayer; i++) { - if (!(data->layers[i].flag & CD_FLAG_NOFREE)) { - const LayerTypeInfo *typeInfo = layerType_getInfo(data->layers[i].type); + const LayerTypeInfo *typeInfo = layerType_getInfo(data->layers[i].type); - if (typeInfo->free) { - int offset = data->layers[i].offset; - typeInfo->free(POINTER_OFFSET(*block, offset), 1, typeInfo->size); - } + if (typeInfo->free) { + int offset = data->layers[i].offset; + typeInfo->free(POINTER_OFFSET(*block, offset), 1, typeInfo->size); } } @@ -3723,12 +3786,10 @@ void CustomData_bmesh_free_block_data(CustomData *data, void *block) return; } for (int i = 0; i < data->totlayer; i++) { - if (!(data->layers[i].flag & CD_FLAG_NOFREE)) { - const LayerTypeInfo *typeInfo = layerType_getInfo(data->layers[i].type); - if (typeInfo->free) { - const size_t offset = data->layers[i].offset; - typeInfo->free(POINTER_OFFSET(block, offset), 1, typeInfo->size); - } + const LayerTypeInfo *typeInfo = layerType_getInfo(data->layers[i].type); + if (typeInfo->free) { + const size_t offset = data->layers[i].offset; + typeInfo->free(POINTER_OFFSET(block, offset), 1, typeInfo->size); } } if (data->totsize) { @@ -3761,10 +3822,8 @@ void CustomData_bmesh_free_block_data_exclude_by_type(CustomData *data, if ((CD_TYPE_AS_MASK(data->layers[i].type) & mask_exclude) == 0) { const LayerTypeInfo *typeInfo = layerType_getInfo(data->layers[i].type); const size_t offset = data->layers[i].offset; - if (!(data->layers[i].flag & CD_FLAG_NOFREE)) { - if (typeInfo->free) { - typeInfo->free(POINTER_OFFSET(block, offset), 1, typeInfo->size); - } + if (typeInfo->free) { + typeInfo->free(POINTER_OFFSET(block, offset), 1, typeInfo->size); } memset(POINTER_OFFSET(block, offset), 0, typeInfo->size); } @@ -3937,11 +3996,9 @@ bool CustomData_has_math(const CustomData *data) bool CustomData_bmesh_has_free(const CustomData *data) { for (int i = 0; i < data->totlayer; i++) { - if (!(data->layers[i].flag & CD_FLAG_NOFREE)) { - const LayerTypeInfo *typeInfo = layerType_getInfo(data->layers[i].type); - if (typeInfo->free) { - return true; - } + const LayerTypeInfo *typeInfo = layerType_getInfo(data->layers[i].type); + if (typeInfo->free) { + return true; } } return false; @@ -3959,16 +4016,6 @@ bool CustomData_has_interp(const CustomData *data) return false; } -bool CustomData_has_referenced(const CustomData *data) -{ - for (int i = 0; i < data->totlayer; i++) { - if (data->layers[i].flag & CD_FLAG_NOFREE) { - return true; - } - } - return false; -} - void CustomData_data_copy_value(int type, const void *source, void *dest) { const LayerTypeInfo *typeInfo = layerType_getInfo(type); @@ -5029,6 +5076,10 @@ void CustomData_blend_write(BlendWriter *writer, writer, CustomDataLayer, data->totlayer, data->layers, layers_to_write.data()); for (const CustomDataLayer &layer : layers_to_write) { + if (BLO_write_is_undo(writer) && layer.cow != nullptr) { + BLO_write_cow(writer, layer.data, layer.cow); + continue; + } switch (layer.type) { case CD_MDEFORMVERT: BKE_defvert_blend_write(writer, count, static_cast(layer.data)); @@ -5144,10 +5195,18 @@ void CustomData_blend_read(BlendDataReader *reader, CustomData *data, const int layer->flag &= ~CD_FLAG_IN_MEMORY; } - layer->flag &= ~CD_FLAG_NOFREE; - if (CustomData_verify_versions(data, i)) { + if (BLO_read_is_cow_data(reader, layer->data)) { + BLI_assert(layer->cow != nullptr); + layer->cow->add_user(); + i++; + continue; + } BLO_read_data_address(reader, &layer->data); + if (layer->data != nullptr) { + /* Make layer data shareable. */ + layer->cow = make_cow_for_array(eCustomDataType(layer->type), layer->data, count); + } if (CustomData_layer_ensure_data_exists(layer, count)) { /* Under normal operations, this shouldn't happen, but... * For a CD_PROP_BOOL example, see #84935. diff --git a/source/blender/blenkernel/intern/mesh.cc b/source/blender/blenkernel/intern/mesh.cc index 79e03ccd933..b433e4437b7 100644 --- a/source/blender/blenkernel/intern/mesh.cc +++ b/source/blender/blenkernel/intern/mesh.cc @@ -151,13 +151,12 @@ static void mesh_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int mesh_dst->default_color_attribute = static_cast( MEM_dupallocN(mesh_src->default_color_attribute)); - const eCDAllocType alloc_type = (flag & LIB_ID_COPY_CD_REFERENCE) ? CD_REFERENCE : CD_DUPLICATE; - CustomData_copy(&mesh_src->vdata, &mesh_dst->vdata, mask.vmask, alloc_type, mesh_dst->totvert); - CustomData_copy(&mesh_src->edata, &mesh_dst->edata, mask.emask, alloc_type, mesh_dst->totedge); - CustomData_copy(&mesh_src->ldata, &mesh_dst->ldata, mask.lmask, alloc_type, mesh_dst->totloop); - CustomData_copy(&mesh_src->pdata, &mesh_dst->pdata, mask.pmask, alloc_type, mesh_dst->totpoly); + CustomData_copy(&mesh_src->vdata, &mesh_dst->vdata, mask.vmask, mesh_dst->totvert); + CustomData_copy(&mesh_src->edata, &mesh_dst->edata, mask.emask, mesh_dst->totedge); + CustomData_copy(&mesh_src->ldata, &mesh_dst->ldata, mask.lmask, mesh_dst->totloop); + CustomData_copy(&mesh_src->pdata, &mesh_dst->pdata, mask.pmask, mesh_dst->totpoly); if (do_tessface) { - CustomData_copy(&mesh_src->fdata, &mesh_dst->fdata, mask.fmask, alloc_type, mesh_dst->totface); + CustomData_copy(&mesh_src->fdata, &mesh_dst->fdata, mask.fmask, mesh_dst->totface); } else { mesh_tessface_clear_intern(mesh_dst, false); @@ -1068,12 +1067,12 @@ Mesh *BKE_mesh_new_nomain_from_template_ex(const Mesh *me_src, BKE_mesh_copy_parameters_for_eval(me_dst, me_src); - CustomData_copy(&me_src->vdata, &me_dst->vdata, mask.vmask, CD_SET_DEFAULT, verts_len); - CustomData_copy(&me_src->edata, &me_dst->edata, mask.emask, CD_SET_DEFAULT, edges_len); - CustomData_copy(&me_src->ldata, &me_dst->ldata, mask.lmask, CD_SET_DEFAULT, loops_len); - CustomData_copy(&me_src->pdata, &me_dst->pdata, mask.pmask, CD_SET_DEFAULT, polys_len); + CustomData_copy_new(&me_src->vdata, &me_dst->vdata, mask.vmask, CD_SET_DEFAULT, verts_len); + CustomData_copy_new(&me_src->edata, &me_dst->edata, mask.emask, CD_SET_DEFAULT, edges_len); + CustomData_copy_new(&me_src->ldata, &me_dst->ldata, mask.lmask, CD_SET_DEFAULT, loops_len); + CustomData_copy_new(&me_src->pdata, &me_dst->pdata, mask.pmask, CD_SET_DEFAULT, polys_len); if (do_tessface) { - CustomData_copy(&me_src->fdata, &me_dst->fdata, mask.fmask, CD_SET_DEFAULT, tessface_len); + CustomData_copy_new(&me_src->fdata, &me_dst->fdata, mask.fmask, CD_SET_DEFAULT, tessface_len); } else { mesh_tessface_clear_intern(me_dst, false); @@ -1349,7 +1348,7 @@ void BKE_mesh_orco_ensure(Object *ob, Mesh *mesh) /* Orcos are stored in normalized 0..1 range by convention. */ float(*orcodata)[3] = BKE_mesh_orco_verts_get(ob); BKE_mesh_orco_verts_transform(mesh, orcodata, mesh->totvert, false); - CustomData_add_layer_with_data(&mesh->vdata, CD_ORCO, orcodata, mesh->totvert); + CustomData_add_layer_with_data(&mesh->vdata, CD_ORCO, orcodata, mesh->totvert, nullptr); } Mesh *BKE_mesh_from_object(Object *ob) diff --git a/source/blender/blenkernel/intern/mesh_boolean_convert.cc b/source/blender/blenkernel/intern/mesh_boolean_convert.cc index b4f208bcfda..68cc5bab8c8 100644 --- a/source/blender/blenkernel/intern/mesh_boolean_convert.cc +++ b/source/blender/blenkernel/intern/mesh_boolean_convert.cc @@ -658,15 +658,15 @@ static void merge_vertex_loop_poly_customdata_layers(Mesh *target, MeshesToIMesh for (int mesh_index = 1; mesh_index < mim.meshes.size(); ++mesh_index) { const Mesh *me = mim.meshes[mesh_index]; if (me->totvert) { - CustomData_merge( + CustomData_merge_new( &me->vdata, &target->vdata, CD_MASK_MESH.vmask, CD_SET_DEFAULT, target->totvert); } if (me->totloop) { - CustomData_merge( + CustomData_merge_new( &me->ldata, &target->ldata, CD_MASK_MESH.lmask, CD_SET_DEFAULT, target->totloop); } if (me->totpoly) { - CustomData_merge( + CustomData_merge_new( &me->pdata, &target->pdata, CD_MASK_MESH.pmask, CD_SET_DEFAULT, target->totpoly); } } @@ -677,7 +677,7 @@ static void merge_edge_customdata_layers(Mesh *target, MeshesToIMeshInfo &mim) for (int mesh_index = 0; mesh_index < mim.meshes.size(); ++mesh_index) { const Mesh *me = mim.meshes[mesh_index]; if (me->totedge) { - CustomData_merge( + CustomData_merge_new( &me->edata, &target->edata, CD_MASK_MESH.emask, CD_SET_DEFAULT, target->totedge); } } diff --git a/source/blender/blenkernel/intern/mesh_calc_edges.cc b/source/blender/blenkernel/intern/mesh_calc_edges.cc index bef3ad351ec..b504df0eb86 100644 --- a/source/blender/blenkernel/intern/mesh_calc_edges.cc +++ b/source/blender/blenkernel/intern/mesh_calc_edges.cc @@ -248,7 +248,7 @@ void BKE_mesh_calc_edges(Mesh *mesh, bool keep_existing_edges, const bool select /* Free old CustomData and assign new one. */ CustomData_free(&mesh->edata, mesh->totedge); CustomData_reset(&mesh->edata); - CustomData_add_layer_with_data(&mesh->edata, CD_MEDGE, new_edges.data(), new_totedge); + CustomData_add_layer_with_data(&mesh->edata, CD_MEDGE, new_edges.data(), new_totedge, nullptr); mesh->totedge = new_totedge; if (select_new_edges) { diff --git a/source/blender/blenkernel/intern/mesh_convert.cc b/source/blender/blenkernel/intern/mesh_convert.cc index 878edb31d8a..675acf5fbfe 100644 --- a/source/blender/blenkernel/intern/mesh_convert.cc +++ b/source/blender/blenkernel/intern/mesh_convert.cc @@ -629,7 +629,8 @@ void BKE_pointcloud_from_mesh(const Mesh *me, PointCloud *pointcloud) { CustomData_free(&pointcloud->pdata, pointcloud->totpoint); pointcloud->totpoint = me->totvert; - CustomData_merge(&me->vdata, &pointcloud->pdata, CD_MASK_PROP_ALL, CD_DUPLICATE, me->totvert); + + CustomData_merge(&me->vdata, &pointcloud->pdata, CD_MASK_PROP_ALL, me->totvert); } void BKE_mesh_to_pointcloud(Main *bmain, Depsgraph *depsgraph, Scene * /*scene*/, Object *ob) @@ -656,8 +657,7 @@ void BKE_mesh_to_pointcloud(Main *bmain, Depsgraph *depsgraph, Scene * /*scene*/ void BKE_mesh_from_pointcloud(const PointCloud *pointcloud, Mesh *me) { me->totvert = pointcloud->totpoint; - CustomData_merge( - &pointcloud->pdata, &me->vdata, CD_MASK_PROP_ALL, CD_DUPLICATE, pointcloud->totpoint); + CustomData_merge(&pointcloud->pdata, &me->vdata, CD_MASK_PROP_ALL, pointcloud->totpoint); } void BKE_pointcloud_to_mesh(Main *bmain, Depsgraph *depsgraph, Scene * /*scene*/, Object *ob) @@ -1120,13 +1120,6 @@ void BKE_mesh_nomain_to_mesh(Mesh *mesh_src, Mesh *mesh_dst, Object *ob) BKE_mesh_clear_geometry(mesh_dst); - /* Make sure referenced layers have a single user so assigning them to the mesh in main doesn't - * share them. "Referenced" layers are not expected to be shared between original meshes. */ - CustomData_duplicate_referenced_layers(&mesh_src->vdata, mesh_src->totvert); - CustomData_duplicate_referenced_layers(&mesh_src->edata, mesh_src->totedge); - CustomData_duplicate_referenced_layers(&mesh_src->pdata, mesh_src->totpoly); - CustomData_duplicate_referenced_layers(&mesh_src->ldata, mesh_src->totloop); - const bool verts_num_changed = mesh_dst->totvert != mesh_src->totvert; mesh_dst->totvert = mesh_src->totvert; mesh_dst->totedge = mesh_src->totedge; @@ -1135,10 +1128,10 @@ void BKE_mesh_nomain_to_mesh(Mesh *mesh_src, Mesh *mesh_dst, Object *ob) /* Using #CD_MASK_MESH ensures that only data that should exist in Main meshes is moved. */ const CustomData_MeshMasks mask = CD_MASK_MESH; - CustomData_copy(&mesh_src->vdata, &mesh_dst->vdata, mask.vmask, CD_ASSIGN, mesh_src->totvert); - CustomData_copy(&mesh_src->edata, &mesh_dst->edata, mask.emask, CD_ASSIGN, mesh_src->totedge); - CustomData_copy(&mesh_src->pdata, &mesh_dst->pdata, mask.pmask, CD_ASSIGN, mesh_src->totpoly); - CustomData_copy(&mesh_src->ldata, &mesh_dst->ldata, mask.lmask, CD_ASSIGN, mesh_src->totloop); + CustomData_copy(&mesh_src->vdata, &mesh_dst->vdata, mask.vmask, mesh_src->totvert); + CustomData_copy(&mesh_src->edata, &mesh_dst->edata, mask.emask, mesh_src->totedge); + CustomData_copy(&mesh_src->pdata, &mesh_dst->pdata, mask.pmask, mesh_src->totpoly); + CustomData_copy(&mesh_src->ldata, &mesh_dst->ldata, mask.lmask, mesh_src->totloop); /* Make sure active/default color attribute (names) are brought over. */ if (mesh_src->active_color_attribute) { diff --git a/source/blender/blenkernel/intern/mesh_legacy_convert.cc b/source/blender/blenkernel/intern/mesh_legacy_convert.cc index 10de69832a5..92a5f685ca3 100644 --- a/source/blender/blenkernel/intern/mesh_legacy_convert.cc +++ b/source/blender/blenkernel/intern/mesh_legacy_convert.cc @@ -228,7 +228,7 @@ void BKE_mesh_calc_edges_legacy(Mesh *me) return; } - edges = (MEdge *)CustomData_add_layer_with_data(&me->edata, CD_MEDGE, edges, totedge); + edges = (MEdge *)CustomData_add_layer_with_data(&me->edata, CD_MEDGE, edges, totedge, nullptr); me->totedge = totedge; BKE_mesh_tag_topology_changed(me); @@ -1152,11 +1152,11 @@ static int mesh_tessface_calc(Mesh &mesh, sizeof(*mface_to_poly_map) * size_t(totface)); } - CustomData_add_layer_with_data(fdata, CD_MFACE, mface, totface); + CustomData_add_layer_with_data(fdata, CD_MFACE, mface, totface, nullptr); /* #CD_ORIGINDEX will contain an array of indices from tessellation-faces to the polygons * they are directly tessellated from. */ - CustomData_add_layer_with_data(fdata, CD_ORIGINDEX, mface_to_poly_map, totface); + CustomData_add_layer_with_data(fdata, CD_ORIGINDEX, mface_to_poly_map, totface, nullptr); add_mface_layers(mesh, fdata, ldata, totface); /* NOTE: quad detection issue - fourth vertex-index vs fourth loop-index: @@ -1300,17 +1300,22 @@ void BKE_mesh_legacy_face_set_to_generic(Mesh *mesh) return; } void *faceset_data = nullptr; + const bCopyOnWrite *faceset_cow = nullptr; for (const int i : IndexRange(mesh->pdata.totlayer)) { - if (mesh->pdata.layers[i].type == CD_SCULPT_FACE_SETS) { - faceset_data = mesh->pdata.layers[i].data; - mesh->pdata.layers[i].data = nullptr; + CustomDataLayer &layer = mesh->pdata.layers[i]; + if (layer.type == CD_SCULPT_FACE_SETS) { + faceset_data = layer.data; + faceset_cow = layer.cow; + layer.data = nullptr; + layer.cow = nullptr; CustomData_free_layer(&mesh->pdata, CD_SCULPT_FACE_SETS, mesh->totpoly, i); break; } } if (faceset_data != nullptr) { CustomData_add_layer_named_with_data( - &mesh->pdata, CD_PROP_INT32, faceset_data, mesh->totpoly, ".sculpt_face_set"); + &mesh->pdata, CD_PROP_INT32, faceset_data, mesh->totpoly, ".sculpt_face_set", faceset_cow); + faceset_cow->remove_user_and_delete_if_last(); } } @@ -1811,28 +1816,31 @@ void BKE_mesh_legacy_convert_uvs_to_generic(Mesh *mesh) CustomData_free_layer_named(&mesh->ldata, name.c_str(), mesh->totloop); CustomData_add_layer_named_with_data( - &mesh->ldata, CD_PROP_FLOAT2, coords, mesh->totloop, name.c_str()); + &mesh->ldata, CD_PROP_FLOAT2, coords, mesh->totloop, name.c_str(), nullptr); char buffer[MAX_CUSTOMDATA_LAYER_NAME]; if (vert_selection) { CustomData_add_layer_named_with_data(&mesh->ldata, CD_PROP_BOOL, vert_selection, mesh->totloop, - BKE_uv_map_vert_select_name_get(name.c_str(), buffer)); + BKE_uv_map_vert_select_name_get(name.c_str(), buffer), + nullptr); } if (edge_selection) { CustomData_add_layer_named_with_data(&mesh->ldata, CD_PROP_BOOL, edge_selection, mesh->totloop, - BKE_uv_map_edge_select_name_get(name.c_str(), buffer)); + BKE_uv_map_edge_select_name_get(name.c_str(), buffer), + nullptr); } if (pin) { CustomData_add_layer_named_with_data(&mesh->ldata, CD_PROP_BOOL, pin, mesh->totloop, - BKE_uv_map_pin_name_get(name.c_str(), buffer)); + BKE_uv_map_pin_name_get(name.c_str(), buffer), + nullptr); } } diff --git a/source/blender/blenkernel/intern/pointcloud.cc b/source/blender/blenkernel/intern/pointcloud.cc index 93457239348..c9dece1d212 100644 --- a/source/blender/blenkernel/intern/pointcloud.cc +++ b/source/blender/blenkernel/intern/pointcloud.cc @@ -71,18 +71,17 @@ static void pointcloud_init_data(ID *id) pointcloud->runtime = new blender::bke::PointCloudRuntime(); } -static void pointcloud_copy_data(Main * /*bmain*/, ID *id_dst, const ID *id_src, const int flag) +static void pointcloud_copy_data(Main * /*bmain*/, + ID *id_dst, + const ID *id_src, + const int /*flag*/) { PointCloud *pointcloud_dst = (PointCloud *)id_dst; const PointCloud *pointcloud_src = (const PointCloud *)id_src; pointcloud_dst->mat = static_cast(MEM_dupallocN(pointcloud_src->mat)); - const eCDAllocType alloc_type = (flag & LIB_ID_COPY_CD_REFERENCE) ? CD_REFERENCE : CD_DUPLICATE; - CustomData_copy(&pointcloud_src->pdata, - &pointcloud_dst->pdata, - CD_MASK_ALL, - alloc_type, - pointcloud_dst->totpoint); + CustomData_copy( + &pointcloud_src->pdata, &pointcloud_dst->pdata, CD_MASK_ALL, pointcloud_dst->totpoint); pointcloud_dst->runtime = new blender::bke::PointCloudRuntime(); pointcloud_dst->runtime->bounds_cache = pointcloud_src->runtime->bounds_cache; @@ -259,27 +258,12 @@ void BKE_pointcloud_nomain_to_pointcloud(PointCloud *pointcloud_src, { BLI_assert(pointcloud_src->id.tag & LIB_TAG_NO_MAIN); - eCDAllocType alloctype = CD_DUPLICATE; - - if (take_ownership) { - bool has_any_referenced_layers = CustomData_has_referenced(&pointcloud_src->pdata); - - if (!has_any_referenced_layers) { - alloctype = CD_ASSIGN; - } - } - CustomData_free(&pointcloud_dst->pdata, pointcloud_dst->totpoint); const int totpoint = pointcloud_dst->totpoint = pointcloud_src->totpoint; - CustomData_copy( - &pointcloud_src->pdata, &pointcloud_dst->pdata, CD_MASK_ALL, alloctype, totpoint); + CustomData_copy(&pointcloud_src->pdata, &pointcloud_dst->pdata, CD_MASK_ALL, totpoint); if (take_ownership) { - if (alloctype == CD_ASSIGN) { - /* Free the CustomData but keep the layers. */ - CustomData_free_typemask(&pointcloud_src->pdata, pointcloud_src->totpoint, 0); - } BKE_id_free(nullptr, pointcloud_src); } } diff --git a/source/blender/blenkernel/intern/subdiv_mesh.cc b/source/blender/blenkernel/intern/subdiv_mesh.cc index 4945a9180dc..aa17251f402 100644 --- a/source/blender/blenkernel/intern/subdiv_mesh.cc +++ b/source/blender/blenkernel/intern/subdiv_mesh.cc @@ -219,11 +219,11 @@ static void vertex_interpolation_init(const SubdivMeshContext *ctx, else { vertex_interpolation->vertex_data = &vertex_interpolation->vertex_data_storage; /* Allocate storage for loops corresponding to ptex corners. */ - CustomData_copy(&ctx->coarse_mesh->vdata, - &vertex_interpolation->vertex_data_storage, - CD_MASK_EVERYTHING.vmask, - CD_SET_DEFAULT, - 4); + CustomData_copy_new(&ctx->coarse_mesh->vdata, + &vertex_interpolation->vertex_data_storage, + CD_MASK_EVERYTHING.vmask, + CD_SET_DEFAULT, + 4); /* Initialize indices. */ vertex_interpolation->vertex_indices[0] = 0; vertex_interpolation->vertex_indices[1] = 1; @@ -349,11 +349,11 @@ static void loop_interpolation_init(const SubdivMeshContext *ctx, else { loop_interpolation->loop_data = &loop_interpolation->loop_data_storage; /* Allocate storage for loops corresponding to ptex corners. */ - CustomData_copy(&ctx->coarse_mesh->ldata, - &loop_interpolation->loop_data_storage, - CD_MASK_EVERYTHING.lmask, - CD_SET_DEFAULT, - 4); + CustomData_copy_new(&ctx->coarse_mesh->ldata, + &loop_interpolation->loop_data_storage, + CD_MASK_EVERYTHING.lmask, + CD_SET_DEFAULT, + 4); /* Initialize indices. */ loop_interpolation->loop_indices[0] = 0; loop_interpolation->loop_indices[1] = 1; diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt index 04ba4a672ee..39b7b60b554 100644 --- a/source/blender/blenlib/CMakeLists.txt +++ b/source/blender/blenlib/CMakeLists.txt @@ -200,6 +200,8 @@ set(SRC BLI_compute_context.hh BLI_console.h BLI_convexhull_2d.h + BLI_copy_on_write.hh + BLI_copy_on_write_user.hh BLI_cpp_type.hh BLI_cpp_type_make.hh BLI_cpp_types.hh diff --git a/source/blender/blenloader/BLO_read_write.h b/source/blender/blenloader/BLO_read_write.h index f1685d079e4..de8d0277f53 100644 --- a/source/blender/blenloader/BLO_read_write.h +++ b/source/blender/blenloader/BLO_read_write.h @@ -42,6 +42,7 @@ typedef struct BlendWriter BlendWriter; struct BlendFileReadReport; struct Main; +struct bCopyOnWrite; /* -------------------------------------------------------------------- */ /** \name Blend Write API @@ -175,6 +176,14 @@ void BLO_write_string(BlendWriter *writer, const char *data_ptr); /* Misc. */ +#ifdef __cplusplus +/** + * Give (shared) ownership of the data to the undo system so that the data does not have to be + * copied. + */ +void BLO_write_cow(BlendWriter *writer, const void *data_ptr, const bCopyOnWrite *cow); +#endif + /** * Sometimes different data is written depending on whether the file is saved to disk or used for * undo. This function returns true when the current file-writing is done for undo. @@ -236,6 +245,12 @@ void BLO_read_float3_array(BlendDataReader *reader, int array_size, float **ptr_ void BLO_read_double_array(BlendDataReader *reader, int array_size, double **ptr_p); void BLO_read_pointer_array(BlendDataReader *reader, void **ptr_p); +/** + * True when the pointer refers to valid data and can still be used. In order to take (shared) + * ownership of the data, the user count of the corresponding #bCopyOnWrite has to be increased. + */ +bool BLO_read_is_cow_data(BlendDataReader *reader, const void *cow_data); + /* Misc. */ int BLO_read_fileversion_get(BlendDataReader *reader); diff --git a/source/blender/blenloader/BLO_undofile.h b/source/blender/blenloader/BLO_undofile.h index 0dee167db53..ebb1d727bac 100644 --- a/source/blender/blenloader/BLO_undofile.h +++ b/source/blender/blenloader/BLO_undofile.h @@ -13,6 +13,25 @@ struct GHash; struct Scene; +#ifdef __cplusplus + +# include "BLI_copy_on_write.hh" +# include "BLI_map.hh" + +/** + * Takes (shared) ownership of copy-on-write data so that it does not have to be copied into the + * undo step. + */ +struct MemFileCowStorage { + blender::Map map; + + ~MemFileCowStorage(); +}; + +#else +typedef struct MemFileCowStorage MemFileCowStorage; +#endif + typedef struct { void *next, *prev; const char *buf; @@ -32,6 +51,7 @@ typedef struct { typedef struct MemFile { ListBase chunks; size_t size; + MemFileCowStorage *cow_storage; } MemFile; typedef struct MemFileWriteData { @@ -102,7 +122,6 @@ extern struct Main *BLO_memfile_main_get(struct MemFile *memfile, * * \return success. */ -extern bool BLO_memfile_write_file(struct MemFile *memfile, const char *filepath); FileReader *BLO_memfile_new_filereader(MemFile *memfile, int undo_direction); diff --git a/source/blender/blenloader/intern/readfile.cc b/source/blender/blenloader/intern/readfile.cc index 74c8442c212..3cfcc54fc1d 100644 --- a/source/blender/blenloader/intern/readfile.cc +++ b/source/blender/blenloader/intern/readfile.cc @@ -5205,4 +5205,20 @@ void BLO_expand_id(BlendExpander *expander, ID *id) expand_doit(expander->fd, expander->main, id); } +bool BLO_read_is_cow_data(BlendDataReader *reader, const void *cow_data) +{ + if (!BLO_read_data_is_undo(reader)) { + return false; + } + if (!(reader->fd->flags & FD_FLAGS_IS_MEMFILE)) { + return false; + } + UndoReader *undo_reader = reinterpret_cast(reader->fd->file); + MemFile &memfile = *undo_reader->memfile; + if (memfile.cow_storage == nullptr) { + return false; + } + return memfile.cow_storage->map.contains(cow_data); +} + /** \} */ diff --git a/source/blender/blenloader/intern/undofile.cc b/source/blender/blenloader/intern/undofile.cc index 5db5b465b96..0dba88a91e2 100644 --- a/source/blender/blenloader/intern/undofile.cc +++ b/source/blender/blenloader/intern/undofile.cc @@ -24,6 +24,7 @@ #include "DNA_listBase.h" #include "BLI_blenlib.h" +#include "BLI_copy_on_write.hh" #include "BLI_ghash.h" #include "BLO_readfile.h" @@ -48,9 +49,20 @@ void BLO_memfile_free(MemFile *memfile) } MEM_freeN(chunk); } + if (memfile->cow_storage) { + MEM_delete(memfile->cow_storage); + memfile->cow_storage = nullptr; + } memfile->size = 0; } +MemFileCowStorage::~MemFileCowStorage() +{ + for (auto item : this->map.items()) { + item.value->remove_user_and_delete_if_last(); + } +} + void BLO_memfile_merge(MemFile *first, MemFile *second) { /* We use this mapping to store the memory buffers from second memfile chunks which are not owned @@ -199,61 +211,6 @@ struct Main *BLO_memfile_main_get(struct MemFile *memfile, return bmain_undo; } -bool BLO_memfile_write_file(struct MemFile *memfile, const char *filepath) -{ - MemFileChunk *chunk; - int file, oflags; - - /* NOTE: This is currently used for autosave and 'quit.blend', - * where _not_ following symlinks is OK, - * however if this is ever executed explicitly by the user, - * we may want to allow writing to symlinks. - */ - - oflags = O_BINARY | O_WRONLY | O_CREAT | O_TRUNC; -#ifdef O_NOFOLLOW - /* use O_NOFOLLOW to avoid writing to a symlink - use 'O_EXCL' (CVE-2008-1103) */ - oflags |= O_NOFOLLOW; -#else - /* TODO(sergey): How to deal with symlinks on windows? */ -# ifndef _MSC_VER -# warning "Symbolic links will be followed on undo save, possibly causing CVE-2008-1103" -# endif -#endif - file = BLI_open(filepath, oflags, 0666); - - if (file == -1) { - fprintf(stderr, - "Unable to save '%s': %s\n", - filepath, - errno ? strerror(errno) : "Unknown error opening file"); - return false; - } - - for (chunk = static_cast(memfile->chunks.first); chunk; - chunk = static_cast(chunk->next)) { -#ifdef _WIN32 - if (size_t(write(file, chunk->buf, uint(chunk->size))) != chunk->size) -#else - if (size_t(write(file, chunk->buf, chunk->size)) != chunk->size) -#endif - { - break; - } - } - - close(file); - - if (chunk) { - fprintf(stderr, - "Unable to save '%s': %s\n", - filepath, - errno ? strerror(errno) : "Unknown error writing file"); - return false; - } - return true; -} - static ssize_t undo_read(FileReader *reader, void *buffer, size_t size) { UndoReader *undo = (UndoReader *)reader; diff --git a/source/blender/blenloader/intern/versioning_legacy.c b/source/blender/blenloader/intern/versioning_legacy.c index 25304b68e40..5329c59a724 100644 --- a/source/blender/blenloader/intern/versioning_legacy.c +++ b/source/blender/blenloader/intern/versioning_legacy.c @@ -273,19 +273,19 @@ static void customdata_version_242(Mesh *me) int a, mtfacen, mcoln; if (!me->vdata.totlayer) { - CustomData_add_layer_with_data(&me->vdata, CD_MVERT, me->mvert, me->totvert); + CustomData_add_layer_with_data(&me->vdata, CD_MVERT, me->mvert, me->totvert, NULL); if (me->dvert) { - CustomData_add_layer_with_data(&me->vdata, CD_MDEFORMVERT, me->dvert, me->totvert); + CustomData_add_layer_with_data(&me->vdata, CD_MDEFORMVERT, me->dvert, me->totvert, NULL); } } if (!me->edata.totlayer) { - CustomData_add_layer_with_data(&me->edata, CD_MEDGE, me->medge, me->totedge); + CustomData_add_layer_with_data(&me->edata, CD_MEDGE, me->medge, me->totedge, NULL); } if (!me->fdata.totlayer) { - CustomData_add_layer_with_data(&me->fdata, CD_MFACE, me->mface, me->totface); + CustomData_add_layer_with_data(&me->fdata, CD_MFACE, me->mface, me->totface, NULL); if (me->tface) { if (me->mcol) { @@ -308,7 +308,7 @@ static void customdata_version_242(Mesh *me) me->tface = NULL; } else if (me->mcol) { - CustomData_add_layer_with_data(&me->fdata, CD_MCOL, me->mcol, me->totface); + CustomData_add_layer_with_data(&me->fdata, CD_MCOL, me->mcol, me->totface, NULL); } } diff --git a/source/blender/blenloader/intern/writefile.cc b/source/blender/blenloader/intern/writefile.cc index 8d38457cc01..935a54fcb10 100644 --- a/source/blender/blenloader/intern/writefile.cc +++ b/source/blender/blenloader/intern/writefile.cc @@ -85,6 +85,7 @@ #include "BLI_bitmap.h" #include "BLI_blenlib.h" +#include "BLI_copy_on_write.hh" #include "BLI_endian_defines.h" #include "BLI_endian_switch.h" #include "BLI_link_utils.h" @@ -1696,4 +1697,19 @@ bool BLO_write_is_undo(BlendWriter *writer) return writer->wd->use_memfile; } +void BLO_write_cow(BlendWriter *writer, const void *data_ptr, const bCopyOnWrite *cow) +{ + BLI_assert(writer->wd->use_memfile); + if (data_ptr == nullptr) { + return; + } + MemFile &memfile = *writer->wd->mem.written_memfile; + if (memfile.cow_storage == nullptr) { + memfile.cow_storage = MEM_new(__func__); + } + if (memfile.cow_storage->map.add(data_ptr, cow)) { + cow->add_user(); + } +} + /** \} */ diff --git a/source/blender/bmesh/intern/bmesh_construct.c b/source/blender/bmesh/intern/bmesh_construct.c index 397c576a773..a2be5427978 100644 --- a/source/blender/bmesh/intern/bmesh_construct.c +++ b/source/blender/bmesh/intern/bmesh_construct.c @@ -517,16 +517,16 @@ void BM_mesh_copy_init_customdata_from_mesh_array(BMesh *bm_dst, &me_src->ldata, CD_MASK_BMESH.pmask); if (i == 0) { - CustomData_copy(&mesh_vdata, &bm_dst->vdata, CD_MASK_BMESH.vmask, CD_SET_DEFAULT, 0); - CustomData_copy(&mesh_edata, &bm_dst->edata, CD_MASK_BMESH.emask, CD_SET_DEFAULT, 0); - CustomData_copy(&mesh_pdata, &bm_dst->pdata, CD_MASK_BMESH.pmask, CD_SET_DEFAULT, 0); - CustomData_copy(&mesh_ldata, &bm_dst->ldata, CD_MASK_BMESH.lmask, CD_SET_DEFAULT, 0); + CustomData_copy_new(&mesh_vdata, &bm_dst->vdata, CD_MASK_BMESH.vmask, CD_SET_DEFAULT, 0); + CustomData_copy_new(&mesh_edata, &bm_dst->edata, CD_MASK_BMESH.emask, CD_SET_DEFAULT, 0); + CustomData_copy_new(&mesh_pdata, &bm_dst->pdata, CD_MASK_BMESH.pmask, CD_SET_DEFAULT, 0); + CustomData_copy_new(&mesh_ldata, &bm_dst->ldata, CD_MASK_BMESH.lmask, CD_SET_DEFAULT, 0); } else { - CustomData_merge(&mesh_vdata, &bm_dst->vdata, CD_MASK_BMESH.vmask, CD_SET_DEFAULT, 0); - CustomData_merge(&mesh_edata, &bm_dst->edata, CD_MASK_BMESH.emask, CD_SET_DEFAULT, 0); - CustomData_merge(&mesh_pdata, &bm_dst->pdata, CD_MASK_BMESH.pmask, CD_SET_DEFAULT, 0); - CustomData_merge(&mesh_ldata, &bm_dst->ldata, CD_MASK_BMESH.lmask, CD_SET_DEFAULT, 0); + CustomData_merge_new(&mesh_vdata, &bm_dst->vdata, CD_MASK_BMESH.vmask, CD_SET_DEFAULT, 0); + CustomData_merge_new(&mesh_edata, &bm_dst->edata, CD_MASK_BMESH.emask, CD_SET_DEFAULT, 0); + CustomData_merge_new(&mesh_pdata, &bm_dst->pdata, CD_MASK_BMESH.pmask, CD_SET_DEFAULT, 0); + CustomData_merge_new(&mesh_ldata, &bm_dst->ldata, CD_MASK_BMESH.lmask, CD_SET_DEFAULT, 0); } MEM_SAFE_FREE(mesh_vdata.layers); @@ -554,10 +554,10 @@ void BM_mesh_copy_init_customdata(BMesh *bm_dst, BMesh *bm_src, const BMAllocTem allocsize = &bm_mesh_allocsize_default; } - CustomData_copy(&bm_src->vdata, &bm_dst->vdata, CD_MASK_BMESH.vmask, CD_SET_DEFAULT, 0); - CustomData_copy(&bm_src->edata, &bm_dst->edata, CD_MASK_BMESH.emask, CD_SET_DEFAULT, 0); - CustomData_copy(&bm_src->ldata, &bm_dst->ldata, CD_MASK_BMESH.lmask, CD_SET_DEFAULT, 0); - CustomData_copy(&bm_src->pdata, &bm_dst->pdata, CD_MASK_BMESH.pmask, CD_SET_DEFAULT, 0); + CustomData_copy_new(&bm_src->vdata, &bm_dst->vdata, CD_MASK_BMESH.vmask, CD_SET_DEFAULT, 0); + CustomData_copy_new(&bm_src->edata, &bm_dst->edata, CD_MASK_BMESH.emask, CD_SET_DEFAULT, 0); + CustomData_copy_new(&bm_src->ldata, &bm_dst->ldata, CD_MASK_BMESH.lmask, CD_SET_DEFAULT, 0); + CustomData_copy_new(&bm_src->pdata, &bm_dst->pdata, CD_MASK_BMESH.pmask, CD_SET_DEFAULT, 0); CustomData_bmesh_init_pool(&bm_dst->vdata, allocsize->totvert, BM_VERT); CustomData_bmesh_init_pool(&bm_dst->edata, allocsize->totedge, BM_EDGE); diff --git a/source/blender/bmesh/intern/bmesh_mesh_convert.cc b/source/blender/bmesh/intern/bmesh_mesh_convert.cc index 402cfb5dc79..54cd175148a 100644 --- a/source/blender/bmesh/intern/bmesh_mesh_convert.cc +++ b/source/blender/bmesh/intern/bmesh_mesh_convert.cc @@ -268,10 +268,10 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar if (me->totvert == 0) { if (is_new) { /* No verts? still copy custom-data layout. */ - CustomData_copy(&mesh_vdata, &bm->vdata, mask.vmask, CD_CONSTRUCT, 0); - CustomData_copy(&mesh_edata, &bm->edata, mask.emask, CD_CONSTRUCT, 0); - CustomData_copy(&mesh_pdata, &bm->pdata, mask.pmask, CD_CONSTRUCT, 0); - CustomData_copy(&mesh_ldata, &bm->ldata, mask.lmask, CD_CONSTRUCT, 0); + CustomData_copy_new(&mesh_vdata, &bm->vdata, mask.vmask, CD_CONSTRUCT, 0); + CustomData_copy_new(&mesh_edata, &bm->edata, mask.emask, CD_CONSTRUCT, 0); + CustomData_copy_new(&mesh_pdata, &bm->pdata, mask.pmask, CD_CONSTRUCT, 0); + CustomData_copy_new(&mesh_ldata, &bm->ldata, mask.lmask, CD_CONSTRUCT, 0); CustomData_bmesh_init_pool(&bm->vdata, me->totvert, BM_VERT); CustomData_bmesh_init_pool(&bm->edata, me->totedge, BM_EDGE); @@ -287,16 +287,16 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar } if (is_new) { - CustomData_copy(&mesh_vdata, &bm->vdata, mask.vmask, CD_SET_DEFAULT, 0); - CustomData_copy(&mesh_edata, &bm->edata, mask.emask, CD_SET_DEFAULT, 0); - CustomData_copy(&mesh_pdata, &bm->pdata, mask.pmask, CD_SET_DEFAULT, 0); - CustomData_copy(&mesh_ldata, &bm->ldata, mask.lmask, CD_SET_DEFAULT, 0); + CustomData_copy_new(&mesh_vdata, &bm->vdata, mask.vmask, CD_SET_DEFAULT, 0); + CustomData_copy_new(&mesh_edata, &bm->edata, mask.emask, CD_SET_DEFAULT, 0); + CustomData_copy_new(&mesh_pdata, &bm->pdata, mask.pmask, CD_SET_DEFAULT, 0); + CustomData_copy_new(&mesh_ldata, &bm->ldata, mask.lmask, CD_SET_DEFAULT, 0); } else { - CustomData_bmesh_merge(&mesh_vdata, &bm->vdata, mask.vmask, CD_SET_DEFAULT, bm, BM_VERT); - CustomData_bmesh_merge(&mesh_edata, &bm->edata, mask.emask, CD_SET_DEFAULT, bm, BM_EDGE); - CustomData_bmesh_merge(&mesh_pdata, &bm->pdata, mask.pmask, CD_SET_DEFAULT, bm, BM_FACE); - CustomData_bmesh_merge(&mesh_ldata, &bm->ldata, mask.lmask, CD_SET_DEFAULT, bm, BM_LOOP); + CustomData_bmesh_merge_new(&mesh_vdata, &bm->vdata, mask.vmask, CD_SET_DEFAULT, bm, BM_VERT); + CustomData_bmesh_merge_new(&mesh_edata, &bm->edata, mask.emask, CD_SET_DEFAULT, bm, BM_EDGE); + CustomData_bmesh_merge_new(&mesh_pdata, &bm->pdata, mask.pmask, CD_SET_DEFAULT, bm, BM_FACE); + CustomData_bmesh_merge_new(&mesh_ldata, &bm->ldata, mask.lmask, CD_SET_DEFAULT, bm, BM_LOOP); } /* -------------------------------------------------------------------- */ @@ -1403,10 +1403,10 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh { CustomData_MeshMasks mask = CD_MASK_MESH; CustomData_MeshMasks_update(&mask, ¶ms->cd_mask_extra); - CustomData_copy(&bm->vdata, &me->vdata, mask.vmask, CD_SET_DEFAULT, me->totvert); - CustomData_copy(&bm->edata, &me->edata, mask.emask, CD_SET_DEFAULT, me->totedge); - CustomData_copy(&bm->ldata, &me->ldata, mask.lmask, CD_SET_DEFAULT, me->totloop); - CustomData_copy(&bm->pdata, &me->pdata, mask.pmask, CD_SET_DEFAULT, me->totpoly); + CustomData_copy_new(&bm->vdata, &me->vdata, mask.vmask, CD_SET_DEFAULT, me->totvert); + CustomData_copy_new(&bm->edata, &me->edata, mask.emask, CD_SET_DEFAULT, me->totedge); + CustomData_copy_new(&bm->ldata, &me->ldata, mask.lmask, CD_SET_DEFAULT, me->totloop); + CustomData_copy_new(&bm->pdata, &me->pdata, mask.pmask, CD_SET_DEFAULT, me->totpoly); } bool need_select_vert = false; @@ -1617,10 +1617,10 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks * CustomData_MeshMasks_update(&mask, cd_mask_extra); } mask.vmask &= ~CD_MASK_SHAPEKEY; - CustomData_merge(&bm->vdata, &me->vdata, mask.vmask, CD_CONSTRUCT, me->totvert); - CustomData_merge(&bm->edata, &me->edata, mask.emask, CD_CONSTRUCT, me->totedge); - CustomData_merge(&bm->ldata, &me->ldata, mask.lmask, CD_CONSTRUCT, me->totloop); - CustomData_merge(&bm->pdata, &me->pdata, mask.pmask, CD_CONSTRUCT, me->totpoly); + CustomData_merge_new(&bm->vdata, &me->vdata, mask.vmask, CD_CONSTRUCT, me->totvert); + CustomData_merge_new(&bm->edata, &me->edata, mask.emask, CD_CONSTRUCT, me->totedge); + CustomData_merge_new(&bm->ldata, &me->ldata, mask.lmask, CD_CONSTRUCT, me->totloop); + CustomData_merge_new(&bm->pdata, &me->pdata, mask.pmask, CD_CONSTRUCT, me->totpoly); me->runtime->deformed_only = true; diff --git a/source/blender/editors/mesh/editmesh_undo.cc b/source/blender/editors/mesh/editmesh_undo.cc index d9aedb82878..adb1563efe4 100644 --- a/source/blender/editors/mesh/editmesh_undo.cc +++ b/source/blender/editors/mesh/editmesh_undo.cc @@ -16,6 +16,7 @@ #include "DNA_scene_types.h" #include "BLI_array_utils.h" +#include "BLI_copy_on_write.hh" #include "BLI_listbase.h" #include "BLI_task.hh" @@ -271,8 +272,16 @@ static void um_arraystore_cd_compact(CustomData *cdata, } if (layer->data) { + if (layer->cow) { + /* This assumes that the layer is not shared, which it is not here because it has just + * been created in #BM_mesh_bm_to_me. The situation is a bit tricky here, because the + * layer data may be freed partially below for e.g. vertex groups. */ + BLI_assert(layer->cow->is_mutable()); + MEM_delete(layer->cow); + } MEM_freeN(layer->data); layer->data = nullptr; + layer->cow = nullptr; } } diff --git a/source/blender/editors/mesh/mesh_data.cc b/source/blender/editors/mesh/mesh_data.cc index 856f021f529..0645a6c50fb 100644 --- a/source/blender/editors/mesh/mesh_data.cc +++ b/source/blender/editors/mesh/mesh_data.cc @@ -278,7 +278,8 @@ int ED_mesh_uv_add( CD_PROP_FLOAT2, MEM_dupallocN(CustomData_get_layer(&me->ldata, CD_PROP_FLOAT2)), me->totloop, - unique_name); + unique_name, + nullptr); is_init = true; } @@ -1140,7 +1141,7 @@ static void mesh_add_verts(Mesh *mesh, int len) int totvert = mesh->totvert + len; CustomData vdata; - CustomData_copy(&mesh->vdata, &vdata, CD_MASK_MESH.vmask, CD_SET_DEFAULT, totvert); + CustomData_copy_new(&mesh->vdata, &vdata, CD_MASK_MESH.vmask, CD_SET_DEFAULT, totvert); CustomData_copy_data(&mesh->vdata, &vdata, 0, 0, mesh->totvert); if (!CustomData_get_layer_named(&vdata, CD_PROP_FLOAT3, "position")) { @@ -1174,7 +1175,7 @@ static void mesh_add_edges(Mesh *mesh, int len) totedge = mesh->totedge + len; /* Update custom-data. */ - CustomData_copy(&mesh->edata, &edata, CD_MASK_MESH.emask, CD_SET_DEFAULT, totedge); + CustomData_copy_new(&mesh->edata, &edata, CD_MASK_MESH.emask, CD_SET_DEFAULT, totedge); CustomData_copy_data(&mesh->edata, &edata, 0, 0, mesh->totedge); if (!CustomData_has_layer(&edata, CD_MEDGE)) { @@ -1207,7 +1208,7 @@ static void mesh_add_loops(Mesh *mesh, int len) totloop = mesh->totloop + len; /* new face count */ /* update customdata */ - CustomData_copy(&mesh->ldata, &ldata, CD_MASK_MESH.lmask, CD_SET_DEFAULT, totloop); + CustomData_copy_new(&mesh->ldata, &ldata, CD_MASK_MESH.lmask, CD_SET_DEFAULT, totloop); CustomData_copy_data(&mesh->ldata, &ldata, 0, 0, mesh->totloop); if (!CustomData_get_layer_named(&ldata, CD_PROP_INT32, ".corner_vert")) { @@ -1238,7 +1239,7 @@ static void mesh_add_polys(Mesh *mesh, int len) totpoly = mesh->totpoly + len; /* new face count */ /* update customdata */ - CustomData_copy(&mesh->pdata, &pdata, CD_MASK_MESH.pmask, CD_SET_DEFAULT, totpoly); + CustomData_copy_new(&mesh->pdata, &pdata, CD_MASK_MESH.pmask, CD_SET_DEFAULT, totpoly); CustomData_copy_data(&mesh->pdata, &pdata, 0, 0, mesh->totpoly); if (!CustomData_has_layer(&pdata, CD_MPOLY)) { diff --git a/source/blender/editors/mesh/meshtools.cc b/source/blender/editors/mesh/meshtools.cc index 91acc042474..5a15612a943 100644 --- a/source/blender/editors/mesh/meshtools.cc +++ b/source/blender/editors/mesh/meshtools.cc @@ -105,7 +105,7 @@ static void join_mesh_single(Depsgraph *depsgraph, if (me->totvert) { /* standard data */ - CustomData_merge(&me->vdata, vdata, CD_MASK_MESH.vmask, CD_SET_DEFAULT, totvert); + CustomData_merge_new(&me->vdata, vdata, CD_MASK_MESH.vmask, CD_SET_DEFAULT, totvert); CustomData_copy_data_named(&me->vdata, vdata, 0, *vertofs, me->totvert); /* vertex groups */ @@ -205,7 +205,7 @@ static void join_mesh_single(Depsgraph *depsgraph, } if (me->totedge) { - CustomData_merge(&me->edata, edata, CD_MASK_MESH.emask, CD_SET_DEFAULT, totedge); + CustomData_merge_new(&me->edata, edata, CD_MASK_MESH.emask, CD_SET_DEFAULT, totedge); CustomData_copy_data_named(&me->edata, edata, 0, *edgeofs, me->totedge); for (a = 0; a < me->totedge; a++, edge++) { @@ -226,7 +226,7 @@ static void join_mesh_single(Depsgraph *depsgraph, } } - CustomData_merge(&me->ldata, ldata, CD_MASK_MESH.lmask, CD_SET_DEFAULT, totloop); + CustomData_merge_new(&me->ldata, ldata, CD_MASK_MESH.lmask, CD_SET_DEFAULT, totloop); CustomData_copy_data_named(&me->ldata, ldata, 0, *loopofs, me->totloop); for (a = 0; a < me->totloop; a++) { @@ -250,7 +250,7 @@ static void join_mesh_single(Depsgraph *depsgraph, } } - CustomData_merge(&me->pdata, pdata, CD_MASK_MESH.pmask, CD_SET_DEFAULT, totpoly); + CustomData_merge_new(&me->pdata, pdata, CD_MASK_MESH.pmask, CD_SET_DEFAULT, totpoly); CustomData_copy_data_named(&me->pdata, pdata, 0, *polyofs, me->totpoly); /* Apply matmap. In case we don't have material indices yet, create them if more than one diff --git a/source/blender/editors/object/object_modifier.cc b/source/blender/editors/object/object_modifier.cc index c8ae73c3013..93341a0470e 100644 --- a/source/blender/editors/object/object_modifier.cc +++ b/source/blender/editors/object/object_modifier.cc @@ -731,7 +731,7 @@ static void add_shapekey_layers(Mesh &mesh_dest, const Mesh &mesh_src) } CustomData_add_layer_named_with_data( - &mesh_dest.vdata, CD_SHAPEKEY, array, mesh_dest.totvert, kb->name); + &mesh_dest.vdata, CD_SHAPEKEY, array, mesh_dest.totvert, kb->name, nullptr); const int ci = CustomData_get_layer_index_n(&mesh_dest.vdata, CD_SHAPEKEY, i); mesh_dest.vdata.layers[ci].uid = kb->uid; diff --git a/source/blender/editors/sculpt_paint/sculpt_dyntopo.cc b/source/blender/editors/sculpt_paint/sculpt_dyntopo.cc index 3e914f0fa76..f3ce244ba81 100644 --- a/source/blender/editors/sculpt_paint/sculpt_dyntopo.cc +++ b/source/blender/editors/sculpt_paint/sculpt_dyntopo.cc @@ -161,14 +161,10 @@ static void SCULPT_dynamic_topology_disable_ex( me->totpoly = geometry->totpoly; me->totedge = geometry->totedge; me->totface = 0; - CustomData_copy( - &geometry->vdata, &me->vdata, CD_MASK_MESH.vmask, CD_DUPLICATE, geometry->totvert); - CustomData_copy( - &geometry->edata, &me->edata, CD_MASK_MESH.emask, CD_DUPLICATE, geometry->totedge); - CustomData_copy( - &geometry->ldata, &me->ldata, CD_MASK_MESH.lmask, CD_DUPLICATE, geometry->totloop); - CustomData_copy( - &geometry->pdata, &me->pdata, CD_MASK_MESH.pmask, CD_DUPLICATE, geometry->totpoly); + CustomData_copy(&geometry->vdata, &me->vdata, CD_MASK_MESH.vmask, geometry->totvert); + CustomData_copy(&geometry->edata, &me->edata, CD_MASK_MESH.emask, geometry->totedge); + CustomData_copy(&geometry->ldata, &me->ldata, CD_MASK_MESH.lmask, geometry->totloop); + CustomData_copy(&geometry->pdata, &me->pdata, CD_MASK_MESH.pmask, geometry->totpoly); } else { BKE_sculptsession_bm_to_me(ob, true); diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.cc b/source/blender/editors/sculpt_paint/sculpt_undo.cc index ae604443f78..0f0055e1475 100644 --- a/source/blender/editors/sculpt_paint/sculpt_undo.cc +++ b/source/blender/editors/sculpt_paint/sculpt_undo.cc @@ -745,10 +745,10 @@ static void sculpt_undo_geometry_store_data(SculptUndoNodeGeometry *geometry, Ob BLI_assert(!geometry->is_initialized); geometry->is_initialized = true; - CustomData_copy(&mesh->vdata, &geometry->vdata, CD_MASK_MESH.vmask, CD_DUPLICATE, mesh->totvert); - CustomData_copy(&mesh->edata, &geometry->edata, CD_MASK_MESH.emask, CD_DUPLICATE, mesh->totedge); - CustomData_copy(&mesh->ldata, &geometry->ldata, CD_MASK_MESH.lmask, CD_DUPLICATE, mesh->totloop); - CustomData_copy(&mesh->pdata, &geometry->pdata, CD_MASK_MESH.pmask, CD_DUPLICATE, mesh->totpoly); + CustomData_copy(&mesh->vdata, &geometry->vdata, CD_MASK_MESH.vmask, mesh->totvert); + CustomData_copy(&mesh->edata, &geometry->edata, CD_MASK_MESH.emask, mesh->totedge); + CustomData_copy(&mesh->ldata, &geometry->ldata, CD_MASK_MESH.lmask, mesh->totloop); + CustomData_copy(&mesh->pdata, &geometry->pdata, CD_MASK_MESH.pmask, mesh->totpoly); geometry->totvert = mesh->totvert; geometry->totedge = mesh->totedge; @@ -774,14 +774,10 @@ static void sculpt_undo_geometry_restore_data(SculptUndoNodeGeometry *geometry, mesh->totpoly = geometry->totpoly; mesh->totface = 0; - CustomData_copy( - &geometry->vdata, &mesh->vdata, CD_MASK_MESH.vmask, CD_DUPLICATE, geometry->totvert); - CustomData_copy( - &geometry->edata, &mesh->edata, CD_MASK_MESH.emask, CD_DUPLICATE, geometry->totedge); - CustomData_copy( - &geometry->ldata, &mesh->ldata, CD_MASK_MESH.lmask, CD_DUPLICATE, geometry->totloop); - CustomData_copy( - &geometry->pdata, &mesh->pdata, CD_MASK_MESH.pmask, CD_DUPLICATE, geometry->totpoly); + CustomData_copy(&geometry->vdata, &mesh->vdata, CD_MASK_MESH.vmask, geometry->totvert); + CustomData_copy(&geometry->edata, &mesh->edata, CD_MASK_MESH.emask, geometry->totedge); + CustomData_copy(&geometry->ldata, &mesh->ldata, CD_MASK_MESH.lmask, geometry->totloop); + CustomData_copy(&geometry->pdata, &mesh->pdata, CD_MASK_MESH.pmask, geometry->totpoly); BKE_mesh_runtime_clear_cache(mesh); } diff --git a/source/blender/geometry/intern/mesh_split_edges.cc b/source/blender/geometry/intern/mesh_split_edges.cc index 00cfa5eb756..ad3191f6949 100644 --- a/source/blender/geometry/intern/mesh_split_edges.cc +++ b/source/blender/geometry/intern/mesh_split_edges.cc @@ -138,7 +138,8 @@ static void add_new_edges(Mesh &mesh, mesh.edges_for_write().copy_from(new_edges); if (new_orig_indices != nullptr) { - CustomData_add_layer_with_data(&mesh.edata, CD_ORIGINDEX, new_orig_indices, mesh.totedge); + CustomData_add_layer_with_data( + &mesh.edata, CD_ORIGINDEX, new_orig_indices, mesh.totedge, nullptr); } for (NewAttributeData &new_data : dst_attributes) { diff --git a/source/blender/io/collada/MeshImporter.cpp b/source/blender/io/collada/MeshImporter.cpp index 8c289e55157..37026abbbb7 100644 --- a/source/blender/io/collada/MeshImporter.cpp +++ b/source/blender/io/collada/MeshImporter.cpp @@ -554,7 +554,7 @@ void MeshImporter::mesh_add_edges(Mesh *mesh, int len) totedge = mesh->totedge + len; /* Update custom-data. */ - CustomData_copy(&mesh->edata, &edata, CD_MASK_MESH.emask, CD_SET_DEFAULT, totedge); + CustomData_copy_new(&mesh->edata, &edata, CD_MASK_MESH.emask, CD_SET_DEFAULT, totedge); CustomData_copy_data(&mesh->edata, &edata, 0, 0, mesh->totedge); if (!CustomData_has_layer(&edata, CD_MEDGE)) { diff --git a/source/blender/makesdna/DNA_customdata_types.h b/source/blender/makesdna/DNA_customdata_types.h index 95f89462cfb..a1220b0e92c 100644 --- a/source/blender/makesdna/DNA_customdata_types.h +++ b/source/blender/makesdna/DNA_customdata_types.h @@ -25,6 +25,8 @@ using AnonymousAttributeIDHandle = blender::bke::AnonymousAttributeID; typedef struct AnonymousAttributeIDHandle AnonymousAttributeIDHandle; #endif +struct bCopyOnWrite; + /** Descriptor and storage for a custom data layer. */ typedef struct CustomDataLayer { /** Type of data in layer. */ @@ -53,6 +55,11 @@ typedef struct CustomDataLayer { * attribute was created. */ const AnonymousAttributeIDHandle *anonymous_id; + /** + * Run-time data that allows sharing `data` with other entities (mostly custom data layers on + * other geometries). + */ + const struct bCopyOnWrite *cow; } CustomDataLayer; #define MAX_CUSTOMDATA_LAYER_NAME 68 @@ -242,8 +249,7 @@ typedef struct CustomData_MeshMasks { enum { /* Indicates layer should not be copied by CustomData_from_template or CustomData_copy_data */ CD_FLAG_NOCOPY = (1 << 0), - /* Indicates layer should not be freed (for layers backed by external data) */ - CD_FLAG_NOFREE = (1 << 1), + CD_FLAG_UNUSED = (1 << 1), /* Indicates the layer is only temporary, also implies no copy */ CD_FLAG_TEMPORARY = ((1 << 2) | CD_FLAG_NOCOPY), /* Indicates the layer is stored in an external file */ diff --git a/source/blender/windowmanager/intern/wm_files.cc b/source/blender/windowmanager/intern/wm_files.cc index 0ba47e2cf4d..5d973a688ac 100644 --- a/source/blender/windowmanager/intern/wm_files.cc +++ b/source/blender/windowmanager/intern/wm_files.cc @@ -2010,33 +2010,20 @@ static void wm_autosave_location(char filepath[FILE_MAX]) BLI_path_join(filepath, FILE_MAX, tempdir_base, filename); } -static void wm_autosave_write(Main *bmain, wmWindowManager *wm) +static void wm_autosave_write(Main *bmain) { char filepath[FILE_MAX]; wm_autosave_location(filepath); - /* Fast save of last undo-buffer, now with UI. */ - const bool use_memfile = (U.uiflag & USER_GLOBALUNDO) != 0; - MemFile *memfile = use_memfile ? ED_undosys_stack_memfile_get_active(wm->undo_stack) : nullptr; - if (memfile != nullptr) { - BLO_memfile_write_file(memfile, filepath); - } - else { - if (use_memfile) { - /* This is very unlikely, alert developers of this unexpected case. */ - CLOG_WARN(&LOG, "undo-data not found for writing, fallback to regular file write!"); - } + /* Save as regular blend file with recovery information. */ + const int fileflags = (G.fileflags & ~G_FILE_COMPRESS) | G_FILE_RECOVER_WRITE; - /* Save as regular blend file with recovery information. */ - const int fileflags = (G.fileflags & ~G_FILE_COMPRESS) | G_FILE_RECOVER_WRITE; + ED_editors_flush_edits(bmain); - ED_editors_flush_edits(bmain); - - /* Error reporting into console. */ - BlendFileWriteParams params{}; - BLO_write_file(bmain, filepath, fileflags, ¶ms, nullptr); - } + /* Error reporting into console. */ + BlendFileWriteParams params{}; + BLO_write_file(bmain, filepath, fileflags, ¶ms, nullptr); } static void wm_autosave_timer_begin_ex(wmWindowManager *wm, double timestep) @@ -2084,7 +2071,7 @@ void wm_autosave_timer(Main *bmain, wmWindowManager *wm, wmTimer * /*wt*/) } } - wm_autosave_write(bmain, wm); + wm_autosave_write(bmain); /* Restart the timer after file write, just in case file write takes a long time. */ wm_autosave_timer_begin(wm); diff --git a/source/blender/windowmanager/intern/wm_init_exit.cc b/source/blender/windowmanager/intern/wm_init_exit.cc index 683e3ec0dd7..c0fdf51bd46 100644 --- a/source/blender/windowmanager/intern/wm_init_exit.cc +++ b/source/blender/windowmanager/intern/wm_init_exit.cc @@ -439,27 +439,16 @@ void WM_exit_ex(bContext *C, const bool do_python) /* NOTE: same code copied in `wm_files.cc`. */ if (C && wm) { if (!G.background) { - struct MemFile *undo_memfile = wm->undo_stack ? - ED_undosys_stack_memfile_get_active(wm->undo_stack) : - nullptr; - if (undo_memfile != nullptr) { - /* save the undo state as quit.blend */ - Main *bmain = CTX_data_main(C); - char filepath[FILE_MAX]; - bool has_edited; - const int fileflags = G.fileflags & ~G_FILE_COMPRESS; + /* Save latest state before closing as quit.blend. */ + char filepath[FILE_MAX]; + const int fileflags = G.fileflags & ~G_FILE_COMPRESS; + BLI_path_join(filepath, sizeof(filepath), BKE_tempdir_base(), BLENDER_QUIT_FILE); - BLI_path_join(filepath, sizeof(filepath), BKE_tempdir_base(), BLENDER_QUIT_FILE); - - has_edited = ED_editors_flush_edits(bmain); - - BlendFileWriteParams blend_file_write_params{}; - if ((has_edited && - BLO_write_file(bmain, filepath, fileflags, &blend_file_write_params, nullptr)) || - BLO_memfile_write_file(undo_memfile, filepath)) { - printf("Saved session recovery to \"%s\"\n", filepath); - } - } + Main *bmain = CTX_data_main(C); + ED_editors_flush_edits(bmain); + BlendFileWriteParams blend_file_write_params{}; + BLO_write_file(bmain, filepath, fileflags, &blend_file_write_params, nullptr); + printf("Saved session recovery to \"%s\"\n", filepath); } WM_jobs_kill_all(wm); diff --git a/source/creator/creator_signals.c b/source/creator/creator_signals.c index c733ee617cb..23d82a448e5 100644 --- a/source/creator/creator_signals.c +++ b/source/creator/creator_signals.c @@ -51,12 +51,6 @@ # include "creator_intern.h" /* own include */ -// #define USE_WRITE_CRASH_BLEND -# ifdef USE_WRITE_CRASH_BLEND -# include "BKE_undo_system.h" -# include "BLO_undofile.h" -# endif - /* set breakpoints here when running in debug mode, useful to catch floating point errors */ # if defined(__linux__) || defined(_WIN32) || defined(OSX_SSE_FPE) static void sig_handle_fpe(int UNUSED(sig)) @@ -94,28 +88,6 @@ static void sig_handle_crash(int signum) wmWindowManager *wm = G_MAIN ? G_MAIN->wm.first : NULL; -# ifdef USE_WRITE_CRASH_BLEND - if (wm && wm->undo_stack) { - struct MemFile *memfile = BKE_undosys_stack_memfile_get_active(wm->undo_stack); - if (memfile) { - char fname[FILE_MAX]; - - if (!(G_MAIN && G_MAIN->filepath[0])) { - BLI_path_join(fname, sizeof(fname), BKE_tempdir_base(), "crash.blend"); - } - else { - STRNCPY(fname, G_MAIN->filepath); - BLI_path_extension_replace(fname, sizeof(fname), ".crash.blend"); - } - - printf("Writing: %s\n", fname); - fflush(stdout); - - BLO_memfile_write_file(memfile, fname); - } - } -# endif - FILE *fp; char header[512]; -- 2.30.2 From dca532b4fba44e3fd53b951474841c27aacde41f Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Tue, 28 Mar 2023 14:37:42 +0200 Subject: [PATCH 02/46] remove undo changes --- .../blender/blenkernel/intern/customdata.cc | 14 ---- source/blender/blenloader/BLO_read_write.h | 15 ----- source/blender/blenloader/BLO_undofile.h | 20 ------ source/blender/blenloader/intern/readfile.cc | 16 ----- source/blender/blenloader/intern/undofile.cc | 67 +++++++++++++++---- source/blender/blenloader/intern/writefile.cc | 16 ----- .../blender/windowmanager/intern/wm_files.cc | 29 +++++--- .../windowmanager/intern/wm_init_exit.cc | 29 +++++--- source/creator/creator_signals.c | 28 ++++++++ 9 files changed, 124 insertions(+), 110 deletions(-) diff --git a/source/blender/blenkernel/intern/customdata.cc b/source/blender/blenkernel/intern/customdata.cc index d7f5b7365b4..9735b65a28e 100644 --- a/source/blender/blenkernel/intern/customdata.cc +++ b/source/blender/blenkernel/intern/customdata.cc @@ -5076,10 +5076,6 @@ void CustomData_blend_write(BlendWriter *writer, writer, CustomDataLayer, data->totlayer, data->layers, layers_to_write.data()); for (const CustomDataLayer &layer : layers_to_write) { - if (BLO_write_is_undo(writer) && layer.cow != nullptr) { - BLO_write_cow(writer, layer.data, layer.cow); - continue; - } switch (layer.type) { case CD_MDEFORMVERT: BKE_defvert_blend_write(writer, count, static_cast(layer.data)); @@ -5196,17 +5192,7 @@ void CustomData_blend_read(BlendDataReader *reader, CustomData *data, const int } if (CustomData_verify_versions(data, i)) { - if (BLO_read_is_cow_data(reader, layer->data)) { - BLI_assert(layer->cow != nullptr); - layer->cow->add_user(); - i++; - continue; - } BLO_read_data_address(reader, &layer->data); - if (layer->data != nullptr) { - /* Make layer data shareable. */ - layer->cow = make_cow_for_array(eCustomDataType(layer->type), layer->data, count); - } if (CustomData_layer_ensure_data_exists(layer, count)) { /* Under normal operations, this shouldn't happen, but... * For a CD_PROP_BOOL example, see #84935. diff --git a/source/blender/blenloader/BLO_read_write.h b/source/blender/blenloader/BLO_read_write.h index de8d0277f53..f1685d079e4 100644 --- a/source/blender/blenloader/BLO_read_write.h +++ b/source/blender/blenloader/BLO_read_write.h @@ -42,7 +42,6 @@ typedef struct BlendWriter BlendWriter; struct BlendFileReadReport; struct Main; -struct bCopyOnWrite; /* -------------------------------------------------------------------- */ /** \name Blend Write API @@ -176,14 +175,6 @@ void BLO_write_string(BlendWriter *writer, const char *data_ptr); /* Misc. */ -#ifdef __cplusplus -/** - * Give (shared) ownership of the data to the undo system so that the data does not have to be - * copied. - */ -void BLO_write_cow(BlendWriter *writer, const void *data_ptr, const bCopyOnWrite *cow); -#endif - /** * Sometimes different data is written depending on whether the file is saved to disk or used for * undo. This function returns true when the current file-writing is done for undo. @@ -245,12 +236,6 @@ void BLO_read_float3_array(BlendDataReader *reader, int array_size, float **ptr_ void BLO_read_double_array(BlendDataReader *reader, int array_size, double **ptr_p); void BLO_read_pointer_array(BlendDataReader *reader, void **ptr_p); -/** - * True when the pointer refers to valid data and can still be used. In order to take (shared) - * ownership of the data, the user count of the corresponding #bCopyOnWrite has to be increased. - */ -bool BLO_read_is_cow_data(BlendDataReader *reader, const void *cow_data); - /* Misc. */ int BLO_read_fileversion_get(BlendDataReader *reader); diff --git a/source/blender/blenloader/BLO_undofile.h b/source/blender/blenloader/BLO_undofile.h index ebb1d727bac..91ba3ed1740 100644 --- a/source/blender/blenloader/BLO_undofile.h +++ b/source/blender/blenloader/BLO_undofile.h @@ -13,25 +13,6 @@ struct GHash; struct Scene; -#ifdef __cplusplus - -# include "BLI_copy_on_write.hh" -# include "BLI_map.hh" - -/** - * Takes (shared) ownership of copy-on-write data so that it does not have to be copied into the - * undo step. - */ -struct MemFileCowStorage { - blender::Map map; - - ~MemFileCowStorage(); -}; - -#else -typedef struct MemFileCowStorage MemFileCowStorage; -#endif - typedef struct { void *next, *prev; const char *buf; @@ -51,7 +32,6 @@ typedef struct { typedef struct MemFile { ListBase chunks; size_t size; - MemFileCowStorage *cow_storage; } MemFile; typedef struct MemFileWriteData { diff --git a/source/blender/blenloader/intern/readfile.cc b/source/blender/blenloader/intern/readfile.cc index 3cfcc54fc1d..74c8442c212 100644 --- a/source/blender/blenloader/intern/readfile.cc +++ b/source/blender/blenloader/intern/readfile.cc @@ -5205,20 +5205,4 @@ void BLO_expand_id(BlendExpander *expander, ID *id) expand_doit(expander->fd, expander->main, id); } -bool BLO_read_is_cow_data(BlendDataReader *reader, const void *cow_data) -{ - if (!BLO_read_data_is_undo(reader)) { - return false; - } - if (!(reader->fd->flags & FD_FLAGS_IS_MEMFILE)) { - return false; - } - UndoReader *undo_reader = reinterpret_cast(reader->fd->file); - MemFile &memfile = *undo_reader->memfile; - if (memfile.cow_storage == nullptr) { - return false; - } - return memfile.cow_storage->map.contains(cow_data); -} - /** \} */ diff --git a/source/blender/blenloader/intern/undofile.cc b/source/blender/blenloader/intern/undofile.cc index 0dba88a91e2..5db5b465b96 100644 --- a/source/blender/blenloader/intern/undofile.cc +++ b/source/blender/blenloader/intern/undofile.cc @@ -24,7 +24,6 @@ #include "DNA_listBase.h" #include "BLI_blenlib.h" -#include "BLI_copy_on_write.hh" #include "BLI_ghash.h" #include "BLO_readfile.h" @@ -49,20 +48,9 @@ void BLO_memfile_free(MemFile *memfile) } MEM_freeN(chunk); } - if (memfile->cow_storage) { - MEM_delete(memfile->cow_storage); - memfile->cow_storage = nullptr; - } memfile->size = 0; } -MemFileCowStorage::~MemFileCowStorage() -{ - for (auto item : this->map.items()) { - item.value->remove_user_and_delete_if_last(); - } -} - void BLO_memfile_merge(MemFile *first, MemFile *second) { /* We use this mapping to store the memory buffers from second memfile chunks which are not owned @@ -211,6 +199,61 @@ struct Main *BLO_memfile_main_get(struct MemFile *memfile, return bmain_undo; } +bool BLO_memfile_write_file(struct MemFile *memfile, const char *filepath) +{ + MemFileChunk *chunk; + int file, oflags; + + /* NOTE: This is currently used for autosave and 'quit.blend', + * where _not_ following symlinks is OK, + * however if this is ever executed explicitly by the user, + * we may want to allow writing to symlinks. + */ + + oflags = O_BINARY | O_WRONLY | O_CREAT | O_TRUNC; +#ifdef O_NOFOLLOW + /* use O_NOFOLLOW to avoid writing to a symlink - use 'O_EXCL' (CVE-2008-1103) */ + oflags |= O_NOFOLLOW; +#else + /* TODO(sergey): How to deal with symlinks on windows? */ +# ifndef _MSC_VER +# warning "Symbolic links will be followed on undo save, possibly causing CVE-2008-1103" +# endif +#endif + file = BLI_open(filepath, oflags, 0666); + + if (file == -1) { + fprintf(stderr, + "Unable to save '%s': %s\n", + filepath, + errno ? strerror(errno) : "Unknown error opening file"); + return false; + } + + for (chunk = static_cast(memfile->chunks.first); chunk; + chunk = static_cast(chunk->next)) { +#ifdef _WIN32 + if (size_t(write(file, chunk->buf, uint(chunk->size))) != chunk->size) +#else + if (size_t(write(file, chunk->buf, chunk->size)) != chunk->size) +#endif + { + break; + } + } + + close(file); + + if (chunk) { + fprintf(stderr, + "Unable to save '%s': %s\n", + filepath, + errno ? strerror(errno) : "Unknown error writing file"); + return false; + } + return true; +} + static ssize_t undo_read(FileReader *reader, void *buffer, size_t size) { UndoReader *undo = (UndoReader *)reader; diff --git a/source/blender/blenloader/intern/writefile.cc b/source/blender/blenloader/intern/writefile.cc index 935a54fcb10..8d38457cc01 100644 --- a/source/blender/blenloader/intern/writefile.cc +++ b/source/blender/blenloader/intern/writefile.cc @@ -85,7 +85,6 @@ #include "BLI_bitmap.h" #include "BLI_blenlib.h" -#include "BLI_copy_on_write.hh" #include "BLI_endian_defines.h" #include "BLI_endian_switch.h" #include "BLI_link_utils.h" @@ -1697,19 +1696,4 @@ bool BLO_write_is_undo(BlendWriter *writer) return writer->wd->use_memfile; } -void BLO_write_cow(BlendWriter *writer, const void *data_ptr, const bCopyOnWrite *cow) -{ - BLI_assert(writer->wd->use_memfile); - if (data_ptr == nullptr) { - return; - } - MemFile &memfile = *writer->wd->mem.written_memfile; - if (memfile.cow_storage == nullptr) { - memfile.cow_storage = MEM_new(__func__); - } - if (memfile.cow_storage->map.add(data_ptr, cow)) { - cow->add_user(); - } -} - /** \} */ diff --git a/source/blender/windowmanager/intern/wm_files.cc b/source/blender/windowmanager/intern/wm_files.cc index 5d973a688ac..0ba47e2cf4d 100644 --- a/source/blender/windowmanager/intern/wm_files.cc +++ b/source/blender/windowmanager/intern/wm_files.cc @@ -2010,20 +2010,33 @@ static void wm_autosave_location(char filepath[FILE_MAX]) BLI_path_join(filepath, FILE_MAX, tempdir_base, filename); } -static void wm_autosave_write(Main *bmain) +static void wm_autosave_write(Main *bmain, wmWindowManager *wm) { char filepath[FILE_MAX]; wm_autosave_location(filepath); - /* Save as regular blend file with recovery information. */ - const int fileflags = (G.fileflags & ~G_FILE_COMPRESS) | G_FILE_RECOVER_WRITE; + /* Fast save of last undo-buffer, now with UI. */ + const bool use_memfile = (U.uiflag & USER_GLOBALUNDO) != 0; + MemFile *memfile = use_memfile ? ED_undosys_stack_memfile_get_active(wm->undo_stack) : nullptr; + if (memfile != nullptr) { + BLO_memfile_write_file(memfile, filepath); + } + else { + if (use_memfile) { + /* This is very unlikely, alert developers of this unexpected case. */ + CLOG_WARN(&LOG, "undo-data not found for writing, fallback to regular file write!"); + } - ED_editors_flush_edits(bmain); + /* Save as regular blend file with recovery information. */ + const int fileflags = (G.fileflags & ~G_FILE_COMPRESS) | G_FILE_RECOVER_WRITE; - /* Error reporting into console. */ - BlendFileWriteParams params{}; - BLO_write_file(bmain, filepath, fileflags, ¶ms, nullptr); + ED_editors_flush_edits(bmain); + + /* Error reporting into console. */ + BlendFileWriteParams params{}; + BLO_write_file(bmain, filepath, fileflags, ¶ms, nullptr); + } } static void wm_autosave_timer_begin_ex(wmWindowManager *wm, double timestep) @@ -2071,7 +2084,7 @@ void wm_autosave_timer(Main *bmain, wmWindowManager *wm, wmTimer * /*wt*/) } } - wm_autosave_write(bmain); + wm_autosave_write(bmain, wm); /* Restart the timer after file write, just in case file write takes a long time. */ wm_autosave_timer_begin(wm); diff --git a/source/blender/windowmanager/intern/wm_init_exit.cc b/source/blender/windowmanager/intern/wm_init_exit.cc index c0fdf51bd46..683e3ec0dd7 100644 --- a/source/blender/windowmanager/intern/wm_init_exit.cc +++ b/source/blender/windowmanager/intern/wm_init_exit.cc @@ -439,16 +439,27 @@ void WM_exit_ex(bContext *C, const bool do_python) /* NOTE: same code copied in `wm_files.cc`. */ if (C && wm) { if (!G.background) { - /* Save latest state before closing as quit.blend. */ - char filepath[FILE_MAX]; - const int fileflags = G.fileflags & ~G_FILE_COMPRESS; - BLI_path_join(filepath, sizeof(filepath), BKE_tempdir_base(), BLENDER_QUIT_FILE); + struct MemFile *undo_memfile = wm->undo_stack ? + ED_undosys_stack_memfile_get_active(wm->undo_stack) : + nullptr; + if (undo_memfile != nullptr) { + /* save the undo state as quit.blend */ + Main *bmain = CTX_data_main(C); + char filepath[FILE_MAX]; + bool has_edited; + const int fileflags = G.fileflags & ~G_FILE_COMPRESS; - Main *bmain = CTX_data_main(C); - ED_editors_flush_edits(bmain); - BlendFileWriteParams blend_file_write_params{}; - BLO_write_file(bmain, filepath, fileflags, &blend_file_write_params, nullptr); - printf("Saved session recovery to \"%s\"\n", filepath); + BLI_path_join(filepath, sizeof(filepath), BKE_tempdir_base(), BLENDER_QUIT_FILE); + + has_edited = ED_editors_flush_edits(bmain); + + BlendFileWriteParams blend_file_write_params{}; + if ((has_edited && + BLO_write_file(bmain, filepath, fileflags, &blend_file_write_params, nullptr)) || + BLO_memfile_write_file(undo_memfile, filepath)) { + printf("Saved session recovery to \"%s\"\n", filepath); + } + } } WM_jobs_kill_all(wm); diff --git a/source/creator/creator_signals.c b/source/creator/creator_signals.c index 23d82a448e5..c733ee617cb 100644 --- a/source/creator/creator_signals.c +++ b/source/creator/creator_signals.c @@ -51,6 +51,12 @@ # include "creator_intern.h" /* own include */ +// #define USE_WRITE_CRASH_BLEND +# ifdef USE_WRITE_CRASH_BLEND +# include "BKE_undo_system.h" +# include "BLO_undofile.h" +# endif + /* set breakpoints here when running in debug mode, useful to catch floating point errors */ # if defined(__linux__) || defined(_WIN32) || defined(OSX_SSE_FPE) static void sig_handle_fpe(int UNUSED(sig)) @@ -88,6 +94,28 @@ static void sig_handle_crash(int signum) wmWindowManager *wm = G_MAIN ? G_MAIN->wm.first : NULL; +# ifdef USE_WRITE_CRASH_BLEND + if (wm && wm->undo_stack) { + struct MemFile *memfile = BKE_undosys_stack_memfile_get_active(wm->undo_stack); + if (memfile) { + char fname[FILE_MAX]; + + if (!(G_MAIN && G_MAIN->filepath[0])) { + BLI_path_join(fname, sizeof(fname), BKE_tempdir_base(), "crash.blend"); + } + else { + STRNCPY(fname, G_MAIN->filepath); + BLI_path_extension_replace(fname, sizeof(fname), ".crash.blend"); + } + + printf("Writing: %s\n", fname); + fflush(stdout); + + BLO_memfile_write_file(memfile, fname); + } + } +# endif + FILE *fp; char header[512]; -- 2.30.2 From 11d6228ba97458f15ca80489db8c06fdfa2ce777 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Tue, 28 Mar 2023 15:27:58 +0200 Subject: [PATCH 03/46] progress --- source/blender/blenkernel/BKE_customdata.h | 21 ++-- .../blenkernel/intern/attribute_access.cc | 6 +- .../blender/blenkernel/intern/customdata.cc | 103 ++++++++++-------- .../blenkernel/intern/mesh_legacy_convert.cc | 16 ++- source/blender/blenlib/BLI_implicit_sharing.h | 20 ++++ source/blender/blenlib/CMakeLists.txt | 3 +- source/blender/blenloader/BLO_undofile.h | 1 + source/blender/editors/mesh/editmesh_undo.cc | 10 +- .../blender/makesdna/DNA_customdata_types.h | 6 +- 9 files changed, 111 insertions(+), 75 deletions(-) create mode 100644 source/blender/blenlib/BLI_implicit_sharing.h diff --git a/source/blender/blenkernel/BKE_customdata.h b/source/blender/blenkernel/BKE_customdata.h index 013863a0822..662dcefcec8 100644 --- a/source/blender/blenkernel/BKE_customdata.h +++ b/source/blender/blenkernel/BKE_customdata.h @@ -8,6 +8,7 @@ #pragma once +#include "BLI_implicit_sharing.h" #include "BLI_sys_types.h" #include "BLI_utildefines.h" #ifdef __cplusplus @@ -247,13 +248,14 @@ void *CustomData_add_layer(struct CustomData *data, /** * Adds a layer of the given type to the #CustomData object. The new layer takes ownership of the - * passed in `layer_data`. If a #bCopyOnWrite is passed in, it's user count is increased. + * passed in `layer_data`. If a #ImplicitSharingInfoHandle is passed in, it's user count is + * increased. */ const void *CustomData_add_layer_with_data(struct CustomData *data, eCustomDataType type, void *layer_data, int totelem, - const struct bCopyOnWrite *cow); + const ImplicitSharingInfoHandle *implicit_sharing_info); /** * Same as above but accepts a name. @@ -264,12 +266,13 @@ void *CustomData_add_layer_named(struct CustomData *data, int totelem, const char *name); -const void *CustomData_add_layer_named_with_data(struct CustomData *data, - eCustomDataType type, - void *layer_data, - int totelem, - const char *name, - const struct bCopyOnWrite *cow); +const void *CustomData_add_layer_named_with_data( + struct CustomData *data, + eCustomDataType type, + void *layer_data, + int totelem, + const char *name, + const ImplicitSharingInfoHandle *implicit_sharing_info); void *CustomData_add_layer_anonymous(struct CustomData *data, eCustomDataType type, @@ -282,7 +285,7 @@ const void *CustomData_add_layer_anonymous_with_data( const AnonymousAttributeIDHandle *anonymous_id, int totelem, void *layer_data, - const struct bCopyOnWrite *cow); + const ImplicitSharingInfoHandle *implicit_sharing_info); /** * Frees the active or first data layer with the give type. diff --git a/source/blender/blenkernel/intern/attribute_access.cc b/source/blender/blenkernel/intern/attribute_access.cc index c92da85f8b4..66c13a75373 100644 --- a/source/blender/blenkernel/intern/attribute_access.cc +++ b/source/blender/blenkernel/intern/attribute_access.cc @@ -242,17 +242,17 @@ static const void *add_generic_custom_data_layer_with_existing_data( const AttributeIDRef &attribute_id, const int domain_size, void *layer_data, - const bCopyOnWrite *cow) + const ImplicitSharingInfo *implicit_sharing_info) { if (attribute_id.is_anonymous()) { const AnonymousAttributeID &anonymous_id = attribute_id.anonymous_id(); return CustomData_add_layer_anonymous_with_data( - &custom_data, data_type, &anonymous_id, domain_size, layer_data, cow); + &custom_data, data_type, &anonymous_id, domain_size, layer_data, implicit_sharing_info); } char attribute_name_c[MAX_CUSTOMDATA_LAYER_NAME]; attribute_id.name().copy(attribute_name_c); return CustomData_add_layer_named_with_data( - &custom_data, data_type, layer_data, domain_size, attribute_name_c, cow); + &custom_data, data_type, layer_data, domain_size, attribute_name_c, implicit_sharing_info); } static bool add_custom_data_layer_from_attribute_init(const AttributeIDRef &attribute_id, diff --git a/source/blender/blenkernel/intern/customdata.cc b/source/blender/blenkernel/intern/customdata.cc index 9735b65a28e..fe87490b50d 100644 --- a/source/blender/blenkernel/intern/customdata.cc +++ b/source/blender/blenkernel/intern/customdata.cc @@ -59,6 +59,7 @@ #include "data_transfer_intern.h" using blender::float2; +using blender::ImplicitSharingInfo; using blender::IndexRange; using blender::Set; using blender::Span; @@ -2158,13 +2159,14 @@ void customData_mask_layers__print(const CustomData_MeshMasks *mask) static void customData_update_offsets(CustomData *data); -static CustomDataLayer *customData_add_layer__internal(CustomData *data, - eCustomDataType type, - eCDAllocType alloctype, - void *layer_data_to_assign, - const bCopyOnWrite *cow_to_assign, - int totelem, - const char *name); +static CustomDataLayer *customData_add_layer__internal( + CustomData *data, + eCustomDataType type, + eCDAllocType alloctype, + void *layer_data_to_assign, + const ImplicitSharingInfo *implicit_sharing_info_to_assign, + int totelem, + const char *name); void CustomData_update_typemap(CustomData *data) { @@ -2266,23 +2268,28 @@ static bool customdata_merge_internal(const CustomData *source, } void *layer_data_to_assign = nullptr; - const bCopyOnWrite *cow_to_assign = nullptr; + const ImplicitSharingInfo *implicit_sharing_info_to_assign = nullptr; if (alloctype == CD_ASSIGN) { if (src_layer.data != nullptr) { - if (src_layer.cow == nullptr) { + if (src_layer.implicit_sharing_info == nullptr) { /* Can't share the layer, duplicate it instead. */ layer_data_to_assign = copy_layer_data(type, src_layer.data, totelem); } else { /* Share the layer. */ layer_data_to_assign = src_layer.data; - cow_to_assign = src_layer.cow; + implicit_sharing_info_to_assign = src_layer.implicit_sharing_info; } } } - CustomDataLayer *new_layer = customData_add_layer__internal( - dest, type, alloctype, layer_data_to_assign, cow_to_assign, totelem, src_layer.name); + CustomDataLayer *new_layer = customData_add_layer__internal(dest, + type, + alloctype, + layer_data_to_assign, + implicit_sharing_info_to_assign, + totelem, + src_layer.name); new_layer->uid = src_layer.uid; new_layer->flag |= src_layer_flag & (CD_FLAG_EXTERNAL | CD_FLAG_IN_MEMORY); @@ -2345,18 +2352,18 @@ CustomData CustomData_shallow_copy_remove_non_bmesh_attributes(const CustomData } /** - * A #bCopyOnWrite that knows how to free the entire referenced custom data layer (including + * A #ImplicitSharingInfo that knows how to free the entire referenced custom data layer (including * potentially separately allocated chunks like for vertex groups). */ -class CustomDataLayerCOW : public bCopyOnWrite { +class CustomDataLayerImplicitSharing : public ImplicitSharingInfo { private: const void *data_; const int totelem_; const eCustomDataType type_; public: - CustomDataLayerCOW(const void *data, const int totelem, const eCustomDataType type) - : bCopyOnWrite(1), data_(data), totelem_(totelem), type_(type) + CustomDataLayerImplicitSharing(const void *data, const int totelem, const eCustomDataType type) + : ImplicitSharingInfo(1), data_(data), totelem_(totelem), type_(type) { } @@ -2368,12 +2375,12 @@ class CustomDataLayerCOW : public bCopyOnWrite { } }; -/** Create a #bCopyOnWrite that takes ownership of the data. */ -static bCopyOnWrite *make_cow_for_array(const eCustomDataType type, - const void *data, - const int totelem) +/** Create a #ImplicitSharingInfo that takes ownership of the data. */ +static ImplicitSharingInfo *make_cow_for_array(const eCustomDataType type, + const void *data, + const int totelem) { - return MEM_new(__func__, data, totelem, type); + return MEM_new(__func__, data, totelem, type); } /** @@ -2384,16 +2391,16 @@ static void ensure_layer_data_is_mutable(CustomDataLayer &layer, const int totel if (layer.data == nullptr) { return; } - if (layer.cow == nullptr) { + if (layer.implicit_sharing_info == nullptr) { /* Can not be shared without cow data. */ return; } - if (layer.cow->is_shared()) { + if (layer.implicit_sharing_info->is_shared()) { const eCustomDataType type = eCustomDataType(layer.type); const void *old_data = layer.data; layer.data = copy_layer_data(type, old_data, totelem); - layer.cow->remove_user_and_delete_if_last(); - layer.cow = make_cow_for_array(type, layer.data, totelem); + layer.implicit_sharing_info->remove_user_and_delete_if_last(); + layer.implicit_sharing_info = make_cow_for_array(type, layer.data, totelem); } } @@ -2415,14 +2422,15 @@ void CustomData_realloc(CustomData *data, const int old_size, const int new_size memcpy(new_layer_data, layer->data, std::min(old_size_in_bytes, new_size_in_bytes)); } /* Remove ownership of old array */ - if (layer->cow) { - layer->cow->remove_user_and_delete_if_last(); - layer->cow = nullptr; + if (layer->implicit_sharing_info) { + layer->implicit_sharing_info->remove_user_and_delete_if_last(); + layer->implicit_sharing_info = nullptr; } /* Take ownership of new array. */ layer->data = new_layer_data; if (layer->data) { - layer->cow = make_cow_for_array(eCustomDataType(layer->type), layer->data, new_size); + layer->implicit_sharing_info = make_cow_for_array( + eCustomDataType(layer->type), layer->data, new_size); } if (new_size > old_size) { @@ -2468,13 +2476,13 @@ static void customData_free_layer__internal(CustomDataLayer *layer, const int to layer->anonymous_id = nullptr; } const eCustomDataType type = eCustomDataType(layer->type); - if (layer->cow == nullptr) { + if (layer->implicit_sharing_info == nullptr) { if (layer->data) { free_layer_data(type, layer->data, totelem); } } else { - layer->cow->remove_user_and_delete_if_last(); + layer->implicit_sharing_info->remove_user_and_delete_if_last(); } } @@ -2830,13 +2838,14 @@ static void customData_resize(CustomData *data, const int grow_amount) data->maxlayer += grow_amount; } -static CustomDataLayer *customData_add_layer__internal(CustomData *data, - const eCustomDataType type, - const eCDAllocType alloctype, - void *layer_data_to_assign, - const bCopyOnWrite *cow_to_assign, - const int totelem, - const char *name) +static CustomDataLayer *customData_add_layer__internal( + CustomData *data, + const eCustomDataType type, + const eCDAllocType alloctype, + void *layer_data_to_assign, + const ImplicitSharingInfo *implicit_sharing_info_to_assign, + const int totelem, + const char *name) { const LayerTypeInfo &type_info = *layerType_getInfo(type); int flag = 0; @@ -2891,23 +2900,23 @@ static CustomDataLayer *customData_add_layer__internal(CustomData *data, break; } case CD_ASSIGN: { - if (totelem == 0 && cow_to_assign == nullptr) { + if (totelem == 0 && implicit_sharing_info_to_assign == nullptr) { MEM_SAFE_FREE(layer_data_to_assign); } else { new_layer.data = layer_data_to_assign; - new_layer.cow = cow_to_assign; - if (new_layer.cow) { - new_layer.cow->add_user(); + new_layer.implicit_sharing_info = implicit_sharing_info_to_assign; + if (new_layer.implicit_sharing_info) { + new_layer.implicit_sharing_info->add_user(); } } break; } } - if (new_layer.data != nullptr && new_layer.cow == nullptr) { + if (new_layer.data != nullptr && new_layer.implicit_sharing_info == nullptr) { /* Make layer data shareable. */ - new_layer.cow = make_cow_for_array(type, new_layer.data, totelem); + new_layer.implicit_sharing_info = make_cow_for_array(type, new_layer.data, totelem); } new_layer.type = type; @@ -2968,7 +2977,7 @@ const void *CustomData_add_layer_with_data(CustomData *data, const eCustomDataType type, void *layer_data, const int totelem, - const bCopyOnWrite *cow) + const ImplicitSharingInfo *cow) { const LayerTypeInfo *typeInfo = layerType_getInfo(type); @@ -3004,7 +3013,7 @@ const void *CustomData_add_layer_named_with_data(CustomData *data, void *layer_data, int totelem, const char *name, - const bCopyOnWrite *cow) + const ImplicitSharingInfo *cow) { CustomDataLayer *layer = customData_add_layer__internal( data, type, CD_ASSIGN, layer_data, cow, totelem, name); @@ -3042,7 +3051,7 @@ const void *CustomData_add_layer_anonymous_with_data( const AnonymousAttributeIDHandle *anonymous_id, const int totelem, void *layer_data, - const bCopyOnWrite *cow) + const ImplicitSharingInfo *cow) { const char *name = anonymous_id->name().c_str(); CustomDataLayer *layer = customData_add_layer__internal( diff --git a/source/blender/blenkernel/intern/mesh_legacy_convert.cc b/source/blender/blenkernel/intern/mesh_legacy_convert.cc index 92a5f685ca3..0a64f2a23d7 100644 --- a/source/blender/blenkernel/intern/mesh_legacy_convert.cc +++ b/source/blender/blenkernel/intern/mesh_legacy_convert.cc @@ -1300,22 +1300,26 @@ void BKE_mesh_legacy_face_set_to_generic(Mesh *mesh) return; } void *faceset_data = nullptr; - const bCopyOnWrite *faceset_cow = nullptr; + const ImplicitSharingInfo *faceset_implicit_sharing_info = nullptr; for (const int i : IndexRange(mesh->pdata.totlayer)) { CustomDataLayer &layer = mesh->pdata.layers[i]; if (layer.type == CD_SCULPT_FACE_SETS) { faceset_data = layer.data; - faceset_cow = layer.cow; + faceset_implicit_sharing_info = layer.implicit_sharing_info; layer.data = nullptr; - layer.cow = nullptr; + layer.implicit_sharing_info = nullptr; CustomData_free_layer(&mesh->pdata, CD_SCULPT_FACE_SETS, mesh->totpoly, i); break; } } if (faceset_data != nullptr) { - CustomData_add_layer_named_with_data( - &mesh->pdata, CD_PROP_INT32, faceset_data, mesh->totpoly, ".sculpt_face_set", faceset_cow); - faceset_cow->remove_user_and_delete_if_last(); + CustomData_add_layer_named_with_data(&mesh->pdata, + CD_PROP_INT32, + faceset_data, + mesh->totpoly, + ".sculpt_face_set", + faceset_implicit_sharing_info); + faceset_implicit_sharing_info->remove_user_and_delete_if_last(); } } diff --git a/source/blender/blenlib/BLI_implicit_sharing.h b/source/blender/blenlib/BLI_implicit_sharing.h new file mode 100644 index 00000000000..c3dcc26b0d0 --- /dev/null +++ b/source/blender/blenlib/BLI_implicit_sharing.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#pragma once + +/** \file + * \ingroup bli + */ + +#ifdef __cplusplus + +namespace blender { +class ImplicitSharingInfo; +} +using ImplicitSharingInfoHandle = blender::ImplicitSharingInfo; + +#else + +typedef struct ImplicitSharingInfoHandle ImplicitSharingInfoHandle; + +#endif diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt index 39b7b60b554..a3f64a04692 100644 --- a/source/blender/blenlib/CMakeLists.txt +++ b/source/blender/blenlib/CMakeLists.txt @@ -200,8 +200,6 @@ set(SRC BLI_compute_context.hh BLI_console.h BLI_convexhull_2d.h - BLI_copy_on_write.hh - BLI_copy_on_write_user.hh BLI_cpp_type.hh BLI_cpp_type_make.hh BLI_cpp_types.hh @@ -245,6 +243,7 @@ set(SRC BLI_hash_tables.hh BLI_heap.h BLI_heap_simple.h + BLI_implicit_sharing.h BLI_implicit_sharing.hh BLI_implicit_sharing_ptr.hh BLI_index_mask.hh diff --git a/source/blender/blenloader/BLO_undofile.h b/source/blender/blenloader/BLO_undofile.h index 91ba3ed1740..0dee167db53 100644 --- a/source/blender/blenloader/BLO_undofile.h +++ b/source/blender/blenloader/BLO_undofile.h @@ -102,6 +102,7 @@ extern struct Main *BLO_memfile_main_get(struct MemFile *memfile, * * \return success. */ +extern bool BLO_memfile_write_file(struct MemFile *memfile, const char *filepath); FileReader *BLO_memfile_new_filereader(MemFile *memfile, int undo_direction); diff --git a/source/blender/editors/mesh/editmesh_undo.cc b/source/blender/editors/mesh/editmesh_undo.cc index adb1563efe4..bb3db79cb2d 100644 --- a/source/blender/editors/mesh/editmesh_undo.cc +++ b/source/blender/editors/mesh/editmesh_undo.cc @@ -16,7 +16,7 @@ #include "DNA_scene_types.h" #include "BLI_array_utils.h" -#include "BLI_copy_on_write.hh" +#include "BLI_implicit_sharing.hh" #include "BLI_listbase.h" #include "BLI_task.hh" @@ -272,16 +272,16 @@ static void um_arraystore_cd_compact(CustomData *cdata, } if (layer->data) { - if (layer->cow) { + if (layer->implicit_sharing_info) { /* This assumes that the layer is not shared, which it is not here because it has just * been created in #BM_mesh_bm_to_me. The situation is a bit tricky here, because the * layer data may be freed partially below for e.g. vertex groups. */ - BLI_assert(layer->cow->is_mutable()); - MEM_delete(layer->cow); + BLI_assert(layer->implicit_sharing_info->is_mutable()); + MEM_delete(layer->implicit_sharing_info); } MEM_freeN(layer->data); layer->data = nullptr; - layer->cow = nullptr; + layer->implicit_sharing_info = nullptr; } } diff --git a/source/blender/makesdna/DNA_customdata_types.h b/source/blender/makesdna/DNA_customdata_types.h index a1220b0e92c..bf95b1072ef 100644 --- a/source/blender/makesdna/DNA_customdata_types.h +++ b/source/blender/makesdna/DNA_customdata_types.h @@ -11,6 +11,8 @@ #include "DNA_defs.h" +#include "BLI_implicit_sharing.h" + #ifdef __cplusplus extern "C" { #endif @@ -25,8 +27,6 @@ using AnonymousAttributeIDHandle = blender::bke::AnonymousAttributeID; typedef struct AnonymousAttributeIDHandle AnonymousAttributeIDHandle; #endif -struct bCopyOnWrite; - /** Descriptor and storage for a custom data layer. */ typedef struct CustomDataLayer { /** Type of data in layer. */ @@ -59,7 +59,7 @@ typedef struct CustomDataLayer { * Run-time data that allows sharing `data` with other entities (mostly custom data layers on * other geometries). */ - const struct bCopyOnWrite *cow; + const ImplicitSharingInfoHandle *implicit_sharing_info; } CustomDataLayer; #define MAX_CUSTOMDATA_LAYER_NAME 68 -- 2.30.2 From 15ec5bb15955f959a46f83f3b913e76e3df95de8 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Tue, 28 Mar 2023 15:35:26 +0200 Subject: [PATCH 04/46] fix --- source/blender/blenkernel/intern/mesh_legacy_convert.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/blender/blenkernel/intern/mesh_legacy_convert.cc b/source/blender/blenkernel/intern/mesh_legacy_convert.cc index 0a64f2a23d7..5d27bce29f6 100644 --- a/source/blender/blenkernel/intern/mesh_legacy_convert.cc +++ b/source/blender/blenkernel/intern/mesh_legacy_convert.cc @@ -1319,6 +1319,8 @@ void BKE_mesh_legacy_face_set_to_generic(Mesh *mesh) mesh->totpoly, ".sculpt_face_set", faceset_implicit_sharing_info); + } + if (faceset_implicit_sharing_info != nullptr) { faceset_implicit_sharing_info->remove_user_and_delete_if_last(); } } -- 2.30.2 From 7e783f845236a12d174b9e528c49e8d6f9794896 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Tue, 28 Mar 2023 16:33:46 +0200 Subject: [PATCH 05/46] fix --- source/blender/blenkernel/intern/customdata.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/blender/blenkernel/intern/customdata.cc b/source/blender/blenkernel/intern/customdata.cc index fe87490b50d..a219c5d083b 100644 --- a/source/blender/blenkernel/intern/customdata.cc +++ b/source/blender/blenkernel/intern/customdata.cc @@ -2483,6 +2483,7 @@ static void customData_free_layer__internal(CustomDataLayer *layer, const int to } else { layer->implicit_sharing_info->remove_user_and_delete_if_last(); + layer->implicit_sharing_info = nullptr; } } @@ -5199,6 +5200,7 @@ void CustomData_blend_read(BlendDataReader *reader, CustomData *data, const int if (layer->flag & CD_FLAG_EXTERNAL) { layer->flag &= ~CD_FLAG_IN_MEMORY; } + layer->implicit_sharing_info = nullptr; if (CustomData_verify_versions(data, i)) { BLO_read_data_address(reader, &layer->data); -- 2.30.2 From 19de6f302ccd8c37dc7d5cb92187bcadb27681e7 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Tue, 28 Mar 2023 16:39:02 +0200 Subject: [PATCH 06/46] fix --- source/blender/blenkernel/intern/customdata.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/source/blender/blenkernel/intern/customdata.cc b/source/blender/blenkernel/intern/customdata.cc index a219c5d083b..bf49aca45c7 100644 --- a/source/blender/blenkernel/intern/customdata.cc +++ b/source/blender/blenkernel/intern/customdata.cc @@ -5204,6 +5204,10 @@ void CustomData_blend_read(BlendDataReader *reader, CustomData *data, const int if (CustomData_verify_versions(data, i)) { BLO_read_data_address(reader, &layer->data); + if (layer->data != nullptr) { + layer->implicit_sharing_info = make_cow_for_array( + eCustomDataType(layer->type), layer->data, count); + } if (CustomData_layer_ensure_data_exists(layer, count)) { /* Under normal operations, this shouldn't happen, but... * For a CD_PROP_BOOL example, see #84935. -- 2.30.2 From 994bab29342fee8b49cb4e34d808eeb6235bcdfe Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Tue, 28 Mar 2023 16:56:46 +0200 Subject: [PATCH 07/46] improve naming --- source/blender/blenkernel/BKE_customdata.h | 17 +++---- .../blenkernel/intern/attribute_access.cc | 6 +-- .../blender/blenkernel/intern/customdata.cc | 51 +++++++++---------- .../blenkernel/intern/mesh_legacy_convert.cc | 12 ++--- source/blender/editors/mesh/editmesh_undo.cc | 8 +-- .../blender/makesdna/DNA_customdata_types.h | 2 +- 6 files changed, 47 insertions(+), 49 deletions(-) diff --git a/source/blender/blenkernel/BKE_customdata.h b/source/blender/blenkernel/BKE_customdata.h index 662dcefcec8..be2afb0614e 100644 --- a/source/blender/blenkernel/BKE_customdata.h +++ b/source/blender/blenkernel/BKE_customdata.h @@ -255,7 +255,7 @@ const void *CustomData_add_layer_with_data(struct CustomData *data, eCustomDataType type, void *layer_data, int totelem, - const ImplicitSharingInfoHandle *implicit_sharing_info); + const ImplicitSharingInfoHandle *sharing_info); /** * Same as above but accepts a name. @@ -266,13 +266,12 @@ void *CustomData_add_layer_named(struct CustomData *data, int totelem, const char *name); -const void *CustomData_add_layer_named_with_data( - struct CustomData *data, - eCustomDataType type, - void *layer_data, - int totelem, - const char *name, - const ImplicitSharingInfoHandle *implicit_sharing_info); +const void *CustomData_add_layer_named_with_data(struct CustomData *data, + eCustomDataType type, + void *layer_data, + int totelem, + const char *name, + const ImplicitSharingInfoHandle *sharing_info); void *CustomData_add_layer_anonymous(struct CustomData *data, eCustomDataType type, @@ -285,7 +284,7 @@ const void *CustomData_add_layer_anonymous_with_data( const AnonymousAttributeIDHandle *anonymous_id, int totelem, void *layer_data, - const ImplicitSharingInfoHandle *implicit_sharing_info); + const ImplicitSharingInfoHandle *sharing_info); /** * Frees the active or first data layer with the give type. diff --git a/source/blender/blenkernel/intern/attribute_access.cc b/source/blender/blenkernel/intern/attribute_access.cc index 66c13a75373..8b0e454a895 100644 --- a/source/blender/blenkernel/intern/attribute_access.cc +++ b/source/blender/blenkernel/intern/attribute_access.cc @@ -242,17 +242,17 @@ static const void *add_generic_custom_data_layer_with_existing_data( const AttributeIDRef &attribute_id, const int domain_size, void *layer_data, - const ImplicitSharingInfo *implicit_sharing_info) + const ImplicitSharingInfo *sharing_info) { if (attribute_id.is_anonymous()) { const AnonymousAttributeID &anonymous_id = attribute_id.anonymous_id(); return CustomData_add_layer_anonymous_with_data( - &custom_data, data_type, &anonymous_id, domain_size, layer_data, implicit_sharing_info); + &custom_data, data_type, &anonymous_id, domain_size, layer_data, sharing_info); } char attribute_name_c[MAX_CUSTOMDATA_LAYER_NAME]; attribute_id.name().copy(attribute_name_c); return CustomData_add_layer_named_with_data( - &custom_data, data_type, layer_data, domain_size, attribute_name_c, implicit_sharing_info); + &custom_data, data_type, layer_data, domain_size, attribute_name_c, sharing_info); } static bool add_custom_data_layer_from_attribute_init(const AttributeIDRef &attribute_id, diff --git a/source/blender/blenkernel/intern/customdata.cc b/source/blender/blenkernel/intern/customdata.cc index bf49aca45c7..01d34d07aac 100644 --- a/source/blender/blenkernel/intern/customdata.cc +++ b/source/blender/blenkernel/intern/customdata.cc @@ -2164,7 +2164,7 @@ static CustomDataLayer *customData_add_layer__internal( eCustomDataType type, eCDAllocType alloctype, void *layer_data_to_assign, - const ImplicitSharingInfo *implicit_sharing_info_to_assign, + const ImplicitSharingInfo *sharing_info_to_assign, int totelem, const char *name); @@ -2268,17 +2268,17 @@ static bool customdata_merge_internal(const CustomData *source, } void *layer_data_to_assign = nullptr; - const ImplicitSharingInfo *implicit_sharing_info_to_assign = nullptr; + const ImplicitSharingInfo *sharing_info_to_assign = nullptr; if (alloctype == CD_ASSIGN) { if (src_layer.data != nullptr) { - if (src_layer.implicit_sharing_info == nullptr) { + if (src_layer.sharing_info == nullptr) { /* Can't share the layer, duplicate it instead. */ layer_data_to_assign = copy_layer_data(type, src_layer.data, totelem); } else { /* Share the layer. */ layer_data_to_assign = src_layer.data; - implicit_sharing_info_to_assign = src_layer.implicit_sharing_info; + sharing_info_to_assign = src_layer.sharing_info; } } } @@ -2287,7 +2287,7 @@ static bool customdata_merge_internal(const CustomData *source, type, alloctype, layer_data_to_assign, - implicit_sharing_info_to_assign, + sharing_info_to_assign, totelem, src_layer.name); @@ -2391,16 +2391,16 @@ static void ensure_layer_data_is_mutable(CustomDataLayer &layer, const int totel if (layer.data == nullptr) { return; } - if (layer.implicit_sharing_info == nullptr) { + if (layer.sharing_info == nullptr) { /* Can not be shared without cow data. */ return; } - if (layer.implicit_sharing_info->is_shared()) { + if (layer.sharing_info->is_shared()) { const eCustomDataType type = eCustomDataType(layer.type); const void *old_data = layer.data; layer.data = copy_layer_data(type, old_data, totelem); - layer.implicit_sharing_info->remove_user_and_delete_if_last(); - layer.implicit_sharing_info = make_cow_for_array(type, layer.data, totelem); + layer.sharing_info->remove_user_and_delete_if_last(); + layer.sharing_info = make_cow_for_array(type, layer.data, totelem); } } @@ -2422,14 +2422,14 @@ void CustomData_realloc(CustomData *data, const int old_size, const int new_size memcpy(new_layer_data, layer->data, std::min(old_size_in_bytes, new_size_in_bytes)); } /* Remove ownership of old array */ - if (layer->implicit_sharing_info) { - layer->implicit_sharing_info->remove_user_and_delete_if_last(); - layer->implicit_sharing_info = nullptr; + if (layer->sharing_info) { + layer->sharing_info->remove_user_and_delete_if_last(); + layer->sharing_info = nullptr; } /* Take ownership of new array. */ layer->data = new_layer_data; if (layer->data) { - layer->implicit_sharing_info = make_cow_for_array( + layer->sharing_info = make_cow_for_array( eCustomDataType(layer->type), layer->data, new_size); } @@ -2476,14 +2476,14 @@ static void customData_free_layer__internal(CustomDataLayer *layer, const int to layer->anonymous_id = nullptr; } const eCustomDataType type = eCustomDataType(layer->type); - if (layer->implicit_sharing_info == nullptr) { + if (layer->sharing_info == nullptr) { if (layer->data) { free_layer_data(type, layer->data, totelem); } } else { - layer->implicit_sharing_info->remove_user_and_delete_if_last(); - layer->implicit_sharing_info = nullptr; + layer->sharing_info->remove_user_and_delete_if_last(); + layer->sharing_info = nullptr; } } @@ -2844,7 +2844,7 @@ static CustomDataLayer *customData_add_layer__internal( const eCustomDataType type, const eCDAllocType alloctype, void *layer_data_to_assign, - const ImplicitSharingInfo *implicit_sharing_info_to_assign, + const ImplicitSharingInfo *sharing_info_to_assign, const int totelem, const char *name) { @@ -2901,23 +2901,23 @@ static CustomDataLayer *customData_add_layer__internal( break; } case CD_ASSIGN: { - if (totelem == 0 && implicit_sharing_info_to_assign == nullptr) { + if (totelem == 0 && sharing_info_to_assign == nullptr) { MEM_SAFE_FREE(layer_data_to_assign); } else { new_layer.data = layer_data_to_assign; - new_layer.implicit_sharing_info = implicit_sharing_info_to_assign; - if (new_layer.implicit_sharing_info) { - new_layer.implicit_sharing_info->add_user(); + new_layer.sharing_info = sharing_info_to_assign; + if (new_layer.sharing_info) { + new_layer.sharing_info->add_user(); } } break; } } - if (new_layer.data != nullptr && new_layer.implicit_sharing_info == nullptr) { + if (new_layer.data != nullptr && new_layer.sharing_info == nullptr) { /* Make layer data shareable. */ - new_layer.implicit_sharing_info = make_cow_for_array(type, new_layer.data, totelem); + new_layer.sharing_info = make_cow_for_array(type, new_layer.data, totelem); } new_layer.type = type; @@ -5200,13 +5200,12 @@ void CustomData_blend_read(BlendDataReader *reader, CustomData *data, const int if (layer->flag & CD_FLAG_EXTERNAL) { layer->flag &= ~CD_FLAG_IN_MEMORY; } - layer->implicit_sharing_info = nullptr; + layer->sharing_info = nullptr; if (CustomData_verify_versions(data, i)) { BLO_read_data_address(reader, &layer->data); if (layer->data != nullptr) { - layer->implicit_sharing_info = make_cow_for_array( - eCustomDataType(layer->type), layer->data, count); + layer->sharing_info = make_cow_for_array(eCustomDataType(layer->type), layer->data, count); } if (CustomData_layer_ensure_data_exists(layer, count)) { /* Under normal operations, this shouldn't happen, but... diff --git a/source/blender/blenkernel/intern/mesh_legacy_convert.cc b/source/blender/blenkernel/intern/mesh_legacy_convert.cc index 5d27bce29f6..a91a19236ac 100644 --- a/source/blender/blenkernel/intern/mesh_legacy_convert.cc +++ b/source/blender/blenkernel/intern/mesh_legacy_convert.cc @@ -1300,14 +1300,14 @@ void BKE_mesh_legacy_face_set_to_generic(Mesh *mesh) return; } void *faceset_data = nullptr; - const ImplicitSharingInfo *faceset_implicit_sharing_info = nullptr; + const ImplicitSharingInfo *faceset_sharing_info = nullptr; for (const int i : IndexRange(mesh->pdata.totlayer)) { CustomDataLayer &layer = mesh->pdata.layers[i]; if (layer.type == CD_SCULPT_FACE_SETS) { faceset_data = layer.data; - faceset_implicit_sharing_info = layer.implicit_sharing_info; + faceset_sharing_info = layer.sharing_info; layer.data = nullptr; - layer.implicit_sharing_info = nullptr; + layer.sharing_info = nullptr; CustomData_free_layer(&mesh->pdata, CD_SCULPT_FACE_SETS, mesh->totpoly, i); break; } @@ -1318,10 +1318,10 @@ void BKE_mesh_legacy_face_set_to_generic(Mesh *mesh) faceset_data, mesh->totpoly, ".sculpt_face_set", - faceset_implicit_sharing_info); + faceset_sharing_info); } - if (faceset_implicit_sharing_info != nullptr) { - faceset_implicit_sharing_info->remove_user_and_delete_if_last(); + if (faceset_sharing_info != nullptr) { + faceset_sharing_info->remove_user_and_delete_if_last(); } } diff --git a/source/blender/editors/mesh/editmesh_undo.cc b/source/blender/editors/mesh/editmesh_undo.cc index bb3db79cb2d..58c758a6f11 100644 --- a/source/blender/editors/mesh/editmesh_undo.cc +++ b/source/blender/editors/mesh/editmesh_undo.cc @@ -272,16 +272,16 @@ static void um_arraystore_cd_compact(CustomData *cdata, } if (layer->data) { - if (layer->implicit_sharing_info) { + if (layer->sharing_info) { /* This assumes that the layer is not shared, which it is not here because it has just * been created in #BM_mesh_bm_to_me. The situation is a bit tricky here, because the * layer data may be freed partially below for e.g. vertex groups. */ - BLI_assert(layer->implicit_sharing_info->is_mutable()); - MEM_delete(layer->implicit_sharing_info); + BLI_assert(layer->sharing_info->is_mutable()); + MEM_delete(layer->sharing_info); } MEM_freeN(layer->data); layer->data = nullptr; - layer->implicit_sharing_info = nullptr; + layer->sharing_info = nullptr; } } diff --git a/source/blender/makesdna/DNA_customdata_types.h b/source/blender/makesdna/DNA_customdata_types.h index bf95b1072ef..0d63f5a1111 100644 --- a/source/blender/makesdna/DNA_customdata_types.h +++ b/source/blender/makesdna/DNA_customdata_types.h @@ -59,7 +59,7 @@ typedef struct CustomDataLayer { * Run-time data that allows sharing `data` with other entities (mostly custom data layers on * other geometries). */ - const ImplicitSharingInfoHandle *implicit_sharing_info; + const ImplicitSharingInfoHandle *sharing_info; } CustomDataLayer; #define MAX_CUSTOMDATA_LAYER_NAME 68 -- 2.30.2 From d84c176e1940ca653a42e48a5dc1b0d122ef2adb Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Wed, 29 Mar 2023 14:53:19 +0200 Subject: [PATCH 08/46] don't retrieve mutable attribute of geometry from multiple threads at the same time --- .../sculpt_paint/curves_sculpt_grow_shrink.cc | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_grow_shrink.cc b/source/blender/editors/sculpt_paint/curves_sculpt_grow_shrink.cc index 26bec5ecfa1..0e5cb73b120 100644 --- a/source/blender/editors/sculpt_paint/curves_sculpt_grow_shrink.cc +++ b/source/blender/editors/sculpt_paint/curves_sculpt_grow_shrink.cc @@ -52,7 +52,8 @@ class CurvesEffect { virtual ~CurvesEffect() = default; virtual void execute(CurvesGeometry &curves, Span curve_indices, - Span move_distances_cu) = 0; + Span move_distances_cu, + MutableSpan positions_cu) = 0; }; /** @@ -87,10 +88,10 @@ class ShrinkCurvesEffect : public CurvesEffect { void execute(CurvesGeometry &curves, const Span curve_indices, - const Span move_distances_cu) override + const Span move_distances_cu, + MutableSpan positions_cu) override { const OffsetIndices points_by_curve = curves.points_by_curve(); - MutableSpan positions_cu = curves.positions_for_write(); threading::parallel_for(curve_indices.index_range(), 256, [&](const IndexRange range) { ParameterizationBuffers data; for (const int influence_i : range) { @@ -137,10 +138,10 @@ class ShrinkCurvesEffect : public CurvesEffect { class ExtrapolateCurvesEffect : public CurvesEffect { void execute(CurvesGeometry &curves, const Span curve_indices, - const Span move_distances_cu) override + const Span move_distances_cu, + MutableSpan positions_cu) override { const OffsetIndices points_by_curve = curves.points_by_curve(); - MutableSpan positions_cu = curves.positions_for_write(); threading::parallel_for(curve_indices.index_range(), 256, [&](const IndexRange range) { MoveAndResampleBuffers resample_buffer; for (const int influence_i : range) { @@ -179,10 +180,10 @@ class ScaleCurvesEffect : public CurvesEffect { void execute(CurvesGeometry &curves, const Span curve_indices, - const Span move_distances_cu) override + const Span move_distances_cu, + MutableSpan positions_cu) override { const OffsetIndices points_by_curve = curves.points_by_curve(); - MutableSpan positions_cu = curves.positions_for_write(); threading::parallel_for(curve_indices.index_range(), 256, [&](const IndexRange range) { for (const int influence_i : range) { const int curve_i = curve_indices[influence_i]; @@ -330,9 +331,11 @@ struct CurvesEffectOperationExecutor { } /* Execute effect. */ + MutableSpan positions_cu = curves_->positions_for_write(); threading::parallel_for_each(influences_for_thread, [&](const Influences &influences) { BLI_assert(influences.curve_indices.size() == influences.move_distances_cu.size()); - self_->effect_->execute(*curves_, influences.curve_indices, influences.move_distances_cu); + self_->effect_->execute( + *curves_, influences.curve_indices, influences.move_distances_cu, positions_cu); }); curves_->tag_positions_changed(); -- 2.30.2 From 4b94101cc6fa7a14bbc5152775372bc05ed95aeb Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Fri, 7 Apr 2023 12:05:47 +0200 Subject: [PATCH 09/46] fixes --- .../blender/blenkernel/intern/DerivedMesh.cc | 10 +++++----- .../blenkernel/intern/cdderivedmesh.cc | 4 ++-- source/blender/blenkernel/intern/mesh.cc | 9 ++++----- .../blender/blenkernel/intern/mesh_convert.cc | 8 ++++---- .../blenkernel/intern/mesh_legacy_convert.cc | 14 ++++++++----- .../editors/sculpt_paint/sculpt_dyntopo.cc | 12 ++++------- .../editors/sculpt_paint/sculpt_undo.cc | 20 ++++++++----------- 7 files changed, 36 insertions(+), 41 deletions(-) diff --git a/source/blender/blenkernel/intern/DerivedMesh.cc b/source/blender/blenkernel/intern/DerivedMesh.cc index af777ed7122..3048905dc80 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.cc +++ b/source/blender/blenkernel/intern/DerivedMesh.cc @@ -207,11 +207,11 @@ void DM_from_template(DerivedMesh *dm, int numPolys) { const CustomData_MeshMasks *mask = &CD_MASK_DERIVEDMESH; - CustomData_copy(&source->vertData, &dm->vertData, mask->vmask, CD_SET_DEFAULT, numVerts); - CustomData_copy(&source->edgeData, &dm->edgeData, mask->emask, CD_SET_DEFAULT, numEdges); - CustomData_copy(&source->faceData, &dm->faceData, mask->fmask, CD_SET_DEFAULT, numTessFaces); - CustomData_copy(&source->loopData, &dm->loopData, mask->lmask, CD_SET_DEFAULT, numLoops); - CustomData_copy(&source->polyData, &dm->polyData, mask->pmask, CD_SET_DEFAULT, numPolys); + CustomData_copy_new(&source->vertData, &dm->vertData, mask->vmask, CD_SET_DEFAULT, numVerts); + CustomData_copy_new(&source->edgeData, &dm->edgeData, mask->emask, CD_SET_DEFAULT, numEdges); + CustomData_copy_new(&source->faceData, &dm->faceData, mask->fmask, CD_SET_DEFAULT, numTessFaces); + CustomData_copy_new(&source->loopData, &dm->loopData, mask->lmask, CD_SET_DEFAULT, numLoops); + CustomData_copy_new(&source->polyData, &dm->polyData, mask->pmask, CD_SET_DEFAULT, numPolys); dm->poly_offsets = static_cast(MEM_dupallocN(source->poly_offsets)); dm->type = type; diff --git a/source/blender/blenkernel/intern/cdderivedmesh.cc b/source/blender/blenkernel/intern/cdderivedmesh.cc index bd1ef8af21c..d6882ab2203 100644 --- a/source/blender/blenkernel/intern/cdderivedmesh.cc +++ b/source/blender/blenkernel/intern/cdderivedmesh.cc @@ -165,8 +165,8 @@ static DerivedMesh *cdDM_from_mesh_ex(Mesh *mesh, const CustomData_MeshMasks *ma mesh->totloop, mesh->totpoly); - CustomData_merge(&mesh->vdata, &dm->vertData, cddata_masks.vmask, alloctype, mesh->totvert); - CustomData_merge(&mesh->edata, &dm->edgeData, cddata_masks.emask, alloctype, mesh->totedge); + CustomData_merge(&mesh->vdata, &dm->vertData, cddata_masks.vmask, mesh->totvert); + CustomData_merge(&mesh->edata, &dm->edgeData, cddata_masks.emask, mesh->totedge); CustomData_merge(&mesh->fdata, &dm->faceData, cddata_masks.fmask | CD_MASK_ORIGINDEX, diff --git a/source/blender/blenkernel/intern/mesh.cc b/source/blender/blenkernel/intern/mesh.cc index 679e3117271..8afd805096e 100644 --- a/source/blender/blenkernel/intern/mesh.cc +++ b/source/blender/blenkernel/intern/mesh.cc @@ -151,11 +151,10 @@ static void mesh_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int mesh_dst->default_color_attribute = static_cast( MEM_dupallocN(mesh_src->default_color_attribute)); - const eCDAllocType alloc_type = (flag & LIB_ID_COPY_CD_REFERENCE) ? CD_REFERENCE : CD_DUPLICATE; - CustomData_copy(&mesh_src->vdata, &mesh_dst->vdata, mask.vmask, alloc_type, mesh_dst->totvert); - CustomData_copy(&mesh_src->edata, &mesh_dst->edata, mask.emask, alloc_type, mesh_dst->totedge); - CustomData_copy(&mesh_src->ldata, &mesh_dst->ldata, mask.lmask, alloc_type, mesh_dst->totloop); - CustomData_copy(&mesh_src->pdata, &mesh_dst->pdata, mask.pmask, alloc_type, mesh_dst->totpoly); + CustomData_copy(&mesh_src->vdata, &mesh_dst->vdata, mask.vmask, mesh_dst->totvert); + CustomData_copy(&mesh_src->edata, &mesh_dst->edata, mask.emask, mesh_dst->totedge); + CustomData_copy(&mesh_src->ldata, &mesh_dst->ldata, mask.lmask, mesh_dst->totloop); + CustomData_copy(&mesh_src->pdata, &mesh_dst->pdata, mask.pmask, mesh_dst->totpoly); mesh_dst->poly_offset_indices = static_cast(MEM_dupallocN(mesh_src->poly_offset_indices)); if (do_tessface) { CustomData_copy(&mesh_src->fdata, &mesh_dst->fdata, mask.fmask, mesh_dst->totface); diff --git a/source/blender/blenkernel/intern/mesh_convert.cc b/source/blender/blenkernel/intern/mesh_convert.cc index c0578a2aa17..ddf9b156383 100644 --- a/source/blender/blenkernel/intern/mesh_convert.cc +++ b/source/blender/blenkernel/intern/mesh_convert.cc @@ -1124,10 +1124,10 @@ void BKE_mesh_nomain_to_mesh(Mesh *mesh_src, Mesh *mesh_dst, Object *ob) /* Using #CD_MASK_MESH ensures that only data that should exist in Main meshes is moved. */ const CustomData_MeshMasks mask = CD_MASK_MESH; - CustomData_copy(&mesh_src->vdata, &mesh_dst->vdata, mask.vmask, CD_ASSIGN, mesh_src->totvert); - CustomData_copy(&mesh_src->edata, &mesh_dst->edata, mask.emask, CD_ASSIGN, mesh_src->totedge); - CustomData_copy(&mesh_src->pdata, &mesh_dst->pdata, mask.pmask, CD_ASSIGN, mesh_src->totpoly); - CustomData_copy(&mesh_src->ldata, &mesh_dst->ldata, mask.lmask, CD_ASSIGN, mesh_src->totloop); + CustomData_copy(&mesh_src->vdata, &mesh_dst->vdata, mask.vmask, mesh_src->totvert); + CustomData_copy(&mesh_src->edata, &mesh_dst->edata, mask.emask, mesh_src->totedge); + CustomData_copy(&mesh_src->pdata, &mesh_dst->pdata, mask.pmask, mesh_src->totpoly); + CustomData_copy(&mesh_src->ldata, &mesh_dst->ldata, mask.lmask, mesh_src->totloop); mesh_dst->poly_offset_indices = static_cast(mesh_src->poly_offset_indices); mesh_src->poly_offset_indices = nullptr; diff --git a/source/blender/blenkernel/intern/mesh_legacy_convert.cc b/source/blender/blenkernel/intern/mesh_legacy_convert.cc index dccb8a1d7bc..f1108891caa 100644 --- a/source/blender/blenkernel/intern/mesh_legacy_convert.cc +++ b/source/blender/blenkernel/intern/mesh_legacy_convert.cc @@ -1826,28 +1826,31 @@ void BKE_mesh_legacy_convert_uvs_to_generic(Mesh *mesh) uv_names[i] = new_name; CustomData_add_layer_named_with_data( - &mesh->ldata, CD_PROP_FLOAT2, coords, mesh->totloop, new_name); + &mesh->ldata, CD_PROP_FLOAT2, coords, mesh->totloop, new_name, nullptr); char buffer[MAX_CUSTOMDATA_LAYER_NAME]; if (vert_selection) { CustomData_add_layer_named_with_data(&mesh->ldata, CD_PROP_BOOL, vert_selection, mesh->totloop, - BKE_uv_map_vert_select_name_get(new_name, buffer)); + BKE_uv_map_vert_select_name_get(new_name, buffer), + nullptr); } if (edge_selection) { CustomData_add_layer_named_with_data(&mesh->ldata, CD_PROP_BOOL, edge_selection, mesh->totloop, - BKE_uv_map_edge_select_name_get(new_name, buffer)); + BKE_uv_map_edge_select_name_get(new_name, buffer), + nullptr); } if (pin) { CustomData_add_layer_named_with_data(&mesh->ldata, CD_PROP_BOOL, pin, mesh->totloop, - BKE_uv_map_pin_name_get(new_name, buffer)); + BKE_uv_map_pin_name_get(new_name, buffer), + nullptr); } } @@ -2283,7 +2286,8 @@ void BKE_mesh_legacy_convert_polys_to_offsets(Mesh *mesh) }); CustomData old_poly_data = mesh->pdata; CustomData_reset(&mesh->pdata); - CustomData_copy(&old_poly_data, &mesh->pdata, CD_MASK_MESH.pmask, CD_CONSTRUCT, mesh->totpoly); + CustomData_copy_new( + &old_poly_data, &mesh->pdata, CD_MASK_MESH.pmask, CD_CONSTRUCT, mesh->totpoly); int offset = 0; for (const int i : orig_indices.index_range()) { diff --git a/source/blender/editors/sculpt_paint/sculpt_dyntopo.cc b/source/blender/editors/sculpt_paint/sculpt_dyntopo.cc index cffb6636483..608c8a30374 100644 --- a/source/blender/editors/sculpt_paint/sculpt_dyntopo.cc +++ b/source/blender/editors/sculpt_paint/sculpt_dyntopo.cc @@ -162,14 +162,10 @@ static void SCULPT_dynamic_topology_disable_ex( me->totpoly = geometry->totpoly; me->totedge = geometry->totedge; me->totface = 0; - CustomData_copy( - &geometry->vdata, &me->vdata, CD_MASK_MESH.vmask, CD_DUPLICATE, geometry->totvert); - CustomData_copy( - &geometry->edata, &me->edata, CD_MASK_MESH.emask, CD_DUPLICATE, geometry->totedge); - CustomData_copy( - &geometry->ldata, &me->ldata, CD_MASK_MESH.lmask, CD_DUPLICATE, geometry->totloop); - CustomData_copy( - &geometry->pdata, &me->pdata, CD_MASK_MESH.pmask, CD_DUPLICATE, geometry->totpoly); + CustomData_copy(&geometry->vdata, &me->vdata, CD_MASK_MESH.vmask, geometry->totvert); + CustomData_copy(&geometry->edata, &me->edata, CD_MASK_MESH.emask, geometry->totedge); + CustomData_copy(&geometry->ldata, &me->ldata, CD_MASK_MESH.lmask, geometry->totloop); + CustomData_copy(&geometry->pdata, &me->pdata, CD_MASK_MESH.pmask, geometry->totpoly); me->poly_offset_indices = static_cast(MEM_dupallocN(geometry->poly_offset_indices)); } else { diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.cc b/source/blender/editors/sculpt_paint/sculpt_undo.cc index f2815ff8c39..6e01933cd6b 100644 --- a/source/blender/editors/sculpt_paint/sculpt_undo.cc +++ b/source/blender/editors/sculpt_paint/sculpt_undo.cc @@ -745,10 +745,10 @@ static void sculpt_undo_geometry_store_data(SculptUndoNodeGeometry *geometry, Ob BLI_assert(!geometry->is_initialized); geometry->is_initialized = true; - CustomData_copy(&mesh->vdata, &geometry->vdata, CD_MASK_MESH.vmask, CD_DUPLICATE, mesh->totvert); - CustomData_copy(&mesh->edata, &geometry->edata, CD_MASK_MESH.emask, CD_DUPLICATE, mesh->totedge); - CustomData_copy(&mesh->ldata, &geometry->ldata, CD_MASK_MESH.lmask, CD_DUPLICATE, mesh->totloop); - CustomData_copy(&mesh->pdata, &geometry->pdata, CD_MASK_MESH.pmask, CD_DUPLICATE, mesh->totpoly); + CustomData_copy(&mesh->vdata, &geometry->vdata, CD_MASK_MESH.vmask, mesh->totvert); + CustomData_copy(&mesh->edata, &geometry->edata, CD_MASK_MESH.emask, mesh->totedge); + CustomData_copy(&mesh->ldata, &geometry->ldata, CD_MASK_MESH.lmask, mesh->totloop); + CustomData_copy(&mesh->pdata, &geometry->pdata, CD_MASK_MESH.pmask, mesh->totpoly); geometry->poly_offset_indices = static_cast(MEM_dupallocN(mesh->poly_offset_indices)); geometry->totvert = mesh->totvert; @@ -776,14 +776,10 @@ static void sculpt_undo_geometry_restore_data(SculptUndoNodeGeometry *geometry, mesh->totpoly = geometry->totpoly; mesh->totface = 0; - CustomData_copy( - &geometry->vdata, &mesh->vdata, CD_MASK_MESH.vmask, CD_DUPLICATE, geometry->totvert); - CustomData_copy( - &geometry->edata, &mesh->edata, CD_MASK_MESH.emask, CD_DUPLICATE, geometry->totedge); - CustomData_copy( - &geometry->ldata, &mesh->ldata, CD_MASK_MESH.lmask, CD_DUPLICATE, geometry->totloop); - CustomData_copy( - &geometry->pdata, &mesh->pdata, CD_MASK_MESH.pmask, CD_DUPLICATE, geometry->totpoly); + CustomData_copy(&geometry->vdata, &mesh->vdata, CD_MASK_MESH.vmask, geometry->totvert); + CustomData_copy(&geometry->edata, &mesh->edata, CD_MASK_MESH.emask, geometry->totedge); + CustomData_copy(&geometry->ldata, &mesh->ldata, CD_MASK_MESH.lmask, geometry->totloop); + CustomData_copy(&geometry->pdata, &mesh->pdata, CD_MASK_MESH.pmask, geometry->totpoly); mesh->poly_offset_indices = static_cast(geometry->poly_offset_indices); BKE_mesh_runtime_clear_cache(mesh); -- 2.30.2 From 0b1379f00ac4736660ec2b874dbaf4b5398e5a21 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Fri, 7 Apr 2023 12:21:30 +0200 Subject: [PATCH 10/46] improve naming and comments --- source/blender/blenkernel/BKE_customdata.h | 27 +++++++++------- .../blender/blenkernel/intern/DerivedMesh.cc | 11 ++++--- .../blender/blenkernel/intern/customdata.cc | 24 +++++++------- source/blender/blenkernel/intern/mesh.cc | 11 ++++--- .../blenkernel/intern/mesh_boolean_convert.cc | 8 ++--- .../blenkernel/intern/mesh_legacy_convert.cc | 2 +- .../blender/blenkernel/intern/subdiv_mesh.cc | 20 ++++++------ source/blender/bmesh/intern/bmesh_construct.c | 24 +++++++------- .../bmesh/intern/bmesh_mesh_convert.cc | 32 +++++++++---------- source/blender/editors/mesh/mesh_data.cc | 8 ++--- source/blender/editors/mesh/meshtools.cc | 8 ++--- source/blender/io/collada/MeshImporter.cpp | 2 +- 12 files changed, 91 insertions(+), 86 deletions(-) diff --git a/source/blender/blenkernel/BKE_customdata.h b/source/blender/blenkernel/BKE_customdata.h index fca2e77667f..0e87c3050d6 100644 --- a/source/blender/blenkernel/BKE_customdata.h +++ b/source/blender/blenkernel/BKE_customdata.h @@ -167,28 +167,31 @@ void CustomData_copy(const struct CustomData *source, * Initializes a CustomData object with the same layers as source. The data is not copied from the * source. Instead, the new layers are initialized using the given `alloctype`. */ -void CustomData_copy_new(const struct CustomData *source, - struct CustomData *dest, - eCustomDataMask mask, - eCDAllocType alloctype, - int totelem); +void CustomData_copy_layout(const struct CustomData *source, + struct CustomData *dest, + eCustomDataMask mask, + eCDAllocType alloctype, + int totelem); /* BMESH_TODO, not really a public function but readfile.c needs it */ void CustomData_update_typemap(struct CustomData *data); /** - * Same as the above, except that this will preserve existing layers, and only - * add the layers that were not there yet. + * Copies all layers from source to destination that don't exist there yet. */ bool CustomData_merge(const struct CustomData *source, struct CustomData *dest, eCustomDataMask mask, int totelem); -bool CustomData_merge_new(const struct CustomData *source, - struct CustomData *dest, - eCustomDataMask mask, - eCDAllocType alloctype, - int totelem); +/** + * Copies all layers from source to destination that don't exist there yet. The layer data is not + * copied. Instead the newly created layers are initialized using the given `alloctype`. + */ +bool CustomData_merge_layout(const struct CustomData *source, + struct CustomData *dest, + eCustomDataMask mask, + eCDAllocType alloctype, + int totelem); /** * Reallocate custom data to a new element count. If the new size is larger, the new values use diff --git a/source/blender/blenkernel/intern/DerivedMesh.cc b/source/blender/blenkernel/intern/DerivedMesh.cc index 3048905dc80..4085f064a31 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.cc +++ b/source/blender/blenkernel/intern/DerivedMesh.cc @@ -207,11 +207,12 @@ void DM_from_template(DerivedMesh *dm, int numPolys) { const CustomData_MeshMasks *mask = &CD_MASK_DERIVEDMESH; - CustomData_copy_new(&source->vertData, &dm->vertData, mask->vmask, CD_SET_DEFAULT, numVerts); - CustomData_copy_new(&source->edgeData, &dm->edgeData, mask->emask, CD_SET_DEFAULT, numEdges); - CustomData_copy_new(&source->faceData, &dm->faceData, mask->fmask, CD_SET_DEFAULT, numTessFaces); - CustomData_copy_new(&source->loopData, &dm->loopData, mask->lmask, CD_SET_DEFAULT, numLoops); - CustomData_copy_new(&source->polyData, &dm->polyData, mask->pmask, CD_SET_DEFAULT, numPolys); + CustomData_copy_layout(&source->vertData, &dm->vertData, mask->vmask, CD_SET_DEFAULT, numVerts); + CustomData_copy_layout(&source->edgeData, &dm->edgeData, mask->emask, CD_SET_DEFAULT, numEdges); + CustomData_copy_layout( + &source->faceData, &dm->faceData, mask->fmask, CD_SET_DEFAULT, numTessFaces); + CustomData_copy_layout(&source->loopData, &dm->loopData, mask->lmask, CD_SET_DEFAULT, numLoops); + CustomData_copy_layout(&source->polyData, &dm->polyData, mask->pmask, CD_SET_DEFAULT, numPolys); dm->poly_offsets = static_cast(MEM_dupallocN(source->poly_offsets)); dm->type = type; diff --git a/source/blender/blenkernel/intern/customdata.cc b/source/blender/blenkernel/intern/customdata.cc index 914b6fd561e..55e364f1f50 100644 --- a/source/blender/blenkernel/intern/customdata.cc +++ b/source/blender/blenkernel/intern/customdata.cc @@ -2317,11 +2317,11 @@ bool CustomData_merge(const CustomData *source, return customdata_merge_internal(source, dest, mask, CD_ASSIGN, totelem); } -bool CustomData_merge_new(const CustomData *source, - CustomData *dest, - const eCustomDataMask mask, - const eCDAllocType alloctype, - const int totelem) +bool CustomData_merge_layout(const CustomData *source, + CustomData *dest, + const eCustomDataMask mask, + const eCDAllocType alloctype, + const int totelem) { return customdata_merge_internal(source, dest, mask, alloctype, totelem); } @@ -2454,11 +2454,11 @@ void CustomData_copy(const CustomData *source, CustomData *dest, eCustomDataMask CustomData_merge(source, dest, mask, totelem); } -void CustomData_copy_new(const struct CustomData *source, - struct CustomData *dest, - eCustomDataMask mask, - eCDAllocType alloctype, - int totelem) +void CustomData_copy_layout(const struct CustomData *source, + struct CustomData *dest, + eCustomDataMask mask, + eCDAllocType alloctype, + int totelem) { CustomData_reset(dest); @@ -2466,7 +2466,7 @@ void CustomData_copy_new(const struct CustomData *source, dest->external = static_cast(MEM_dupallocN(source->external)); } - CustomData_merge_new(source, dest, mask, alloctype, totelem); + CustomData_merge_layout(source, dest, mask, alloctype, totelem); } static void customData_free_layer__internal(CustomDataLayer *layer, const int totelem) @@ -3717,7 +3717,7 @@ bool CustomData_bmesh_merge_new(const CustomData *source, destold.layers = static_cast(MEM_dupallocN(destold.layers)); } - if (CustomData_merge_new(source, dest, mask, alloctype, 0) == false) { + if (CustomData_merge_layout(source, dest, mask, alloctype, 0) == false) { if (destold.layers) { MEM_freeN(destold.layers); } diff --git a/source/blender/blenkernel/intern/mesh.cc b/source/blender/blenkernel/intern/mesh.cc index 8afd805096e..89523660587 100644 --- a/source/blender/blenkernel/intern/mesh.cc +++ b/source/blender/blenkernel/intern/mesh.cc @@ -1095,12 +1095,13 @@ Mesh *BKE_mesh_new_nomain_from_template_ex(const Mesh *me_src, BKE_mesh_copy_parameters_for_eval(me_dst, me_src); - CustomData_copy_new(&me_src->vdata, &me_dst->vdata, mask.vmask, CD_SET_DEFAULT, verts_len); - CustomData_copy_new(&me_src->edata, &me_dst->edata, mask.emask, CD_SET_DEFAULT, edges_len); - CustomData_copy_new(&me_src->ldata, &me_dst->ldata, mask.lmask, CD_SET_DEFAULT, loops_len); - CustomData_copy_new(&me_src->pdata, &me_dst->pdata, mask.pmask, CD_SET_DEFAULT, polys_len); + CustomData_copy_layout(&me_src->vdata, &me_dst->vdata, mask.vmask, CD_SET_DEFAULT, verts_len); + CustomData_copy_layout(&me_src->edata, &me_dst->edata, mask.emask, CD_SET_DEFAULT, edges_len); + CustomData_copy_layout(&me_src->ldata, &me_dst->ldata, mask.lmask, CD_SET_DEFAULT, loops_len); + CustomData_copy_layout(&me_src->pdata, &me_dst->pdata, mask.pmask, CD_SET_DEFAULT, polys_len); if (do_tessface) { - CustomData_copy_new(&me_src->fdata, &me_dst->fdata, mask.fmask, CD_SET_DEFAULT, tessface_len); + CustomData_copy_layout( + &me_src->fdata, &me_dst->fdata, mask.fmask, CD_SET_DEFAULT, tessface_len); } else { mesh_tessface_clear_intern(me_dst, false); diff --git a/source/blender/blenkernel/intern/mesh_boolean_convert.cc b/source/blender/blenkernel/intern/mesh_boolean_convert.cc index d79490a22b8..42890c3e04b 100644 --- a/source/blender/blenkernel/intern/mesh_boolean_convert.cc +++ b/source/blender/blenkernel/intern/mesh_boolean_convert.cc @@ -656,15 +656,15 @@ static void merge_vertex_loop_poly_customdata_layers(Mesh *target, MeshesToIMesh for (int mesh_index = 1; mesh_index < mim.meshes.size(); ++mesh_index) { const Mesh *me = mim.meshes[mesh_index]; if (me->totvert) { - CustomData_merge_new( + CustomData_merge_layout( &me->vdata, &target->vdata, CD_MASK_MESH.vmask, CD_SET_DEFAULT, target->totvert); } if (me->totloop) { - CustomData_merge_new( + CustomData_merge_layout( &me->ldata, &target->ldata, CD_MASK_MESH.lmask, CD_SET_DEFAULT, target->totloop); } if (me->totpoly) { - CustomData_merge_new( + CustomData_merge_layout( &me->pdata, &target->pdata, CD_MASK_MESH.pmask, CD_SET_DEFAULT, target->totpoly); } } @@ -675,7 +675,7 @@ static void merge_edge_customdata_layers(Mesh *target, MeshesToIMeshInfo &mim) for (int mesh_index = 0; mesh_index < mim.meshes.size(); ++mesh_index) { const Mesh *me = mim.meshes[mesh_index]; if (me->totedge) { - CustomData_merge_new( + CustomData_merge_layout( &me->edata, &target->edata, CD_MASK_MESH.emask, CD_SET_DEFAULT, target->totedge); } } diff --git a/source/blender/blenkernel/intern/mesh_legacy_convert.cc b/source/blender/blenkernel/intern/mesh_legacy_convert.cc index f1108891caa..8dcac9e0ae4 100644 --- a/source/blender/blenkernel/intern/mesh_legacy_convert.cc +++ b/source/blender/blenkernel/intern/mesh_legacy_convert.cc @@ -2286,7 +2286,7 @@ void BKE_mesh_legacy_convert_polys_to_offsets(Mesh *mesh) }); CustomData old_poly_data = mesh->pdata; CustomData_reset(&mesh->pdata); - CustomData_copy_new( + CustomData_copy_layout( &old_poly_data, &mesh->pdata, CD_MASK_MESH.pmask, CD_CONSTRUCT, mesh->totpoly); int offset = 0; diff --git a/source/blender/blenkernel/intern/subdiv_mesh.cc b/source/blender/blenkernel/intern/subdiv_mesh.cc index 730ae41b781..71ea31ba13b 100644 --- a/source/blender/blenkernel/intern/subdiv_mesh.cc +++ b/source/blender/blenkernel/intern/subdiv_mesh.cc @@ -220,11 +220,11 @@ static void vertex_interpolation_init(const SubdivMeshContext *ctx, else { vertex_interpolation->vertex_data = &vertex_interpolation->vertex_data_storage; /* Allocate storage for loops corresponding to ptex corners. */ - CustomData_copy_new(&ctx->coarse_mesh->vdata, - &vertex_interpolation->vertex_data_storage, - CD_MASK_EVERYTHING.vmask, - CD_SET_DEFAULT, - 4); + CustomData_copy_layout(&ctx->coarse_mesh->vdata, + &vertex_interpolation->vertex_data_storage, + CD_MASK_EVERYTHING.vmask, + CD_SET_DEFAULT, + 4); /* Initialize indices. */ vertex_interpolation->vertex_indices[0] = 0; vertex_interpolation->vertex_indices[1] = 1; @@ -350,11 +350,11 @@ static void loop_interpolation_init(const SubdivMeshContext *ctx, else { loop_interpolation->loop_data = &loop_interpolation->loop_data_storage; /* Allocate storage for loops corresponding to ptex corners. */ - CustomData_copy_new(&ctx->coarse_mesh->ldata, - &loop_interpolation->loop_data_storage, - CD_MASK_EVERYTHING.lmask, - CD_SET_DEFAULT, - 4); + CustomData_copy_layout(&ctx->coarse_mesh->ldata, + &loop_interpolation->loop_data_storage, + CD_MASK_EVERYTHING.lmask, + CD_SET_DEFAULT, + 4); /* Initialize indices. */ loop_interpolation->loop_indices[0] = 0; loop_interpolation->loop_indices[1] = 1; diff --git a/source/blender/bmesh/intern/bmesh_construct.c b/source/blender/bmesh/intern/bmesh_construct.c index 6e1c43e6690..a62258e94ab 100644 --- a/source/blender/bmesh/intern/bmesh_construct.c +++ b/source/blender/bmesh/intern/bmesh_construct.c @@ -517,16 +517,16 @@ void BM_mesh_copy_init_customdata_from_mesh_array(BMesh *bm_dst, &me_src->ldata, CD_MASK_BMESH.pmask); if (i == 0) { - CustomData_copy_new(&mesh_vdata, &bm_dst->vdata, CD_MASK_BMESH.vmask, CD_SET_DEFAULT, 0); - CustomData_copy_new(&mesh_edata, &bm_dst->edata, CD_MASK_BMESH.emask, CD_SET_DEFAULT, 0); - CustomData_copy_new(&mesh_pdata, &bm_dst->pdata, CD_MASK_BMESH.pmask, CD_SET_DEFAULT, 0); - CustomData_copy_new(&mesh_ldata, &bm_dst->ldata, CD_MASK_BMESH.lmask, CD_SET_DEFAULT, 0); + CustomData_copy_layout(&mesh_vdata, &bm_dst->vdata, CD_MASK_BMESH.vmask, CD_SET_DEFAULT, 0); + CustomData_copy_layout(&mesh_edata, &bm_dst->edata, CD_MASK_BMESH.emask, CD_SET_DEFAULT, 0); + CustomData_copy_layout(&mesh_pdata, &bm_dst->pdata, CD_MASK_BMESH.pmask, CD_SET_DEFAULT, 0); + CustomData_copy_layout(&mesh_ldata, &bm_dst->ldata, CD_MASK_BMESH.lmask, CD_SET_DEFAULT, 0); } else { - CustomData_merge_new(&mesh_vdata, &bm_dst->vdata, CD_MASK_BMESH.vmask, CD_SET_DEFAULT, 0); - CustomData_merge_new(&mesh_edata, &bm_dst->edata, CD_MASK_BMESH.emask, CD_SET_DEFAULT, 0); - CustomData_merge_new(&mesh_pdata, &bm_dst->pdata, CD_MASK_BMESH.pmask, CD_SET_DEFAULT, 0); - CustomData_merge_new(&mesh_ldata, &bm_dst->ldata, CD_MASK_BMESH.lmask, CD_SET_DEFAULT, 0); + CustomData_merge_layout(&mesh_vdata, &bm_dst->vdata, CD_MASK_BMESH.vmask, CD_SET_DEFAULT, 0); + CustomData_merge_layout(&mesh_edata, &bm_dst->edata, CD_MASK_BMESH.emask, CD_SET_DEFAULT, 0); + CustomData_merge_layout(&mesh_pdata, &bm_dst->pdata, CD_MASK_BMESH.pmask, CD_SET_DEFAULT, 0); + CustomData_merge_layout(&mesh_ldata, &bm_dst->ldata, CD_MASK_BMESH.lmask, CD_SET_DEFAULT, 0); } MEM_SAFE_FREE(mesh_vdata.layers); @@ -554,10 +554,10 @@ void BM_mesh_copy_init_customdata(BMesh *bm_dst, BMesh *bm_src, const BMAllocTem allocsize = &bm_mesh_allocsize_default; } - CustomData_copy_new(&bm_src->vdata, &bm_dst->vdata, CD_MASK_BMESH.vmask, CD_SET_DEFAULT, 0); - CustomData_copy_new(&bm_src->edata, &bm_dst->edata, CD_MASK_BMESH.emask, CD_SET_DEFAULT, 0); - CustomData_copy_new(&bm_src->ldata, &bm_dst->ldata, CD_MASK_BMESH.lmask, CD_SET_DEFAULT, 0); - CustomData_copy_new(&bm_src->pdata, &bm_dst->pdata, CD_MASK_BMESH.pmask, CD_SET_DEFAULT, 0); + CustomData_copy_layout(&bm_src->vdata, &bm_dst->vdata, CD_MASK_BMESH.vmask, CD_SET_DEFAULT, 0); + CustomData_copy_layout(&bm_src->edata, &bm_dst->edata, CD_MASK_BMESH.emask, CD_SET_DEFAULT, 0); + CustomData_copy_layout(&bm_src->ldata, &bm_dst->ldata, CD_MASK_BMESH.lmask, CD_SET_DEFAULT, 0); + CustomData_copy_layout(&bm_src->pdata, &bm_dst->pdata, CD_MASK_BMESH.pmask, CD_SET_DEFAULT, 0); CustomData_bmesh_init_pool(&bm_dst->vdata, allocsize->totvert, BM_VERT); CustomData_bmesh_init_pool(&bm_dst->edata, allocsize->totedge, BM_EDGE); diff --git a/source/blender/bmesh/intern/bmesh_mesh_convert.cc b/source/blender/bmesh/intern/bmesh_mesh_convert.cc index 2d31f4996dc..123dd089289 100644 --- a/source/blender/bmesh/intern/bmesh_mesh_convert.cc +++ b/source/blender/bmesh/intern/bmesh_mesh_convert.cc @@ -268,10 +268,10 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar if (me->totvert == 0) { if (is_new) { /* No verts? still copy custom-data layout. */ - CustomData_copy_new(&mesh_vdata, &bm->vdata, mask.vmask, CD_CONSTRUCT, 0); - CustomData_copy_new(&mesh_edata, &bm->edata, mask.emask, CD_CONSTRUCT, 0); - CustomData_copy_new(&mesh_pdata, &bm->pdata, mask.pmask, CD_CONSTRUCT, 0); - CustomData_copy_new(&mesh_ldata, &bm->ldata, mask.lmask, CD_CONSTRUCT, 0); + CustomData_copy_layout(&mesh_vdata, &bm->vdata, mask.vmask, CD_CONSTRUCT, 0); + CustomData_copy_layout(&mesh_edata, &bm->edata, mask.emask, CD_CONSTRUCT, 0); + CustomData_copy_layout(&mesh_pdata, &bm->pdata, mask.pmask, CD_CONSTRUCT, 0); + CustomData_copy_layout(&mesh_ldata, &bm->ldata, mask.lmask, CD_CONSTRUCT, 0); CustomData_bmesh_init_pool(&bm->vdata, me->totvert, BM_VERT); CustomData_bmesh_init_pool(&bm->edata, me->totedge, BM_EDGE); @@ -287,10 +287,10 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar } if (is_new) { - CustomData_copy_new(&mesh_vdata, &bm->vdata, mask.vmask, CD_SET_DEFAULT, 0); - CustomData_copy_new(&mesh_edata, &bm->edata, mask.emask, CD_SET_DEFAULT, 0); - CustomData_copy_new(&mesh_pdata, &bm->pdata, mask.pmask, CD_SET_DEFAULT, 0); - CustomData_copy_new(&mesh_ldata, &bm->ldata, mask.lmask, CD_SET_DEFAULT, 0); + CustomData_copy_layout(&mesh_vdata, &bm->vdata, mask.vmask, CD_SET_DEFAULT, 0); + CustomData_copy_layout(&mesh_edata, &bm->edata, mask.emask, CD_SET_DEFAULT, 0); + CustomData_copy_layout(&mesh_pdata, &bm->pdata, mask.pmask, CD_SET_DEFAULT, 0); + CustomData_copy_layout(&mesh_ldata, &bm->ldata, mask.lmask, CD_SET_DEFAULT, 0); } else { CustomData_bmesh_merge_new(&mesh_vdata, &bm->vdata, mask.vmask, CD_SET_DEFAULT, bm, BM_VERT); @@ -1400,10 +1400,10 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh { CustomData_MeshMasks mask = CD_MASK_MESH; CustomData_MeshMasks_update(&mask, ¶ms->cd_mask_extra); - CustomData_copy_new(&bm->vdata, &me->vdata, mask.vmask, CD_SET_DEFAULT, me->totvert); - CustomData_copy_new(&bm->edata, &me->edata, mask.emask, CD_SET_DEFAULT, me->totedge); - CustomData_copy_new(&bm->ldata, &me->ldata, mask.lmask, CD_SET_DEFAULT, me->totloop); - CustomData_copy_new(&bm->pdata, &me->pdata, mask.pmask, CD_SET_DEFAULT, me->totpoly); + CustomData_copy_layout(&bm->vdata, &me->vdata, mask.vmask, CD_SET_DEFAULT, me->totvert); + CustomData_copy_layout(&bm->edata, &me->edata, mask.emask, CD_SET_DEFAULT, me->totedge); + CustomData_copy_layout(&bm->ldata, &me->ldata, mask.lmask, CD_SET_DEFAULT, me->totloop); + CustomData_copy_layout(&bm->pdata, &me->pdata, mask.pmask, CD_SET_DEFAULT, me->totpoly); } bool need_select_vert = false; @@ -1615,10 +1615,10 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks * CustomData_MeshMasks_update(&mask, cd_mask_extra); } mask.vmask &= ~CD_MASK_SHAPEKEY; - CustomData_merge_new(&bm->vdata, &me->vdata, mask.vmask, CD_CONSTRUCT, me->totvert); - CustomData_merge_new(&bm->edata, &me->edata, mask.emask, CD_CONSTRUCT, me->totedge); - CustomData_merge_new(&bm->ldata, &me->ldata, mask.lmask, CD_CONSTRUCT, me->totloop); - CustomData_merge_new(&bm->pdata, &me->pdata, mask.pmask, CD_CONSTRUCT, me->totpoly); + CustomData_merge_layout(&bm->vdata, &me->vdata, mask.vmask, CD_CONSTRUCT, me->totvert); + CustomData_merge_layout(&bm->edata, &me->edata, mask.emask, CD_CONSTRUCT, me->totedge); + CustomData_merge_layout(&bm->ldata, &me->ldata, mask.lmask, CD_CONSTRUCT, me->totloop); + CustomData_merge_layout(&bm->pdata, &me->pdata, mask.pmask, CD_CONSTRUCT, me->totpoly); me->runtime->deformed_only = true; diff --git a/source/blender/editors/mesh/mesh_data.cc b/source/blender/editors/mesh/mesh_data.cc index 83e3a43634d..ce417294187 100644 --- a/source/blender/editors/mesh/mesh_data.cc +++ b/source/blender/editors/mesh/mesh_data.cc @@ -1144,7 +1144,7 @@ static void mesh_add_verts(Mesh *mesh, int len) int totvert = mesh->totvert + len; CustomData vdata; - CustomData_copy_new(&mesh->vdata, &vdata, CD_MASK_MESH.vmask, CD_SET_DEFAULT, totvert); + CustomData_copy_layout(&mesh->vdata, &vdata, CD_MASK_MESH.vmask, CD_SET_DEFAULT, totvert); CustomData_copy_data(&mesh->vdata, &vdata, 0, 0, mesh->totvert); if (!CustomData_get_layer_named(&vdata, CD_PROP_FLOAT3, "position")) { @@ -1178,7 +1178,7 @@ static void mesh_add_edges(Mesh *mesh, int len) totedge = mesh->totedge + len; /* Update custom-data. */ - CustomData_copy_new(&mesh->edata, &edata, CD_MASK_MESH.emask, CD_SET_DEFAULT, totedge); + CustomData_copy_layout(&mesh->edata, &edata, CD_MASK_MESH.emask, CD_SET_DEFAULT, totedge); CustomData_copy_data(&mesh->edata, &edata, 0, 0, mesh->totedge); if (!CustomData_has_layer(&edata, CD_MEDGE)) { @@ -1211,7 +1211,7 @@ static void mesh_add_loops(Mesh *mesh, int len) totloop = mesh->totloop + len; /* new face count */ /* update customdata */ - CustomData_copy_new(&mesh->ldata, &ldata, CD_MASK_MESH.lmask, CD_SET_DEFAULT, totloop); + CustomData_copy_layout(&mesh->ldata, &ldata, CD_MASK_MESH.lmask, CD_SET_DEFAULT, totloop); CustomData_copy_data(&mesh->ldata, &ldata, 0, 0, mesh->totloop); if (!CustomData_get_layer_named(&ldata, CD_PROP_INT32, ".corner_vert")) { @@ -1248,7 +1248,7 @@ static void mesh_add_polys(Mesh *mesh, int len) totpoly = mesh->totpoly + len; /* new face count */ /* update customdata */ - CustomData_copy_new(&mesh->pdata, &pdata, CD_MASK_MESH.pmask, CD_SET_DEFAULT, totpoly); + CustomData_copy_layout(&mesh->pdata, &pdata, CD_MASK_MESH.pmask, CD_SET_DEFAULT, totpoly); CustomData_copy_data(&mesh->pdata, &pdata, 0, 0, mesh->totpoly); mesh->poly_offset_indices = static_cast( diff --git a/source/blender/editors/mesh/meshtools.cc b/source/blender/editors/mesh/meshtools.cc index 5a0b1a40755..791381de1c7 100644 --- a/source/blender/editors/mesh/meshtools.cc +++ b/source/blender/editors/mesh/meshtools.cc @@ -105,7 +105,7 @@ static void join_mesh_single(Depsgraph *depsgraph, if (me->totvert) { /* standard data */ - CustomData_merge_new(&me->vdata, vdata, CD_MASK_MESH.vmask, CD_SET_DEFAULT, totvert); + CustomData_merge_layout(&me->vdata, vdata, CD_MASK_MESH.vmask, CD_SET_DEFAULT, totvert); CustomData_copy_data_named(&me->vdata, vdata, 0, *vertofs, me->totvert); /* vertex groups */ @@ -205,7 +205,7 @@ static void join_mesh_single(Depsgraph *depsgraph, } if (me->totedge) { - CustomData_merge_new(&me->edata, edata, CD_MASK_MESH.emask, CD_SET_DEFAULT, totedge); + CustomData_merge_layout(&me->edata, edata, CD_MASK_MESH.emask, CD_SET_DEFAULT, totedge); CustomData_copy_data_named(&me->edata, edata, 0, *edgeofs, me->totedge); for (a = 0; a < me->totedge; a++, edge++) { @@ -226,7 +226,7 @@ static void join_mesh_single(Depsgraph *depsgraph, } } - CustomData_merge_new(&me->ldata, ldata, CD_MASK_MESH.lmask, CD_SET_DEFAULT, totloop); + CustomData_merge_layout(&me->ldata, ldata, CD_MASK_MESH.lmask, CD_SET_DEFAULT, totloop); CustomData_copy_data_named(&me->ldata, ldata, 0, *loopofs, me->totloop); for (a = 0; a < me->totloop; a++) { @@ -250,7 +250,7 @@ static void join_mesh_single(Depsgraph *depsgraph, } } - CustomData_merge_new(&me->pdata, pdata, CD_MASK_MESH.pmask, CD_SET_DEFAULT, totpoly); + CustomData_merge_layout(&me->pdata, pdata, CD_MASK_MESH.pmask, CD_SET_DEFAULT, totpoly); CustomData_copy_data_named(&me->pdata, pdata, 0, *polyofs, me->totpoly); /* Apply matmap. In case we don't have material indices yet, create them if more than one diff --git a/source/blender/io/collada/MeshImporter.cpp b/source/blender/io/collada/MeshImporter.cpp index 2e41adf0333..1efdb3926d3 100644 --- a/source/blender/io/collada/MeshImporter.cpp +++ b/source/blender/io/collada/MeshImporter.cpp @@ -550,7 +550,7 @@ void MeshImporter::mesh_add_edges(Mesh *mesh, int len) totedge = mesh->totedge + len; /* Update custom-data. */ - CustomData_copy_new(&mesh->edata, &edata, CD_MASK_MESH.emask, CD_SET_DEFAULT, totedge); + CustomData_copy_layout(&mesh->edata, &edata, CD_MASK_MESH.emask, CD_SET_DEFAULT, totedge); CustomData_copy_data(&mesh->edata, &edata, 0, 0, mesh->totedge); if (!CustomData_has_layer(&edata, CD_MEDGE)) { -- 2.30.2 From 2fae2036ba99bf5b7bdb1441f3dc3106aaf274dd Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Fri, 7 Apr 2023 12:38:21 +0200 Subject: [PATCH 11/46] remove CD_ASSIGN --- source/blender/blenkernel/BKE_customdata.h | 2 - .../blender/blenkernel/intern/customdata.cc | 73 ++++++++++--------- 2 files changed, 37 insertions(+), 38 deletions(-) diff --git a/source/blender/blenkernel/BKE_customdata.h b/source/blender/blenkernel/BKE_customdata.h index 0e87c3050d6..7fe954de57b 100644 --- a/source/blender/blenkernel/BKE_customdata.h +++ b/source/blender/blenkernel/BKE_customdata.h @@ -75,8 +75,6 @@ extern const CustomData_MeshMasks CD_MASK_EVERYTHING; /** Add/copy/merge allocation types. */ typedef enum eCDAllocType { - /** Use the data pointer. This is only used internally. */ - CD_ASSIGN = 0, /** Allocate and set to default, which is usually just zeroed memory. */ CD_SET_DEFAULT = 2, /** diff --git a/source/blender/blenkernel/intern/customdata.cc b/source/blender/blenkernel/intern/customdata.cc index 55e364f1f50..c328422eabc 100644 --- a/source/blender/blenkernel/intern/customdata.cc +++ b/source/blender/blenkernel/intern/customdata.cc @@ -2162,7 +2162,7 @@ static void customData_update_offsets(CustomData *data); static CustomDataLayer *customData_add_layer__internal( CustomData *data, eCustomDataType type, - eCDAllocType alloctype, + std::optional alloctype, void *layer_data_to_assign, const ImplicitSharingInfo *sharing_info_to_assign, int totelem, @@ -2218,7 +2218,7 @@ static void free_layer_data(const eCustomDataType type, const void *data, const static bool customdata_merge_internal(const CustomData *source, CustomData *dest, const eCustomDataMask mask, - const eCDAllocType alloctype, + const std::optional alloctype, const int totelem) { bool changed = false; @@ -2269,7 +2269,7 @@ static bool customdata_merge_internal(const CustomData *source, void *layer_data_to_assign = nullptr; const ImplicitSharingInfo *sharing_info_to_assign = nullptr; - if (alloctype == CD_ASSIGN) { + if (!alloctype.has_value()) { if (src_layer.data != nullptr) { if (src_layer.sharing_info == nullptr) { /* Can't share the layer, duplicate it instead. */ @@ -2314,7 +2314,7 @@ bool CustomData_merge(const CustomData *source, eCustomDataMask mask, int totelem) { - return customdata_merge_internal(source, dest, mask, CD_ASSIGN, totelem); + return customdata_merge_internal(source, dest, mask, std::nullopt, totelem); } bool CustomData_merge_layout(const CustomData *source, @@ -2847,7 +2847,7 @@ static void customData_resize(CustomData *data, const int grow_amount) static CustomDataLayer *customData_add_layer__internal( CustomData *data, const eCustomDataType type, - const eCDAllocType alloctype, + const std::optional alloctype, void *layer_data_to_assign, const ImplicitSharingInfo *sharing_info_to_assign, const int totelem, @@ -2883,40 +2883,41 @@ static CustomDataLayer *customData_add_layer__internal( * leaks into the new layer. */ memset(&new_layer, 0, sizeof(CustomDataLayer)); - switch (alloctype) { - case CD_SET_DEFAULT: { - if (totelem > 0) { - if (type_info.set_default_value) { + if (alloctype.has_value()) { + switch (*alloctype) { + case CD_SET_DEFAULT: { + if (totelem > 0) { + if (type_info.set_default_value) { + new_layer.data = MEM_malloc_arrayN(totelem, type_info.size, layerType_getName(type)); + type_info.set_default_value(new_layer.data, totelem); + } + else { + new_layer.data = MEM_calloc_arrayN(totelem, type_info.size, layerType_getName(type)); + } + } + break; + } + case CD_CONSTRUCT: { + if (totelem > 0) { new_layer.data = MEM_malloc_arrayN(totelem, type_info.size, layerType_getName(type)); - type_info.set_default_value(new_layer.data, totelem); - } - else { - new_layer.data = MEM_calloc_arrayN(totelem, type_info.size, layerType_getName(type)); + if (type_info.construct) { + type_info.construct(new_layer.data, totelem); + } } + break; } - break; } - case CD_CONSTRUCT: { - if (totelem > 0) { - new_layer.data = MEM_malloc_arrayN(totelem, type_info.size, layerType_getName(type)); - if (type_info.construct) { - type_info.construct(new_layer.data, totelem); - } - } - break; + } + else { + if (totelem == 0 && sharing_info_to_assign == nullptr) { + MEM_SAFE_FREE(layer_data_to_assign); } - case CD_ASSIGN: { - if (totelem == 0 && sharing_info_to_assign == nullptr) { - MEM_SAFE_FREE(layer_data_to_assign); + else { + new_layer.data = layer_data_to_assign; + new_layer.sharing_info = sharing_info_to_assign; + if (new_layer.sharing_info) { + new_layer.sharing_info->add_user(); } - else { - new_layer.data = layer_data_to_assign; - new_layer.sharing_info = sharing_info_to_assign; - if (new_layer.sharing_info) { - new_layer.sharing_info->add_user(); - } - } - break; } } @@ -2988,7 +2989,7 @@ const void *CustomData_add_layer_with_data(CustomData *data, const LayerTypeInfo *typeInfo = layerType_getInfo(type); CustomDataLayer *layer = customData_add_layer__internal( - data, type, CD_ASSIGN, layer_data, cow, totelem, typeInfo->defaultname); + data, type, std::nullopt, layer_data, cow, totelem, typeInfo->defaultname); CustomData_update_typemap(data); if (layer) { @@ -3022,7 +3023,7 @@ const void *CustomData_add_layer_named_with_data(CustomData *data, const ImplicitSharingInfo *cow) { CustomDataLayer *layer = customData_add_layer__internal( - data, type, CD_ASSIGN, layer_data, cow, totelem, name); + data, type, std::nullopt, layer_data, cow, totelem, name); CustomData_update_typemap(data); if (layer) { @@ -3061,7 +3062,7 @@ const void *CustomData_add_layer_anonymous_with_data( { const char *name = anonymous_id->name().c_str(); CustomDataLayer *layer = customData_add_layer__internal( - data, type, CD_ASSIGN, layer_data, cow, totelem, name); + data, type, std::nullopt, layer_data, cow, totelem, name); CustomData_update_typemap(data); if (layer == nullptr) { -- 2.30.2 From 3f17b7bebb5426dab8deb217b3888902ba28eb81 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Fri, 7 Apr 2023 13:58:59 +0200 Subject: [PATCH 12/46] cleanup naming --- source/blender/blenkernel/BKE_customdata.h | 14 +++++++------- source/blender/blenkernel/intern/customdata.cc | 12 ++++++------ source/blender/bmesh/intern/bmesh_mesh_convert.cc | 12 ++++++++---- 3 files changed, 21 insertions(+), 17 deletions(-) diff --git a/source/blender/blenkernel/BKE_customdata.h b/source/blender/blenkernel/BKE_customdata.h index 7fe954de57b..cc7b53a2cac 100644 --- a/source/blender/blenkernel/BKE_customdata.h +++ b/source/blender/blenkernel/BKE_customdata.h @@ -199,16 +199,16 @@ bool CustomData_merge_layout(const struct CustomData *source, void CustomData_realloc(struct CustomData *data, int old_size, int new_size); /** - * BMesh version of CustomData_merge; merges the layouts of source and `dest`, + * BMesh version of CustomData_merge_layout; merges the layouts of source and `dest`, * then goes through the mesh and makes sure all the custom-data blocks are * consistent with the new layout. */ -bool CustomData_bmesh_merge_new(const struct CustomData *source, - struct CustomData *dest, - eCustomDataMask mask, - eCDAllocType alloctype, - struct BMesh *bm, - char htype); +bool CustomData_bmesh_merge_layout(const struct CustomData *source, + struct CustomData *dest, + eCustomDataMask mask, + eCDAllocType alloctype, + struct BMesh *bm, + char htype); /** * Remove layers that aren't stored in BMesh or are stored as flags on BMesh. diff --git a/source/blender/blenkernel/intern/customdata.cc b/source/blender/blenkernel/intern/customdata.cc index c328422eabc..4e3a53870ec 100644 --- a/source/blender/blenkernel/intern/customdata.cc +++ b/source/blender/blenkernel/intern/customdata.cc @@ -3699,12 +3699,12 @@ void CustomData_bmesh_init_pool(CustomData *data, const int totelem, const char } } -bool CustomData_bmesh_merge_new(const CustomData *source, - CustomData *dest, - eCustomDataMask mask, - eCDAllocType alloctype, - BMesh *bm, - const char htype) +bool CustomData_bmesh_merge_layout(const CustomData *source, + CustomData *dest, + eCustomDataMask mask, + eCDAllocType alloctype, + BMesh *bm, + const char htype) { if (CustomData_number_of_layers_typemask(source, mask) == 0) { diff --git a/source/blender/bmesh/intern/bmesh_mesh_convert.cc b/source/blender/bmesh/intern/bmesh_mesh_convert.cc index 123dd089289..634302e156e 100644 --- a/source/blender/bmesh/intern/bmesh_mesh_convert.cc +++ b/source/blender/bmesh/intern/bmesh_mesh_convert.cc @@ -293,10 +293,14 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar CustomData_copy_layout(&mesh_ldata, &bm->ldata, mask.lmask, CD_SET_DEFAULT, 0); } else { - CustomData_bmesh_merge_new(&mesh_vdata, &bm->vdata, mask.vmask, CD_SET_DEFAULT, bm, BM_VERT); - CustomData_bmesh_merge_new(&mesh_edata, &bm->edata, mask.emask, CD_SET_DEFAULT, bm, BM_EDGE); - CustomData_bmesh_merge_new(&mesh_pdata, &bm->pdata, mask.pmask, CD_SET_DEFAULT, bm, BM_FACE); - CustomData_bmesh_merge_new(&mesh_ldata, &bm->ldata, mask.lmask, CD_SET_DEFAULT, bm, BM_LOOP); + CustomData_bmesh_merge_layout( + &mesh_vdata, &bm->vdata, mask.vmask, CD_SET_DEFAULT, bm, BM_VERT); + CustomData_bmesh_merge_layout( + &mesh_edata, &bm->edata, mask.emask, CD_SET_DEFAULT, bm, BM_EDGE); + CustomData_bmesh_merge_layout( + &mesh_pdata, &bm->pdata, mask.pmask, CD_SET_DEFAULT, bm, BM_FACE); + CustomData_bmesh_merge_layout( + &mesh_ldata, &bm->ldata, mask.lmask, CD_SET_DEFAULT, bm, BM_LOOP); } /* -------------------------------------------------------------------- */ -- 2.30.2 From 1d465bc67f393e97e005a2f47e42875af4518b8d Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Fri, 7 Apr 2023 14:21:51 +0200 Subject: [PATCH 13/46] cleanup --- source/blender/blenkernel/intern/customdata.cc | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/source/blender/blenkernel/intern/customdata.cc b/source/blender/blenkernel/intern/customdata.cc index 4e3a53870ec..da69d477a38 100644 --- a/source/blender/blenkernel/intern/customdata.cc +++ b/source/blender/blenkernel/intern/customdata.cc @@ -2352,8 +2352,8 @@ CustomData CustomData_shallow_copy_remove_non_bmesh_attributes(const CustomData } /** - * A #ImplicitSharingInfo that knows how to free the entire referenced custom data layer (including - * potentially separately allocated chunks like for vertex groups). + * An #ImplicitSharingInfo that knows how to free the entire referenced custom data layer + * (including potentially separately allocated chunks like for vertex groups). */ class CustomDataLayerImplicitSharing : public ImplicitSharingInfo { private: @@ -2398,6 +2398,8 @@ static void ensure_layer_data_is_mutable(CustomDataLayer &layer, const int totel if (layer.sharing_info->is_shared()) { const eCustomDataType type = eCustomDataType(layer.type); const void *old_data = layer.data; + /* Copy the layer before removing the user because otherwise the data might be freed while + * we're still copying from it here. */ layer.data = copy_layer_data(type, old_data, totelem); layer.sharing_info->remove_user_and_delete_if_last(); layer.sharing_info = make_cow_for_array(type, layer.data, totelem); @@ -2414,7 +2416,7 @@ void CustomData_realloc(CustomData *data, const int old_size, const int new_size const int64_t new_size_in_bytes = int64_t(new_size) * typeInfo->size; void *new_layer_data = MEM_mallocN(new_size_in_bytes, __func__); - /* Copy or relocate data to new array. */ + /* Copy data to new array. */ if (typeInfo->copy) { typeInfo->copy(layer->data, new_layer_data, std::min(old_size, new_size)); } @@ -5264,6 +5266,7 @@ void CustomData_blend_read(BlendDataReader *reader, CustomData *data, const int if (CustomData_verify_versions(data, i)) { BLO_read_data_address(reader, &layer->data); if (layer->data != nullptr) { + /* Make layer data shareable. */ layer->sharing_info = make_cow_for_array(eCustomDataType(layer->type), layer->data, count); } if (CustomData_layer_ensure_data_exists(layer, count)) { -- 2.30.2 From c77e2c1c2c45226b3b4141b96511f054df63c70f Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Sat, 8 Apr 2023 12:55:35 +0200 Subject: [PATCH 14/46] improve comment --- source/blender/blenkernel/BKE_customdata.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/source/blender/blenkernel/BKE_customdata.h b/source/blender/blenkernel/BKE_customdata.h index cc7b53a2cac..dfe4dca0574 100644 --- a/source/blender/blenkernel/BKE_customdata.h +++ b/source/blender/blenkernel/BKE_customdata.h @@ -154,8 +154,8 @@ void CustomData_data_add(eCustomDataType type, void *data1, const void *data2); /** * Initializes a CustomData object with the same layer setup as source. `mask` is a bit-field where - * `(mask & (1 << (layer type)))` indicates if a layer should be copied or not. The data layers - * will be shared or copied depending on whether the layer uses COW. + * `(mask & (1 << (layer type)))` indicates if a layer should be copied or not. Data layers using + * implicit-sharing will not actually be copied but will be shared between source and destination. */ void CustomData_copy(const struct CustomData *source, struct CustomData *dest, @@ -240,7 +240,8 @@ void CustomData_free_temporary(struct CustomData *data, int totelem); /** * Adds a layer of the given type to the #CustomData object. The new layer is initialized based on - * the given alloctype. \return The layer data. + * the given alloctype. + * \return The layer data. */ void *CustomData_add_layer(struct CustomData *data, eCustomDataType type, -- 2.30.2 From 8aa9f55e85ad34dd3095e22f79b2db92d95e06bd Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Sat, 8 Apr 2023 12:55:48 +0200 Subject: [PATCH 15/46] rename cow to implicit-sharing in a few places --- .../blender/blenkernel/intern/customdata.cc | 29 ++++++++++--------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/source/blender/blenkernel/intern/customdata.cc b/source/blender/blenkernel/intern/customdata.cc index da69d477a38..66939dcc3d2 100644 --- a/source/blender/blenkernel/intern/customdata.cc +++ b/source/blender/blenkernel/intern/customdata.cc @@ -2376,9 +2376,9 @@ class CustomDataLayerImplicitSharing : public ImplicitSharingInfo { }; /** Create a #ImplicitSharingInfo that takes ownership of the data. */ -static ImplicitSharingInfo *make_cow_for_array(const eCustomDataType type, - const void *data, - const int totelem) +static ImplicitSharingInfo *make_implicit_sharing_info_for_layer(const eCustomDataType type, + const void *data, + const int totelem) { return MEM_new(__func__, data, totelem, type); } @@ -2392,7 +2392,7 @@ static void ensure_layer_data_is_mutable(CustomDataLayer &layer, const int totel return; } if (layer.sharing_info == nullptr) { - /* Can not be shared without cow data. */ + /* Can not be shared without implicit-sharing data. */ return; } if (layer.sharing_info->is_shared()) { @@ -2402,7 +2402,7 @@ static void ensure_layer_data_is_mutable(CustomDataLayer &layer, const int totel * we're still copying from it here. */ layer.data = copy_layer_data(type, old_data, totelem); layer.sharing_info->remove_user_and_delete_if_last(); - layer.sharing_info = make_cow_for_array(type, layer.data, totelem); + layer.sharing_info = make_implicit_sharing_info_for_layer(type, layer.data, totelem); } } @@ -2431,7 +2431,7 @@ void CustomData_realloc(CustomData *data, const int old_size, const int new_size /* Take ownership of new array. */ layer->data = new_layer_data; if (layer->data) { - layer->sharing_info = make_cow_for_array( + layer->sharing_info = make_implicit_sharing_info_for_layer( eCustomDataType(layer->type), layer->data, new_size); } @@ -2925,7 +2925,7 @@ static CustomDataLayer *customData_add_layer__internal( if (new_layer.data != nullptr && new_layer.sharing_info == nullptr) { /* Make layer data shareable. */ - new_layer.sharing_info = make_cow_for_array(type, new_layer.data, totelem); + new_layer.sharing_info = make_implicit_sharing_info_for_layer(type, new_layer.data, totelem); } new_layer.type = type; @@ -2986,12 +2986,12 @@ const void *CustomData_add_layer_with_data(CustomData *data, const eCustomDataType type, void *layer_data, const int totelem, - const ImplicitSharingInfo *cow) + const ImplicitSharingInfo *sharing_info) { const LayerTypeInfo *typeInfo = layerType_getInfo(type); CustomDataLayer *layer = customData_add_layer__internal( - data, type, std::nullopt, layer_data, cow, totelem, typeInfo->defaultname); + data, type, std::nullopt, layer_data, sharing_info, totelem, typeInfo->defaultname); CustomData_update_typemap(data); if (layer) { @@ -3022,10 +3022,10 @@ const void *CustomData_add_layer_named_with_data(CustomData *data, void *layer_data, int totelem, const char *name, - const ImplicitSharingInfo *cow) + const ImplicitSharingInfo *sharing_info) { CustomDataLayer *layer = customData_add_layer__internal( - data, type, std::nullopt, layer_data, cow, totelem, name); + data, type, std::nullopt, layer_data, sharing_info, totelem, name); CustomData_update_typemap(data); if (layer) { @@ -3060,11 +3060,11 @@ const void *CustomData_add_layer_anonymous_with_data( const AnonymousAttributeIDHandle *anonymous_id, const int totelem, void *layer_data, - const ImplicitSharingInfo *cow) + const ImplicitSharingInfo *sharing_info) { const char *name = anonymous_id->name().c_str(); CustomDataLayer *layer = customData_add_layer__internal( - data, type, std::nullopt, layer_data, cow, totelem, name); + data, type, std::nullopt, layer_data, sharing_info, totelem, name); CustomData_update_typemap(data); if (layer == nullptr) { @@ -5267,7 +5267,8 @@ void CustomData_blend_read(BlendDataReader *reader, CustomData *data, const int BLO_read_data_address(reader, &layer->data); if (layer->data != nullptr) { /* Make layer data shareable. */ - layer->sharing_info = make_cow_for_array(eCustomDataType(layer->type), layer->data, count); + layer->sharing_info = make_implicit_sharing_info_for_layer( + eCustomDataType(layer->type), layer->data, count); } if (CustomData_layer_ensure_data_exists(layer, count)) { /* Under normal operations, this shouldn't happen, but... -- 2.30.2 From d1824ff9de4425636d471e02fc94019d2a91c294 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Sat, 8 Apr 2023 12:56:21 +0200 Subject: [PATCH 16/46] remove newline --- source/blender/blenkernel/intern/mesh_convert.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/source/blender/blenkernel/intern/mesh_convert.cc b/source/blender/blenkernel/intern/mesh_convert.cc index ddf9b156383..7dcd55f4a4a 100644 --- a/source/blender/blenkernel/intern/mesh_convert.cc +++ b/source/blender/blenkernel/intern/mesh_convert.cc @@ -625,7 +625,6 @@ void BKE_pointcloud_from_mesh(const Mesh *me, PointCloud *pointcloud) { CustomData_free(&pointcloud->pdata, pointcloud->totpoint); pointcloud->totpoint = me->totvert; - CustomData_merge(&me->vdata, &pointcloud->pdata, CD_MASK_PROP_ALL, me->totvert); } -- 2.30.2 From 8610875628a21220f6df0b539dd5a01efc9df166 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Sat, 8 Apr 2023 12:59:10 +0200 Subject: [PATCH 17/46] improve comment --- source/blender/editors/mesh/editmesh_undo.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/source/blender/editors/mesh/editmesh_undo.cc b/source/blender/editors/mesh/editmesh_undo.cc index 5b344c11256..098a4ef48ee 100644 --- a/source/blender/editors/mesh/editmesh_undo.cc +++ b/source/blender/editors/mesh/editmesh_undo.cc @@ -277,7 +277,9 @@ static void um_arraystore_cd_compact(CustomData *cdata, if (layer->sharing_info) { /* This assumes that the layer is not shared, which it is not here because it has just * been created in #BM_mesh_bm_to_me. The situation is a bit tricky here, because the - * layer data may be freed partially below for e.g. vertex groups. */ + * layer data may be freed partially below for e.g. vertex groups. A potentially better + * solution might be to not pass "dynamic" layers (see `layer_type_is_dynamic`) to the + * array store at all. */ BLI_assert(layer->sharing_info->is_mutable()); MEM_delete(layer->sharing_info); } -- 2.30.2 From a283341b2eeb0fc7adf5928e11422f65d02b3492 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Mon, 10 Apr 2023 13:19:00 -0400 Subject: [PATCH 18/46] Fix: memcpy called with null src argument (size was 0) --- source/blender/blenkernel/intern/customdata.cc | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/source/blender/blenkernel/intern/customdata.cc b/source/blender/blenkernel/intern/customdata.cc index 66939dcc3d2..28ae7bfa145 100644 --- a/source/blender/blenkernel/intern/customdata.cc +++ b/source/blender/blenkernel/intern/customdata.cc @@ -2417,11 +2417,14 @@ void CustomData_realloc(CustomData *data, const int old_size, const int new_size void *new_layer_data = MEM_mallocN(new_size_in_bytes, __func__); /* Copy data to new array. */ - if (typeInfo->copy) { - typeInfo->copy(layer->data, new_layer_data, std::min(old_size, new_size)); - } - else { - memcpy(new_layer_data, layer->data, std::min(old_size_in_bytes, new_size_in_bytes)); + if (old_size_in_bytes) { + if (typeInfo->copy) { + typeInfo->copy(layer->data, new_layer_data, std::min(old_size, new_size)); + } + else { + BLI_assert(layer->data != nullptr); + memcpy(new_layer_data, layer->data, std::min(old_size_in_bytes, new_size_in_bytes)); + } } /* Remove ownership of old array */ if (layer->sharing_info) { -- 2.30.2 From a66aeb221323c2a9c1d9c61ea0e9a9b3273d6e1e Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Mon, 10 Apr 2023 13:19:41 -0400 Subject: [PATCH 19/46] Curves: Use implicit sharing to avoid copying curve offsets --- source/blender/blenkernel/BKE_curves.hh | 23 ++++++- .../blenkernel/intern/curve_legacy_convert.cc | 7 +- source/blender/blenkernel/intern/curves.cc | 32 +-------- .../blenkernel/intern/curves_geometry.cc | 67 +++++++++++++------ .../editors/curves/intern/curves_data.cc | 5 ++ source/blender/editors/include/ED_curves.h | 2 + source/blender/makesrna/intern/rna_curves.c | 32 +++++++-- 7 files changed, 109 insertions(+), 59 deletions(-) diff --git a/source/blender/blenkernel/BKE_curves.hh b/source/blender/blenkernel/BKE_curves.hh index 16b0c212a6c..f45dc620bd5 100644 --- a/source/blender/blenkernel/BKE_curves.hh +++ b/source/blender/blenkernel/BKE_curves.hh @@ -48,11 +48,29 @@ struct BasisCache { } // namespace curves::nurbs +template +class SharedVector : public Vector, + public ImplicitSharingMixin { + + public: + SharedVector() = default; + SharedVector(const int64_t size) : Vector(size) {} + SharedVector(const Span data) : Vector(data) {} + void delete_self() override + { + delete this; + } +}; + /** * Contains derived data, caches, and other information not saved in files. */ class CurvesGeometryRuntime { public: + ImplicitSharingPtr> curve_offset_indices; + /** * The cached number of curves with each type. Unlike other caches here, this is not computed * lazily, since it is needed so often and types are not adjusted much anyway. @@ -846,7 +864,10 @@ inline const std::array &CurvesGeometry::curve_type_counts inline OffsetIndices CurvesGeometry::points_by_curve() const { - return OffsetIndices({this->curve_offsets, this->curve_num + 1}); + if (!this->runtime->curve_offset_indices) { + return {}; + } + return OffsetIndices(this->runtime->curve_offset_indices->as_span()); } inline int CurvesGeometry::evaluated_points_num() const diff --git a/source/blender/blenkernel/intern/curve_legacy_convert.cc b/source/blender/blenkernel/intern/curve_legacy_convert.cc index c8ae56220c3..f8cc9985d17 100644 --- a/source/blender/blenkernel/intern/curve_legacy_convert.cc +++ b/source/blender/blenkernel/intern/curve_legacy_convert.cc @@ -80,6 +80,9 @@ static KnotsMode knots_mode_from_legacy(const short flag) Curves *curve_legacy_to_curves(const Curve &curve_legacy, const ListBase &nurbs_list) { const Vector src_curves(nurbs_list); + if (src_curves.is_empty()) { + return nullptr; + } Curves *curves_id = curves_new_nomain(0, src_curves.size()); CurvesGeometry &curves = curves_id->geometry.wrap(); @@ -104,10 +107,6 @@ Curves *curve_legacy_to_curves(const Curve &curve_legacy, const ListBase &nurbs_ curves.update_curve_types(); - if (curves.curves_num() == 0) { - return curves_id; - } - const OffsetIndices points_by_curve = curves.points_by_curve(); MutableSpan positions = curves.positions_for_write(); SpanAttributeWriter radius_attribute = diff --git a/source/blender/blenkernel/intern/curves.cc b/source/blender/blenkernel/intern/curves.cc index c4d1cc10f8a..50dfc502695 100644 --- a/source/blender/blenkernel/intern/curves.cc +++ b/source/blender/blenkernel/intern/curves.cc @@ -70,36 +70,13 @@ static void curves_copy_data(Main * /*bmain*/, ID *id_dst, const ID *id_src, con const Curves *curves_src = (const Curves *)id_src; curves_dst->mat = static_cast(MEM_dupallocN(curves_src->mat)); - const bke::CurvesGeometry &src = curves_src->geometry.wrap(); - bke::CurvesGeometry &dst = curves_dst->geometry.wrap(); - - /* We need special handling here because the generic ID management code has already done a - * shallow copy from the source to the destination, and because the copy-on-write functionality - * isn't supported more generically yet. */ - - dst.point_num = src.point_num; - dst.curve_num = src.curve_num; - - CustomData_copy(&src.point_data, &dst.point_data, CD_MASK_ALL, dst.point_num); - CustomData_copy(&src.curve_data, &dst.curve_data, CD_MASK_ALL, dst.curve_num); - - dst.curve_offsets = static_cast(MEM_dupallocN(src.curve_offsets)); + new (&curves_dst->geometry) bke::CurvesGeometry(curves_src->geometry.wrap()); + BLI_assert(curves_dst->geometry.runtime->curve_offset_indices->is_shared()); if (curves_src->surface_uv_map != nullptr) { curves_dst->surface_uv_map = BLI_strdup(curves_src->surface_uv_map); } - dst.runtime = MEM_new(__func__); - - dst.runtime->type_counts = src.runtime->type_counts; - dst.runtime->evaluated_offsets_cache = src.runtime->evaluated_offsets_cache; - dst.runtime->nurbs_basis_cache = src.runtime->nurbs_basis_cache; - dst.runtime->evaluated_position_cache = src.runtime->evaluated_position_cache; - dst.runtime->bounds_cache = src.runtime->bounds_cache; - dst.runtime->evaluated_length_cache = src.runtime->evaluated_length_cache; - dst.runtime->evaluated_tangent_cache = src.runtime->evaluated_tangent_cache; - dst.runtime->evaluated_normal_cache = src.runtime->evaluated_normal_cache; - curves_dst->batch_cache = nullptr; } @@ -155,11 +132,6 @@ static void curves_blend_read_data(BlendDataReader *reader, ID *id) BLO_read_data_address(reader, &curves->surface_uv_map); - curves->geometry.runtime = MEM_new(__func__); - - /* Recalculate curve type count cache that isn't saved in files. */ - curves->geometry.wrap().update_curve_types(); - /* Materials */ BLO_read_pointer_array(reader, (void **)&curves->mat); } diff --git a/source/blender/blenkernel/intern/curves_geometry.cc b/source/blender/blenkernel/intern/curves_geometry.cc index e9ece4aab70..661770dd66d 100644 --- a/source/blender/blenkernel/intern/curves_geometry.cc +++ b/source/blender/blenkernel/intern/curves_geometry.cc @@ -60,13 +60,16 @@ CurvesGeometry::CurvesGeometry(const int point_num, const int curve_num) CustomData_add_layer_named( &this->point_data, CD_PROP_FLOAT3, CD_CONSTRUCT, this->point_num, ATTR_POSITION.c_str()); - this->curve_offsets = (int *)MEM_malloc_arrayN(this->curve_num + 1, sizeof(int), __func__); -#ifdef DEBUG - this->offsets_for_write().fill(-1); -#endif - this->offsets_for_write().first() = 0; - this->runtime = MEM_new(__func__); + + if (curve_num > 0) { + this->runtime->curve_offset_indices = new SharedVector(this->curve_num + 1); +#ifdef DEBUG + this->offsets_for_write().fill(-1); +#endif + this->offsets_for_write().first() = 0; + } + /* Fill the type counts with the default so they're in a valid state. */ this->runtime->type_counts[CURVE_TYPE_CATMULL_ROM] = curve_num; } @@ -83,9 +86,7 @@ static void copy_curves_geometry(CurvesGeometry &dst, const CurvesGeometry &src) CustomData_copy(&src.point_data, &dst.point_data, CD_MASK_ALL, dst.point_num); CustomData_copy(&src.curve_data, &dst.curve_data, CD_MASK_ALL, dst.curve_num); - MEM_SAFE_FREE(dst.curve_offsets); - dst.curve_offsets = (int *)MEM_malloc_arrayN(dst.point_num + 1, sizeof(int), __func__); - dst.offsets_for_write().copy_from(src.offsets()); + dst.runtime->curve_offset_indices = src.runtime->curve_offset_indices; dst.tag_topology_changed(); @@ -100,8 +101,7 @@ static void copy_curves_geometry(CurvesGeometry &dst, const CurvesGeometry &src) dst.runtime->evaluated_normal_cache = src.runtime->evaluated_normal_cache; } -CurvesGeometry::CurvesGeometry(const CurvesGeometry &other) - : CurvesGeometry(other.point_num, other.curve_num) +CurvesGeometry::CurvesGeometry(const CurvesGeometry &other) : CurvesGeometry() { copy_curves_geometry(*this, other); } @@ -127,14 +127,10 @@ static void move_curves_geometry(CurvesGeometry &dst, CurvesGeometry &src) CustomData_free(&src.curve_data, src.curve_num); src.curve_num = 0; - std::swap(dst.curve_offsets, src.curve_offsets); - MEM_SAFE_FREE(src.curve_offsets); - std::swap(dst.runtime, src.runtime); } -CurvesGeometry::CurvesGeometry(CurvesGeometry &&other) - : CurvesGeometry(other.point_num, other.curve_num) +CurvesGeometry::CurvesGeometry(CurvesGeometry &&other) : CurvesGeometry() { move_curves_geometry(*this, other); } @@ -151,7 +147,6 @@ CurvesGeometry::~CurvesGeometry() { CustomData_free(&this->point_data, this->point_num); CustomData_free(&this->curve_data, this->curve_num); - MEM_SAFE_FREE(this->curve_offsets); MEM_delete(this->runtime); this->runtime = nullptr; } @@ -324,11 +319,19 @@ MutableSpan CurvesGeometry::positions_for_write() Span CurvesGeometry::offsets() const { - return {this->curve_offsets, this->curve_num + 1}; + return this->runtime->curve_offset_indices->as_span(); } + MutableSpan CurvesGeometry::offsets_for_write() { - return {this->curve_offsets, this->curve_num + 1}; + if (!this->runtime->curve_offset_indices) { + return {}; + } + if (this->runtime->curve_offset_indices->is_shared()) { + SharedVector *data = new SharedVector(this->runtime->curve_offset_indices); + this->runtime->curve_offset_indices = data; + } + return this->runtime->curve_offset_indices->as_mutable_span(); } VArray CurvesGeometry::cyclic() const @@ -950,8 +953,23 @@ void CurvesGeometry::resize(const int points_num, const int curves_num) } if (curves_num != this->curve_num) { CustomData_realloc(&this->curve_data, this->curves_num(), curves_num); + if (!this->runtime->curve_offset_indices) { + this->runtime->curve_offset_indices = new SharedVector(curves_num + 1); + this->runtime->curve_offset_indices->first() = 0; + this->runtime->curve_offset_indices->last() = points_num; + } + else if (this->runtime->curve_offset_indices->is_mutable()) { + this->runtime->curve_offset_indices->resize(curves_num + 1); + this->runtime->curve_offset_indices->last() = points_num; + } + else { + SharedVector *new_offsets = new SharedVector(curves_num + 1); + new_offsets->as_mutable_span() + .take_front(this->curve_num + 1) + .copy_from({this->curve_offsets, this->curve_num + 1}); + this->runtime->curve_offset_indices = new_offsets; + } this->curve_num = curves_num; - this->curve_offsets = (int *)MEM_reallocN(this->curve_offsets, sizeof(int) * (curves_num + 1)); } this->tag_topology_changed(); } @@ -1585,7 +1603,15 @@ void CurvesGeometry::blend_read(BlendDataReader &reader) CustomData_blend_read(&reader, &this->point_data, this->point_num); CustomData_blend_read(&reader, &this->curve_data, this->curve_num); + this->runtime = MEM_new(__func__); + BLO_read_int32_array(&reader, this->curve_num + 1, &this->curve_offsets); + SharedVector *vector = new SharedVector({this->curve_offsets, this->curve_num + 1}); + this->runtime->curve_offset_indices = ImplicitSharingPtr(vector); + MEM_SAFE_FREE(this->curve_offsets); + + /* Recalculate curve type count cache that isn't saved in files. */ + this->update_curve_types(); } void CurvesGeometry::blend_write(BlendWriter &writer, ID &id) @@ -1600,6 +1626,7 @@ void CurvesGeometry::blend_write(BlendWriter &writer, ID &id) CustomData_blend_write( &writer, &this->curve_data, curve_layers, this->curve_num, CD_MASK_ALL, &id); + this->curve_offsets = this->runtime->curve_offset_indices->data(); BLO_write_int32_array(&writer, this->curve_num + 1, this->curve_offsets); } diff --git a/source/blender/editors/curves/intern/curves_data.cc b/source/blender/editors/curves/intern/curves_data.cc index d178ee60890..d955a40cf45 100644 --- a/source/blender/editors/curves/intern/curves_data.cc +++ b/source/blender/editors/curves/intern/curves_data.cc @@ -57,3 +57,8 @@ void ED_curves_transverts_create(Curves *curves_id, TransVertStore *tvs) bke::CurvesGeometry &curves = curves_id->geometry.wrap(); ed::curves::transverts_from_curves_positions_create(curves, tvs); } + +int *ED_curves_offsets_for_write(struct Curves *curves_id) +{ + return curves_id->geometry.wrap().offsets_for_write().data(); +} diff --git a/source/blender/editors/include/ED_curves.h b/source/blender/editors/include/ED_curves.h index d6c058a3dd9..574dd1826fd 100644 --- a/source/blender/editors/include/ED_curves.h +++ b/source/blender/editors/include/ED_curves.h @@ -38,6 +38,8 @@ float (*ED_curves_point_normals_array_create(const struct Curves *curves_id))[3] */ void ED_curves_transverts_create(struct Curves *curves_id, struct TransVertStore *tvs); +int *ED_curves_offsets_for_write(struct Curves *curves_id); + /** \} */ #ifdef __cplusplus diff --git a/source/blender/makesrna/intern/rna_curves.c b/source/blender/makesrna/intern/rna_curves.c index 24b3de95123..2ac738de914 100644 --- a/source/blender/makesrna/intern/rna_curves.c +++ b/source/blender/makesrna/intern/rna_curves.c @@ -68,9 +68,9 @@ static int rna_Curves_curve_offset_data_length(PointerRNA *ptr) static void rna_Curves_curve_offset_data_begin(CollectionPropertyIterator *iter, PointerRNA *ptr) { - const Curves *curves = rna_curves(ptr); + Curves *curves = rna_curves(ptr); rna_iterator_array_begin(iter, - (void *)curves->geometry.curve_offsets, + ED_curves_offsets_for_write(curves), sizeof(int), curves->geometry.curve_num + 1, false, @@ -97,6 +97,23 @@ static int rna_CurvePoint_index_get_const(const PointerRNA *ptr) return (int)(co - positions); } +static void rna_Curves_curves_begin(CollectionPropertyIterator *iter, PointerRNA *ptr) +{ + Curves *curves = rna_curves(ptr); + rna_iterator_array_begin(iter, + ED_curves_offsets_for_write(curves), + sizeof(int), + curves->geometry.curve_num, + false, + NULL); +} + +static int rna_Curves_curves_length(PointerRNA *ptr) +{ + const Curves *curves = rna_curves(ptr); + return curves->geometry.curve_num; +} + static int rna_Curves_position_data_length(PointerRNA *ptr) { const Curves *curves = rna_curves(ptr); @@ -343,7 +360,15 @@ static void rna_def_curves(BlenderRNA *brna) /* Point and Curve RNA API helpers. */ prop = RNA_def_property(srna, "curves", PROP_COLLECTION, PROP_NONE); - RNA_def_property_collection_sdna(prop, NULL, "geometry.curve_offsets", "geometry.curve_num"); + RNA_def_property_collection_funcs(prop, + "rna_Curves_curves_begin", + "rna_iterator_array_next", + "rna_iterator_array_end", + "rna_iterator_array_get", + "rna_Curves_curves_length", + NULL, + NULL, + NULL); RNA_def_property_struct_type(prop, "CurveSlice"); RNA_def_property_ui_text(prop, "Curves", "All curves in the data-block"); @@ -376,7 +401,6 @@ static void rna_def_curves(BlenderRNA *brna) RNA_def_property_update(prop, 0, "rna_Curves_update_data"); prop = RNA_def_property(srna, "curve_offset_data", PROP_COLLECTION, PROP_NONE); - RNA_def_property_collection_sdna(prop, NULL, "geometry.curve_offsets", NULL); RNA_def_property_struct_type(prop, "IntAttributeValue"); RNA_def_property_collection_funcs(prop, "rna_Curves_curve_offset_data_begin", -- 2.30.2 From 2e3c21c1458b027087f299f1c61a8df9f3932009 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Mon, 10 Apr 2023 13:20:09 -0400 Subject: [PATCH 20/46] Revert "Curves: Use implicit sharing to avoid copying curve offsets" This reverts commit a66aeb221323c2a9c1d9c61ea0e9a9b3273d6e1e. --- source/blender/blenkernel/BKE_curves.hh | 23 +------ .../blenkernel/intern/curve_legacy_convert.cc | 7 ++- source/blender/blenkernel/intern/curves.cc | 32 +++++++++- .../blenkernel/intern/curves_geometry.cc | 63 ++++++------------- .../editors/curves/intern/curves_data.cc | 5 -- source/blender/editors/include/ED_curves.h | 2 - source/blender/makesrna/intern/rna_curves.c | 32 ++-------- 7 files changed, 57 insertions(+), 107 deletions(-) diff --git a/source/blender/blenkernel/BKE_curves.hh b/source/blender/blenkernel/BKE_curves.hh index f45dc620bd5..16b0c212a6c 100644 --- a/source/blender/blenkernel/BKE_curves.hh +++ b/source/blender/blenkernel/BKE_curves.hh @@ -48,29 +48,11 @@ struct BasisCache { } // namespace curves::nurbs -template -class SharedVector : public Vector, - public ImplicitSharingMixin { - - public: - SharedVector() = default; - SharedVector(const int64_t size) : Vector(size) {} - SharedVector(const Span data) : Vector(data) {} - void delete_self() override - { - delete this; - } -}; - /** * Contains derived data, caches, and other information not saved in files. */ class CurvesGeometryRuntime { public: - ImplicitSharingPtr> curve_offset_indices; - /** * The cached number of curves with each type. Unlike other caches here, this is not computed * lazily, since it is needed so often and types are not adjusted much anyway. @@ -864,10 +846,7 @@ inline const std::array &CurvesGeometry::curve_type_counts inline OffsetIndices CurvesGeometry::points_by_curve() const { - if (!this->runtime->curve_offset_indices) { - return {}; - } - return OffsetIndices(this->runtime->curve_offset_indices->as_span()); + return OffsetIndices({this->curve_offsets, this->curve_num + 1}); } inline int CurvesGeometry::evaluated_points_num() const diff --git a/source/blender/blenkernel/intern/curve_legacy_convert.cc b/source/blender/blenkernel/intern/curve_legacy_convert.cc index f8cc9985d17..c8ae56220c3 100644 --- a/source/blender/blenkernel/intern/curve_legacy_convert.cc +++ b/source/blender/blenkernel/intern/curve_legacy_convert.cc @@ -80,9 +80,6 @@ static KnotsMode knots_mode_from_legacy(const short flag) Curves *curve_legacy_to_curves(const Curve &curve_legacy, const ListBase &nurbs_list) { const Vector src_curves(nurbs_list); - if (src_curves.is_empty()) { - return nullptr; - } Curves *curves_id = curves_new_nomain(0, src_curves.size()); CurvesGeometry &curves = curves_id->geometry.wrap(); @@ -107,6 +104,10 @@ Curves *curve_legacy_to_curves(const Curve &curve_legacy, const ListBase &nurbs_ curves.update_curve_types(); + if (curves.curves_num() == 0) { + return curves_id; + } + const OffsetIndices points_by_curve = curves.points_by_curve(); MutableSpan positions = curves.positions_for_write(); SpanAttributeWriter radius_attribute = diff --git a/source/blender/blenkernel/intern/curves.cc b/source/blender/blenkernel/intern/curves.cc index 50dfc502695..c4d1cc10f8a 100644 --- a/source/blender/blenkernel/intern/curves.cc +++ b/source/blender/blenkernel/intern/curves.cc @@ -70,13 +70,36 @@ static void curves_copy_data(Main * /*bmain*/, ID *id_dst, const ID *id_src, con const Curves *curves_src = (const Curves *)id_src; curves_dst->mat = static_cast(MEM_dupallocN(curves_src->mat)); - new (&curves_dst->geometry) bke::CurvesGeometry(curves_src->geometry.wrap()); - BLI_assert(curves_dst->geometry.runtime->curve_offset_indices->is_shared()); + const bke::CurvesGeometry &src = curves_src->geometry.wrap(); + bke::CurvesGeometry &dst = curves_dst->geometry.wrap(); + + /* We need special handling here because the generic ID management code has already done a + * shallow copy from the source to the destination, and because the copy-on-write functionality + * isn't supported more generically yet. */ + + dst.point_num = src.point_num; + dst.curve_num = src.curve_num; + + CustomData_copy(&src.point_data, &dst.point_data, CD_MASK_ALL, dst.point_num); + CustomData_copy(&src.curve_data, &dst.curve_data, CD_MASK_ALL, dst.curve_num); + + dst.curve_offsets = static_cast(MEM_dupallocN(src.curve_offsets)); if (curves_src->surface_uv_map != nullptr) { curves_dst->surface_uv_map = BLI_strdup(curves_src->surface_uv_map); } + dst.runtime = MEM_new(__func__); + + dst.runtime->type_counts = src.runtime->type_counts; + dst.runtime->evaluated_offsets_cache = src.runtime->evaluated_offsets_cache; + dst.runtime->nurbs_basis_cache = src.runtime->nurbs_basis_cache; + dst.runtime->evaluated_position_cache = src.runtime->evaluated_position_cache; + dst.runtime->bounds_cache = src.runtime->bounds_cache; + dst.runtime->evaluated_length_cache = src.runtime->evaluated_length_cache; + dst.runtime->evaluated_tangent_cache = src.runtime->evaluated_tangent_cache; + dst.runtime->evaluated_normal_cache = src.runtime->evaluated_normal_cache; + curves_dst->batch_cache = nullptr; } @@ -132,6 +155,11 @@ static void curves_blend_read_data(BlendDataReader *reader, ID *id) BLO_read_data_address(reader, &curves->surface_uv_map); + curves->geometry.runtime = MEM_new(__func__); + + /* Recalculate curve type count cache that isn't saved in files. */ + curves->geometry.wrap().update_curve_types(); + /* Materials */ BLO_read_pointer_array(reader, (void **)&curves->mat); } diff --git a/source/blender/blenkernel/intern/curves_geometry.cc b/source/blender/blenkernel/intern/curves_geometry.cc index 661770dd66d..e9ece4aab70 100644 --- a/source/blender/blenkernel/intern/curves_geometry.cc +++ b/source/blender/blenkernel/intern/curves_geometry.cc @@ -60,16 +60,13 @@ CurvesGeometry::CurvesGeometry(const int point_num, const int curve_num) CustomData_add_layer_named( &this->point_data, CD_PROP_FLOAT3, CD_CONSTRUCT, this->point_num, ATTR_POSITION.c_str()); - this->runtime = MEM_new(__func__); - - if (curve_num > 0) { - this->runtime->curve_offset_indices = new SharedVector(this->curve_num + 1); + this->curve_offsets = (int *)MEM_malloc_arrayN(this->curve_num + 1, sizeof(int), __func__); #ifdef DEBUG - this->offsets_for_write().fill(-1); + this->offsets_for_write().fill(-1); #endif - this->offsets_for_write().first() = 0; - } + this->offsets_for_write().first() = 0; + this->runtime = MEM_new(__func__); /* Fill the type counts with the default so they're in a valid state. */ this->runtime->type_counts[CURVE_TYPE_CATMULL_ROM] = curve_num; } @@ -86,7 +83,9 @@ static void copy_curves_geometry(CurvesGeometry &dst, const CurvesGeometry &src) CustomData_copy(&src.point_data, &dst.point_data, CD_MASK_ALL, dst.point_num); CustomData_copy(&src.curve_data, &dst.curve_data, CD_MASK_ALL, dst.curve_num); - dst.runtime->curve_offset_indices = src.runtime->curve_offset_indices; + MEM_SAFE_FREE(dst.curve_offsets); + dst.curve_offsets = (int *)MEM_malloc_arrayN(dst.point_num + 1, sizeof(int), __func__); + dst.offsets_for_write().copy_from(src.offsets()); dst.tag_topology_changed(); @@ -101,7 +100,8 @@ static void copy_curves_geometry(CurvesGeometry &dst, const CurvesGeometry &src) dst.runtime->evaluated_normal_cache = src.runtime->evaluated_normal_cache; } -CurvesGeometry::CurvesGeometry(const CurvesGeometry &other) : CurvesGeometry() +CurvesGeometry::CurvesGeometry(const CurvesGeometry &other) + : CurvesGeometry(other.point_num, other.curve_num) { copy_curves_geometry(*this, other); } @@ -127,10 +127,14 @@ static void move_curves_geometry(CurvesGeometry &dst, CurvesGeometry &src) CustomData_free(&src.curve_data, src.curve_num); src.curve_num = 0; + std::swap(dst.curve_offsets, src.curve_offsets); + MEM_SAFE_FREE(src.curve_offsets); + std::swap(dst.runtime, src.runtime); } -CurvesGeometry::CurvesGeometry(CurvesGeometry &&other) : CurvesGeometry() +CurvesGeometry::CurvesGeometry(CurvesGeometry &&other) + : CurvesGeometry(other.point_num, other.curve_num) { move_curves_geometry(*this, other); } @@ -147,6 +151,7 @@ CurvesGeometry::~CurvesGeometry() { CustomData_free(&this->point_data, this->point_num); CustomData_free(&this->curve_data, this->curve_num); + MEM_SAFE_FREE(this->curve_offsets); MEM_delete(this->runtime); this->runtime = nullptr; } @@ -319,19 +324,11 @@ MutableSpan CurvesGeometry::positions_for_write() Span CurvesGeometry::offsets() const { - return this->runtime->curve_offset_indices->as_span(); + return {this->curve_offsets, this->curve_num + 1}; } - MutableSpan CurvesGeometry::offsets_for_write() { - if (!this->runtime->curve_offset_indices) { - return {}; - } - if (this->runtime->curve_offset_indices->is_shared()) { - SharedVector *data = new SharedVector(this->runtime->curve_offset_indices); - this->runtime->curve_offset_indices = data; - } - return this->runtime->curve_offset_indices->as_mutable_span(); + return {this->curve_offsets, this->curve_num + 1}; } VArray CurvesGeometry::cyclic() const @@ -953,23 +950,8 @@ void CurvesGeometry::resize(const int points_num, const int curves_num) } if (curves_num != this->curve_num) { CustomData_realloc(&this->curve_data, this->curves_num(), curves_num); - if (!this->runtime->curve_offset_indices) { - this->runtime->curve_offset_indices = new SharedVector(curves_num + 1); - this->runtime->curve_offset_indices->first() = 0; - this->runtime->curve_offset_indices->last() = points_num; - } - else if (this->runtime->curve_offset_indices->is_mutable()) { - this->runtime->curve_offset_indices->resize(curves_num + 1); - this->runtime->curve_offset_indices->last() = points_num; - } - else { - SharedVector *new_offsets = new SharedVector(curves_num + 1); - new_offsets->as_mutable_span() - .take_front(this->curve_num + 1) - .copy_from({this->curve_offsets, this->curve_num + 1}); - this->runtime->curve_offset_indices = new_offsets; - } this->curve_num = curves_num; + this->curve_offsets = (int *)MEM_reallocN(this->curve_offsets, sizeof(int) * (curves_num + 1)); } this->tag_topology_changed(); } @@ -1603,15 +1585,7 @@ void CurvesGeometry::blend_read(BlendDataReader &reader) CustomData_blend_read(&reader, &this->point_data, this->point_num); CustomData_blend_read(&reader, &this->curve_data, this->curve_num); - this->runtime = MEM_new(__func__); - BLO_read_int32_array(&reader, this->curve_num + 1, &this->curve_offsets); - SharedVector *vector = new SharedVector({this->curve_offsets, this->curve_num + 1}); - this->runtime->curve_offset_indices = ImplicitSharingPtr(vector); - MEM_SAFE_FREE(this->curve_offsets); - - /* Recalculate curve type count cache that isn't saved in files. */ - this->update_curve_types(); } void CurvesGeometry::blend_write(BlendWriter &writer, ID &id) @@ -1626,7 +1600,6 @@ void CurvesGeometry::blend_write(BlendWriter &writer, ID &id) CustomData_blend_write( &writer, &this->curve_data, curve_layers, this->curve_num, CD_MASK_ALL, &id); - this->curve_offsets = this->runtime->curve_offset_indices->data(); BLO_write_int32_array(&writer, this->curve_num + 1, this->curve_offsets); } diff --git a/source/blender/editors/curves/intern/curves_data.cc b/source/blender/editors/curves/intern/curves_data.cc index d955a40cf45..d178ee60890 100644 --- a/source/blender/editors/curves/intern/curves_data.cc +++ b/source/blender/editors/curves/intern/curves_data.cc @@ -57,8 +57,3 @@ void ED_curves_transverts_create(Curves *curves_id, TransVertStore *tvs) bke::CurvesGeometry &curves = curves_id->geometry.wrap(); ed::curves::transverts_from_curves_positions_create(curves, tvs); } - -int *ED_curves_offsets_for_write(struct Curves *curves_id) -{ - return curves_id->geometry.wrap().offsets_for_write().data(); -} diff --git a/source/blender/editors/include/ED_curves.h b/source/blender/editors/include/ED_curves.h index 574dd1826fd..d6c058a3dd9 100644 --- a/source/blender/editors/include/ED_curves.h +++ b/source/blender/editors/include/ED_curves.h @@ -38,8 +38,6 @@ float (*ED_curves_point_normals_array_create(const struct Curves *curves_id))[3] */ void ED_curves_transverts_create(struct Curves *curves_id, struct TransVertStore *tvs); -int *ED_curves_offsets_for_write(struct Curves *curves_id); - /** \} */ #ifdef __cplusplus diff --git a/source/blender/makesrna/intern/rna_curves.c b/source/blender/makesrna/intern/rna_curves.c index 2ac738de914..24b3de95123 100644 --- a/source/blender/makesrna/intern/rna_curves.c +++ b/source/blender/makesrna/intern/rna_curves.c @@ -68,9 +68,9 @@ static int rna_Curves_curve_offset_data_length(PointerRNA *ptr) static void rna_Curves_curve_offset_data_begin(CollectionPropertyIterator *iter, PointerRNA *ptr) { - Curves *curves = rna_curves(ptr); + const Curves *curves = rna_curves(ptr); rna_iterator_array_begin(iter, - ED_curves_offsets_for_write(curves), + (void *)curves->geometry.curve_offsets, sizeof(int), curves->geometry.curve_num + 1, false, @@ -97,23 +97,6 @@ static int rna_CurvePoint_index_get_const(const PointerRNA *ptr) return (int)(co - positions); } -static void rna_Curves_curves_begin(CollectionPropertyIterator *iter, PointerRNA *ptr) -{ - Curves *curves = rna_curves(ptr); - rna_iterator_array_begin(iter, - ED_curves_offsets_for_write(curves), - sizeof(int), - curves->geometry.curve_num, - false, - NULL); -} - -static int rna_Curves_curves_length(PointerRNA *ptr) -{ - const Curves *curves = rna_curves(ptr); - return curves->geometry.curve_num; -} - static int rna_Curves_position_data_length(PointerRNA *ptr) { const Curves *curves = rna_curves(ptr); @@ -360,15 +343,7 @@ static void rna_def_curves(BlenderRNA *brna) /* Point and Curve RNA API helpers. */ prop = RNA_def_property(srna, "curves", PROP_COLLECTION, PROP_NONE); - RNA_def_property_collection_funcs(prop, - "rna_Curves_curves_begin", - "rna_iterator_array_next", - "rna_iterator_array_end", - "rna_iterator_array_get", - "rna_Curves_curves_length", - NULL, - NULL, - NULL); + RNA_def_property_collection_sdna(prop, NULL, "geometry.curve_offsets", "geometry.curve_num"); RNA_def_property_struct_type(prop, "CurveSlice"); RNA_def_property_ui_text(prop, "Curves", "All curves in the data-block"); @@ -401,6 +376,7 @@ static void rna_def_curves(BlenderRNA *brna) RNA_def_property_update(prop, 0, "rna_Curves_update_data"); prop = RNA_def_property(srna, "curve_offset_data", PROP_COLLECTION, PROP_NONE); + RNA_def_property_collection_sdna(prop, NULL, "geometry.curve_offsets", NULL); RNA_def_property_struct_type(prop, "IntAttributeValue"); RNA_def_property_collection_funcs(prop, "rna_Curves_curve_offset_data_begin", -- 2.30.2 From 9760cf86bc60d802b755b6bdf3afdbaee793c1e0 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Tue, 11 Apr 2023 11:27:13 +0200 Subject: [PATCH 21/46] initial BLO api for sharing --- .../blender/blenkernel/intern/customdata.cc | 129 +++++++++--------- source/blender/blenloader/BLO_read_write.h | 19 +++ source/blender/blenloader/intern/readfile.cc | 9 ++ source/blender/blenloader/intern/writefile.cc | 9 ++ 4 files changed, 105 insertions(+), 61 deletions(-) diff --git a/source/blender/blenkernel/intern/customdata.cc b/source/blender/blenkernel/intern/customdata.cc index 28ae7bfa145..76e24be8dd3 100644 --- a/source/blender/blenkernel/intern/customdata.cc +++ b/source/blender/blenkernel/intern/customdata.cc @@ -5150,48 +5150,52 @@ void CustomData_blend_write(BlendWriter *writer, writer, CustomDataLayer, data->totlayer, data->layers, layers_to_write.data()); for (const CustomDataLayer &layer : layers_to_write) { - switch (layer.type) { - case CD_MDEFORMVERT: - BKE_defvert_blend_write(writer, count, static_cast(layer.data)); - break; - case CD_MDISPS: - write_mdisps( - writer, count, static_cast(layer.data), layer.flag & CD_FLAG_EXTERNAL); - break; - case CD_PAINT_MASK: - BLO_write_raw(writer, sizeof(float) * count, static_cast(layer.data)); - break; - case CD_SCULPT_FACE_SETS: - BLO_write_raw(writer, sizeof(float) * count, static_cast(layer.data)); - break; - case CD_GRID_PAINT_MASK: - write_grid_paint_mask(writer, count, static_cast(layer.data)); - break; - case CD_FACEMAP: - BLO_write_raw(writer, sizeof(int) * count, static_cast(layer.data)); - break; - case CD_PROP_BOOL: - BLO_write_raw(writer, sizeof(bool) * count, static_cast(layer.data)); - break; - case CD_CREASE: - BLO_write_raw(writer, sizeof(float) * count, static_cast(layer.data)); - break; - default: { - const char *structname; - int structnum; - CustomData_file_write_info(eCustomDataType(layer.type), &structname, &structnum); - if (structnum) { - int datasize = structnum * count; - BLO_write_struct_array_by_name(writer, structname, datasize, layer.data); - } - else if (!BLO_write_is_undo(writer)) { /* Do not warn on undo. */ - printf("%s error: layer '%s':%d - can't be written to file\n", - __func__, - structname, - layer.type); + BLO_write_shared(writer, layer.data, layer.sharing_info, [&]() { + switch (layer.type) { + case CD_MDEFORMVERT: + BKE_defvert_blend_write(writer, count, static_cast(layer.data)); + break; + case CD_MDISPS: + write_mdisps(writer, + count, + static_cast(layer.data), + layer.flag & CD_FLAG_EXTERNAL); + break; + case CD_PAINT_MASK: + BLO_write_raw(writer, sizeof(float) * count, static_cast(layer.data)); + break; + case CD_SCULPT_FACE_SETS: + BLO_write_raw(writer, sizeof(float) * count, static_cast(layer.data)); + break; + case CD_GRID_PAINT_MASK: + write_grid_paint_mask(writer, count, static_cast(layer.data)); + break; + case CD_FACEMAP: + BLO_write_raw(writer, sizeof(int) * count, static_cast(layer.data)); + break; + case CD_PROP_BOOL: + BLO_write_raw(writer, sizeof(bool) * count, static_cast(layer.data)); + break; + case CD_CREASE: + BLO_write_raw(writer, sizeof(float) * count, static_cast(layer.data)); + break; + default: { + const char *structname; + int structnum; + CustomData_file_write_info(eCustomDataType(layer.type), &structname, &structnum); + if (structnum) { + int datasize = structnum * count; + BLO_write_struct_array_by_name(writer, structname, datasize, layer.data); + } + else if (!BLO_write_is_undo(writer)) { /* Do not warn on undo. */ + printf("%s error: layer '%s':%d - can't be written to file\n", + __func__, + structname, + layer.type); + } } } - } + }); } if (data->external) { @@ -5267,31 +5271,34 @@ void CustomData_blend_read(BlendDataReader *reader, CustomData *data, const int layer->sharing_info = nullptr; if (CustomData_verify_versions(data, i)) { - BLO_read_data_address(reader, &layer->data); - if (layer->data != nullptr) { + layer->sharing_info = BLO_read_shared(reader, &layer->data, [&]() { + BLO_read_data_address(reader, &layer->data); + if (CustomData_layer_ensure_data_exists(layer, count)) { + /* Under normal operations, this shouldn't happen, but... + * For a CD_PROP_BOOL example, see #84935. + * For a CD_MLOOPUV example, see #90620. */ + CLOG_WARN( + &LOG, + "Allocated custom data layer that was not saved correctly for layer->type = %d.", + layer->type); + } + + if (layer->type == CD_MDISPS) { + blend_read_mdisps( + reader, count, static_cast(layer->data), layer->flag & CD_FLAG_EXTERNAL); + } + else if (layer->type == CD_GRID_PAINT_MASK) { + blend_read_paint_mask(reader, count, static_cast(layer->data)); + } + else if (layer->type == CD_MDEFORMVERT) { + BKE_defvert_blend_read(reader, count, static_cast(layer->data)); + } + }); + if (layer->data != nullptr && layer->sharing_info == nullptr) { /* Make layer data shareable. */ layer->sharing_info = make_implicit_sharing_info_for_layer( eCustomDataType(layer->type), layer->data, count); } - if (CustomData_layer_ensure_data_exists(layer, count)) { - /* Under normal operations, this shouldn't happen, but... - * For a CD_PROP_BOOL example, see #84935. - * For a CD_MLOOPUV example, see #90620. */ - CLOG_WARN(&LOG, - "Allocated custom data layer that was not saved correctly for layer->type = %d.", - layer->type); - } - - if (layer->type == CD_MDISPS) { - blend_read_mdisps( - reader, count, static_cast(layer->data), layer->flag & CD_FLAG_EXTERNAL); - } - else if (layer->type == CD_GRID_PAINT_MASK) { - blend_read_paint_mask(reader, count, static_cast(layer->data)); - } - else if (layer->type == CD_MDEFORMVERT) { - BKE_defvert_blend_read(reader, count, static_cast(layer->data)); - } i++; } } diff --git a/source/blender/blenloader/BLO_read_write.h b/source/blender/blenloader/BLO_read_write.h index f1685d079e4..6aff34a1028 100644 --- a/source/blender/blenloader/BLO_read_write.h +++ b/source/blender/blenloader/BLO_read_write.h @@ -31,6 +31,12 @@ #include "DNA_windowmanager_types.h" /* for eReportType */ +#include "BLI_implicit_sharing.h" + +#ifdef __cplusplus +# include "BLI_function_ref.hh" +#endif + #ifdef __cplusplus extern "C" { #endif @@ -175,6 +181,13 @@ void BLO_write_string(BlendWriter *writer, const char *data_ptr); /* Misc. */ +#ifdef __cplusplus +void BLO_write_shared(BlendWriter *writer, + const void *data, + const ImplicitSharingInfoHandle *sharing_info, + blender::FunctionRef write_cb); +#endif + /** * Sometimes different data is written depending on whether the file is saved to disk or used for * undo. This function returns true when the current file-writing is done for undo. @@ -238,6 +251,12 @@ void BLO_read_pointer_array(BlendDataReader *reader, void **ptr_p); /* Misc. */ +#ifdef __cplusplus +const ImplicitSharingInfoHandle *BLO_read_shared(BlendDataReader *reader, + void **data_ptr, + blender::FunctionRef read_cb); +#endif + int BLO_read_fileversion_get(BlendDataReader *reader); bool BLO_read_requires_endian_switch(BlendDataReader *reader); bool BLO_read_data_is_undo(BlendDataReader *reader); diff --git a/source/blender/blenloader/intern/readfile.cc b/source/blender/blenloader/intern/readfile.cc index a9353e8ba13..6eef85441fa 100644 --- a/source/blender/blenloader/intern/readfile.cc +++ b/source/blender/blenloader/intern/readfile.cc @@ -5150,6 +5150,15 @@ void BLO_read_pointer_array(BlendDataReader *reader, void **ptr_p) *ptr_p = final_array; } +const ImplicitSharingInfoHandle *BLO_read_shared(BlendDataReader *reader, + void **data_ptr, + blender::FunctionRef read_cb) +{ + UNUSED_VARS(reader, data_ptr); + read_cb(); + return nullptr; +} + bool BLO_read_data_is_undo(BlendDataReader *reader) { return (reader->fd->flags & FD_FLAGS_IS_MEMFILE); diff --git a/source/blender/blenloader/intern/writefile.cc b/source/blender/blenloader/intern/writefile.cc index ca8c9f75b44..1dcb1ad7fd9 100644 --- a/source/blender/blenloader/intern/writefile.cc +++ b/source/blender/blenloader/intern/writefile.cc @@ -1692,6 +1692,15 @@ void BLO_write_string(BlendWriter *writer, const char *data_ptr) } } +void BLO_write_shared(BlendWriter *writer, + const void *data, + const ImplicitSharingInfoHandle *sharing_info, + blender::FunctionRef write_cb) +{ + UNUSED_VARS(writer, data, sharing_info); + write_cb(); +} + bool BLO_write_is_undo(BlendWriter *writer) { return writer->wd->use_memfile; -- 2.30.2 From 508a7cf8ff3ff48bcf909eb9975aac49abeab437 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Tue, 11 Apr 2023 11:44:28 +0200 Subject: [PATCH 22/46] undo integration --- source/blender/blenloader/BLO_read_write.h | 11 +++++----- source/blender/blenloader/BLO_undofile.h | 15 ++++++++++++++ source/blender/blenloader/intern/readfile.cc | 20 +++++++++++++++---- source/blender/blenloader/intern/undofile.cc | 9 +++++++++ source/blender/blenloader/intern/writefile.cc | 16 ++++++++++++++- 5 files changed, 60 insertions(+), 11 deletions(-) diff --git a/source/blender/blenloader/BLO_read_write.h b/source/blender/blenloader/BLO_read_write.h index 6aff34a1028..264defb33c0 100644 --- a/source/blender/blenloader/BLO_read_write.h +++ b/source/blender/blenloader/BLO_read_write.h @@ -31,10 +31,9 @@ #include "DNA_windowmanager_types.h" /* for eReportType */ -#include "BLI_implicit_sharing.h" - #ifdef __cplusplus # include "BLI_function_ref.hh" +# include "BLI_implicit_sharing.hh" #endif #ifdef __cplusplus @@ -184,7 +183,7 @@ void BLO_write_string(BlendWriter *writer, const char *data_ptr); #ifdef __cplusplus void BLO_write_shared(BlendWriter *writer, const void *data, - const ImplicitSharingInfoHandle *sharing_info, + const blender::ImplicitSharingInfo *sharing_info, blender::FunctionRef write_cb); #endif @@ -252,9 +251,9 @@ void BLO_read_pointer_array(BlendDataReader *reader, void **ptr_p); /* Misc. */ #ifdef __cplusplus -const ImplicitSharingInfoHandle *BLO_read_shared(BlendDataReader *reader, - void **data_ptr, - blender::FunctionRef read_cb); +const blender::ImplicitSharingInfo *BLO_read_shared(BlendDataReader *reader, + void **data_ptr, + blender::FunctionRef read_cb); #endif int BLO_read_fileversion_get(BlendDataReader *reader); diff --git a/source/blender/blenloader/BLO_undofile.h b/source/blender/blenloader/BLO_undofile.h index 3fba3e2f301..acdd48b83ee 100644 --- a/source/blender/blenloader/BLO_undofile.h +++ b/source/blender/blenloader/BLO_undofile.h @@ -13,6 +13,20 @@ struct GHash; struct Scene; +#ifdef __cplusplus +# include "BLI_implicit_sharing.hh" +# include "BLI_map.hh" + +struct MemFileSharedStorage { + blender::Map map; + + ~MemFileSharedStorage(); +}; + +#else +typedef struct MemFileSharedStorage MemFileSharedStorage; +#endif + typedef struct { void *next, *prev; const char *buf; @@ -32,6 +46,7 @@ typedef struct { typedef struct MemFile { ListBase chunks; size_t size; + MemFileSharedStorage *shared_storage; } MemFile; typedef struct MemFileWriteData { diff --git a/source/blender/blenloader/intern/readfile.cc b/source/blender/blenloader/intern/readfile.cc index 6eef85441fa..07502e874e4 100644 --- a/source/blender/blenloader/intern/readfile.cc +++ b/source/blender/blenloader/intern/readfile.cc @@ -5150,11 +5150,23 @@ void BLO_read_pointer_array(BlendDataReader *reader, void **ptr_p) *ptr_p = final_array; } -const ImplicitSharingInfoHandle *BLO_read_shared(BlendDataReader *reader, - void **data_ptr, - blender::FunctionRef read_cb) +const blender::ImplicitSharingInfo *BLO_read_shared(BlendDataReader *reader, + void **data_ptr, + blender::FunctionRef read_cb) { - UNUSED_VARS(reader, data_ptr); + if (BLO_read_data_is_undo(reader)) { + if (reader->fd->flags & FD_FLAGS_IS_MEMFILE) { + UndoReader *undo_reader = reinterpret_cast(reader->fd->file); + MemFile &memfile = *undo_reader->memfile; + if (memfile.shared_storage) { + if (const blender::ImplicitSharingInfo *sharing_info = + memfile.shared_storage->map.lookup_default(*data_ptr, nullptr)) { + sharing_info->add_user(); + return sharing_info; + } + } + } + } read_cb(); return nullptr; } diff --git a/source/blender/blenloader/intern/undofile.cc b/source/blender/blenloader/intern/undofile.cc index 43643f25eb2..86d9d4388eb 100644 --- a/source/blender/blenloader/intern/undofile.cc +++ b/source/blender/blenloader/intern/undofile.cc @@ -48,9 +48,18 @@ void BLO_memfile_free(MemFile *memfile) } MEM_freeN(chunk); } + MEM_delete(memfile->shared_storage); + memfile->shared_storage = nullptr; memfile->size = 0; } +MemFileSharedStorage::~MemFileSharedStorage() +{ + for (const blender::ImplicitSharingInfo *sharing_info : map.values()) { + sharing_info->remove_user_and_delete_if_last(); + } +} + void BLO_memfile_merge(MemFile *first, MemFile *second) { /* We use this mapping to store the memory buffers from second memfile chunks which are not owned diff --git a/source/blender/blenloader/intern/writefile.cc b/source/blender/blenloader/intern/writefile.cc index 1dcb1ad7fd9..0e0fcad8539 100644 --- a/source/blender/blenloader/intern/writefile.cc +++ b/source/blender/blenloader/intern/writefile.cc @@ -1697,7 +1697,21 @@ void BLO_write_shared(BlendWriter *writer, const ImplicitSharingInfoHandle *sharing_info, blender::FunctionRef write_cb) { - UNUSED_VARS(writer, data, sharing_info); + if (data == nullptr) { + return; + } + if (BLO_write_is_undo(writer)) { + if (sharing_info != nullptr) { + MemFile &memfile = *writer->wd->mem.written_memfile; + if (memfile.shared_storage == nullptr) { + memfile.shared_storage = MEM_new(__func__); + } + if (memfile.shared_storage->map.add(data, sharing_info)) { + sharing_info->add_user(); + return; + } + } + } write_cb(); } -- 2.30.2 From 78aa83e23555ce0e124a8dc5c1cc800892cbf947 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Tue, 11 Apr 2023 16:17:41 +0200 Subject: [PATCH 23/46] add clarifying comment in BLI_implicit_sharing.h --- source/blender/blenlib/BLI_implicit_sharing.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/blender/blenlib/BLI_implicit_sharing.h b/source/blender/blenlib/BLI_implicit_sharing.h index c3dcc26b0d0..37ddb005bf3 100644 --- a/source/blender/blenlib/BLI_implicit_sharing.h +++ b/source/blender/blenlib/BLI_implicit_sharing.h @@ -4,6 +4,8 @@ /** \file * \ingroup bli + * + * This file only exists to forward declare `blender::ImplicitSharingInfo` in C code. */ #ifdef __cplusplus -- 2.30.2 From 0fd27ddb7dcaa8c9ef8736808e91f677f8d21f75 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Thu, 20 Apr 2023 22:44:06 +0200 Subject: [PATCH 24/46] remove ability to store MemFile on disk --- source/blender/blenloader/BLO_undofile.h | 6 -- source/blender/blenloader/intern/undofile.cc | 55 ------------------- .../blender/windowmanager/intern/wm_files.cc | 29 +++------- .../windowmanager/intern/wm_init_exit.cc | 26 +++------ source/creator/creator_signals.c | 28 ---------- 5 files changed, 17 insertions(+), 127 deletions(-) diff --git a/source/blender/blenloader/BLO_undofile.h b/source/blender/blenloader/BLO_undofile.h index acdd48b83ee..5bd18f81e59 100644 --- a/source/blender/blenloader/BLO_undofile.h +++ b/source/blender/blenloader/BLO_undofile.h @@ -112,12 +112,6 @@ extern void BLO_memfile_clear_future(MemFile *memfile); extern struct Main *BLO_memfile_main_get(struct MemFile *memfile, struct Main *bmain, struct Scene **r_scene); -/** - * Saves .blend using undo buffer. - * - * \return success. - */ -extern bool BLO_memfile_write_file(struct MemFile *memfile, const char *filepath); FileReader *BLO_memfile_new_filereader(MemFile *memfile, int undo_direction); diff --git a/source/blender/blenloader/intern/undofile.cc b/source/blender/blenloader/intern/undofile.cc index 86d9d4388eb..8fef1802daa 100644 --- a/source/blender/blenloader/intern/undofile.cc +++ b/source/blender/blenloader/intern/undofile.cc @@ -208,61 +208,6 @@ struct Main *BLO_memfile_main_get(struct MemFile *memfile, return bmain_undo; } -bool BLO_memfile_write_file(struct MemFile *memfile, const char *filepath) -{ - MemFileChunk *chunk; - int file, oflags; - - /* NOTE: This is currently used for autosave and 'quit.blend', - * where _not_ following symlinks is OK, - * however if this is ever executed explicitly by the user, - * we may want to allow writing to symlinks. - */ - - oflags = O_BINARY | O_WRONLY | O_CREAT | O_TRUNC; -#ifdef O_NOFOLLOW - /* use O_NOFOLLOW to avoid writing to a symlink - use 'O_EXCL' (CVE-2008-1103) */ - oflags |= O_NOFOLLOW; -#else - /* TODO(sergey): How to deal with symlinks on windows? */ -# ifndef _MSC_VER -# warning "Symbolic links will be followed on undo save, possibly causing CVE-2008-1103" -# endif -#endif - file = BLI_open(filepath, oflags, 0666); - - if (file == -1) { - fprintf(stderr, - "Unable to save '%s': %s\n", - filepath, - errno ? strerror(errno) : "Unknown error opening file"); - return false; - } - - for (chunk = static_cast(memfile->chunks.first); chunk; - chunk = static_cast(chunk->next)) { -#ifdef _WIN32 - if (size_t(write(file, chunk->buf, uint(chunk->size))) != chunk->size) -#else - if (size_t(write(file, chunk->buf, chunk->size)) != chunk->size) -#endif - { - break; - } - } - - close(file); - - if (chunk) { - fprintf(stderr, - "Unable to save '%s': %s\n", - filepath, - errno ? strerror(errno) : "Unknown error writing file"); - return false; - } - return true; -} - static ssize_t undo_read(FileReader *reader, void *buffer, size_t size) { UndoReader *undo = (UndoReader *)reader; diff --git a/source/blender/windowmanager/intern/wm_files.cc b/source/blender/windowmanager/intern/wm_files.cc index 0ca6d2372a9..357fc338c70 100644 --- a/source/blender/windowmanager/intern/wm_files.cc +++ b/source/blender/windowmanager/intern/wm_files.cc @@ -2011,33 +2011,20 @@ static void wm_autosave_location(char filepath[FILE_MAX]) BLI_path_join(filepath, FILE_MAX, tempdir_base, filename); } -static void wm_autosave_write(Main *bmain, wmWindowManager *wm) +static void wm_autosave_write(Main *bmain) { char filepath[FILE_MAX]; wm_autosave_location(filepath); - /* Fast save of last undo-buffer, now with UI. */ - const bool use_memfile = (U.uiflag & USER_GLOBALUNDO) != 0; - MemFile *memfile = use_memfile ? ED_undosys_stack_memfile_get_active(wm->undo_stack) : nullptr; - if (memfile != nullptr) { - BLO_memfile_write_file(memfile, filepath); - } - else { - if (use_memfile) { - /* This is very unlikely, alert developers of this unexpected case. */ - CLOG_WARN(&LOG, "undo-data not found for writing, fallback to regular file write!"); - } + /* Save as regular blend file with recovery information. */ + const int fileflags = (G.fileflags & ~G_FILE_COMPRESS) | G_FILE_RECOVER_WRITE; - /* Save as regular blend file with recovery information. */ - const int fileflags = (G.fileflags & ~G_FILE_COMPRESS) | G_FILE_RECOVER_WRITE; + ED_editors_flush_edits(bmain); - ED_editors_flush_edits(bmain); - - /* Error reporting into console. */ - BlendFileWriteParams params{}; - BLO_write_file(bmain, filepath, fileflags, ¶ms, nullptr); - } + /* Error reporting into console. */ + BlendFileWriteParams params{}; + BLO_write_file(bmain, filepath, fileflags, ¶ms, nullptr); } static void wm_autosave_timer_begin_ex(wmWindowManager *wm, double timestep) @@ -2085,7 +2072,7 @@ void wm_autosave_timer(Main *bmain, wmWindowManager *wm, wmTimer * /*wt*/) } } - wm_autosave_write(bmain, wm); + wm_autosave_write(bmain); /* Restart the timer after file write, just in case file write takes a long time. */ wm_autosave_timer_begin(wm); diff --git a/source/blender/windowmanager/intern/wm_init_exit.cc b/source/blender/windowmanager/intern/wm_init_exit.cc index 764177fcc18..b425b4d8c64 100644 --- a/source/blender/windowmanager/intern/wm_init_exit.cc +++ b/source/blender/windowmanager/intern/wm_init_exit.cc @@ -481,26 +481,18 @@ void WM_exit_ex(bContext *C, const bool do_python) /* NOTE: same code copied in `wm_files.cc`. */ if (C && wm) { if (!G.background) { - struct MemFile *undo_memfile = wm->undo_stack ? - ED_undosys_stack_memfile_get_active(wm->undo_stack) : - nullptr; - if (undo_memfile != nullptr) { - /* save the undo state as quit.blend */ - Main *bmain = CTX_data_main(C); - char filepath[FILE_MAX]; - bool has_edited; - const int fileflags = G.fileflags & ~G_FILE_COMPRESS; + /* Save quit.blend. */ + Main *bmain = CTX_data_main(C); + char filepath[FILE_MAX]; + const int fileflags = G.fileflags & ~G_FILE_COMPRESS; - BLI_path_join(filepath, sizeof(filepath), BKE_tempdir_base(), BLENDER_QUIT_FILE); + BLI_path_join(filepath, sizeof(filepath), BKE_tempdir_base(), BLENDER_QUIT_FILE); - has_edited = ED_editors_flush_edits(bmain); + ED_editors_flush_edits(bmain); - BlendFileWriteParams blend_file_write_params{}; - if ((has_edited && - BLO_write_file(bmain, filepath, fileflags, &blend_file_write_params, nullptr)) || - BLO_memfile_write_file(undo_memfile, filepath)) { - printf("Saved session recovery to \"%s\"\n", filepath); - } + BlendFileWriteParams blend_file_write_params{}; + if (BLO_write_file(bmain, filepath, fileflags, &blend_file_write_params, nullptr)) { + printf("Saved session recovery to \"%s\"\n", filepath); } } diff --git a/source/creator/creator_signals.c b/source/creator/creator_signals.c index c733ee617cb..23d82a448e5 100644 --- a/source/creator/creator_signals.c +++ b/source/creator/creator_signals.c @@ -51,12 +51,6 @@ # include "creator_intern.h" /* own include */ -// #define USE_WRITE_CRASH_BLEND -# ifdef USE_WRITE_CRASH_BLEND -# include "BKE_undo_system.h" -# include "BLO_undofile.h" -# endif - /* set breakpoints here when running in debug mode, useful to catch floating point errors */ # if defined(__linux__) || defined(_WIN32) || defined(OSX_SSE_FPE) static void sig_handle_fpe(int UNUSED(sig)) @@ -94,28 +88,6 @@ static void sig_handle_crash(int signum) wmWindowManager *wm = G_MAIN ? G_MAIN->wm.first : NULL; -# ifdef USE_WRITE_CRASH_BLEND - if (wm && wm->undo_stack) { - struct MemFile *memfile = BKE_undosys_stack_memfile_get_active(wm->undo_stack); - if (memfile) { - char fname[FILE_MAX]; - - if (!(G_MAIN && G_MAIN->filepath[0])) { - BLI_path_join(fname, sizeof(fname), BKE_tempdir_base(), "crash.blend"); - } - else { - STRNCPY(fname, G_MAIN->filepath); - BLI_path_extension_replace(fname, sizeof(fname), ".crash.blend"); - } - - printf("Writing: %s\n", fname); - fflush(stdout); - - BLO_memfile_write_file(memfile, fname); - } - } -# endif - FILE *fp; char header[512]; -- 2.30.2 From dfcb6ab68e5494f9cc9ed50934d6b13677114ce4 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Thu, 20 Apr 2023 23:10:14 +0200 Subject: [PATCH 25/46] add comments --- source/blender/blenloader/BLO_undofile.h | 7 +++++++ source/blender/blenloader/intern/readfile.cc | 2 ++ source/blender/blenloader/intern/undofile.cc | 2 ++ source/blender/blenloader/intern/writefile.cc | 1 + 4 files changed, 12 insertions(+) diff --git a/source/blender/blenloader/BLO_undofile.h b/source/blender/blenloader/BLO_undofile.h index 5bd18f81e59..182bc4d2f30 100644 --- a/source/blender/blenloader/BLO_undofile.h +++ b/source/blender/blenloader/BLO_undofile.h @@ -18,6 +18,9 @@ struct Scene; # include "BLI_map.hh" struct MemFileSharedStorage { + /** + * Maps the data pointer to the sharing info that it is owned by. + */ blender::Map map; ~MemFileSharedStorage(); @@ -46,6 +49,10 @@ typedef struct { typedef struct MemFile { ListBase chunks; size_t size; + /** + * Some data is not serialized into a new buffer because the undo-step can take ownership of it + * without making a copy. This is faster and requires less memory. + */ MemFileSharedStorage *shared_storage; } MemFile; diff --git a/source/blender/blenloader/intern/readfile.cc b/source/blender/blenloader/intern/readfile.cc index 82dc32e780d..89deb84625d 100644 --- a/source/blender/blenloader/intern/readfile.cc +++ b/source/blender/blenloader/intern/readfile.cc @@ -5142,8 +5142,10 @@ const blender::ImplicitSharingInfo *BLO_read_shared(BlendDataReader *reader, UndoReader *undo_reader = reinterpret_cast(reader->fd->file); MemFile &memfile = *undo_reader->memfile; if (memfile.shared_storage) { + /* Check if the data was saved with sharing-info. */ if (const blender::ImplicitSharingInfo *sharing_info = memfile.shared_storage->map.lookup_default(*data_ptr, nullptr)) { + /* Add a new owner of the data that is passed to the caller. */ sharing_info->add_user(); return sharing_info; } diff --git a/source/blender/blenloader/intern/undofile.cc b/source/blender/blenloader/intern/undofile.cc index 8fef1802daa..aae1ea1576b 100644 --- a/source/blender/blenloader/intern/undofile.cc +++ b/source/blender/blenloader/intern/undofile.cc @@ -56,6 +56,8 @@ void BLO_memfile_free(MemFile *memfile) MemFileSharedStorage::~MemFileSharedStorage() { for (const blender::ImplicitSharingInfo *sharing_info : map.values()) { + /* Removing the user makes sure that the shared data is freed when the undo step was the last + * owner of it. */ sharing_info->remove_user_and_delete_if_last(); } } diff --git a/source/blender/blenloader/intern/writefile.cc b/source/blender/blenloader/intern/writefile.cc index 37327c45866..1f76d0ea387 100644 --- a/source/blender/blenloader/intern/writefile.cc +++ b/source/blender/blenloader/intern/writefile.cc @@ -1758,6 +1758,7 @@ void BLO_write_shared(BlendWriter *writer, memfile.shared_storage = MEM_new(__func__); } if (memfile.shared_storage->map.add(data, sharing_info)) { + /* The undo-step takes (shared) ownership of the data, which also makes it immutable. */ sharing_info->add_user(); return; } -- 2.30.2 From 2019fe37de083f6c2061c7cdef383d73308a783b Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Thu, 20 Apr 2023 23:23:21 +0200 Subject: [PATCH 26/46] progress --- source/blender/blenkernel/intern/customdata.cc | 8 +++----- source/blender/blenkernel/intern/mesh.cc | 14 ++++++++++---- source/blender/blenloader/BLO_read_write.h | 7 ++++--- source/blender/blenloader/intern/readfile.cc | 10 +++++----- 4 files changed, 22 insertions(+), 17 deletions(-) diff --git a/source/blender/blenkernel/intern/customdata.cc b/source/blender/blenkernel/intern/customdata.cc index 4e47b73df73..e8c38f27091 100644 --- a/source/blender/blenkernel/intern/customdata.cc +++ b/source/blender/blenkernel/intern/customdata.cc @@ -5293,12 +5293,10 @@ void CustomData_blend_read(BlendDataReader *reader, CustomData *data, const int else if (layer->type == CD_MDEFORMVERT) { BKE_defvert_blend_read(reader, count, static_cast(layer->data)); } + return layer->data ? make_implicit_sharing_info_for_layer( + eCustomDataType(layer->type), layer->data, count) : + nullptr; }); - if (layer->data != nullptr && layer->sharing_info == nullptr) { - /* Make layer data shareable. */ - layer->sharing_info = make_implicit_sharing_info_for_layer( - eCustomDataType(layer->type), layer->data, count); - } i++; } } diff --git a/source/blender/blenkernel/intern/mesh.cc b/source/blender/blenkernel/intern/mesh.cc index f7c032e2867..3d3dc77eba8 100644 --- a/source/blender/blenkernel/intern/mesh.cc +++ b/source/blender/blenkernel/intern/mesh.cc @@ -318,6 +318,7 @@ static void mesh_blend_write(BlendWriter *writer, ID *id, const void *id_address } } + const blender::bke::MeshRuntime *mesh_runtime = mesh->runtime; mesh->runtime = nullptr; BLO_write_id_struct(writer, Mesh, id_address, &mesh->id); @@ -347,7 +348,10 @@ static void mesh_blend_write(BlendWriter *writer, ID *id, const void *id_address writer, &mesh->pdata, poly_layers, mesh->totpoly, CD_MASK_MESH.pmask, &mesh->id); if (mesh->poly_offset_indices) { - BLO_write_int32_array(writer, mesh->totpoly + 1, mesh->poly_offset_indices); + BLO_write_shared( + writer, mesh->poly_offset_indices, mesh_runtime->poly_offsets_sharing_info, [&]() { + BLO_write_int32_array(writer, mesh->totpoly + 1, mesh->poly_offset_indices); + }); } } @@ -393,9 +397,11 @@ static void mesh_blend_read_data(BlendDataReader *reader, ID *id) mesh->runtime = new blender::bke::MeshRuntime(); if (mesh->poly_offset_indices) { - BLO_read_int32_array(reader, mesh->totpoly + 1, &mesh->poly_offset_indices); - mesh->runtime->poly_offsets_sharing_info = blender::implicit_sharing::info_for_mem_free( - mesh->poly_offset_indices); + mesh->runtime->poly_offsets_sharing_info = (blender::ImplicitSharingInfo *)BLO_read_shared( + reader, (void **)&mesh->poly_offset_indices, [&]() { + BLO_read_int32_array(reader, mesh->totpoly + 1, &mesh->poly_offset_indices); + return blender::implicit_sharing::info_for_mem_free(mesh->poly_offset_indices); + }); } /* happens with old files */ diff --git a/source/blender/blenloader/BLO_read_write.h b/source/blender/blenloader/BLO_read_write.h index 34b438d65c2..781df0c63af 100644 --- a/source/blender/blenloader/BLO_read_write.h +++ b/source/blender/blenloader/BLO_read_write.h @@ -268,9 +268,10 @@ void BLO_read_pointer_array(BlendDataReader *reader, void **ptr_p); /* Misc. */ #ifdef __cplusplus -const blender::ImplicitSharingInfo *BLO_read_shared(BlendDataReader *reader, - void **data_ptr, - blender::FunctionRef read_cb); +const blender::ImplicitSharingInfo *BLO_read_shared( + BlendDataReader *reader, + void **data_ptr, + blender::FunctionRef read_cb); #endif int BLO_read_fileversion_get(BlendDataReader *reader); diff --git a/source/blender/blenloader/intern/readfile.cc b/source/blender/blenloader/intern/readfile.cc index 89deb84625d..74375909074 100644 --- a/source/blender/blenloader/intern/readfile.cc +++ b/source/blender/blenloader/intern/readfile.cc @@ -5133,9 +5133,10 @@ void BLO_read_pointer_array(BlendDataReader *reader, void **ptr_p) *ptr_p = final_array; } -const blender::ImplicitSharingInfo *BLO_read_shared(BlendDataReader *reader, - void **data_ptr, - blender::FunctionRef read_cb) +const blender::ImplicitSharingInfo *BLO_read_shared( + BlendDataReader *reader, + void **data_ptr, + blender::FunctionRef read_cb) { if (BLO_read_data_is_undo(reader)) { if (reader->fd->flags & FD_FLAGS_IS_MEMFILE) { @@ -5152,8 +5153,7 @@ const blender::ImplicitSharingInfo *BLO_read_shared(BlendDataReader *reader, } } } - read_cb(); - return nullptr; + return read_cb(); } bool BLO_read_data_is_undo(BlendDataReader *reader) -- 2.30.2 From 60e8b155fd4aa132d87f06a34c6faa553b9baefc Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Thu, 20 Apr 2023 23:39:17 +0200 Subject: [PATCH 27/46] cleanup --- .../blender/blenkernel/intern/curves_geometry.cc | 15 +++++++++++---- source/blender/blenkernel/intern/mesh.cc | 2 +- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/source/blender/blenkernel/intern/curves_geometry.cc b/source/blender/blenkernel/intern/curves_geometry.cc index 637fdc78d95..a53c0823666 100644 --- a/source/blender/blenkernel/intern/curves_geometry.cc +++ b/source/blender/blenkernel/intern/curves_geometry.cc @@ -1622,9 +1622,11 @@ void CurvesGeometry::blend_read(BlendDataReader &reader) CustomData_blend_read(&reader, &this->curve_data, this->curve_num); if (this->curve_offsets) { - BLO_read_int32_array(&reader, this->curve_num + 1, &this->curve_offsets); - this->runtime->curve_offsets_sharing_info = implicit_sharing::info_for_mem_free( - this->curve_offsets); + this->runtime->curve_offsets_sharing_info = BLO_read_shared( + &reader, (void **)&this->curve_offsets, [&]() { + BLO_read_int32_array(&reader, this->curve_num + 1, &this->curve_offsets); + return implicit_sharing::info_for_mem_free(this->curve_offsets); + }); } /* Recalculate curve type count cache that isn't saved in files. */ @@ -1643,7 +1645,12 @@ void CurvesGeometry::blend_write(BlendWriter &writer, ID &id) CustomData_blend_write( &writer, &this->curve_data, curve_layers, this->curve_num, CD_MASK_ALL, &id); - BLO_write_int32_array(&writer, this->curve_num + 1, this->curve_offsets); + if (this->curve_offsets) { + BLO_write_shared( + &writer, this->curve_offsets, this->runtime->curve_offsets_sharing_info, [&]() { + BLO_write_int32_array(&writer, this->curve_num + 1, this->curve_offsets); + }); + } } /** \} */ diff --git a/source/blender/blenkernel/intern/mesh.cc b/source/blender/blenkernel/intern/mesh.cc index 3d3dc77eba8..42688a2d63f 100644 --- a/source/blender/blenkernel/intern/mesh.cc +++ b/source/blender/blenkernel/intern/mesh.cc @@ -397,7 +397,7 @@ static void mesh_blend_read_data(BlendDataReader *reader, ID *id) mesh->runtime = new blender::bke::MeshRuntime(); if (mesh->poly_offset_indices) { - mesh->runtime->poly_offsets_sharing_info = (blender::ImplicitSharingInfo *)BLO_read_shared( + mesh->runtime->poly_offsets_sharing_info = BLO_read_shared( reader, (void **)&mesh->poly_offset_indices, [&]() { BLO_read_int32_array(reader, mesh->totpoly + 1, &mesh->poly_offset_indices); return blender::implicit_sharing::info_for_mem_free(mesh->poly_offset_indices); -- 2.30.2 From ca4cd009460bd6597d25bd1a78531b833cdb9f07 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Thu, 20 Apr 2023 23:45:26 +0200 Subject: [PATCH 28/46] cleanup --- source/blender/blenkernel/intern/curves_geometry.cc | 2 +- source/blender/blenkernel/intern/mesh.cc | 2 +- source/blender/blenloader/BLO_read_write.h | 4 +++- source/blender/blenloader/intern/readfile.cc | 2 +- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/source/blender/blenkernel/intern/curves_geometry.cc b/source/blender/blenkernel/intern/curves_geometry.cc index a53c0823666..2228b1704d2 100644 --- a/source/blender/blenkernel/intern/curves_geometry.cc +++ b/source/blender/blenkernel/intern/curves_geometry.cc @@ -1623,7 +1623,7 @@ void CurvesGeometry::blend_read(BlendDataReader &reader) if (this->curve_offsets) { this->runtime->curve_offsets_sharing_info = BLO_read_shared( - &reader, (void **)&this->curve_offsets, [&]() { + &reader, &this->curve_offsets, [&]() { BLO_read_int32_array(&reader, this->curve_num + 1, &this->curve_offsets); return implicit_sharing::info_for_mem_free(this->curve_offsets); }); diff --git a/source/blender/blenkernel/intern/mesh.cc b/source/blender/blenkernel/intern/mesh.cc index 42688a2d63f..c0a8edd821c 100644 --- a/source/blender/blenkernel/intern/mesh.cc +++ b/source/blender/blenkernel/intern/mesh.cc @@ -398,7 +398,7 @@ static void mesh_blend_read_data(BlendDataReader *reader, ID *id) if (mesh->poly_offset_indices) { mesh->runtime->poly_offsets_sharing_info = BLO_read_shared( - reader, (void **)&mesh->poly_offset_indices, [&]() { + reader, &mesh->poly_offset_indices, [&]() { BLO_read_int32_array(reader, mesh->totpoly + 1, &mesh->poly_offset_indices); return blender::implicit_sharing::info_for_mem_free(mesh->poly_offset_indices); }); diff --git a/source/blender/blenloader/BLO_read_write.h b/source/blender/blenloader/BLO_read_write.h index 781df0c63af..8994fc726d2 100644 --- a/source/blender/blenloader/BLO_read_write.h +++ b/source/blender/blenloader/BLO_read_write.h @@ -268,10 +268,12 @@ void BLO_read_pointer_array(BlendDataReader *reader, void **ptr_p); /* Misc. */ #ifdef __cplusplus -const blender::ImplicitSharingInfo *BLO_read_shared( +const blender::ImplicitSharingInfo *BLO_read_shared_impl( BlendDataReader *reader, void **data_ptr, blender::FunctionRef read_cb); +# define BLO_read_shared(reader, ptr_p, read_cb) \ + BLO_read_shared_impl(reader, (void **)ptr_p, read_cb) #endif int BLO_read_fileversion_get(BlendDataReader *reader); diff --git a/source/blender/blenloader/intern/readfile.cc b/source/blender/blenloader/intern/readfile.cc index 74375909074..a67d3795725 100644 --- a/source/blender/blenloader/intern/readfile.cc +++ b/source/blender/blenloader/intern/readfile.cc @@ -5133,7 +5133,7 @@ void BLO_read_pointer_array(BlendDataReader *reader, void **ptr_p) *ptr_p = final_array; } -const blender::ImplicitSharingInfo *BLO_read_shared( +const blender::ImplicitSharingInfo *BLO_read_shared_impl( BlendDataReader *reader, void **data_ptr, blender::FunctionRef read_cb) -- 2.30.2 From 03b5d6c4c9ef24203b307bd96b91caba024f45ca Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Thu, 20 Apr 2023 23:53:55 +0200 Subject: [PATCH 29/46] add comments --- source/blender/blenloader/BLO_read_write.h | 17 +++++++++++++---- source/blender/blenloader/intern/readfile.cc | 4 ++-- source/blender/blenloader/intern/writefile.cc | 4 ++-- 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/source/blender/blenloader/BLO_read_write.h b/source/blender/blenloader/BLO_read_write.h index 8994fc726d2..28561698717 100644 --- a/source/blender/blenloader/BLO_read_write.h +++ b/source/blender/blenloader/BLO_read_write.h @@ -198,10 +198,15 @@ void BLO_write_string(BlendWriter *writer, const char *data_ptr); /* Misc. */ #ifdef __cplusplus +/** + * Check if the data can be written more efficiently by making use of implicit-sharing. If yes, the + * user count of the sharing-info is increased making the data immutable. The provided callback + * should serialize the potentially shared data. It is only called when necessary. + */ void BLO_write_shared(BlendWriter *writer, const void *data, const blender::ImplicitSharingInfo *sharing_info, - blender::FunctionRef write_cb); + blender::FunctionRef write_fn); #endif /** @@ -268,12 +273,16 @@ void BLO_read_pointer_array(BlendDataReader *reader, void **ptr_p); /* Misc. */ #ifdef __cplusplus +/** + * Check if there is any shared data for the given data pointer. If yes, return the existing + * sharing-info. If not, call the provided function to actually read the data now. + */ const blender::ImplicitSharingInfo *BLO_read_shared_impl( BlendDataReader *reader, void **data_ptr, - blender::FunctionRef read_cb); -# define BLO_read_shared(reader, ptr_p, read_cb) \ - BLO_read_shared_impl(reader, (void **)ptr_p, read_cb) + blender::FunctionRef read_fn); +# define BLO_read_shared(reader, ptr_p, read_fn) \ + BLO_read_shared_impl(reader, (void **)ptr_p, read_fn) #endif int BLO_read_fileversion_get(BlendDataReader *reader); diff --git a/source/blender/blenloader/intern/readfile.cc b/source/blender/blenloader/intern/readfile.cc index a67d3795725..a3639770732 100644 --- a/source/blender/blenloader/intern/readfile.cc +++ b/source/blender/blenloader/intern/readfile.cc @@ -5136,7 +5136,7 @@ void BLO_read_pointer_array(BlendDataReader *reader, void **ptr_p) const blender::ImplicitSharingInfo *BLO_read_shared_impl( BlendDataReader *reader, void **data_ptr, - blender::FunctionRef read_cb) + const blender::FunctionRef read_fn) { if (BLO_read_data_is_undo(reader)) { if (reader->fd->flags & FD_FLAGS_IS_MEMFILE) { @@ -5153,7 +5153,7 @@ const blender::ImplicitSharingInfo *BLO_read_shared_impl( } } } - return read_cb(); + return read_fn(); } bool BLO_read_data_is_undo(BlendDataReader *reader) diff --git a/source/blender/blenloader/intern/writefile.cc b/source/blender/blenloader/intern/writefile.cc index 1f76d0ea387..42b7ca3300b 100644 --- a/source/blender/blenloader/intern/writefile.cc +++ b/source/blender/blenloader/intern/writefile.cc @@ -1746,7 +1746,7 @@ void BLO_write_string(BlendWriter *writer, const char *data_ptr) void BLO_write_shared(BlendWriter *writer, const void *data, const ImplicitSharingInfoHandle *sharing_info, - blender::FunctionRef write_cb) + const blender::FunctionRef write_fn) { if (data == nullptr) { return; @@ -1764,7 +1764,7 @@ void BLO_write_shared(BlendWriter *writer, } } } - write_cb(); + write_fn(); } bool BLO_write_is_undo(BlendWriter *writer) -- 2.30.2 From a2e0700867472e5d8100850d1e933cc813c87864 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Fri, 21 Apr 2023 11:18:54 +0200 Subject: [PATCH 30/46] don't auto-save in mesh edit/sculpt mode because it is potentially very slow --- source/blender/windowmanager/intern/wm_files.cc | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/source/blender/windowmanager/intern/wm_files.cc b/source/blender/windowmanager/intern/wm_files.cc index 357fc338c70..b25497a13a6 100644 --- a/source/blender/windowmanager/intern/wm_files.cc +++ b/source/blender/windowmanager/intern/wm_files.cc @@ -2058,20 +2058,32 @@ void wm_autosave_timer(Main *bmain, wmWindowManager *wm, wmTimer * /*wt*/) { wm_autosave_timer_end(wm); + /* Time to wait until the next attempt to autosave if it is disabled right now. */ + const double try_again_time_step = 0.01; + /* If a modal operator is running, don't autosave because we might not be in - * a valid state to save. But try again in 10ms. */ + * a valid state to save. */ LISTBASE_FOREACH (wmWindow *, win, &wm->windows) { LISTBASE_FOREACH (wmEventHandler *, handler_base, &win->modalhandlers) { if (handler_base->type == WM_HANDLER_TYPE_OP) { wmEventHandler_Op *handler = (wmEventHandler_Op *)handler_base; if (handler->op) { - wm_autosave_timer_begin_ex(wm, 0.01); + wm_autosave_timer_begin_ex(wm, try_again_time_step); return; } } } } + LISTBASE_FOREACH (Object *, object, &bmain->objects) { + if (object->type == OB_MESH && object->mode & (OB_MODE_EDIT | OB_MODE_SCULPT)) { + /* Don't autosave in modes that require #ED_editors_flush_edits to be called because this can + * potentially be very slow. */ + wm_autosave_timer_begin_ex(wm, try_again_time_step); + return; + } + } + wm_autosave_write(bmain); /* Restart the timer after file write, just in case file write takes a long time. */ -- 2.30.2 From 5a7187985aaf88a3ce874c6d9a4069f0a2d87bb0 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Fri, 21 Apr 2023 11:36:36 +0200 Subject: [PATCH 31/46] remove unused ED_undosys_stack_memfile_get_active function --- source/blender/editors/include/ED_undo.h | 1 - source/blender/editors/undo/memfile_undo.cc | 19 ------------------- 2 files changed, 20 deletions(-) diff --git a/source/blender/editors/include/ED_undo.h b/source/blender/editors/include/ED_undo.h index 3308391cca4..4526558fd1e 100644 --- a/source/blender/editors/include/ED_undo.h +++ b/source/blender/editors/include/ED_undo.h @@ -111,7 +111,6 @@ void ED_undosys_type_free(void); /* memfile_undo.c */ -struct MemFile *ED_undosys_stack_memfile_get_active(struct UndoStack *ustack); /** * If the last undo step is a memfile one, find the first #MemFileChunk matching given ID * (using its session UUID), and tag it as "changed in the future". diff --git a/source/blender/editors/undo/memfile_undo.cc b/source/blender/editors/undo/memfile_undo.cc index 0df00e5050e..7ceae2945d3 100644 --- a/source/blender/editors/undo/memfile_undo.cc +++ b/source/blender/editors/undo/memfile_undo.cc @@ -348,25 +348,6 @@ void ED_memfile_undosys_type(UndoType *ut) /** \name Utilities * \{ */ -/** - * Ideally we wouldn't need to export global undo internals, - * there are some cases where it's needed though. - */ -static struct MemFile *ed_undosys_step_get_memfile(UndoStep *us_p) -{ - MemFileUndoStep *us = (MemFileUndoStep *)us_p; - return &us->data->memfile; -} - -struct MemFile *ED_undosys_stack_memfile_get_active(UndoStack *ustack) -{ - UndoStep *us = BKE_undosys_stack_active_with_type(ustack, BKE_UNDOSYS_TYPE_MEMFILE); - if (us) { - return ed_undosys_step_get_memfile(us); - } - return nullptr; -} - void ED_undosys_stack_memfile_id_changed_tag(UndoStack *ustack, ID *id) { UndoStep *us = ustack->step_active; -- 2.30.2 From f0533e434c19e5c6f343e22b13c5c8f57c4c6ae9 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Fri, 21 Apr 2023 14:51:35 -0400 Subject: [PATCH 32/46] Avoid the need for a macro and void ** BLO_read_shared doesn't actually read the data itself, so it doesn't need to change its pointer. That's up to the lambda it calls. --- .../blenkernel/intern/curves_geometry.cc | 2 +- .../blender/blenkernel/intern/customdata.cc | 2 +- source/blender/blenkernel/intern/mesh.cc | 2 +- source/blender/blenloader/BLO_read_write.h | 8 ++++---- source/blender/blenloader/intern/readfile.cc | 20 +++++++++---------- .../intern/lazy_function_graph_executor.cc | 2 +- 6 files changed, 17 insertions(+), 19 deletions(-) diff --git a/source/blender/blenkernel/intern/curves_geometry.cc b/source/blender/blenkernel/intern/curves_geometry.cc index 2228b1704d2..3339493c49c 100644 --- a/source/blender/blenkernel/intern/curves_geometry.cc +++ b/source/blender/blenkernel/intern/curves_geometry.cc @@ -1623,7 +1623,7 @@ void CurvesGeometry::blend_read(BlendDataReader &reader) if (this->curve_offsets) { this->runtime->curve_offsets_sharing_info = BLO_read_shared( - &reader, &this->curve_offsets, [&]() { + &reader, this->curve_offsets, [&]() { BLO_read_int32_array(&reader, this->curve_num + 1, &this->curve_offsets); return implicit_sharing::info_for_mem_free(this->curve_offsets); }); diff --git a/source/blender/blenkernel/intern/customdata.cc b/source/blender/blenkernel/intern/customdata.cc index cb2fd71da88..28455daf509 100644 --- a/source/blender/blenkernel/intern/customdata.cc +++ b/source/blender/blenkernel/intern/customdata.cc @@ -5271,7 +5271,7 @@ void CustomData_blend_read(BlendDataReader *reader, CustomData *data, const int layer->sharing_info = nullptr; if (CustomData_verify_versions(data, i)) { - layer->sharing_info = BLO_read_shared(reader, &layer->data, [&]() { + layer->sharing_info = BLO_read_shared(reader, layer->data, [&]() { BLO_read_data_address(reader, &layer->data); if (CustomData_layer_ensure_data_exists(layer, count)) { /* Under normal operations, this shouldn't happen, but... diff --git a/source/blender/blenkernel/intern/mesh.cc b/source/blender/blenkernel/intern/mesh.cc index c0a8edd821c..35f00b03a1d 100644 --- a/source/blender/blenkernel/intern/mesh.cc +++ b/source/blender/blenkernel/intern/mesh.cc @@ -398,7 +398,7 @@ static void mesh_blend_read_data(BlendDataReader *reader, ID *id) if (mesh->poly_offset_indices) { mesh->runtime->poly_offsets_sharing_info = BLO_read_shared( - reader, &mesh->poly_offset_indices, [&]() { + reader, mesh->poly_offset_indices, [&]() { BLO_read_int32_array(reader, mesh->totpoly + 1, &mesh->poly_offset_indices); return blender::implicit_sharing::info_for_mem_free(mesh->poly_offset_indices); }); diff --git a/source/blender/blenloader/BLO_read_write.h b/source/blender/blenloader/BLO_read_write.h index 28561698717..426cbde2ddd 100644 --- a/source/blender/blenloader/BLO_read_write.h +++ b/source/blender/blenloader/BLO_read_write.h @@ -273,16 +273,16 @@ void BLO_read_pointer_array(BlendDataReader *reader, void **ptr_p); /* Misc. */ #ifdef __cplusplus + /** * Check if there is any shared data for the given data pointer. If yes, return the existing * sharing-info. If not, call the provided function to actually read the data now. */ -const blender::ImplicitSharingInfo *BLO_read_shared_impl( +const blender::ImplicitSharingInfo *BLO_read_shared( BlendDataReader *reader, - void **data_ptr, + void *data, blender::FunctionRef read_fn); -# define BLO_read_shared(reader, ptr_p, read_fn) \ - BLO_read_shared_impl(reader, (void **)ptr_p, read_fn) + #endif int BLO_read_fileversion_get(BlendDataReader *reader); diff --git a/source/blender/blenloader/intern/readfile.cc b/source/blender/blenloader/intern/readfile.cc index a3639770732..1d25add9472 100644 --- a/source/blender/blenloader/intern/readfile.cc +++ b/source/blender/blenloader/intern/readfile.cc @@ -5133,23 +5133,21 @@ void BLO_read_pointer_array(BlendDataReader *reader, void **ptr_p) *ptr_p = final_array; } -const blender::ImplicitSharingInfo *BLO_read_shared_impl( +const blender::ImplicitSharingInfo *BLO_read_shared( BlendDataReader *reader, - void **data_ptr, - const blender::FunctionRef read_fn) + void *data, + blender::FunctionRef read_fn) { if (BLO_read_data_is_undo(reader)) { if (reader->fd->flags & FD_FLAGS_IS_MEMFILE) { UndoReader *undo_reader = reinterpret_cast(reader->fd->file); MemFile &memfile = *undo_reader->memfile; - if (memfile.shared_storage) { - /* Check if the data was saved with sharing-info. */ - if (const blender::ImplicitSharingInfo *sharing_info = - memfile.shared_storage->map.lookup_default(*data_ptr, nullptr)) { - /* Add a new owner of the data that is passed to the caller. */ - sharing_info->add_user(); - return sharing_info; - } + /* Check if the data was saved with sharing-info. */ + if (const blender::ImplicitSharingInfo *sharing_info = + memfile.shared_storage->map.lookup_default(data, nullptr)) { + /* Add a new owner of the data that is passed to the caller. */ + sharing_info->add_user(); + return sharing_info; } } } diff --git a/source/blender/functions/intern/lazy_function_graph_executor.cc b/source/blender/functions/intern/lazy_function_graph_executor.cc index 6361c687693..f80af106ffb 100644 --- a/source/blender/functions/intern/lazy_function_graph_executor.cc +++ b/source/blender/functions/intern/lazy_function_graph_executor.cc @@ -964,7 +964,7 @@ class Executor { const int input_index = input_socket.index(); InputState &input_state = node_state.inputs[input_index]; - BLI_assert(input_state.usage != ValueUsage::Used); + // BLI_assert(input_state.usage != ValueUsage::Used); if (input_state.usage == ValueUsage::Unused) { return; } -- 2.30.2 From 307d8090cd18f1f9b7b478642158946bfdd95f57 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Fri, 21 Apr 2023 14:52:25 -0400 Subject: [PATCH 33/46] Simplify comment wording --- source/blender/blenloader/intern/undofile.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/source/blender/blenloader/intern/undofile.cc b/source/blender/blenloader/intern/undofile.cc index aae1ea1576b..1b33174ce8c 100644 --- a/source/blender/blenloader/intern/undofile.cc +++ b/source/blender/blenloader/intern/undofile.cc @@ -56,8 +56,7 @@ void BLO_memfile_free(MemFile *memfile) MemFileSharedStorage::~MemFileSharedStorage() { for (const blender::ImplicitSharingInfo *sharing_info : map.values()) { - /* Removing the user makes sure that the shared data is freed when the undo step was the last - * owner of it. */ + /* Removing the user makes sure shared data is freed when the undo step was its last owner. */ sharing_info->remove_user_and_delete_if_last(); } } -- 2.30.2 From cfa22ffd3bdbbe1068e71026530bf7c6c0b6d205 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Fri, 21 Apr 2023 15:00:28 -0400 Subject: [PATCH 34/46] Remove unrelated change --- source/blender/functions/intern/lazy_function_graph_executor.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/functions/intern/lazy_function_graph_executor.cc b/source/blender/functions/intern/lazy_function_graph_executor.cc index f80af106ffb..6361c687693 100644 --- a/source/blender/functions/intern/lazy_function_graph_executor.cc +++ b/source/blender/functions/intern/lazy_function_graph_executor.cc @@ -964,7 +964,7 @@ class Executor { const int input_index = input_socket.index(); InputState &input_state = node_state.inputs[input_index]; - // BLI_assert(input_state.usage != ValueUsage::Used); + BLI_assert(input_state.usage != ValueUsage::Used); if (input_state.usage == ValueUsage::Unused) { return; } -- 2.30.2 From bf5dba36a46843b791f29f37903d83593c8da0d5 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Fri, 21 Apr 2023 15:10:41 -0400 Subject: [PATCH 35/46] Revert "Avoid the need for a macro and void **" This reverts commit f0533e434c19e5c6f343e22b13c5c8f57c4c6ae9. --- .../blenkernel/intern/curves_geometry.cc | 2 +- .../blender/blenkernel/intern/customdata.cc | 2 +- source/blender/blenkernel/intern/mesh.cc | 2 +- source/blender/blenloader/BLO_read_write.h | 8 ++++---- source/blender/blenloader/intern/readfile.cc | 20 ++++++++++--------- 5 files changed, 18 insertions(+), 16 deletions(-) diff --git a/source/blender/blenkernel/intern/curves_geometry.cc b/source/blender/blenkernel/intern/curves_geometry.cc index 3339493c49c..2228b1704d2 100644 --- a/source/blender/blenkernel/intern/curves_geometry.cc +++ b/source/blender/blenkernel/intern/curves_geometry.cc @@ -1623,7 +1623,7 @@ void CurvesGeometry::blend_read(BlendDataReader &reader) if (this->curve_offsets) { this->runtime->curve_offsets_sharing_info = BLO_read_shared( - &reader, this->curve_offsets, [&]() { + &reader, &this->curve_offsets, [&]() { BLO_read_int32_array(&reader, this->curve_num + 1, &this->curve_offsets); return implicit_sharing::info_for_mem_free(this->curve_offsets); }); diff --git a/source/blender/blenkernel/intern/customdata.cc b/source/blender/blenkernel/intern/customdata.cc index 28455daf509..cb2fd71da88 100644 --- a/source/blender/blenkernel/intern/customdata.cc +++ b/source/blender/blenkernel/intern/customdata.cc @@ -5271,7 +5271,7 @@ void CustomData_blend_read(BlendDataReader *reader, CustomData *data, const int layer->sharing_info = nullptr; if (CustomData_verify_versions(data, i)) { - layer->sharing_info = BLO_read_shared(reader, layer->data, [&]() { + layer->sharing_info = BLO_read_shared(reader, &layer->data, [&]() { BLO_read_data_address(reader, &layer->data); if (CustomData_layer_ensure_data_exists(layer, count)) { /* Under normal operations, this shouldn't happen, but... diff --git a/source/blender/blenkernel/intern/mesh.cc b/source/blender/blenkernel/intern/mesh.cc index 35f00b03a1d..c0a8edd821c 100644 --- a/source/blender/blenkernel/intern/mesh.cc +++ b/source/blender/blenkernel/intern/mesh.cc @@ -398,7 +398,7 @@ static void mesh_blend_read_data(BlendDataReader *reader, ID *id) if (mesh->poly_offset_indices) { mesh->runtime->poly_offsets_sharing_info = BLO_read_shared( - reader, mesh->poly_offset_indices, [&]() { + reader, &mesh->poly_offset_indices, [&]() { BLO_read_int32_array(reader, mesh->totpoly + 1, &mesh->poly_offset_indices); return blender::implicit_sharing::info_for_mem_free(mesh->poly_offset_indices); }); diff --git a/source/blender/blenloader/BLO_read_write.h b/source/blender/blenloader/BLO_read_write.h index 426cbde2ddd..28561698717 100644 --- a/source/blender/blenloader/BLO_read_write.h +++ b/source/blender/blenloader/BLO_read_write.h @@ -273,16 +273,16 @@ void BLO_read_pointer_array(BlendDataReader *reader, void **ptr_p); /* Misc. */ #ifdef __cplusplus - /** * Check if there is any shared data for the given data pointer. If yes, return the existing * sharing-info. If not, call the provided function to actually read the data now. */ -const blender::ImplicitSharingInfo *BLO_read_shared( +const blender::ImplicitSharingInfo *BLO_read_shared_impl( BlendDataReader *reader, - void *data, + void **data_ptr, blender::FunctionRef read_fn); - +# define BLO_read_shared(reader, ptr_p, read_fn) \ + BLO_read_shared_impl(reader, (void **)ptr_p, read_fn) #endif int BLO_read_fileversion_get(BlendDataReader *reader); diff --git a/source/blender/blenloader/intern/readfile.cc b/source/blender/blenloader/intern/readfile.cc index 1d25add9472..a3639770732 100644 --- a/source/blender/blenloader/intern/readfile.cc +++ b/source/blender/blenloader/intern/readfile.cc @@ -5133,21 +5133,23 @@ void BLO_read_pointer_array(BlendDataReader *reader, void **ptr_p) *ptr_p = final_array; } -const blender::ImplicitSharingInfo *BLO_read_shared( +const blender::ImplicitSharingInfo *BLO_read_shared_impl( BlendDataReader *reader, - void *data, - blender::FunctionRef read_fn) + void **data_ptr, + const blender::FunctionRef read_fn) { if (BLO_read_data_is_undo(reader)) { if (reader->fd->flags & FD_FLAGS_IS_MEMFILE) { UndoReader *undo_reader = reinterpret_cast(reader->fd->file); MemFile &memfile = *undo_reader->memfile; - /* Check if the data was saved with sharing-info. */ - if (const blender::ImplicitSharingInfo *sharing_info = - memfile.shared_storage->map.lookup_default(data, nullptr)) { - /* Add a new owner of the data that is passed to the caller. */ - sharing_info->add_user(); - return sharing_info; + if (memfile.shared_storage) { + /* Check if the data was saved with sharing-info. */ + if (const blender::ImplicitSharingInfo *sharing_info = + memfile.shared_storage->map.lookup_default(*data_ptr, nullptr)) { + /* Add a new owner of the data that is passed to the caller. */ + sharing_info->add_user(); + return sharing_info; + } } } } -- 2.30.2 From 35b8e818d0c98dd4b11d032822190949491615af Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Fri, 21 Apr 2023 15:22:15 -0400 Subject: [PATCH 36/46] Replace macro with template (keeping BLO_read_shared interface the same) --- source/blender/blenloader/BLO_read_write.h | 30 +++++++++++++++----- source/blender/blenloader/intern/readfile.cc | 12 ++++---- 2 files changed, 30 insertions(+), 12 deletions(-) diff --git a/source/blender/blenloader/BLO_read_write.h b/source/blender/blenloader/BLO_read_write.h index 28561698717..4d5d3ae3b87 100644 --- a/source/blender/blenloader/BLO_read_write.h +++ b/source/blender/blenloader/BLO_read_write.h @@ -273,16 +273,32 @@ void BLO_read_pointer_array(BlendDataReader *reader, void **ptr_p); /* Misc. */ #ifdef __cplusplus +} + /** * Check if there is any shared data for the given data pointer. If yes, return the existing * sharing-info. If not, call the provided function to actually read the data now. */ -const blender::ImplicitSharingInfo *BLO_read_shared_impl( +void BLO_read_shared_impl(BlendDataReader *reader, + void *data, + const blender::ImplicitSharingInfo **r_sharing_info, + blender::FunctionRef read_fn); + +template +const blender::ImplicitSharingInfo *BLO_read_shared( BlendDataReader *reader, - void **data_ptr, - blender::FunctionRef read_fn); -# define BLO_read_shared(reader, ptr_p, read_fn) \ - BLO_read_shared_impl(reader, (void **)ptr_p, read_fn) + T **data_ptr, + blender::FunctionRef read_fn) +{ + const blender::ImplicitSharingInfo *sharing_info; + BLO_read_shared_impl(reader, *data_ptr, &sharing_info, read_fn); + return sharing_info; +} + +# ifdef __cplusplus +extern "C" { +# endif + #endif int BLO_read_fileversion_get(BlendDataReader *reader); @@ -317,8 +333,8 @@ struct BlendFileReadReport *BLO_read_lib_reports(BlendLibReader *reader); /* -------------------------------------------------------------------- */ /** \name Blend Expand API * - * BLO_expand has to be called for every data block that should be loaded. If the data block is in - * a separate `.blend` file, it will be pulled from there. + * BLO_expand has to be called for every data block that should be loaded. If the data block is + * in a separate `.blend` file, it will be pulled from there. * \{ */ void BLO_expand_id(BlendExpander *expander, struct ID *id); diff --git a/source/blender/blenloader/intern/readfile.cc b/source/blender/blenloader/intern/readfile.cc index a3639770732..cac33d7a94d 100644 --- a/source/blender/blenloader/intern/readfile.cc +++ b/source/blender/blenloader/intern/readfile.cc @@ -5133,9 +5133,10 @@ void BLO_read_pointer_array(BlendDataReader *reader, void **ptr_p) *ptr_p = final_array; } -const blender::ImplicitSharingInfo *BLO_read_shared_impl( +void BLO_read_shared_impl( BlendDataReader *reader, - void **data_ptr, + void *data, + const blender::ImplicitSharingInfo **r_sharing_info, const blender::FunctionRef read_fn) { if (BLO_read_data_is_undo(reader)) { @@ -5145,15 +5146,16 @@ const blender::ImplicitSharingInfo *BLO_read_shared_impl( if (memfile.shared_storage) { /* Check if the data was saved with sharing-info. */ if (const blender::ImplicitSharingInfo *sharing_info = - memfile.shared_storage->map.lookup_default(*data_ptr, nullptr)) { + memfile.shared_storage->map.lookup_default(data, nullptr)) { /* Add a new owner of the data that is passed to the caller. */ sharing_info->add_user(); - return sharing_info; + *r_sharing_info = sharing_info; + return; } } } } - return read_fn(); + *r_sharing_info = read_fn(); } bool BLO_read_data_is_undo(BlendDataReader *reader) -- 2.30.2 From 4fd37178d6d9dde5929ccbbd1f4392adc756ef76 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Fri, 21 Apr 2023 15:23:21 -0400 Subject: [PATCH 37/46] Move comment to interface function instead of impl --- source/blender/blenloader/BLO_read_write.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source/blender/blenloader/BLO_read_write.h b/source/blender/blenloader/BLO_read_write.h index 4d5d3ae3b87..821fae8991c 100644 --- a/source/blender/blenloader/BLO_read_write.h +++ b/source/blender/blenloader/BLO_read_write.h @@ -275,15 +275,15 @@ void BLO_read_pointer_array(BlendDataReader *reader, void **ptr_p); #ifdef __cplusplus } -/** - * Check if there is any shared data for the given data pointer. If yes, return the existing - * sharing-info. If not, call the provided function to actually read the data now. - */ void BLO_read_shared_impl(BlendDataReader *reader, void *data, const blender::ImplicitSharingInfo **r_sharing_info, blender::FunctionRef read_fn); +/** + * Check if there is any shared data for the given data pointer. If yes, return the existing + * sharing-info. If not, call the provided function to actually read the data now. + */ template const blender::ImplicitSharingInfo *BLO_read_shared( BlendDataReader *reader, -- 2.30.2 From 84dd0b28299b33929d7e6ddbd48eabd1189dd11f Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Wed, 15 Nov 2023 12:42:38 +0100 Subject: [PATCH 38/46] fix merge error --- source/blender/blenloader/BLO_read_write.hh | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/source/blender/blenloader/BLO_read_write.hh b/source/blender/blenloader/BLO_read_write.hh index 297fe13e92d..77338f4174b 100644 --- a/source/blender/blenloader/BLO_read_write.hh +++ b/source/blender/blenloader/BLO_read_write.hh @@ -335,19 +335,6 @@ BlendFileReadReport *BLO_read_lib_reports(BlendLibReader *reader); /** \} */ -/* -------------------------------------------------------------------- */ -/** \name Blend Expand API - * - * BLO_expand has to be called for every data block that should be loaded. If the data block is - * in a separate `.blend` file, it will be pulled from there. - * \{ */ - -void BLO_expand_id(BlendExpander *expander, struct ID *id); - -#define BLO_expand(expander, id) BLO_expand_id(expander, (struct ID *)id) - -/** \} */ - /* -------------------------------------------------------------------- */ /** \name Report API * \{ */ -- 2.30.2 From 7b8b74ec920d1d7168a4d51d952e2f9d4691e848 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Mon, 15 Jan 2024 11:11:15 -0500 Subject: [PATCH 39/46] Cleanup: Remove unnecessary custom data layer writing These layers are removed in current versions --- source/blender/blenkernel/intern/customdata.cc | 6 ------ 1 file changed, 6 deletions(-) diff --git a/source/blender/blenkernel/intern/customdata.cc b/source/blender/blenkernel/intern/customdata.cc index 15880c18f78..e90eaad9578 100644 --- a/source/blender/blenkernel/intern/customdata.cc +++ b/source/blender/blenkernel/intern/customdata.cc @@ -5121,15 +5121,9 @@ void CustomData_blend_write(BlendWriter *writer, case CD_GRID_PAINT_MASK: write_grid_paint_mask(writer, count, static_cast(layer.data)); break; - case CD_FACEMAP: - BLO_write_raw(writer, sizeof(int) * count, static_cast(layer.data)); - break; case CD_PROP_BOOL: BLO_write_raw(writer, sizeof(bool) * count, static_cast(layer.data)); break; - case CD_CREASE: - BLO_write_raw(writer, sizeof(float) * count, static_cast(layer.data)); - break; default: { const char *structname; int structnum; -- 2.30.2 From 8cf92e9afa99210d2ebc69e1b7ac6ca9c73386b2 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Mon, 15 Jan 2024 12:01:40 -0500 Subject: [PATCH 40/46] Forward declare implicit sharing class to avoid including everywhere --- source/blender/blenloader/BLO_read_write.hh | 10 ++++------ source/blender/blenloader/BLO_undofile.hh | 4 +++- source/blender/blenloader/intern/undofile.cc | 1 + source/blender/blenloader/intern/writefile.cc | 3 ++- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/source/blender/blenloader/BLO_read_write.hh b/source/blender/blenloader/BLO_read_write.hh index a46514d4b9a..236590ce469 100644 --- a/source/blender/blenloader/BLO_read_write.hh +++ b/source/blender/blenloader/BLO_read_write.hh @@ -34,13 +34,11 @@ #include "DNA_windowmanager_types.h" /* for eReportType */ #include "BLI_function_ref.hh" -#include "BLI_implicit_sharing.hh" - -typedef struct BlendDataReader BlendDataReader; -typedef struct BlendExpander BlendExpander; -typedef struct BlendLibReader BlendLibReader; -typedef struct BlendWriter BlendWriter; +namespace blender { +class ImplicitSharingInfo; +} +struct BlendDataReader; struct BlendFileReadReport; struct BlendLibReader; struct BlendWriter; diff --git a/source/blender/blenloader/BLO_undofile.hh b/source/blender/blenloader/BLO_undofile.hh index d083edf7829..3de31a48838 100644 --- a/source/blender/blenloader/BLO_undofile.hh +++ b/source/blender/blenloader/BLO_undofile.hh @@ -10,10 +10,12 @@ */ #include "BLI_filereader.h" -#include "BLI_implicit_sharing.hh" #include "BLI_listbase.h" #include "BLI_map.hh" +namespace blender { +class ImplicitSharingInfo; +} struct GHash; struct Main; struct Scene; diff --git a/source/blender/blenloader/intern/undofile.cc b/source/blender/blenloader/intern/undofile.cc index f70a804f16f..8c5ce762da6 100644 --- a/source/blender/blenloader/intern/undofile.cc +++ b/source/blender/blenloader/intern/undofile.cc @@ -26,6 +26,7 @@ #include "BLI_blenlib.h" #include "BLI_ghash.h" +#include "BLI_implicit_sharing.hh" #include "BLO_readfile.h" #include "BLO_undofile.hh" diff --git a/source/blender/blenloader/intern/writefile.cc b/source/blender/blenloader/intern/writefile.cc index 787ecc1aacb..f811370de17 100644 --- a/source/blender/blenloader/intern/writefile.cc +++ b/source/blender/blenloader/intern/writefile.cc @@ -91,6 +91,7 @@ #include "BLI_blenlib.h" #include "BLI_endian_defines.h" #include "BLI_endian_switch.h" +#include "BLI_implicit_sharing.hh" #include "BLI_link_utils.h" #include "BLI_linklist.h" #include "BLI_math_base.h" @@ -1827,7 +1828,7 @@ void BLO_write_string(BlendWriter *writer, const char *data_ptr) void BLO_write_shared(BlendWriter *writer, const void *data, - const ImplicitSharingInfoHandle *sharing_info, + const blender::ImplicitSharingInfo *sharing_info, const blender::FunctionRef write_fn) { if (data == nullptr) { -- 2.30.2 From 75328c2da16ba66a51cb93679a96e6ed8cb7bf37 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Tue, 16 Jan 2024 14:11:22 -0500 Subject: [PATCH 41/46] Handle size limit when writing potentially shared data --- source/blender/blenkernel/intern/curves_geometry.cc | 8 +++++--- source/blender/blenkernel/intern/customdata.cc | 3 ++- source/blender/blenkernel/intern/mesh.cc | 8 +++++--- source/blender/blenlib/BLI_implicit_sharing.hh | 5 +++++ source/blender/blenloader/BLO_read_write.hh | 1 + source/blender/blenloader/intern/writefile.cc | 6 +++++- 6 files changed, 23 insertions(+), 8 deletions(-) diff --git a/source/blender/blenkernel/intern/curves_geometry.cc b/source/blender/blenkernel/intern/curves_geometry.cc index 9c9f7a34298..9864a9dabb3 100644 --- a/source/blender/blenkernel/intern/curves_geometry.cc +++ b/source/blender/blenkernel/intern/curves_geometry.cc @@ -1570,9 +1570,11 @@ void CurvesGeometry::blend_write(BlendWriter &writer, if (this->curve_offsets) { BLO_write_shared( - &writer, this->curve_offsets, this->runtime->curve_offsets_sharing_info, [&]() { - BLO_write_int32_array(&writer, this->curve_num + 1, this->curve_offsets); - }); + &writer, + this->curve_offsets, + sizeof(int) * this->curve_num, + this->runtime->curve_offsets_sharing_info, + [&]() { BLO_write_int32_array(&writer, this->curve_num + 1, this->curve_offsets); }); } BKE_defbase_blend_write(&writer, &this->vertex_group_names); diff --git a/source/blender/blenkernel/intern/customdata.cc b/source/blender/blenkernel/intern/customdata.cc index e90eaad9578..6be10d446c6 100644 --- a/source/blender/blenkernel/intern/customdata.cc +++ b/source/blender/blenkernel/intern/customdata.cc @@ -5104,7 +5104,8 @@ void CustomData_blend_write(BlendWriter *writer, writer, CustomDataLayer, data->totlayer, data->layers, layers_to_write.data()); for (const CustomDataLayer &layer : layers_to_write) { - BLO_write_shared(writer, layer.data, layer.sharing_info, [&]() { + const size_t size_in_bytes = CustomData_sizeof(eCustomDataType(layer.type)) * count; + BLO_write_shared(writer, layer.data, size_in_bytes, layer.sharing_info, [&]() { switch (layer.type) { case CD_MDEFORMVERT: BKE_defvert_blend_write(writer, count, static_cast(layer.data)); diff --git a/source/blender/blenkernel/intern/mesh.cc b/source/blender/blenkernel/intern/mesh.cc index 1a728e59229..2ea9f96c054 100644 --- a/source/blender/blenkernel/intern/mesh.cc +++ b/source/blender/blenkernel/intern/mesh.cc @@ -315,9 +315,11 @@ static void mesh_blend_write(BlendWriter *writer, ID *id, const void *id_address if (mesh->face_offset_indices) { BLO_write_shared( - writer, mesh->face_offset_indices, mesh_runtime->face_offsets_sharing_info, [&]() { - BLO_write_int32_array(writer, mesh->faces_num + 1, mesh->face_offset_indices); - }); + writer, + mesh->face_offset_indices, + sizeof(int) * mesh->faces_num, + mesh_runtime->face_offsets_sharing_info, + [&]() { BLO_write_int32_array(writer, mesh->faces_num + 1, mesh->face_offset_indices); }); } } diff --git a/source/blender/blenlib/BLI_implicit_sharing.hh b/source/blender/blenlib/BLI_implicit_sharing.hh index 42a76dcbcc7..e639989d057 100644 --- a/source/blender/blenlib/BLI_implicit_sharing.hh +++ b/source/blender/blenlib/BLI_implicit_sharing.hh @@ -125,6 +125,11 @@ class ImplicitSharingInfo : NonCopyable, NonMovable { return version_.load(std::memory_order_acquire); } + int strong_users() const + { + return strong_users_.load(std::memory_order_acquire); + } + /** * Call when the data is no longer needed. This might just decrement the user count, or it might * also delete the data if this was the last user. diff --git a/source/blender/blenloader/BLO_read_write.hh b/source/blender/blenloader/BLO_read_write.hh index 236590ce469..711a146b0c9 100644 --- a/source/blender/blenloader/BLO_read_write.hh +++ b/source/blender/blenloader/BLO_read_write.hh @@ -194,6 +194,7 @@ void BLO_write_string(BlendWriter *writer, const char *data_ptr); */ void BLO_write_shared(BlendWriter *writer, const void *data, + size_t size_in_bytes, const blender::ImplicitSharingInfo *sharing_info, blender::FunctionRef write_fn); diff --git a/source/blender/blenloader/intern/writefile.cc b/source/blender/blenloader/intern/writefile.cc index a06a2e42476..c757de7c852 100644 --- a/source/blender/blenloader/intern/writefile.cc +++ b/source/blender/blenloader/intern/writefile.cc @@ -1827,6 +1827,7 @@ void BLO_write_string(BlendWriter *writer, const char *data_ptr) void BLO_write_shared(BlendWriter *writer, const void *data, + const size_t size_in_bytes, const blender::ImplicitSharingInfo *sharing_info, const blender::FunctionRef write_fn) { @@ -1834,8 +1835,8 @@ void BLO_write_shared(BlendWriter *writer, return; } if (BLO_write_is_undo(writer)) { + MemFile &memfile = *writer->wd->mem.written_memfile; if (sharing_info != nullptr) { - MemFile &memfile = *writer->wd->mem.written_memfile; if (memfile.shared_storage == nullptr) { memfile.shared_storage = MEM_new(__func__); } @@ -1844,7 +1845,10 @@ void BLO_write_shared(BlendWriter *writer, sharing_info->add_user(); return; } + /* This size is an estimate, but good enough to count data with many users less. */ + memfile.size += size_in_bytes / sharing_info->strong_users(); } + memfile.size += size_in_bytes; } write_fn(); } -- 2.30.2 From e9c40b8ce8a5a7ba87f0be65040d033f48a76ca9 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Thu, 29 Feb 2024 13:36:09 +0100 Subject: [PATCH 42/46] fixes after merge --- source/blender/editors/include/ED_undo.hh | 1 + source/blender/editors/undo/memfile_undo.cc | 21 ++++++++++++++++ .../blender/windowmanager/intern/wm_files.cc | 16 ++++++------ .../windowmanager/intern/wm_init_exit.cc | 25 +++++++------------ 4 files changed, 39 insertions(+), 24 deletions(-) diff --git a/source/blender/editors/include/ED_undo.hh b/source/blender/editors/include/ED_undo.hh index a9e2ed9103b..fc28d9286dd 100644 --- a/source/blender/editors/include/ED_undo.hh +++ b/source/blender/editors/include/ED_undo.hh @@ -129,6 +129,7 @@ void ED_undosys_type_free(); /* `memfile_undo.cc` */ +MemFile *ED_undosys_stack_memfile_get_if_active(UndoStack *ustack); /** * If the last undo step is a memfile one, find the first #MemFileChunk matching given ID * (using its session UUID), and tag it as "changed in the future". diff --git a/source/blender/editors/undo/memfile_undo.cc b/source/blender/editors/undo/memfile_undo.cc index 17abcd5d561..a3fb961e11c 100644 --- a/source/blender/editors/undo/memfile_undo.cc +++ b/source/blender/editors/undo/memfile_undo.cc @@ -345,6 +345,27 @@ void ED_memfile_undosys_type(UndoType *ut) /** \name Utilities * \{ */ +/** + * Ideally we wouldn't need to export global undo internals, + * there are some cases where it's needed though. + */ +static MemFile *ed_undosys_step_get_memfile(UndoStep *us_p) +{ + MemFileUndoStep *us = (MemFileUndoStep *)us_p; + return &us->data->memfile; +} + +MemFile *ED_undosys_stack_memfile_get_if_active(UndoStack *ustack) +{ + if (!ustack->step_active) { + return nullptr; + } + if (ustack->step_active->type != BKE_UNDOSYS_TYPE_MEMFILE) { + return nullptr; + } + return ed_undosys_step_get_memfile(ustack->step_active); +} + void ED_undosys_stack_memfile_id_changed_tag(UndoStack *ustack, ID *id) { UndoStep *us = ustack->step_active; diff --git a/source/blender/windowmanager/intern/wm_files.cc b/source/blender/windowmanager/intern/wm_files.cc index 258e7a2493d..ea62e0d261c 100644 --- a/source/blender/windowmanager/intern/wm_files.cc +++ b/source/blender/windowmanager/intern/wm_files.cc @@ -2115,9 +2115,12 @@ static bool wm_autosave_write_try(Main *bmain, wmWindowManager *wm) wm_autosave_location(filepath); - if (MemFile *memfile = ED_undosys_stack_memfile_get_if_active(wm->undo_stack)) { - /* Fast save of last undo-buffer, now with UI. */ - BLO_memfile_write_file(memfile, filepath); + /* Technically, we could always just save here, but that would cause performance regressions + * compared to when the #MemFile undo step was used for saving undo-steps. So for now just skip + * auto-save when we are in a mode where auto-save wouldn't have worked previously anyway. This + * check can be removed once the performance regressions have been solved. */ + if (ED_undosys_stack_memfile_get_if_active(wm->undo_stack) != nullptr) { + WM_autosave_write(wm, bmain); return true; } if ((U.uiflag & USER_GLOBALUNDO) == 0) { @@ -2184,17 +2187,14 @@ void wm_autosave_timer(Main *bmain, wmWindowManager *wm, wmTimer * /*wt*/) { wm_autosave_timer_end(wm); - /* Time to wait until the next attempt to autosave if it is disabled right now. */ - const double try_again_time_step = 0.01; - /* If a modal operator is running, don't autosave because we might not be in - * a valid state to save. */ + * a valid state to save. But try again in 10ms. */ LISTBASE_FOREACH (wmWindow *, win, &wm->windows) { LISTBASE_FOREACH (wmEventHandler *, handler_base, &win->modalhandlers) { if (handler_base->type == WM_HANDLER_TYPE_OP) { wmEventHandler_Op *handler = (wmEventHandler_Op *)handler_base; if (handler->op) { - wm_autosave_timer_begin_ex(wm, try_again_time_step); + wm_autosave_timer_begin_ex(wm, 0.01); return; } } diff --git a/source/blender/windowmanager/intern/wm_init_exit.cc b/source/blender/windowmanager/intern/wm_init_exit.cc index d7e5fdc5b63..c2f005c2701 100644 --- a/source/blender/windowmanager/intern/wm_init_exit.cc +++ b/source/blender/windowmanager/intern/wm_init_exit.cc @@ -471,26 +471,19 @@ void WM_exit_ex(bContext *C, const bool do_python_exit, const bool do_user_exit_ /* NOTE: same code copied in `wm_files.cc`. */ if (C && wm) { if (do_user_exit_actions) { - /* save the undo state as quit.blend */ + /* Save quit.blend. */ Main *bmain = CTX_data_main(C); char filepath[FILE_MAX]; - BLI_path_join(filepath, sizeof(filepath), BKE_tempdir_base(), BLENDER_QUIT_FILE); - MemFile *undo_memfile = wm->undo_stack ? - ED_undosys_stack_memfile_get_if_active(wm->undo_stack) : - nullptr; - /* When true, the `undo_memfile` doesn't contain all information necessary - * for writing and up to date blend file. */ - const bool is_memfile_outdated = ED_editors_flush_edits(bmain); + const int fileflags = G.fileflags & ~G_FILE_COMPRESS; - if (undo_memfile && !is_memfile_outdated) { - BLO_memfile_write_file(undo_memfile, filepath); + BLI_path_join(filepath, sizeof(filepath), BKE_tempdir_base(), BLENDER_QUIT_FILE); + + ED_editors_flush_edits(bmain); + + BlendFileWriteParams blend_file_write_params{}; + if (BLO_write_file(bmain, filepath, fileflags, &blend_file_write_params, nullptr)) { + printf("Saved session recovery to \"%s\"\n", filepath); } - else { - const int fileflags = G.fileflags & ~G_FILE_COMPRESS; - BlendFileWriteParams blend_file_write_params{}; - BLO_write_file(bmain, filepath, fileflags, &blend_file_write_params, nullptr); - } - printf("Saved session recovery to \"%s\"\n", filepath); } WM_jobs_kill_all(wm); -- 2.30.2 From b94e0bec3257904c2e53d0af4f8b263ac03e8d7a Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Thu, 29 Feb 2024 14:21:39 +0100 Subject: [PATCH 43/46] make format --- source/blender/blenloader/intern/readfile.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/blender/blenloader/intern/readfile.cc b/source/blender/blenloader/intern/readfile.cc index b4d70b5b497..aaa5e85b315 100644 --- a/source/blender/blenloader/intern/readfile.cc +++ b/source/blender/blenloader/intern/readfile.cc @@ -4969,7 +4969,8 @@ void BLO_read_shared_impl( if (memfile.shared_storage) { /* Check if the data was saved with sharing-info. */ if (const blender::ImplicitSharingInfo *sharing_info = - memfile.shared_storage->map.lookup_default(data, nullptr)) { + memfile.shared_storage->map.lookup_default(data, nullptr)) + { /* Add a new owner of the data that is passed to the caller. */ sharing_info->add_user(); *r_sharing_info = sharing_info; -- 2.30.2 From a0afe9da276580dbb1c2094ac8d4edc59554ab5f Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Thu, 29 Feb 2024 16:24:43 +0100 Subject: [PATCH 44/46] fix and cleanup --- source/blender/blenkernel/intern/curves_geometry.cc | 2 +- source/blender/blenloader/BLO_read_write.hh | 6 +++++- source/blender/blenloader/intern/writefile.cc | 8 ++++---- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/source/blender/blenkernel/intern/curves_geometry.cc b/source/blender/blenkernel/intern/curves_geometry.cc index 106c248064b..1925ed4e890 100644 --- a/source/blender/blenkernel/intern/curves_geometry.cc +++ b/source/blender/blenkernel/intern/curves_geometry.cc @@ -1575,7 +1575,7 @@ void CurvesGeometry::blend_write(BlendWriter &writer, BLO_write_shared( &writer, this->curve_offsets, - sizeof(int) * this->curve_num, + sizeof(int) * (this->curve_num + 1), this->runtime->curve_offsets_sharing_info, [&]() { BLO_write_int32_array(&writer, this->curve_num + 1, this->curve_offsets); }); } diff --git a/source/blender/blenloader/BLO_read_write.hh b/source/blender/blenloader/BLO_read_write.hh index 18027e4702c..7f1e842e850 100644 --- a/source/blender/blenloader/BLO_read_write.hh +++ b/source/blender/blenloader/BLO_read_write.hh @@ -191,10 +191,14 @@ void BLO_write_string(BlendWriter *writer, const char *data_ptr); * Check if the data can be written more efficiently by making use of implicit-sharing. If yes, the * user count of the sharing-info is increased making the data immutable. The provided callback * should serialize the potentially shared data. It is only called when necessary. + * + * \param approximate_size_in_bytes: Used to be able to approximate how large the undo step is in + * total. + * \param write_fn: Use the #BlendWrite to serialize the potentially shared data. */ void BLO_write_shared(BlendWriter *writer, const void *data, - size_t size_in_bytes, + size_t approximate_size_in_bytes, const blender::ImplicitSharingInfo *sharing_info, blender::FunctionRef write_fn); diff --git a/source/blender/blenloader/intern/writefile.cc b/source/blender/blenloader/intern/writefile.cc index 08582bff1b3..49b7bb86785 100644 --- a/source/blender/blenloader/intern/writefile.cc +++ b/source/blender/blenloader/intern/writefile.cc @@ -1827,7 +1827,7 @@ void BLO_write_string(BlendWriter *writer, const char *data_ptr) void BLO_write_shared(BlendWriter *writer, const void *data, - const size_t size_in_bytes, + const size_t approximate_size_in_bytes, const blender::ImplicitSharingInfo *sharing_info, const blender::FunctionRef write_fn) { @@ -1843,12 +1843,12 @@ void BLO_write_shared(BlendWriter *writer, if (memfile.shared_storage->map.add(data, sharing_info)) { /* The undo-step takes (shared) ownership of the data, which also makes it immutable. */ sharing_info->add_user(); + /* This size is an estimate, but good enough to count data with many users less. */ + memfile.size += approximate_size_in_bytes / sharing_info->strong_users(); return; } - /* This size is an estimate, but good enough to count data with many users less. */ - memfile.size += size_in_bytes / sharing_info->strong_users(); } - memfile.size += size_in_bytes; + memfile.size += approximate_size_in_bytes; } write_fn(); } -- 2.30.2 From 0fa079f52c2db3161f84a969a7aaec135cda99a9 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Thu, 29 Feb 2024 16:28:24 +0100 Subject: [PATCH 45/46] remove unnecessary memfile.size increase --- source/blender/blenloader/intern/writefile.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/source/blender/blenloader/intern/writefile.cc b/source/blender/blenloader/intern/writefile.cc index 49b7bb86785..4102f0d1aa5 100644 --- a/source/blender/blenloader/intern/writefile.cc +++ b/source/blender/blenloader/intern/writefile.cc @@ -1848,7 +1848,6 @@ void BLO_write_shared(BlendWriter *writer, return; } } - memfile.size += approximate_size_in_bytes; } write_fn(); } -- 2.30.2 From 3ee387ae73ef3983f9700701cecc1493b32124d0 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Thu, 29 Feb 2024 16:30:43 +0100 Subject: [PATCH 46/46] use blo_ instead of BLO_ prefix for private function --- source/blender/blenloader/BLO_read_write.hh | 4 ++-- source/blender/blenloader/intern/readfile.cc | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/source/blender/blenloader/BLO_read_write.hh b/source/blender/blenloader/BLO_read_write.hh index 7f1e842e850..7bacb74d658 100644 --- a/source/blender/blenloader/BLO_read_write.hh +++ b/source/blender/blenloader/BLO_read_write.hh @@ -265,7 +265,7 @@ void BLO_read_pointer_array(BlendDataReader *reader, void **ptr_p); /* Misc. */ -void BLO_read_shared_impl(BlendDataReader *reader, +void blo_read_shared_impl(BlendDataReader *reader, void *data, const blender::ImplicitSharingInfo **r_sharing_info, blender::FunctionRef read_fn); @@ -281,7 +281,7 @@ const blender::ImplicitSharingInfo *BLO_read_shared( blender::FunctionRef read_fn) { const blender::ImplicitSharingInfo *sharing_info; - BLO_read_shared_impl(reader, *data_ptr, &sharing_info, read_fn); + blo_read_shared_impl(reader, *data_ptr, &sharing_info, read_fn); return sharing_info; } diff --git a/source/blender/blenloader/intern/readfile.cc b/source/blender/blenloader/intern/readfile.cc index aaa5e85b315..48f3b9d2611 100644 --- a/source/blender/blenloader/intern/readfile.cc +++ b/source/blender/blenloader/intern/readfile.cc @@ -4956,7 +4956,7 @@ void BLO_read_pointer_array(BlendDataReader *reader, void **ptr_p) *ptr_p = final_array; } -void BLO_read_shared_impl( +void blo_read_shared_impl( BlendDataReader *reader, void *data, const blender::ImplicitSharingInfo **r_sharing_info, -- 2.30.2