diff options
-rw-r--r-- | source/blender/blenkernel/BKE_mesh.h | 11 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/customdata.cc | 10 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/mesh.cc | 20 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/mesh_convert.cc | 10 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/mesh_normals.cc | 63 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/mesh_runtime.c | 6 | ||||
-rw-r--r-- | source/blender/bmesh/intern/bmesh_mesh_convert.cc | 2 | ||||
-rw-r--r-- | source/blender/editors/mesh/mesh_data.c | 9 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_customdata_types.h | 4 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_mesh_types.h | 13 | ||||
-rw-r--r-- | source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc | 4 |
11 files changed, 89 insertions, 63 deletions
diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h index 2b32c6a5420..72a1303fc6b 100644 --- a/source/blender/blenkernel/BKE_mesh.h +++ b/source/blender/blenkernel/BKE_mesh.h @@ -428,6 +428,17 @@ float (*BKE_mesh_vertex_normals_for_write(struct Mesh *mesh))[3]; float (*BKE_mesh_poly_normals_for_write(struct Mesh *mesh))[3]; /** + * Free any cached vertex or poly normals. Face corner (loop) normals are also derived data, + * but are not handled with the same method yet, so they are not included. It's important that this + * is called after the mesh changes size, since otherwise cached normal arrays might not be large + * enough (though it may be called indirectly by other functions). + * + * \note Normally it's preferred to call #BKE_mesh_normals_tag_dirty instead, + * but this can be used in specific situations to reset a mesh or reduce memory usage. + */ +void BKE_mesh_clear_derived_normals(struct Mesh *mesh); + +/** * Mark the mesh's vertex normals non-dirty, for when they are calculated or assigned manually. */ void BKE_mesh_vertex_normals_clear_dirty(struct Mesh *mesh); diff --git a/source/blender/blenkernel/intern/customdata.cc b/source/blender/blenkernel/intern/customdata.cc index e4c18325d76..0935a902c3a 100644 --- a/source/blender/blenkernel/intern/customdata.cc +++ b/source/blender/blenkernel/intern/customdata.cc @@ -2000,10 +2000,10 @@ const CustomData_MeshMasks CD_MASK_FACECORNERS = { CD_MASK_NORMAL | CD_MASK_MLOOPTANGENT), }; const CustomData_MeshMasks CD_MASK_EVERYTHING = { - /* vmask */ (CD_MASK_MVERT | CD_MASK_BM_ELEM_PYPTR | CD_MASK_ORIGINDEX | CD_MASK_NORMAL | - CD_MASK_MDEFORMVERT | CD_MASK_BWEIGHT | CD_MASK_MVERT_SKIN | CD_MASK_ORCO | - CD_MASK_CLOTH_ORCO | CD_MASK_SHAPEKEY | CD_MASK_SHAPE_KEYINDEX | - CD_MASK_PAINT_MASK | CD_MASK_PROP_ALL | CD_MASK_PROP_COLOR | CD_MASK_CREASE), + /* vmask */ (CD_MASK_MVERT | CD_MASK_BM_ELEM_PYPTR | CD_MASK_ORIGINDEX | CD_MASK_MDEFORMVERT | + CD_MASK_BWEIGHT | CD_MASK_MVERT_SKIN | CD_MASK_ORCO | CD_MASK_CLOTH_ORCO | + CD_MASK_SHAPEKEY | CD_MASK_SHAPE_KEYINDEX | CD_MASK_PAINT_MASK | + CD_MASK_PROP_ALL | CD_MASK_PROP_COLOR | CD_MASK_CREASE), /* emask */ (CD_MASK_MEDGE | CD_MASK_BM_ELEM_PYPTR | CD_MASK_ORIGINDEX | CD_MASK_BWEIGHT | CD_MASK_CREASE | CD_MASK_FREESTYLE_EDGE | CD_MASK_PROP_ALL), @@ -2012,7 +2012,7 @@ const CustomData_MeshMasks CD_MASK_EVERYTHING = { CD_MASK_ORIGSPACE | CD_MASK_TANGENT | CD_MASK_TESSLOOPNORMAL | CD_MASK_PREVIEW_MCOL | CD_MASK_PROP_ALL), /* pmask */ - (CD_MASK_MPOLY | CD_MASK_BM_ELEM_PYPTR | CD_MASK_ORIGINDEX | CD_MASK_NORMAL | CD_MASK_FACEMAP | + (CD_MASK_MPOLY | CD_MASK_BM_ELEM_PYPTR | CD_MASK_ORIGINDEX | CD_MASK_FACEMAP | CD_MASK_FREESTYLE_FACE | CD_MASK_PROP_ALL | CD_MASK_SCULPT_FACE_SETS), /* lmask */ (CD_MASK_MLOOP | CD_MASK_BM_ELEM_PYPTR | CD_MASK_MDISPS | CD_MASK_NORMAL | CD_MASK_MLOOPUV | diff --git a/source/blender/blenkernel/intern/mesh.cc b/source/blender/blenkernel/intern/mesh.cc index 351535a6f78..6c51965aa4a 100644 --- a/source/blender/blenkernel/intern/mesh.cc +++ b/source/blender/blenkernel/intern/mesh.cc @@ -1111,16 +1111,6 @@ Mesh *BKE_mesh_new_nomain_from_template_ex(const Mesh *me_src, mesh_tessface_clear_intern(me_dst, false); } - me_dst->runtime.cd_dirty_poly = me_src->runtime.cd_dirty_poly; - me_dst->runtime.cd_dirty_vert = me_src->runtime.cd_dirty_vert; - - /* Ensure that when no normal layers exist, they are marked dirty, because - * normals might not have been included in the mask of copied layers. */ - if (!CustomData_has_layer(&me_dst->vdata, CD_NORMAL) || - !CustomData_has_layer(&me_dst->pdata, CD_NORMAL)) { - BKE_mesh_normals_tag_dirty(me_dst); - } - /* The destination mesh should at least have valid primary CD layers, * even in cases where the source mesh does not. */ mesh_ensure_cdlayers_primary(me_dst, do_tessface); @@ -1986,7 +1976,6 @@ struct SplitFaceNewVert { struct SplitFaceNewVert *next; int new_index; int orig_index; - float *vnor; }; struct SplitFaceNewEdge { @@ -2065,7 +2054,6 @@ static int split_faces_prepare_new_verts(Mesh *mesh, sizeof(*new_vert)); new_vert->orig_index = vert_idx; new_vert->new_index = new_vert_idx; - new_vert->vnor = (*lnor_space)->vec_lnor; /* See note above. */ new_vert->next = *new_verts; *new_verts = new_vert; } @@ -2148,7 +2136,6 @@ static void split_faces_split_new_verts(Mesh *mesh, { const int verts_len = mesh->totvert - num_new_verts; MVert *mvert = mesh->mvert; - float(*vert_normals)[3] = BKE_mesh_vertex_normals_for_write(mesh); /* Remember new_verts is a single linklist, so its items are in reversed order... */ MVert *new_mv = &mvert[mesh->totvert - 1]; @@ -2156,11 +2143,7 @@ static void split_faces_split_new_verts(Mesh *mesh, BLI_assert(new_verts->new_index == i); BLI_assert(new_verts->new_index != new_verts->orig_index); CustomData_copy_data(&mesh->vdata, &mesh->vdata, new_verts->orig_index, i, 1); - if (new_verts->vnor) { - copy_v3_v3(vert_normals[i], new_verts->vnor); - } } - BKE_mesh_vertex_normals_clear_dirty(mesh); } /* Perform actual split of edges. */ @@ -2248,7 +2231,8 @@ void BKE_mesh_split_faces(Mesh *mesh, bool free_loop_normals) /* Also frees new_verts/edges temp data, since we used its memarena to allocate them. */ BKE_lnor_spacearr_free(&lnors_spacearr); - BKE_mesh_assert_normals_dirty_or_calculated(mesh); + BKE_mesh_clear_derived_normals(mesh); + #ifdef VALIDATE_MESH BKE_mesh_validate(mesh, true, true); #endif diff --git a/source/blender/blenkernel/intern/mesh_convert.cc b/source/blender/blenkernel/intern/mesh_convert.cc index 3562f6c6b17..d57f06666f7 100644 --- a/source/blender/blenkernel/intern/mesh_convert.cc +++ b/source/blender/blenkernel/intern/mesh_convert.cc @@ -1495,15 +1495,7 @@ void BKE_mesh_nomain_to_mesh(Mesh *mesh_src, tmp.cd_flag = mesh_src->cd_flag; tmp.runtime.deformed_only = mesh_src->runtime.deformed_only; - tmp.runtime.cd_dirty_poly = mesh_src->runtime.cd_dirty_poly; - tmp.runtime.cd_dirty_vert = mesh_src->runtime.cd_dirty_vert; - - /* Ensure that when no normal layers exist, they are marked dirty, because - * normals might not have been included in the mask of copied layers. */ - if (!CustomData_has_layer(&tmp.vdata, CD_NORMAL) || - !CustomData_has_layer(&tmp.pdata, CD_NORMAL)) { - BKE_mesh_normals_tag_dirty(&tmp); - } + BKE_mesh_clear_derived_normals(&tmp); if (CustomData_has_layer(&mesh_src->vdata, CD_SHAPEKEY)) { KeyBlock *kb; diff --git a/source/blender/blenkernel/intern/mesh_normals.cc b/source/blender/blenkernel/intern/mesh_normals.cc index 1b3c7e01be8..56020db8efd 100644 --- a/source/blender/blenkernel/intern/mesh_normals.cc +++ b/source/blender/blenkernel/intern/mesh_normals.cc @@ -110,53 +110,68 @@ static void add_v3_v3_atomic(float r[3], const float a[3]) void BKE_mesh_normals_tag_dirty(Mesh *mesh) { - mesh->runtime.cd_dirty_vert |= CD_MASK_NORMAL; - mesh->runtime.cd_dirty_poly |= CD_MASK_NORMAL; + mesh->runtime.vert_normals_dirty = true; + mesh->runtime.poly_normals_dirty = true; } float (*BKE_mesh_vertex_normals_for_write(Mesh *mesh))[3] { - CustomData_duplicate_referenced_layer(&mesh->vdata, CD_NORMAL, mesh->totvert); - return (float(*)[3])CustomData_add_layer( - &mesh->vdata, CD_NORMAL, CD_CALLOC, nullptr, mesh->totvert); + if (mesh->runtime.vert_normals == nullptr) { + mesh->runtime.vert_normals = (float(*)[3])MEM_malloc_arrayN( + mesh->totvert, sizeof(float[3]), __func__); + } + return mesh->runtime.vert_normals; } float (*BKE_mesh_poly_normals_for_write(Mesh *mesh))[3] { - CustomData_duplicate_referenced_layer(&mesh->pdata, CD_NORMAL, mesh->totpoly); - return (float(*)[3])CustomData_add_layer( - &mesh->pdata, CD_NORMAL, CD_CALLOC, nullptr, mesh->totpoly); + if (mesh->runtime.poly_normals == nullptr) { + mesh->runtime.poly_normals = (float(*)[3])MEM_malloc_arrayN( + mesh->totpoly, sizeof(float[3]), __func__); + } + return mesh->runtime.poly_normals; } void BKE_mesh_vertex_normals_clear_dirty(Mesh *mesh) { - mesh->runtime.cd_dirty_vert &= ~CD_MASK_NORMAL; + mesh->runtime.vert_normals_dirty = false; BKE_mesh_assert_normals_dirty_or_calculated(mesh); } void BKE_mesh_poly_normals_clear_dirty(Mesh *mesh) { - mesh->runtime.cd_dirty_poly &= ~CD_MASK_NORMAL; + mesh->runtime.poly_normals_dirty = false; BKE_mesh_assert_normals_dirty_or_calculated(mesh); } bool BKE_mesh_vertex_normals_are_dirty(const Mesh *mesh) { - return mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL; + return mesh->runtime.vert_normals_dirty; } bool BKE_mesh_poly_normals_are_dirty(const Mesh *mesh) { - return mesh->runtime.cd_dirty_poly & CD_MASK_NORMAL; + return mesh->runtime.poly_normals_dirty; +} + +void BKE_mesh_clear_derived_normals(Mesh *mesh) +{ + /* This function doesn't change the logical state of a mesh, so there could + * be a version that takes a const mesh and locks the mesh normals mutex. */ + MEM_SAFE_FREE(mesh->runtime.vert_normals); + MEM_SAFE_FREE(mesh->runtime.poly_normals); + + mesh->runtime.vert_normals_dirty = true; + mesh->runtime.poly_normals_dirty = true; } void BKE_mesh_assert_normals_dirty_or_calculated(const Mesh *mesh) { - if (!(mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL)) { - BLI_assert(CustomData_has_layer(&mesh->vdata, CD_NORMAL) || mesh->totvert == 0); + if (!mesh->runtime.vert_normals_dirty) { + BLI_assert(mesh->runtime.vert_normals || mesh->totvert == 0); } - if (!(mesh->runtime.cd_dirty_poly & CD_MASK_NORMAL)) { - BLI_assert(CustomData_has_layer(&mesh->pdata, CD_NORMAL) || mesh->totpoly == 0); + if (!mesh->runtime.poly_normals_dirty) { + BLI_assert(mesh->runtime.poly_normals || mesh->totpoly == 0); } } @@ -358,8 +373,8 @@ static void mesh_calc_normals_poly_and_vertex(MVert *mvert, const float (*BKE_mesh_vertex_normals_ensure(const Mesh *mesh))[3] { if (!(BKE_mesh_vertex_normals_are_dirty(mesh) || BKE_mesh_poly_normals_are_dirty(mesh))) { - BLI_assert(CustomData_has_layer(&mesh->vdata, CD_NORMAL) || mesh->totvert == 0); - return (const float(*)[3])CustomData_get_layer(&mesh->vdata, CD_NORMAL); + BLI_assert(mesh->runtime.vert_normals != nullptr || mesh->totvert == 0); + return mesh->runtime.vert_normals; } if (mesh->totvert == 0) { @@ -369,9 +384,9 @@ const float (*BKE_mesh_vertex_normals_ensure(const Mesh *mesh))[3] ThreadMutex *normals_mutex = (ThreadMutex *)mesh->runtime.normals_mutex; BLI_mutex_lock(normals_mutex); if (!(BKE_mesh_vertex_normals_are_dirty(mesh) || BKE_mesh_poly_normals_are_dirty(mesh))) { - BLI_assert(CustomData_has_layer(&mesh->vdata, CD_NORMAL)); + BLI_assert(mesh->runtime.vert_normals != nullptr); BLI_mutex_unlock(normals_mutex); - return (const float(*)[3])CustomData_get_layer(&mesh->vdata, CD_NORMAL); + return mesh->runtime.vert_normals; } float(*vert_normals)[3]; @@ -404,8 +419,8 @@ const float (*BKE_mesh_vertex_normals_ensure(const Mesh *mesh))[3] const float (*BKE_mesh_poly_normals_ensure(const Mesh *mesh))[3] { if (!BKE_mesh_poly_normals_are_dirty(mesh)) { - BLI_assert(CustomData_has_layer(&mesh->pdata, CD_NORMAL) || mesh->totpoly == 0); - return (const float(*)[3])CustomData_get_layer(&mesh->pdata, CD_NORMAL); + BLI_assert(mesh->runtime.poly_normals != nullptr || mesh->totpoly == 0); + return mesh->runtime.poly_normals; } if (mesh->totpoly == 0) { @@ -415,9 +430,9 @@ const float (*BKE_mesh_poly_normals_ensure(const Mesh *mesh))[3] ThreadMutex *normals_mutex = (ThreadMutex *)mesh->runtime.normals_mutex; BLI_mutex_lock(normals_mutex); if (!BKE_mesh_poly_normals_are_dirty(mesh)) { - BLI_assert(CustomData_has_layer(&mesh->pdata, CD_NORMAL)); + BLI_assert(mesh->runtime.poly_normals != nullptr); BLI_mutex_unlock(normals_mutex); - return (const float(*)[3])CustomData_get_layer(&mesh->pdata, CD_NORMAL); + return mesh->runtime.poly_normals; } float(*poly_normals)[3]; diff --git a/source/blender/blenkernel/intern/mesh_runtime.c b/source/blender/blenkernel/intern/mesh_runtime.c index e7e5064df7c..92bc94c2c96 100644 --- a/source/blender/blenkernel/intern/mesh_runtime.c +++ b/source/blender/blenkernel/intern/mesh_runtime.c @@ -104,6 +104,11 @@ void BKE_mesh_runtime_reset_on_copy(Mesh *mesh, const int UNUSED(flag)) runtime->bvh_cache = NULL; runtime->shrinkwrap_data = NULL; + runtime->vert_normals_dirty = true; + runtime->poly_normals_dirty = true; + runtime->vert_normals = NULL; + runtime->poly_normals = NULL; + mesh_runtime_init_mutexes(mesh); } @@ -117,6 +122,7 @@ void BKE_mesh_runtime_clear_cache(Mesh *mesh) BKE_mesh_runtime_clear_geometry(mesh); BKE_mesh_batch_cache_free(mesh); BKE_mesh_runtime_clear_edit_data(mesh); + BKE_mesh_clear_derived_normals(mesh); } /** diff --git a/source/blender/bmesh/intern/bmesh_mesh_convert.cc b/source/blender/bmesh/intern/bmesh_mesh_convert.cc index d6c642ff80b..ddd2ce25148 100644 --- a/source/blender/bmesh/intern/bmesh_mesh_convert.cc +++ b/source/blender/bmesh/intern/bmesh_mesh_convert.cc @@ -1080,7 +1080,7 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks * const int cd_edge_bweight_offset = CustomData_get_offset(&bm->edata, CD_BWEIGHT); const int cd_edge_crease_offset = CustomData_get_offset(&bm->edata, CD_CREASE); - BKE_mesh_normals_tag_dirty(me); + BKE_mesh_clear_derived_normals(me); me->runtime.deformed_only = true; diff --git a/source/blender/editors/mesh/mesh_data.c b/source/blender/editors/mesh/mesh_data.c index 0f58752f323..7a089d7101e 100644 --- a/source/blender/editors/mesh/mesh_data.c +++ b/source/blender/editors/mesh/mesh_data.c @@ -37,6 +37,7 @@ #include "BKE_customdata.h" #include "BKE_editmesh.h" #include "BKE_mesh.h" +#include "BKE_mesh_runtime.h" #include "BKE_report.h" #include "DEG_depsgraph.h" @@ -1126,6 +1127,8 @@ static void mesh_add_verts(Mesh *mesh, int len) mesh->vdata = vdata; BKE_mesh_update_customdata_pointers(mesh, false); + BKE_mesh_runtime_clear_cache(mesh); + /* scan the input list and insert the new vertices */ /* set default flags */ @@ -1162,6 +1165,8 @@ static void mesh_add_edges(Mesh *mesh, int len) mesh->edata = edata; BKE_mesh_update_customdata_pointers(mesh, false); /* new edges don't change tessellation */ + BKE_mesh_runtime_clear_cache(mesh); + /* set default flags */ medge = &mesh->medge[mesh->totedge]; for (i = 0; i < len; i++, medge++) { @@ -1190,6 +1195,8 @@ static void mesh_add_loops(Mesh *mesh, int len) CustomData_add_layer(&ldata, CD_MLOOP, CD_CALLOC, NULL, totloop); } + BKE_mesh_runtime_clear_cache(mesh); + CustomData_free(&mesh->ldata, mesh->totloop); mesh->ldata = ldata; BKE_mesh_update_customdata_pointers(mesh, true); @@ -1221,6 +1228,8 @@ static void mesh_add_polys(Mesh *mesh, int len) mesh->pdata = pdata; BKE_mesh_update_customdata_pointers(mesh, true); + BKE_mesh_runtime_clear_cache(mesh); + /* set default flags */ mpoly = &mesh->mpoly[mesh->totpoly]; for (i = 0; i < len; i++, mpoly++) { diff --git a/source/blender/makesdna/DNA_customdata_types.h b/source/blender/makesdna/DNA_customdata_types.h index 629a5e88de7..3d65c62b09d 100644 --- a/source/blender/makesdna/DNA_customdata_types.h +++ b/source/blender/makesdna/DNA_customdata_types.h @@ -114,6 +114,10 @@ typedef enum CustomDataType { CD_MTFACE = 5, CD_MCOL = 6, CD_ORIGINDEX = 7, + /** + * Used for derived face corner normals on mesh `ldata`, since currently they are not computed + * lazily. Derived vertex and polygon normals are stored in #Mesh_Runtime. + */ CD_NORMAL = 8, CD_FACEMAP = 9, /* exclusive face group, each face can only be part of one */ CD_PROP_FLOAT = 10, diff --git a/source/blender/makesdna/DNA_mesh_types.h b/source/blender/makesdna/DNA_mesh_types.h index bf50100b302..24f3d1c95ed 100644 --- a/source/blender/makesdna/DNA_mesh_types.h +++ b/source/blender/makesdna/DNA_mesh_types.h @@ -132,14 +132,23 @@ typedef struct Mesh_Runtime { */ char wrapper_type_finalize; + int subsurf_resolution; /** * Settings for lazily evaluating the subdivision on the CPU if needed. These are * set in the modifier when GPU subdivision can be performed. */ char subsurf_apply_render; char subsurf_use_optimal_display; - char _pad[2]; - int subsurf_resolution; + + /** + * Caches for lazily computed vertex and polygon normals. These are stored here rather than in + * #CustomData because they can be calculated on a const mesh, and adding custom data layers on a + * const mesh is not thread-safe. + */ + char vert_normals_dirty; + char poly_normals_dirty; + float (*vert_normals)[3]; + float (*poly_normals)[3]; void *_pad2; diff --git a/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc index 1d1c5bd2285..c39c092f30a 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc @@ -316,7 +316,6 @@ static void extrude_mesh_vertices(MeshComponent &component, } BKE_mesh_runtime_clear_cache(&mesh); - BKE_mesh_normals_tag_dirty(&mesh); } static Array<Vector<int, 2>> mesh_calculate_polys_of_edge(const Mesh &mesh) @@ -640,7 +639,6 @@ static void extrude_mesh_edges(MeshComponent &component, } BKE_mesh_runtime_clear_cache(&mesh); - BKE_mesh_normals_tag_dirty(&mesh); } /** @@ -1009,7 +1007,6 @@ static void extrude_mesh_face_regions(MeshComponent &component, } BKE_mesh_runtime_clear_cache(&mesh); - BKE_mesh_normals_tag_dirty(&mesh); } /* Get the range into an array of extruded corners, edges, or vertices for a particular polygon. */ @@ -1277,7 +1274,6 @@ static void extrude_individual_mesh_faces(MeshComponent &component, } BKE_mesh_runtime_clear_cache(&mesh); - BKE_mesh_normals_tag_dirty(&mesh); } static void node_geo_exec(GeoNodeExecParams params) |