From 176d7bcc2eb47b9820861037f90a7fb26de8c9a0 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Sun, 5 Jun 2022 12:04:42 +0200 Subject: Cleanup: Move remaining mesh draw code to C++ After this commit, all mesh data extraction and drawing code is in C++, including headers, making it possible to use improved types for future performance improvements and simplifications. The only non-trivial changes are in `draw_cache_impl_mesh.cc`, where use of certain features and macros in C necessitated larger changes. Differential Revision: https://developer.blender.org/D15088 --- source/blender/draw/CMakeLists.txt | 10 +- source/blender/draw/intern/draw_attributes.cc | 6 +- source/blender/draw/intern/draw_attributes.h | 2 +- source/blender/draw/intern/draw_cache_extract.h | 333 --- source/blender/draw/intern/draw_cache_extract.hh | 353 ++++ .../blender/draw/intern/draw_cache_extract_mesh.cc | 85 +- .../intern/draw_cache_extract_mesh_render_data.c | 569 ------ .../intern/draw_cache_extract_mesh_render_data.cc | 584 ++++++ .../blender/draw/intern/draw_cache_impl_curves.cc | 2 +- source/blender/draw/intern/draw_cache_impl_mesh.c | 2103 ------------------- source/blender/draw/intern/draw_cache_impl_mesh.cc | 2116 ++++++++++++++++++++ .../draw/intern/draw_cache_impl_subdivision.cc | 6 +- .../draw/intern/mesh_extractors/extract_mesh.c | 153 -- .../draw/intern/mesh_extractors/extract_mesh.cc | 153 ++ .../draw/intern/mesh_extractors/extract_mesh.h | 365 ---- .../draw/intern/mesh_extractors/extract_mesh.hh | 357 ++++ .../mesh_extractors/extract_mesh_ibo_edituv.cc | 4 +- .../mesh_extractors/extract_mesh_ibo_fdots.cc | 4 +- .../mesh_extractors/extract_mesh_ibo_lines.cc | 4 +- .../extract_mesh_ibo_lines_adjacency.cc | 4 +- .../extract_mesh_ibo_lines_paint_mask.cc | 4 +- .../mesh_extractors/extract_mesh_ibo_points.cc | 4 +- .../mesh_extractors/extract_mesh_ibo_tris.cc | 4 +- .../mesh_extractors/extract_mesh_vbo_attributes.cc | 4 +- .../mesh_extractors/extract_mesh_vbo_edge_fac.cc | 4 +- .../mesh_extractors/extract_mesh_vbo_edit_data.cc | 4 +- .../extract_mesh_vbo_edituv_data.cc | 4 +- .../extract_mesh_vbo_edituv_stretch_angle.cc | 4 +- .../extract_mesh_vbo_edituv_stretch_area.cc | 4 +- .../extract_mesh_vbo_fdots_edituv_data.cc | 4 +- .../mesh_extractors/extract_mesh_vbo_fdots_nor.cc | 4 +- .../mesh_extractors/extract_mesh_vbo_fdots_pos.cc | 4 +- .../mesh_extractors/extract_mesh_vbo_fdots_uv.cc | 4 +- .../mesh_extractors/extract_mesh_vbo_lnor.cc | 4 +- .../extract_mesh_vbo_mesh_analysis.cc | 4 +- .../mesh_extractors/extract_mesh_vbo_orco.cc | 4 +- .../mesh_extractors/extract_mesh_vbo_pos_nor.cc | 4 +- .../extract_mesh_vbo_sculpt_data.cc | 4 +- .../mesh_extractors/extract_mesh_vbo_select_idx.cc | 4 +- .../mesh_extractors/extract_mesh_vbo_skin_roots.cc | 4 +- .../intern/mesh_extractors/extract_mesh_vbo_tan.cc | 4 +- .../intern/mesh_extractors/extract_mesh_vbo_uv.cc | 4 +- .../mesh_extractors/extract_mesh_vbo_vcol.cc | 4 +- .../mesh_extractors/extract_mesh_vbo_weights.cc | 4 +- source/blender/gpu/intern/gpu_node_graph.c | 2 +- source/blender/makesdna/DNA_mesh_types.h | 2 +- 46 files changed, 3627 insertions(+), 3686 deletions(-) delete mode 100644 source/blender/draw/intern/draw_cache_extract.h create mode 100644 source/blender/draw/intern/draw_cache_extract.hh delete mode 100644 source/blender/draw/intern/draw_cache_extract_mesh_render_data.c create mode 100644 source/blender/draw/intern/draw_cache_extract_mesh_render_data.cc delete mode 100644 source/blender/draw/intern/draw_cache_impl_mesh.c create mode 100644 source/blender/draw/intern/draw_cache_impl_mesh.cc delete mode 100644 source/blender/draw/intern/mesh_extractors/extract_mesh.c create mode 100644 source/blender/draw/intern/mesh_extractors/extract_mesh.cc delete mode 100644 source/blender/draw/intern/mesh_extractors/extract_mesh.h create mode 100644 source/blender/draw/intern/mesh_extractors/extract_mesh.hh (limited to 'source/blender') diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index e6c8558bb37..9cb3743dd02 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -39,8 +39,8 @@ set(INC set(SRC intern/draw_cache.c intern/draw_cache_extract_mesh.cc - intern/draw_cache_extract_mesh_render_data.c - intern/mesh_extractors/extract_mesh.c + intern/draw_cache_extract_mesh_render_data.cc + intern/mesh_extractors/extract_mesh.cc intern/mesh_extractors/extract_mesh_ibo_edituv.cc intern/mesh_extractors/extract_mesh_ibo_fdots.cc intern/mesh_extractors/extract_mesh_ibo_lines.cc @@ -75,7 +75,7 @@ set(SRC intern/draw_cache_impl_displist.c intern/draw_cache_impl_gpencil.c intern/draw_cache_impl_lattice.c - intern/draw_cache_impl_mesh.c + intern/draw_cache_impl_mesh.cc intern/draw_cache_impl_metaball.c intern/draw_cache_impl_particles.c intern/draw_cache_impl_pointcloud.c @@ -201,7 +201,7 @@ set(SRC intern/DRW_render.h intern/draw_attributes.h intern/draw_cache.h - intern/draw_cache_extract.h + intern/draw_cache_extract.hh intern/draw_cache_impl.h intern/draw_cache_inline.h intern/draw_color_management.h @@ -221,7 +221,7 @@ set(SRC intern/draw_texture_pool.h intern/draw_view.h intern/draw_view_data.h - intern/mesh_extractors/extract_mesh.h + intern/mesh_extractors/extract_mesh.hh intern/smaa_textures.h engines/basic/basic_engine.h engines/basic/basic_private.h diff --git a/source/blender/draw/intern/draw_attributes.cc b/source/blender/draw/intern/draw_attributes.cc index f84a6c86fac..8fb4210901f 100644 --- a/source/blender/draw/intern/draw_attributes.cc +++ b/source/blender/draw/intern/draw_attributes.cc @@ -84,9 +84,9 @@ DRW_AttributeRequest *drw_attributes_add_request(DRW_Attributes *attrs, bool drw_custom_data_match_attribute(const CustomData *custom_data, const char *name, int *r_layer_index, - int *r_type) + eCustomDataType *r_type) { - const int possible_attribute_types[7] = { + const eCustomDataType possible_attribute_types[7] = { CD_PROP_BOOL, CD_PROP_INT8, CD_PROP_INT32, @@ -97,7 +97,7 @@ bool drw_custom_data_match_attribute(const CustomData *custom_data, }; for (int i = 0; i < ARRAY_SIZE(possible_attribute_types); i++) { - const int attr_type = possible_attribute_types[i]; + const eCustomDataType attr_type = possible_attribute_types[i]; int layer_index = CustomData_get_named_layer(custom_data, attr_type, name); if (layer_index == -1) { continue; diff --git a/source/blender/draw/intern/draw_attributes.h b/source/blender/draw/intern/draw_attributes.h index c375670cd70..4f82f3b94e9 100644 --- a/source/blender/draw/intern/draw_attributes.h +++ b/source/blender/draw/intern/draw_attributes.h @@ -53,7 +53,7 @@ DRW_AttributeRequest *drw_attributes_add_request(DRW_Attributes *attrs, bool drw_custom_data_match_attribute(const CustomData *custom_data, const char *name, int *r_layer_index, - int *r_type); + eCustomDataType *r_type); #ifdef __cplusplus } diff --git a/source/blender/draw/intern/draw_cache_extract.h b/source/blender/draw/intern/draw_cache_extract.h deleted file mode 100644 index ce3ad9923da..00000000000 --- a/source/blender/draw/intern/draw_cache_extract.h +++ /dev/null @@ -1,333 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later - * Copyright 2019 Blender Foundation. */ - -/** \file - * \ingroup draw - */ - -#pragma once - -struct DRWSubdivCache; -struct MeshRenderData; -struct TaskGraph; - -#include "DNA_customdata_types.h" - -#include "BKE_attribute.h" -#include "BKE_object.h" - -#include "GPU_batch.h" -#include "GPU_index_buffer.h" -#include "GPU_vertex_buffer.h" - -#include "draw_attributes.h" - -/* Vertex Group Selection and display options */ -typedef struct DRW_MeshWeightState { - int defgroup_active; - int defgroup_len; - - short flags; - char alert_mode; - - /* Set of all selected bones for Multi-paint. */ - bool *defgroup_sel; /* [defgroup_len] */ - int defgroup_sel_count; - - /* Set of all locked and unlocked deform bones for Lock Relative mode. */ - bool *defgroup_locked; /* [defgroup_len] */ - bool *defgroup_unlocked; /* [defgroup_len] */ -} DRW_MeshWeightState; - -/* DRW_MeshWeightState.flags */ -enum { - DRW_MESH_WEIGHT_STATE_MULTIPAINT = (1 << 0), - DRW_MESH_WEIGHT_STATE_AUTO_NORMALIZE = (1 << 1), - DRW_MESH_WEIGHT_STATE_LOCK_RELATIVE = (1 << 2), -}; - -typedef struct DRW_MeshCDMask { - uint32_t uv : 8; - uint32_t tan : 8; - uint32_t vcol : 8; - uint32_t orco : 1; - uint32_t tan_orco : 1; - uint32_t sculpt_overlays : 1; - /** Edit uv layer is from the base edit mesh as - * modifiers could remove it. (see T68857) */ - uint32_t edit_uv : 1; -} DRW_MeshCDMask; -/* Keep `DRW_MeshCDMask` struct within an `uint32_t`. - * bit-wise and atomic operations are used to compare and update the struct. - * See `mesh_cd_layers_type_*` functions. */ -BLI_STATIC_ASSERT(sizeof(DRW_MeshCDMask) <= sizeof(uint32_t), "DRW_MeshCDMask exceeds 32 bits") -typedef enum eMRIterType { - MR_ITER_LOOPTRI = 1 << 0, - MR_ITER_POLY = 1 << 1, - MR_ITER_LEDGE = 1 << 2, - MR_ITER_LVERT = 1 << 3, -} eMRIterType; -ENUM_OPERATORS(eMRIterType, MR_ITER_LVERT) - -typedef enum eMRDataType { - MR_DATA_NONE = 0, - MR_DATA_POLY_NOR = 1 << 1, - MR_DATA_LOOP_NOR = 1 << 2, - MR_DATA_LOOPTRI = 1 << 3, - MR_DATA_LOOSE_GEOM = 1 << 4, - /** Force loop normals calculation. */ - MR_DATA_TAN_LOOP_NOR = 1 << 5, - MR_DATA_POLYS_SORTED = 1 << 6, -} eMRDataType; -ENUM_OPERATORS(eMRDataType, MR_DATA_POLYS_SORTED) - -#ifdef __cplusplus -extern "C" { -#endif - -BLI_INLINE int mesh_render_mat_len_get(const Object *object, const Mesh *me) -{ - if (me->edit_mesh != NULL) { - const Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(object); - if (editmesh_eval_final != NULL) { - return MAX2(1, editmesh_eval_final->totcol); - } - } - return MAX2(1, me->totcol); -} - -typedef struct MeshBufferList { - /* Every VBO below contains at least enough - * data for every loops in the mesh (except fdots and skin roots). - * For some VBOs, it extends to (in this exact order) : - * loops + loose_edges*2 + loose_verts */ - struct { - GPUVertBuf *pos_nor; /* extend */ - GPUVertBuf *lnor; /* extend */ - GPUVertBuf *edge_fac; /* extend */ - GPUVertBuf *weights; /* extend */ - GPUVertBuf *uv; - GPUVertBuf *tan; - GPUVertBuf *vcol; - GPUVertBuf *sculpt_data; - GPUVertBuf *orco; - /* Only for edit mode. */ - GPUVertBuf *edit_data; /* extend */ - GPUVertBuf *edituv_data; - GPUVertBuf *edituv_stretch_area; - GPUVertBuf *edituv_stretch_angle; - GPUVertBuf *mesh_analysis; - GPUVertBuf *fdots_pos; - GPUVertBuf *fdots_nor; - GPUVertBuf *fdots_uv; - // GPUVertBuf *fdots_edit_data; /* inside fdots_nor for now. */ - GPUVertBuf *fdots_edituv_data; - GPUVertBuf *skin_roots; - /* Selection */ - GPUVertBuf *vert_idx; /* extend */ - GPUVertBuf *edge_idx; /* extend */ - GPUVertBuf *poly_idx; - GPUVertBuf *fdot_idx; - GPUVertBuf *attr[GPU_MAX_ATTR]; - } vbo; - /* Index Buffers: - * Only need to be updated when topology changes. */ - struct { - /* Indices to vloops. */ - GPUIndexBuf *tris; /* Ordered per material. */ - GPUIndexBuf *lines; /* Loose edges last. */ - GPUIndexBuf *lines_loose; /* sub buffer of `lines` only containing the loose edges. */ - GPUIndexBuf *points; - GPUIndexBuf *fdots; - /* 3D overlays. */ - GPUIndexBuf *lines_paint_mask; /* no loose edges. */ - GPUIndexBuf *lines_adjacency; - /* Uv overlays. (visibility can differ from 3D view) */ - GPUIndexBuf *edituv_tris; - GPUIndexBuf *edituv_lines; - GPUIndexBuf *edituv_points; - GPUIndexBuf *edituv_fdots; - } ibo; -} MeshBufferList; - -typedef struct MeshBatchList { - /* Surfaces / Render */ - GPUBatch *surface; - GPUBatch *surface_weights; - /* Edit mode */ - GPUBatch *edit_triangles; - GPUBatch *edit_vertices; - GPUBatch *edit_edges; - GPUBatch *edit_vnor; - GPUBatch *edit_lnor; - GPUBatch *edit_fdots; - GPUBatch *edit_mesh_analysis; - GPUBatch *edit_skin_roots; - /* Edit UVs */ - GPUBatch *edituv_faces_stretch_area; - GPUBatch *edituv_faces_stretch_angle; - GPUBatch *edituv_faces; - GPUBatch *edituv_edges; - GPUBatch *edituv_verts; - GPUBatch *edituv_fdots; - /* Edit selection */ - GPUBatch *edit_selection_verts; - GPUBatch *edit_selection_edges; - GPUBatch *edit_selection_faces; - GPUBatch *edit_selection_fdots; - /* Common display / Other */ - GPUBatch *all_verts; - GPUBatch *all_edges; - GPUBatch *loose_edges; - GPUBatch *edge_detection; - GPUBatch *wire_edges; /* Individual edges with face normals. */ - GPUBatch *wire_loops; /* Loops around faces. no edges between selected faces */ - GPUBatch *wire_loops_uvs; /* Same as wire_loops but only has uvs. */ - GPUBatch *sculpt_overlays; -} MeshBatchList; - -#define MBC_BATCH_LEN (sizeof(MeshBatchList) / sizeof(void *)) -#define MBC_VBO_LEN (sizeof(((MeshBufferList){0}).vbo) / sizeof(void *)) -#define MBC_IBO_LEN (sizeof(((MeshBufferList){0}).ibo) / sizeof(void *)) - -#define MBC_BATCH_INDEX(batch) (offsetof(MeshBatchList, batch) / sizeof(void *)) - -typedef enum DRWBatchFlag { - MBC_SURFACE = (1u << MBC_BATCH_INDEX(surface)), - MBC_SURFACE_WEIGHTS = (1u << MBC_BATCH_INDEX(surface_weights)), - MBC_EDIT_TRIANGLES = (1u << MBC_BATCH_INDEX(edit_triangles)), - MBC_EDIT_VERTICES = (1u << MBC_BATCH_INDEX(edit_vertices)), - MBC_EDIT_EDGES = (1u << MBC_BATCH_INDEX(edit_edges)), - MBC_EDIT_VNOR = (1u << MBC_BATCH_INDEX(edit_vnor)), - MBC_EDIT_LNOR = (1u << MBC_BATCH_INDEX(edit_lnor)), - MBC_EDIT_FACEDOTS = (1u << MBC_BATCH_INDEX(edit_fdots)), - MBC_EDIT_MESH_ANALYSIS = (1u << MBC_BATCH_INDEX(edit_mesh_analysis)), - MBC_SKIN_ROOTS = (1u << MBC_BATCH_INDEX(edit_skin_roots)), - MBC_EDITUV_FACES_STRETCH_AREA = (1u << MBC_BATCH_INDEX(edituv_faces_stretch_area)), - MBC_EDITUV_FACES_STRETCH_ANGLE = (1u << MBC_BATCH_INDEX(edituv_faces_stretch_angle)), - MBC_EDITUV_FACES = (1u << MBC_BATCH_INDEX(edituv_faces)), - MBC_EDITUV_EDGES = (1u << MBC_BATCH_INDEX(edituv_edges)), - MBC_EDITUV_VERTS = (1u << MBC_BATCH_INDEX(edituv_verts)), - MBC_EDITUV_FACEDOTS = (1u << MBC_BATCH_INDEX(edituv_fdots)), - MBC_EDIT_SELECTION_VERTS = (1u << MBC_BATCH_INDEX(edit_selection_verts)), - MBC_EDIT_SELECTION_EDGES = (1u << MBC_BATCH_INDEX(edit_selection_edges)), - MBC_EDIT_SELECTION_FACES = (1u << MBC_BATCH_INDEX(edit_selection_faces)), - MBC_EDIT_SELECTION_FACEDOTS = (1u << MBC_BATCH_INDEX(edit_selection_fdots)), - MBC_ALL_VERTS = (1u << MBC_BATCH_INDEX(all_verts)), - MBC_ALL_EDGES = (1u << MBC_BATCH_INDEX(all_edges)), - MBC_LOOSE_EDGES = (1u << MBC_BATCH_INDEX(loose_edges)), - MBC_EDGE_DETECTION = (1u << MBC_BATCH_INDEX(edge_detection)), - MBC_WIRE_EDGES = (1u << MBC_BATCH_INDEX(wire_edges)), - MBC_WIRE_LOOPS = (1u << MBC_BATCH_INDEX(wire_loops)), - MBC_WIRE_LOOPS_UVS = (1u << MBC_BATCH_INDEX(wire_loops_uvs)), - MBC_SCULPT_OVERLAYS = (1u << MBC_BATCH_INDEX(sculpt_overlays)), -} DRWBatchFlag; - -BLI_STATIC_ASSERT(MBC_BATCH_LEN < 32, "Number of batches exceeded the limit of bit fields"); - -typedef struct MeshExtractLooseGeom { - int edge_len; - int vert_len; - int *verts; - int *edges; -} MeshExtractLooseGeom; - -/** - * Data that are kept around between extractions to reduce rebuilding time. - * - * - Loose geometry. - */ -typedef struct MeshBufferCache { - MeshBufferList buff; - - MeshExtractLooseGeom loose_geom; - - struct { - int *tri_first_index; - int *mat_tri_len; - int visible_tri_len; - } poly_sorted; -} MeshBufferCache; - -#define FOREACH_MESH_BUFFER_CACHE(batch_cache, mbc) \ - for (MeshBufferCache *mbc = &batch_cache->final; \ - mbc == &batch_cache->final || mbc == &batch_cache->cage || mbc == &batch_cache->uv_cage; \ - mbc = (mbc == &batch_cache->final) ? \ - &batch_cache->cage : \ - ((mbc == &batch_cache->cage) ? &batch_cache->uv_cage : NULL)) - -typedef struct MeshBatchCache { - MeshBufferCache final, cage, uv_cage; - - MeshBatchList batch; - - /* Index buffer per material. These are subranges of `ibo.tris` */ - GPUIndexBuf **tris_per_mat; - - GPUBatch **surface_per_mat; - - struct DRWSubdivCache *subdiv_cache; - - DRWBatchFlag batch_requested; /* DRWBatchFlag */ - DRWBatchFlag batch_ready; /* DRWBatchFlag */ - - /* settings to determine if cache is invalid */ - int edge_len; - int tri_len; - int poly_len; - int vert_len; - int mat_len; - bool is_dirty; /* Instantly invalidates cache, skipping mesh check */ - bool is_editmode; - bool is_uvsyncsel; - - struct DRW_MeshWeightState weight_state; - - DRW_MeshCDMask cd_used, cd_needed, cd_used_over_time; - - DRW_Attributes attr_used, attr_needed, attr_used_over_time; - - int lastmatch; - - /* Valid only if edge_detection is up to date. */ - bool is_manifold; - - /* Total areas for drawing UV Stretching. Contains the summed area in mesh - * space (`tot_area`) and the summed area in uv space (`tot_uvarea`). - * - * Only valid after `DRW_mesh_batch_cache_create_requested` has been called. */ - float tot_area, tot_uv_area; - - bool no_loose_wire; - - eV3DShadingColorType color_type; - bool pbvh_is_drawing; -} MeshBatchCache; - -#define MBC_EDITUV \ - (MBC_EDITUV_FACES_STRETCH_AREA | MBC_EDITUV_FACES_STRETCH_ANGLE | MBC_EDITUV_FACES | \ - MBC_EDITUV_EDGES | MBC_EDITUV_VERTS | MBC_EDITUV_FACEDOTS | MBC_WIRE_LOOPS_UVS) - -void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph, - MeshBatchCache *cache, - MeshBufferCache *mbc, - Object *object, - Mesh *me, - bool is_editmode, - bool is_paint_mode, - bool is_mode_active, - const float obmat[4][4], - bool do_final, - bool do_uvedit, - const Scene *scene, - const struct ToolSettings *ts, - bool use_hide); - -void mesh_buffer_cache_create_requested_subdiv(MeshBatchCache *cache, - MeshBufferCache *mbc, - struct DRWSubdivCache *subdiv_cache, - struct MeshRenderData *mr); - -#ifdef __cplusplus -} -#endif diff --git a/source/blender/draw/intern/draw_cache_extract.hh b/source/blender/draw/intern/draw_cache_extract.hh new file mode 100644 index 00000000000..b16a35347c0 --- /dev/null +++ b/source/blender/draw/intern/draw_cache_extract.hh @@ -0,0 +1,353 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2019 Blender Foundation. */ + +/** \file + * \ingroup draw + */ + +#pragma once + +#include + +#include "BLI_utildefines.h" + +#include "DNA_customdata_types.h" +#include "DNA_mesh_types.h" +#include "DNA_view3d_enums.h" + +#include "BKE_attribute.h" +#include "BKE_object.h" + +#include "GPU_batch.h" +#include "GPU_index_buffer.h" +#include "GPU_vertex_buffer.h" + +#include "draw_attributes.h" + +struct DRWSubdivCache; +struct MeshRenderData; +struct TaskGraph; + +/* Vertex Group Selection and display options */ +struct DRW_MeshWeightState { + int defgroup_active; + int defgroup_len; + + short flags; + char alert_mode; + + /* Set of all selected bones for Multi-paint. */ + bool *defgroup_sel; /* [defgroup_len] */ + int defgroup_sel_count; + + /* Set of all locked and unlocked deform bones for Lock Relative mode. */ + bool *defgroup_locked; /* [defgroup_len] */ + bool *defgroup_unlocked; /* [defgroup_len] */ +}; + +/* DRW_MeshWeightState.flags */ +enum { + DRW_MESH_WEIGHT_STATE_MULTIPAINT = (1 << 0), + DRW_MESH_WEIGHT_STATE_AUTO_NORMALIZE = (1 << 1), + DRW_MESH_WEIGHT_STATE_LOCK_RELATIVE = (1 << 2), +}; + +struct DRW_MeshCDMask { + uint32_t uv : 8; + uint32_t tan : 8; + uint32_t vcol : 8; + uint32_t orco : 1; + uint32_t tan_orco : 1; + uint32_t sculpt_overlays : 1; + /** Edit uv layer is from the base edit mesh as + * modifiers could remove it. (see T68857) */ + uint32_t edit_uv : 1; +}; +/* Keep `DRW_MeshCDMask` struct within an `uint32_t`. + * bit-wise and atomic operations are used to compare and update the struct. + * See `mesh_cd_layers_type_*` functions. */ +BLI_STATIC_ASSERT(sizeof(DRW_MeshCDMask) <= sizeof(uint32_t), "DRW_MeshCDMask exceeds 32 bits") +enum eMRIterType { + MR_ITER_LOOPTRI = 1 << 0, + MR_ITER_POLY = 1 << 1, + MR_ITER_LEDGE = 1 << 2, + MR_ITER_LVERT = 1 << 3, +}; +ENUM_OPERATORS(eMRIterType, MR_ITER_LVERT) + +enum eMRDataType { + MR_DATA_NONE = 0, + MR_DATA_POLY_NOR = 1 << 1, + MR_DATA_LOOP_NOR = 1 << 2, + MR_DATA_LOOPTRI = 1 << 3, + MR_DATA_LOOSE_GEOM = 1 << 4, + /** Force loop normals calculation. */ + MR_DATA_TAN_LOOP_NOR = 1 << 5, + MR_DATA_POLYS_SORTED = 1 << 6, +}; +ENUM_OPERATORS(eMRDataType, MR_DATA_POLYS_SORTED) + +BLI_INLINE int mesh_render_mat_len_get(const Object *object, const Mesh *me) +{ + if (me->edit_mesh != NULL) { + const Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(object); + if (editmesh_eval_final != NULL) { + return std::max(1, editmesh_eval_final->totcol); + } + } + return std::max(1, me->totcol); +} + +struct MeshBufferList { + + // enum class BufferItem { + // PosNor, + // LNor, + // EdgeFac, + // Weights, + // UV, + // Tan, + // VCol, + // SculptData, + // Orco, + // EditData, + // EditUVData, + // EditUVStretchArea, + + // } + /* Every VBO below contains at least enough + * data for every loops in the mesh (except fdots and skin roots). + * For some VBOs, it extends to (in this exact order) : + * loops + loose_edges*2 + loose_verts */ + struct { + GPUVertBuf *pos_nor; /* extend */ + GPUVertBuf *lnor; /* extend */ + GPUVertBuf *edge_fac; /* extend */ + GPUVertBuf *weights; /* extend */ + GPUVertBuf *uv; + GPUVertBuf *tan; + GPUVertBuf *vcol; + GPUVertBuf *sculpt_data; + GPUVertBuf *orco; + /* Only for edit mode. */ + GPUVertBuf *edit_data; /* extend */ + GPUVertBuf *edituv_data; + GPUVertBuf *edituv_stretch_area; + GPUVertBuf *edituv_stretch_angle; + GPUVertBuf *mesh_analysis; + GPUVertBuf *fdots_pos; + GPUVertBuf *fdots_nor; + GPUVertBuf *fdots_uv; + // GPUVertBuf *fdots_edit_data; /* inside fdots_nor for now. */ + GPUVertBuf *fdots_edituv_data; + GPUVertBuf *skin_roots; + /* Selection */ + GPUVertBuf *vert_idx; /* extend */ + GPUVertBuf *edge_idx; /* extend */ + GPUVertBuf *poly_idx; + GPUVertBuf *fdot_idx; + GPUVertBuf *attr[GPU_MAX_ATTR]; + } vbo; + /* Index Buffers: + * Only need to be updated when topology changes. */ + struct { + /* Indices to vloops. */ + GPUIndexBuf *tris; /* Ordered per material. */ + GPUIndexBuf *lines; /* Loose edges last. */ + GPUIndexBuf *lines_loose; /* sub buffer of `lines` only containing the loose edges. */ + GPUIndexBuf *points; + GPUIndexBuf *fdots; + /* 3D overlays. */ + GPUIndexBuf *lines_paint_mask; /* no loose edges. */ + GPUIndexBuf *lines_adjacency; + /* Uv overlays. (visibility can differ from 3D view) */ + GPUIndexBuf *edituv_tris; + GPUIndexBuf *edituv_lines; + GPUIndexBuf *edituv_points; + GPUIndexBuf *edituv_fdots; + } ibo; +}; + +struct MeshBatchList { + /* Surfaces / Render */ + GPUBatch *surface; + GPUBatch *surface_weights; + /* Edit mode */ + GPUBatch *edit_triangles; + GPUBatch *edit_vertices; + GPUBatch *edit_edges; + GPUBatch *edit_vnor; + GPUBatch *edit_lnor; + GPUBatch *edit_fdots; + GPUBatch *edit_mesh_analysis; + GPUBatch *edit_skin_roots; + /* Edit UVs */ + GPUBatch *edituv_faces_stretch_area; + GPUBatch *edituv_faces_stretch_angle; + GPUBatch *edituv_faces; + GPUBatch *edituv_edges; + GPUBatch *edituv_verts; + GPUBatch *edituv_fdots; + /* Edit selection */ + GPUBatch *edit_selection_verts; + GPUBatch *edit_selection_edges; + GPUBatch *edit_selection_faces; + GPUBatch *edit_selection_fdots; + /* Common display / Other */ + GPUBatch *all_verts; + GPUBatch *all_edges; + GPUBatch *loose_edges; + GPUBatch *edge_detection; + GPUBatch *wire_edges; /* Individual edges with face normals. */ + GPUBatch *wire_loops; /* Loops around faces. no edges between selected faces */ + GPUBatch *wire_loops_uvs; /* Same as wire_loops but only has uvs. */ + GPUBatch *sculpt_overlays; +}; + +#define MBC_BATCH_LEN (sizeof(MeshBatchList) / sizeof(void *)) +#define MBC_VBO_LEN (sizeof(((MeshBufferList){0}).vbo) / sizeof(void *)) +#define MBC_IBO_LEN (sizeof(((MeshBufferList){0}).ibo) / sizeof(void *)) + +#define MBC_BATCH_INDEX(batch) (offsetof(MeshBatchList, batch) / sizeof(void *)) + +enum DRWBatchFlag { + MBC_SURFACE = (1u << MBC_BATCH_INDEX(surface)), + MBC_SURFACE_WEIGHTS = (1u << MBC_BATCH_INDEX(surface_weights)), + MBC_EDIT_TRIANGLES = (1u << MBC_BATCH_INDEX(edit_triangles)), + MBC_EDIT_VERTICES = (1u << MBC_BATCH_INDEX(edit_vertices)), + MBC_EDIT_EDGES = (1u << MBC_BATCH_INDEX(edit_edges)), + MBC_EDIT_VNOR = (1u << MBC_BATCH_INDEX(edit_vnor)), + MBC_EDIT_LNOR = (1u << MBC_BATCH_INDEX(edit_lnor)), + MBC_EDIT_FACEDOTS = (1u << MBC_BATCH_INDEX(edit_fdots)), + MBC_EDIT_MESH_ANALYSIS = (1u << MBC_BATCH_INDEX(edit_mesh_analysis)), + MBC_SKIN_ROOTS = (1u << MBC_BATCH_INDEX(edit_skin_roots)), + MBC_EDITUV_FACES_STRETCH_AREA = (1u << MBC_BATCH_INDEX(edituv_faces_stretch_area)), + MBC_EDITUV_FACES_STRETCH_ANGLE = (1u << MBC_BATCH_INDEX(edituv_faces_stretch_angle)), + MBC_EDITUV_FACES = (1u << MBC_BATCH_INDEX(edituv_faces)), + MBC_EDITUV_EDGES = (1u << MBC_BATCH_INDEX(edituv_edges)), + MBC_EDITUV_VERTS = (1u << MBC_BATCH_INDEX(edituv_verts)), + MBC_EDITUV_FACEDOTS = (1u << MBC_BATCH_INDEX(edituv_fdots)), + MBC_EDIT_SELECTION_VERTS = (1u << MBC_BATCH_INDEX(edit_selection_verts)), + MBC_EDIT_SELECTION_EDGES = (1u << MBC_BATCH_INDEX(edit_selection_edges)), + MBC_EDIT_SELECTION_FACES = (1u << MBC_BATCH_INDEX(edit_selection_faces)), + MBC_EDIT_SELECTION_FACEDOTS = (1u << MBC_BATCH_INDEX(edit_selection_fdots)), + MBC_ALL_VERTS = (1u << MBC_BATCH_INDEX(all_verts)), + MBC_ALL_EDGES = (1u << MBC_BATCH_INDEX(all_edges)), + MBC_LOOSE_EDGES = (1u << MBC_BATCH_INDEX(loose_edges)), + MBC_EDGE_DETECTION = (1u << MBC_BATCH_INDEX(edge_detection)), + MBC_WIRE_EDGES = (1u << MBC_BATCH_INDEX(wire_edges)), + MBC_WIRE_LOOPS = (1u << MBC_BATCH_INDEX(wire_loops)), + MBC_WIRE_LOOPS_UVS = (1u << MBC_BATCH_INDEX(wire_loops_uvs)), + MBC_SCULPT_OVERLAYS = (1u << MBC_BATCH_INDEX(sculpt_overlays)), + MBC_SURFACE_PER_MAT = (1u << MBC_BATCH_LEN), +}; +ENUM_OPERATORS(DRWBatchFlag, MBC_SURFACE_PER_MAT); + +BLI_STATIC_ASSERT(MBC_BATCH_LEN < 32, "Number of batches exceeded the limit of bit fields"); + +struct MeshExtractLooseGeom { + int edge_len; + int vert_len; + int *verts; + int *edges; +}; + +/** + * Data that are kept around between extractions to reduce rebuilding time. + * + * - Loose geometry. + */ +struct MeshBufferCache { + MeshBufferList buff; + + MeshExtractLooseGeom loose_geom; + + struct { + int *tri_first_index; + int *mat_tri_len; + int visible_tri_len; + } poly_sorted; +}; + +#define FOREACH_MESH_BUFFER_CACHE(batch_cache, mbc) \ + for (MeshBufferCache *mbc = &batch_cache->final; \ + mbc == &batch_cache->final || mbc == &batch_cache->cage || mbc == &batch_cache->uv_cage; \ + mbc = (mbc == &batch_cache->final) ? \ + &batch_cache->cage : \ + ((mbc == &batch_cache->cage) ? &batch_cache->uv_cage : NULL)) + +struct MeshBatchCache { + MeshBufferCache final, cage, uv_cage; + + MeshBatchList batch; + + /* Index buffer per material. These are subranges of `ibo.tris` */ + GPUIndexBuf **tris_per_mat; + + GPUBatch **surface_per_mat; + + struct DRWSubdivCache *subdiv_cache; + + DRWBatchFlag batch_requested; /* DRWBatchFlag */ + DRWBatchFlag batch_ready; /* DRWBatchFlag */ + + /* settings to determine if cache is invalid */ + int edge_len; + int tri_len; + int poly_len; + int vert_len; + int mat_len; + bool is_dirty; /* Instantly invalidates cache, skipping mesh check */ + bool is_editmode; + bool is_uvsyncsel; + + struct DRW_MeshWeightState weight_state; + + DRW_MeshCDMask cd_used, cd_needed, cd_used_over_time; + + DRW_Attributes attr_used, attr_needed, attr_used_over_time; + + int lastmatch; + + /* Valid only if edge_detection is up to date. */ + bool is_manifold; + + /* Total areas for drawing UV Stretching. Contains the summed area in mesh + * space (`tot_area`) and the summed area in uv space (`tot_uvarea`). + * + * Only valid after `DRW_mesh_batch_cache_create_requested` has been called. */ + float tot_area, tot_uv_area; + + bool no_loose_wire; + + eV3DShadingColorType color_type; + bool pbvh_is_drawing; +}; + +#define MBC_EDITUV \ + (MBC_EDITUV_FACES_STRETCH_AREA | MBC_EDITUV_FACES_STRETCH_ANGLE | MBC_EDITUV_FACES | \ + MBC_EDITUV_EDGES | MBC_EDITUV_VERTS | MBC_EDITUV_FACEDOTS | MBC_WIRE_LOOPS_UVS) + +namespace blender::draw { + +void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph, + MeshBatchCache *cache, + MeshBufferCache *mbc, + Object *object, + Mesh *me, + bool is_editmode, + bool is_paint_mode, + bool is_mode_active, + const float obmat[4][4], + bool do_final, + bool do_uvedit, + const Scene *scene, + const struct ToolSettings *ts, + bool use_hide); + +void mesh_buffer_cache_create_requested_subdiv(MeshBatchCache *cache, + MeshBufferCache *mbc, + struct DRWSubdivCache *subdiv_cache, + struct MeshRenderData *mr); + +} // namespace blender::draw diff --git a/source/blender/draw/intern/draw_cache_extract_mesh.cc b/source/blender/draw/intern/draw_cache_extract_mesh.cc index 3d44d3d1b3f..00005fd7b4c 100644 --- a/source/blender/draw/intern/draw_cache_extract_mesh.cc +++ b/source/blender/draw/intern/draw_cache_extract_mesh.cc @@ -24,11 +24,11 @@ #include "GPU_capabilities.h" -#include "draw_cache_extract.h" +#include "draw_cache_extract.hh" #include "draw_cache_inline.h" #include "draw_subdivision.h" -#include "mesh_extractors/extract_mesh.h" +#include "mesh_extractors/extract_mesh.hh" // #define DEBUG_TIME @@ -551,21 +551,21 @@ static struct TaskNode *mesh_extract_render_data_node_create(struct TaskGraph *t /** \name Extract Loop * \{ */ -static void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph, - MeshBatchCache *cache, - MeshBufferCache *mbc, - Object *object, - Mesh *me, - - const bool is_editmode, - const bool is_paint_mode, - const bool is_mode_active, - const float obmat[4][4], - const bool do_final, - const bool do_uvedit, - const Scene *scene, - const ToolSettings *ts, - const bool use_hide) +void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph, + MeshBatchCache *cache, + MeshBufferCache *mbc, + Object *object, + Mesh *me, + + const bool is_editmode, + const bool is_paint_mode, + const bool is_mode_active, + const float obmat[4][4], + const bool do_final, + const bool do_uvedit, + const Scene *scene, + const ToolSettings *ts, + const bool use_hide) { /* For each mesh where batches needs to be updated a sub-graph will be added to the task_graph. * This sub-graph starts with an extract_render_data_node. This fills/converts the required @@ -772,10 +772,10 @@ static void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph, /** \name Subdivision Extract Loop * \{ */ -static void mesh_buffer_cache_create_requested_subdiv(MeshBatchCache *cache, - MeshBufferCache *mbc, - DRWSubdivCache *subdiv_cache, - MeshRenderData *mr) +void mesh_buffer_cache_create_requested_subdiv(MeshBatchCache *cache, + MeshBufferCache *mbc, + DRWSubdivCache *subdiv_cache, + MeshRenderData *mr) { /* Create an array containing all the extractors that needs to be executed. */ ExtractorRunDatas extractors; @@ -908,46 +908,3 @@ static void mesh_buffer_cache_create_requested_subdiv(MeshBatchCache *cache, /** \} */ } // namespace blender::draw - -extern "C" { -void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph, - MeshBatchCache *cache, - MeshBufferCache *mbc, - Object *object, - Mesh *me, - - const bool is_editmode, - const bool is_paint_mode, - const bool is_mode_active, - const float obmat[4][4], - const bool do_final, - const bool do_uvedit, - const Scene *scene, - const ToolSettings *ts, - const bool use_hide) -{ - blender::draw::mesh_buffer_cache_create_requested(task_graph, - cache, - mbc, - object, - me, - is_editmode, - is_paint_mode, - is_mode_active, - obmat, - do_final, - do_uvedit, - scene, - ts, - use_hide); -} - -void mesh_buffer_cache_create_requested_subdiv(MeshBatchCache *cache, - MeshBufferCache *mbc, - DRWSubdivCache *subdiv_cache, - MeshRenderData *mr) -{ - blender::draw::mesh_buffer_cache_create_requested_subdiv(cache, mbc, subdiv_cache, mr); -} - -} // extern "C" diff --git a/source/blender/draw/intern/draw_cache_extract_mesh_render_data.c b/source/blender/draw/intern/draw_cache_extract_mesh_render_data.c deleted file mode 100644 index 0a93f346b37..00000000000 --- a/source/blender/draw/intern/draw_cache_extract_mesh_render_data.c +++ /dev/null @@ -1,569 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later - * Copyright 2021 Blender Foundation. All rights reserved. */ - -/** \file - * \ingroup draw - * - * \brief Extraction of Mesh data into VBO to feed to GPU. - */ - -#include "MEM_guardedalloc.h" - -#include "BLI_alloca.h" -#include "BLI_bitmap.h" -#include "BLI_math.h" -#include "BLI_task.h" - -#include "BKE_editmesh.h" -#include "BKE_editmesh_cache.h" -#include "BKE_mesh.h" - -#include "GPU_batch.h" - -#include "ED_mesh.h" - -#include "mesh_extractors/extract_mesh.h" - -/* ---------------------------------------------------------------------- */ -/** \name Update Loose Geometry - * \{ */ - -static void mesh_render_data_lverts_bm(const MeshRenderData *mr, - MeshBufferCache *cache, - BMesh *bm); -static void mesh_render_data_ledges_bm(const MeshRenderData *mr, - MeshBufferCache *cache, - BMesh *bm); -static void mesh_render_data_loose_geom_mesh(const MeshRenderData *mr, MeshBufferCache *cache); -static void mesh_render_data_loose_geom_build(const MeshRenderData *mr, MeshBufferCache *cache); - -static void mesh_render_data_loose_geom_load(MeshRenderData *mr, MeshBufferCache *cache) -{ - mr->ledges = cache->loose_geom.edges; - mr->lverts = cache->loose_geom.verts; - mr->vert_loose_len = cache->loose_geom.vert_len; - mr->edge_loose_len = cache->loose_geom.edge_len; - - mr->loop_loose_len = mr->vert_loose_len + (mr->edge_loose_len * 2); -} - -static void mesh_render_data_loose_geom_ensure(const MeshRenderData *mr, MeshBufferCache *cache) -{ - /* Early exit: Are loose geometry already available. - * Only checking for loose verts as loose edges and verts are calculated at the same time. */ - if (cache->loose_geom.verts) { - return; - } - mesh_render_data_loose_geom_build(mr, cache); -} - -static void mesh_render_data_loose_geom_build(const MeshRenderData *mr, MeshBufferCache *cache) -{ - cache->loose_geom.vert_len = 0; - cache->loose_geom.edge_len = 0; - - if (mr->extract_type != MR_EXTRACT_BMESH) { - /* Mesh */ - mesh_render_data_loose_geom_mesh(mr, cache); - } - else { - /* #BMesh */ - BMesh *bm = mr->bm; - mesh_render_data_lverts_bm(mr, cache, bm); - mesh_render_data_ledges_bm(mr, cache, bm); - } -} - -static void mesh_render_data_loose_geom_mesh(const MeshRenderData *mr, MeshBufferCache *cache) -{ - BLI_bitmap *lvert_map = BLI_BITMAP_NEW(mr->vert_len, __func__); - - cache->loose_geom.edges = MEM_mallocN(mr->edge_len * sizeof(*cache->loose_geom.edges), __func__); - const MEdge *med = mr->medge; - for (int med_index = 0; med_index < mr->edge_len; med_index++, med++) { - if (med->flag & ME_LOOSEEDGE) { - cache->loose_geom.edges[cache->loose_geom.edge_len++] = med_index; - } - /* Tag verts as not loose. */ - BLI_BITMAP_ENABLE(lvert_map, med->v1); - BLI_BITMAP_ENABLE(lvert_map, med->v2); - } - if (cache->loose_geom.edge_len < mr->edge_len) { - cache->loose_geom.edges = MEM_reallocN( - cache->loose_geom.edges, cache->loose_geom.edge_len * sizeof(*cache->loose_geom.edges)); - } - - cache->loose_geom.verts = MEM_mallocN(mr->vert_len * sizeof(*cache->loose_geom.verts), __func__); - for (int v = 0; v < mr->vert_len; v++) { - if (!BLI_BITMAP_TEST(lvert_map, v)) { - cache->loose_geom.verts[cache->loose_geom.vert_len++] = v; - } - } - if (cache->loose_geom.vert_len < mr->vert_len) { - cache->loose_geom.verts = MEM_reallocN( - cache->loose_geom.verts, cache->loose_geom.vert_len * sizeof(*cache->loose_geom.verts)); - } - - MEM_freeN(lvert_map); -} - -static void mesh_render_data_lverts_bm(const MeshRenderData *mr, MeshBufferCache *cache, BMesh *bm) -{ - int elem_id; - BMIter iter; - BMVert *eve; - cache->loose_geom.verts = MEM_mallocN(mr->vert_len * sizeof(*cache->loose_geom.verts), __func__); - BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, elem_id) { - if (eve->e == NULL) { - cache->loose_geom.verts[cache->loose_geom.vert_len++] = elem_id; - } - } - if (cache->loose_geom.vert_len < mr->vert_len) { - cache->loose_geom.verts = MEM_reallocN( - cache->loose_geom.verts, cache->loose_geom.vert_len * sizeof(*cache->loose_geom.verts)); - } -} - -static void mesh_render_data_ledges_bm(const MeshRenderData *mr, MeshBufferCache *cache, BMesh *bm) -{ - int elem_id; - BMIter iter; - BMEdge *ede; - cache->loose_geom.edges = MEM_mallocN(mr->edge_len * sizeof(*cache->loose_geom.edges), __func__); - BM_ITER_MESH_INDEX (ede, &iter, bm, BM_EDGES_OF_MESH, elem_id) { - if (ede->l == NULL) { - cache->loose_geom.edges[cache->loose_geom.edge_len++] = elem_id; - } - } - if (cache->loose_geom.edge_len < mr->edge_len) { - cache->loose_geom.edges = MEM_reallocN( - cache->loose_geom.edges, cache->loose_geom.edge_len * sizeof(*cache->loose_geom.edges)); - } -} - -void mesh_render_data_update_loose_geom(MeshRenderData *mr, - MeshBufferCache *cache, - const eMRIterType iter_type, - const eMRDataType data_flag) -{ - if ((iter_type & (MR_ITER_LEDGE | MR_ITER_LVERT)) || (data_flag & MR_DATA_LOOSE_GEOM)) { - mesh_render_data_loose_geom_ensure(mr, cache); - mesh_render_data_loose_geom_load(mr, cache); - } -} - -/** \} */ - -/* ---------------------------------------------------------------------- */ -/** \name Polygons sorted per material - * - * Contains polygon indices sorted based on their material. - * \{ */ - -static void mesh_render_data_polys_sorted_load(MeshRenderData *mr, const MeshBufferCache *cache); -static void mesh_render_data_polys_sorted_ensure(MeshRenderData *mr, MeshBufferCache *cache); -static void mesh_render_data_polys_sorted_build(MeshRenderData *mr, MeshBufferCache *cache); -static int *mesh_render_data_mat_tri_len_build(MeshRenderData *mr); - -void mesh_render_data_update_polys_sorted(MeshRenderData *mr, - MeshBufferCache *cache, - const eMRDataType data_flag) -{ - if (data_flag & MR_DATA_POLYS_SORTED) { - mesh_render_data_polys_sorted_ensure(mr, cache); - mesh_render_data_polys_sorted_load(mr, cache); - } -} - -static void mesh_render_data_polys_sorted_load(MeshRenderData *mr, const MeshBufferCache *cache) -{ - mr->poly_sorted.tri_first_index = cache->poly_sorted.tri_first_index; - mr->poly_sorted.mat_tri_len = cache->poly_sorted.mat_tri_len; - mr->poly_sorted.visible_tri_len = cache->poly_sorted.visible_tri_len; -} - -static void mesh_render_data_polys_sorted_ensure(MeshRenderData *mr, MeshBufferCache *cache) -{ - if (cache->poly_sorted.tri_first_index) { - return; - } - mesh_render_data_polys_sorted_build(mr, cache); -} - -static void mesh_render_data_polys_sorted_build(MeshRenderData *mr, MeshBufferCache *cache) -{ - int *tri_first_index = MEM_mallocN(sizeof(*tri_first_index) * mr->poly_len, __func__); - int *mat_tri_len = mesh_render_data_mat_tri_len_build(mr); - - /* Apply offset. */ - int visible_tri_len = 0; - int *mat_tri_offs = BLI_array_alloca(mat_tri_offs, mr->mat_len); - { - for (int i = 0; i < mr->mat_len; i++) { - mat_tri_offs[i] = visible_tri_len; - visible_tri_len += mat_tri_len[i]; - } - } - - /* Sort per material. */ - int mat_last = mr->mat_len - 1; - if (mr->extract_type == MR_EXTRACT_BMESH) { - BMIter iter; - BMFace *f; - int i; - BM_ITER_MESH_INDEX (f, &iter, mr->bm, BM_FACES_OF_MESH, i) { - if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) { - const int mat = min_ii(f->mat_nr, mat_last); - tri_first_index[i] = mat_tri_offs[mat]; - mat_tri_offs[mat] += f->len - 2; - } - else { - tri_first_index[i] = -1; - } - } - } - else { - const MPoly *mp = &mr->mpoly[0]; - for (int i = 0; i < mr->poly_len; i++, mp++) { - if (!(mr->use_hide && (mp->flag & ME_HIDE))) { - const int mat = min_ii(mp->mat_nr, mat_last); - tri_first_index[i] = mat_tri_offs[mat]; - mat_tri_offs[mat] += mp->totloop - 2; - } - else { - tri_first_index[i] = -1; - } - } - } - - cache->poly_sorted.tri_first_index = tri_first_index; - cache->poly_sorted.mat_tri_len = mat_tri_len; - cache->poly_sorted.visible_tri_len = visible_tri_len; -} - -static void mesh_render_data_mat_tri_len_bm_range_fn(void *__restrict userdata, - const int iter, - const TaskParallelTLS *__restrict tls) -{ - MeshRenderData *mr = userdata; - int *mat_tri_len = tls->userdata_chunk; - - BMesh *bm = mr->bm; - BMFace *efa = BM_face_at_index(bm, iter); - if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) { - int mat = min_ii(efa->mat_nr, mr->mat_len - 1); - mat_tri_len[mat] += efa->len - 2; - } -} - -static void mesh_render_data_mat_tri_len_mesh_range_fn(void *__restrict userdata, - const int iter, - const TaskParallelTLS *__restrict tls) -{ - MeshRenderData *mr = userdata; - int *mat_tri_len = tls->userdata_chunk; - - const MPoly *mp = &mr->mpoly[iter]; - if (!(mr->use_hide && (mp->flag & ME_HIDE))) { - int mat = min_ii(mp->mat_nr, mr->mat_len - 1); - mat_tri_len[mat] += mp->totloop - 2; - } -} - -static void mesh_render_data_mat_tri_len_reduce_fn(const void *__restrict userdata, - void *__restrict chunk_join, - void *__restrict chunk) -{ - const MeshRenderData *mr = userdata; - int *dst_mat_len = chunk_join; - int *src_mat_len = chunk; - for (int i = 0; i < mr->mat_len; i++) { - dst_mat_len[i] += src_mat_len[i]; - } -} - -static int *mesh_render_data_mat_tri_len_build_threaded(MeshRenderData *mr, - int face_len, - TaskParallelRangeFunc range_func) -{ - /* Extending the #MatOffsetUserData with an int per material slot. */ - size_t mat_tri_len_size = sizeof(int) * mr->mat_len; - int *mat_tri_len = MEM_callocN(mat_tri_len_size, __func__); - - TaskParallelSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.userdata_chunk = mat_tri_len; - settings.userdata_chunk_size = mat_tri_len_size; - settings.min_iter_per_thread = MIN_RANGE_LEN; - settings.func_reduce = mesh_render_data_mat_tri_len_reduce_fn; - BLI_task_parallel_range(0, face_len, mr, range_func, &settings); - - return mat_tri_len; -} - -/* Count how many triangles for each material. */ -static int *mesh_render_data_mat_tri_len_build(MeshRenderData *mr) -{ - if (mr->extract_type == MR_EXTRACT_BMESH) { - BMesh *bm = mr->bm; - return mesh_render_data_mat_tri_len_build_threaded( - mr, bm->totface, mesh_render_data_mat_tri_len_bm_range_fn); - } - return mesh_render_data_mat_tri_len_build_threaded( - mr, mr->poly_len, mesh_render_data_mat_tri_len_mesh_range_fn); -} - -/** \} */ - -/* ---------------------------------------------------------------------- */ -/** \name Mesh/BMesh Interface (indirect, partially cached access to complex data). - * \{ */ - -void mesh_render_data_update_looptris(MeshRenderData *mr, - const eMRIterType iter_type, - const eMRDataType data_flag) -{ - Mesh *me = mr->me; - if (mr->extract_type != MR_EXTRACT_BMESH) { - /* Mesh */ - if ((iter_type & MR_ITER_LOOPTRI) || (data_flag & MR_DATA_LOOPTRI)) { - /* NOTE(campbell): It's possible to skip allocating tessellation, - * the tessellation can be calculated as part of the iterator, see: P2188. - * The overall advantage is small (around 1%), so keep this as-is. */ - mr->mlooptri = MEM_mallocN(sizeof(*mr->mlooptri) * mr->tri_len, "MR_DATATYPE_LOOPTRI"); - if (mr->poly_normals != NULL) { - BKE_mesh_recalc_looptri_with_normals(me->mloop, - me->mpoly, - me->mvert, - me->totloop, - me->totpoly, - mr->mlooptri, - mr->poly_normals); - } - else { - BKE_mesh_recalc_looptri( - me->mloop, me->mpoly, me->mvert, me->totloop, me->totpoly, mr->mlooptri); - } - } - } - else { - /* #BMesh */ - if ((iter_type & MR_ITER_LOOPTRI) || (data_flag & MR_DATA_LOOPTRI)) { - /* Edit mode ensures this is valid, no need to calculate. */ - BLI_assert((mr->bm->totloop == 0) || (mr->edit_bmesh->looptris != NULL)); - } - } -} - -void mesh_render_data_update_normals(MeshRenderData *mr, const eMRDataType data_flag) -{ - Mesh *me = mr->me; - const bool is_auto_smooth = (me->flag & ME_AUTOSMOOTH) != 0; - const float split_angle = is_auto_smooth ? me->smoothresh : (float)M_PI; - - if (mr->extract_type != MR_EXTRACT_BMESH) { - /* Mesh */ - mr->vert_normals = BKE_mesh_vertex_normals_ensure(mr->me); - if (data_flag & (MR_DATA_POLY_NOR | MR_DATA_LOOP_NOR | MR_DATA_TAN_LOOP_NOR)) { - mr->poly_normals = BKE_mesh_poly_normals_ensure(mr->me); - } - if (((data_flag & MR_DATA_LOOP_NOR) && is_auto_smooth) || (data_flag & MR_DATA_TAN_LOOP_NOR)) { - mr->loop_normals = MEM_mallocN(sizeof(*mr->loop_normals) * mr->loop_len, __func__); - short(*clnors)[2] = CustomData_get_layer(&mr->me->ldata, CD_CUSTOMLOOPNORMAL); - BKE_mesh_normals_loop_split(mr->me->mvert, - mr->vert_normals, - mr->vert_len, - mr->me->medge, - mr->edge_len, - mr->me->mloop, - mr->loop_normals, - mr->loop_len, - mr->me->mpoly, - mr->poly_normals, - mr->poly_len, - is_auto_smooth, - split_angle, - NULL, - clnors, - NULL); - } - } - else { - /* #BMesh */ - if (data_flag & MR_DATA_POLY_NOR) { - /* Use #BMFace.no instead. */ - } - if (((data_flag & MR_DATA_LOOP_NOR) && is_auto_smooth) || (data_flag & MR_DATA_TAN_LOOP_NOR)) { - - const float(*vert_coords)[3] = NULL; - const float(*vert_normals)[3] = NULL; - const float(*poly_normals)[3] = NULL; - - if (mr->edit_data && mr->edit_data->vertexCos) { - vert_coords = mr->bm_vert_coords; - vert_normals = mr->bm_vert_normals; - poly_normals = mr->bm_poly_normals; - } - - mr->loop_normals = MEM_mallocN(sizeof(*mr->loop_normals) * mr->loop_len, __func__); - const int clnors_offset = CustomData_get_offset(&mr->bm->ldata, CD_CUSTOMLOOPNORMAL); - BM_loops_calc_normal_vcos(mr->bm, - vert_coords, - vert_normals, - poly_normals, - is_auto_smooth, - split_angle, - mr->loop_normals, - NULL, - NULL, - clnors_offset, - false); - } - } -} - -MeshRenderData *mesh_render_data_create(Object *object, - Mesh *me, - const bool is_editmode, - const bool is_paint_mode, - const bool is_mode_active, - const float obmat[4][4], - const bool do_final, - const bool do_uvedit, - const ToolSettings *ts) -{ - MeshRenderData *mr = MEM_callocN(sizeof(*mr), __func__); - mr->toolsettings = ts; - mr->mat_len = mesh_render_mat_len_get(object, me); - - copy_m4_m4(mr->obmat, obmat); - - if (is_editmode) { - Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(object); - Mesh *editmesh_eval_cage = BKE_object_get_editmesh_eval_cage(object); - - BLI_assert(editmesh_eval_cage && editmesh_eval_final); - mr->bm = me->edit_mesh->bm; - mr->edit_bmesh = me->edit_mesh; - mr->me = (do_final) ? editmesh_eval_final : editmesh_eval_cage; - mr->edit_data = is_mode_active ? mr->me->runtime.edit_data : NULL; - - if (mr->edit_data) { - EditMeshData *emd = mr->edit_data; - if (emd->vertexCos) { - BKE_editmesh_cache_ensure_vert_normals(mr->edit_bmesh, emd); - BKE_editmesh_cache_ensure_poly_normals(mr->edit_bmesh, emd); - } - - mr->bm_vert_coords = mr->edit_data->vertexCos; - mr->bm_vert_normals = mr->edit_data->vertexNos; - mr->bm_poly_normals = mr->edit_data->polyNos; - mr->bm_poly_centers = mr->edit_data->polyCos; - } - - /* A subdivision wrapper may be created in edit mode when X-ray is turned on to ensure that the - * topology seen by the user matches the one used for the selection routines. This wrapper - * seemingly takes precedence over the MDATA one, however the mesh we use for rendering is not - * the subdivided one, but the one where the MDATA wrapper would have been added. So consider - * the subdivision wrapper as well for the `has_mdata` case. */ - bool has_mdata = is_mode_active && ELEM(mr->me->runtime.wrapper_type, - ME_WRAPPER_TYPE_MDATA, - ME_WRAPPER_TYPE_SUBD); - bool use_mapped = is_mode_active && - (has_mdata && !do_uvedit && mr->me && !mr->me->runtime.is_original); - - int bm_ensure_types = BM_VERT | BM_EDGE | BM_LOOP | BM_FACE; - - BM_mesh_elem_index_ensure(mr->bm, bm_ensure_types); - BM_mesh_elem_table_ensure(mr->bm, bm_ensure_types & ~BM_LOOP); - - mr->efa_act_uv = EDBM_uv_active_face_get(mr->edit_bmesh, false, false); - mr->efa_act = BM_mesh_active_face_get(mr->bm, false, true); - mr->eed_act = BM_mesh_active_edge_get(mr->bm); - mr->eve_act = BM_mesh_active_vert_get(mr->bm); - - mr->vert_crease_ofs = CustomData_get_offset(&mr->bm->vdata, CD_CREASE); - mr->edge_crease_ofs = CustomData_get_offset(&mr->bm->edata, CD_CREASE); - mr->bweight_ofs = CustomData_get_offset(&mr->bm->edata, CD_BWEIGHT); -#ifdef WITH_FREESTYLE - mr->freestyle_edge_ofs = CustomData_get_offset(&mr->bm->edata, CD_FREESTYLE_EDGE); - mr->freestyle_face_ofs = CustomData_get_offset(&mr->bm->pdata, CD_FREESTYLE_FACE); -#endif - - if (use_mapped) { - mr->v_origindex = CustomData_get_layer(&mr->me->vdata, CD_ORIGINDEX); - mr->e_origindex = CustomData_get_layer(&mr->me->edata, CD_ORIGINDEX); - mr->p_origindex = CustomData_get_layer(&mr->me->pdata, CD_ORIGINDEX); - - use_mapped = (mr->v_origindex || mr->e_origindex || mr->p_origindex); - } - - mr->extract_type = use_mapped ? MR_EXTRACT_MAPPED : MR_EXTRACT_BMESH; - - /* Seems like the mesh_eval_final do not have the right origin indices. - * Force not mapped in this case. */ - if (has_mdata && do_final && editmesh_eval_final != editmesh_eval_cage) { - // mr->edit_bmesh = NULL; - mr->extract_type = MR_EXTRACT_MESH; - } - } - else { - mr->me = me; - mr->edit_bmesh = NULL; - - bool use_mapped = is_paint_mode && mr->me && !mr->me->runtime.is_original; - if (use_mapped) { - mr->v_origindex = CustomData_get_layer(&mr->me->vdata, CD_ORIGINDEX); - mr->e_origindex = CustomData_get_layer(&mr->me->edata, CD_ORIGINDEX); - mr->p_origindex = CustomData_get_layer(&mr->me->pdata, CD_ORIGINDEX); - - use_mapped = (mr->v_origindex || mr->e_origindex || mr->p_origindex); - } - - mr->extract_type = use_mapped ? MR_EXTRACT_MAPPED : MR_EXTRACT_MESH; - } - - if (mr->extract_type != MR_EXTRACT_BMESH) { - /* Mesh */ - mr->vert_len = mr->me->totvert; - mr->edge_len = mr->me->totedge; - mr->loop_len = mr->me->totloop; - mr->poly_len = mr->me->totpoly; - mr->tri_len = poly_to_tri_count(mr->poly_len, mr->loop_len); - - mr->mvert = CustomData_get_layer(&mr->me->vdata, CD_MVERT); - mr->medge = CustomData_get_layer(&mr->me->edata, CD_MEDGE); - mr->mloop = CustomData_get_layer(&mr->me->ldata, CD_MLOOP); - mr->mpoly = CustomData_get_layer(&mr->me->pdata, CD_MPOLY); - - mr->v_origindex = CustomData_get_layer(&mr->me->vdata, CD_ORIGINDEX); - mr->e_origindex = CustomData_get_layer(&mr->me->edata, CD_ORIGINDEX); - mr->p_origindex = CustomData_get_layer(&mr->me->pdata, CD_ORIGINDEX); - } - else { - /* #BMesh */ - BMesh *bm = mr->bm; - - mr->vert_len = bm->totvert; - mr->edge_len = bm->totedge; - mr->loop_len = bm->totloop; - mr->poly_len = bm->totface; - mr->tri_len = poly_to_tri_count(mr->poly_len, mr->loop_len); - } - - return mr; -} - -void mesh_render_data_free(MeshRenderData *mr) -{ - MEM_SAFE_FREE(mr->mlooptri); - MEM_SAFE_FREE(mr->loop_normals); - - /* Loose geometry are owned by #MeshBufferCache. */ - mr->ledges = NULL; - mr->lverts = NULL; - - MEM_freeN(mr); -} - -/** \} */ diff --git a/source/blender/draw/intern/draw_cache_extract_mesh_render_data.cc b/source/blender/draw/intern/draw_cache_extract_mesh_render_data.cc new file mode 100644 index 00000000000..82be73f6de8 --- /dev/null +++ b/source/blender/draw/intern/draw_cache_extract_mesh_render_data.cc @@ -0,0 +1,584 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2021 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup draw + * + * \brief Extraction of Mesh data into VBO to feed to GPU. + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_array.hh" +#include "BLI_bitmap.h" +#include "BLI_math.h" +#include "BLI_task.h" + +#include "BKE_editmesh.h" +#include "BKE_editmesh_cache.h" +#include "BKE_mesh.h" + +#include "GPU_batch.h" + +#include "ED_mesh.h" + +#include "mesh_extractors/extract_mesh.hh" + +/* ---------------------------------------------------------------------- */ +/** \name Update Loose Geometry + * \{ */ + +static void mesh_render_data_lverts_bm(const MeshRenderData *mr, + MeshBufferCache *cache, + BMesh *bm); +static void mesh_render_data_ledges_bm(const MeshRenderData *mr, + MeshBufferCache *cache, + BMesh *bm); +static void mesh_render_data_loose_geom_mesh(const MeshRenderData *mr, MeshBufferCache *cache); +static void mesh_render_data_loose_geom_build(const MeshRenderData *mr, MeshBufferCache *cache); + +static void mesh_render_data_loose_geom_load(MeshRenderData *mr, MeshBufferCache *cache) +{ + mr->ledges = cache->loose_geom.edges; + mr->lverts = cache->loose_geom.verts; + mr->vert_loose_len = cache->loose_geom.vert_len; + mr->edge_loose_len = cache->loose_geom.edge_len; + + mr->loop_loose_len = mr->vert_loose_len + (mr->edge_loose_len * 2); +} + +static void mesh_render_data_loose_geom_ensure(const MeshRenderData *mr, MeshBufferCache *cache) +{ + /* Early exit: Are loose geometry already available. + * Only checking for loose verts as loose edges and verts are calculated at the same time. */ + if (cache->loose_geom.verts) { + return; + } + mesh_render_data_loose_geom_build(mr, cache); +} + +static void mesh_render_data_loose_geom_build(const MeshRenderData *mr, MeshBufferCache *cache) +{ + cache->loose_geom.vert_len = 0; + cache->loose_geom.edge_len = 0; + + if (mr->extract_type != MR_EXTRACT_BMESH) { + /* Mesh */ + mesh_render_data_loose_geom_mesh(mr, cache); + } + else { + /* #BMesh */ + BMesh *bm = mr->bm; + mesh_render_data_lverts_bm(mr, cache, bm); + mesh_render_data_ledges_bm(mr, cache, bm); + } +} + +static void mesh_render_data_loose_geom_mesh(const MeshRenderData *mr, MeshBufferCache *cache) +{ + BLI_bitmap *lvert_map = BLI_BITMAP_NEW(mr->vert_len, __func__); + + cache->loose_geom.edges = static_cast( + MEM_mallocN(mr->edge_len * sizeof(*cache->loose_geom.edges), __func__)); + const MEdge *med = mr->medge; + for (int med_index = 0; med_index < mr->edge_len; med_index++, med++) { + if (med->flag & ME_LOOSEEDGE) { + cache->loose_geom.edges[cache->loose_geom.edge_len++] = med_index; + } + /* Tag verts as not loose. */ + BLI_BITMAP_ENABLE(lvert_map, med->v1); + BLI_BITMAP_ENABLE(lvert_map, med->v2); + } + if (cache->loose_geom.edge_len < mr->edge_len) { + cache->loose_geom.edges = static_cast(MEM_reallocN( + cache->loose_geom.edges, cache->loose_geom.edge_len * sizeof(*cache->loose_geom.edges))); + } + + cache->loose_geom.verts = static_cast( + MEM_mallocN(mr->vert_len * sizeof(*cache->loose_geom.verts), __func__)); + for (int v = 0; v < mr->vert_len; v++) { + if (!BLI_BITMAP_TEST(lvert_map, v)) { + cache->loose_geom.verts[cache->loose_geom.vert_len++] = v; + } + } + if (cache->loose_geom.vert_len < mr->vert_len) { + cache->loose_geom.verts = static_cast(MEM_reallocN( + cache->loose_geom.verts, cache->loose_geom.vert_len * sizeof(*cache->loose_geom.verts))); + } + + MEM_freeN(lvert_map); +} + +static void mesh_render_data_lverts_bm(const MeshRenderData *mr, MeshBufferCache *cache, BMesh *bm) +{ + int elem_id; + BMIter iter; + BMVert *eve; + cache->loose_geom.verts = static_cast( + MEM_mallocN(mr->vert_len * sizeof(*cache->loose_geom.verts), __func__)); + BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, elem_id) { + if (eve->e == NULL) { + cache->loose_geom.verts[cache->loose_geom.vert_len++] = elem_id; + } + } + if (cache->loose_geom.vert_len < mr->vert_len) { + cache->loose_geom.verts = static_cast(MEM_reallocN( + cache->loose_geom.verts, cache->loose_geom.vert_len * sizeof(*cache->loose_geom.verts))); + } +} + +static void mesh_render_data_ledges_bm(const MeshRenderData *mr, MeshBufferCache *cache, BMesh *bm) +{ + int elem_id; + BMIter iter; + BMEdge *ede; + cache->loose_geom.edges = static_cast( + MEM_mallocN(mr->edge_len * sizeof(*cache->loose_geom.edges), __func__)); + BM_ITER_MESH_INDEX (ede, &iter, bm, BM_EDGES_OF_MESH, elem_id) { + if (ede->l == NULL) { + cache->loose_geom.edges[cache->loose_geom.edge_len++] = elem_id; + } + } + if (cache->loose_geom.edge_len < mr->edge_len) { + cache->loose_geom.edges = static_cast(MEM_reallocN( + cache->loose_geom.edges, cache->loose_geom.edge_len * sizeof(*cache->loose_geom.edges))); + } +} + +void mesh_render_data_update_loose_geom(MeshRenderData *mr, + MeshBufferCache *cache, + const eMRIterType iter_type, + const eMRDataType data_flag) +{ + if ((iter_type & (MR_ITER_LEDGE | MR_ITER_LVERT)) || (data_flag & MR_DATA_LOOSE_GEOM)) { + mesh_render_data_loose_geom_ensure(mr, cache); + mesh_render_data_loose_geom_load(mr, cache); + } +} + +/** \} */ + +/* ---------------------------------------------------------------------- */ +/** \name Polygons sorted per material + * + * Contains polygon indices sorted based on their material. + * \{ */ + +static void mesh_render_data_polys_sorted_load(MeshRenderData *mr, const MeshBufferCache *cache); +static void mesh_render_data_polys_sorted_ensure(MeshRenderData *mr, MeshBufferCache *cache); +static void mesh_render_data_polys_sorted_build(MeshRenderData *mr, MeshBufferCache *cache); +static int *mesh_render_data_mat_tri_len_build(MeshRenderData *mr); + +void mesh_render_data_update_polys_sorted(MeshRenderData *mr, + MeshBufferCache *cache, + const eMRDataType data_flag) +{ + if (data_flag & MR_DATA_POLYS_SORTED) { + mesh_render_data_polys_sorted_ensure(mr, cache); + mesh_render_data_polys_sorted_load(mr, cache); + } +} + +static void mesh_render_data_polys_sorted_load(MeshRenderData *mr, const MeshBufferCache *cache) +{ + mr->poly_sorted.tri_first_index = cache->poly_sorted.tri_first_index; + mr->poly_sorted.mat_tri_len = cache->poly_sorted.mat_tri_len; + mr->poly_sorted.visible_tri_len = cache->poly_sorted.visible_tri_len; +} + +static void mesh_render_data_polys_sorted_ensure(MeshRenderData *mr, MeshBufferCache *cache) +{ + if (cache->poly_sorted.tri_first_index) { + return; + } + mesh_render_data_polys_sorted_build(mr, cache); +} + +static void mesh_render_data_polys_sorted_build(MeshRenderData *mr, MeshBufferCache *cache) +{ + int *tri_first_index = static_cast( + MEM_mallocN(sizeof(*tri_first_index) * mr->poly_len, __func__)); + int *mat_tri_len = mesh_render_data_mat_tri_len_build(mr); + + /* Apply offset. */ + int visible_tri_len = 0; + blender::Array mat_tri_offs(mr->mat_len); + { + for (int i = 0; i < mr->mat_len; i++) { + mat_tri_offs[i] = visible_tri_len; + visible_tri_len += mat_tri_len[i]; + } + } + + /* Sort per material. */ + int mat_last = mr->mat_len - 1; + if (mr->extract_type == MR_EXTRACT_BMESH) { + BMIter iter; + BMFace *f; + int i; + BM_ITER_MESH_INDEX (f, &iter, mr->bm, BM_FACES_OF_MESH, i) { + if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) { + const int mat = min_ii(f->mat_nr, mat_last); + tri_first_index[i] = mat_tri_offs[mat]; + mat_tri_offs[mat] += f->len - 2; + } + else { + tri_first_index[i] = -1; + } + } + } + else { + const MPoly *mp = &mr->mpoly[0]; + for (int i = 0; i < mr->poly_len; i++, mp++) { + if (!(mr->use_hide && (mp->flag & ME_HIDE))) { + const int mat = min_ii(mp->mat_nr, mat_last); + tri_first_index[i] = mat_tri_offs[mat]; + mat_tri_offs[mat] += mp->totloop - 2; + } + else { + tri_first_index[i] = -1; + } + } + } + + cache->poly_sorted.tri_first_index = tri_first_index; + cache->poly_sorted.mat_tri_len = mat_tri_len; + cache->poly_sorted.visible_tri_len = visible_tri_len; +} + +static void mesh_render_data_mat_tri_len_bm_range_fn(void *__restrict userdata, + const int iter, + const TaskParallelTLS *__restrict tls) +{ + MeshRenderData *mr = static_cast(userdata); + int *mat_tri_len = static_cast(tls->userdata_chunk); + + BMesh *bm = mr->bm; + BMFace *efa = BM_face_at_index(bm, iter); + if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) { + int mat = min_ii(efa->mat_nr, mr->mat_len - 1); + mat_tri_len[mat] += efa->len - 2; + } +} + +static void mesh_render_data_mat_tri_len_mesh_range_fn(void *__restrict userdata, + const int iter, + const TaskParallelTLS *__restrict tls) +{ + MeshRenderData *mr = static_cast(userdata); + int *mat_tri_len = static_cast(tls->userdata_chunk); + + const MPoly *mp = &mr->mpoly[iter]; + if (!(mr->use_hide && (mp->flag & ME_HIDE))) { + int mat = min_ii(mp->mat_nr, mr->mat_len - 1); + mat_tri_len[mat] += mp->totloop - 2; + } +} + +static void mesh_render_data_mat_tri_len_reduce_fn(const void *__restrict userdata, + void *__restrict chunk_join, + void *__restrict chunk) +{ + const MeshRenderData *mr = static_cast(userdata); + int *dst_mat_len = static_cast(chunk_join); + int *src_mat_len = static_cast(chunk); + for (int i = 0; i < mr->mat_len; i++) { + dst_mat_len[i] += src_mat_len[i]; + } +} + +static int *mesh_render_data_mat_tri_len_build_threaded(MeshRenderData *mr, + int face_len, + TaskParallelRangeFunc range_func) +{ + /* Extending the #MatOffsetUserData with an int per material slot. */ + size_t mat_tri_len_size = sizeof(int) * mr->mat_len; + int *mat_tri_len = static_cast(MEM_callocN(mat_tri_len_size, __func__)); + + TaskParallelSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.userdata_chunk = mat_tri_len; + settings.userdata_chunk_size = mat_tri_len_size; + settings.min_iter_per_thread = MIN_RANGE_LEN; + settings.func_reduce = mesh_render_data_mat_tri_len_reduce_fn; + BLI_task_parallel_range(0, face_len, mr, range_func, &settings); + + return mat_tri_len; +} + +/* Count how many triangles for each material. */ +static int *mesh_render_data_mat_tri_len_build(MeshRenderData *mr) +{ + if (mr->extract_type == MR_EXTRACT_BMESH) { + BMesh *bm = mr->bm; + return mesh_render_data_mat_tri_len_build_threaded( + mr, bm->totface, mesh_render_data_mat_tri_len_bm_range_fn); + } + return mesh_render_data_mat_tri_len_build_threaded( + mr, mr->poly_len, mesh_render_data_mat_tri_len_mesh_range_fn); +} + +/** \} */ + +/* ---------------------------------------------------------------------- */ +/** \name Mesh/BMesh Interface (indirect, partially cached access to complex data). + * \{ */ + +void mesh_render_data_update_looptris(MeshRenderData *mr, + const eMRIterType iter_type, + const eMRDataType data_flag) +{ + Mesh *me = mr->me; + if (mr->extract_type != MR_EXTRACT_BMESH) { + /* Mesh */ + if ((iter_type & MR_ITER_LOOPTRI) || (data_flag & MR_DATA_LOOPTRI)) { + /* NOTE(campbell): It's possible to skip allocating tessellation, + * the tessellation can be calculated as part of the iterator, see: P2188. + * The overall advantage is small (around 1%), so keep this as-is. */ + mr->mlooptri = static_cast( + MEM_mallocN(sizeof(*mr->mlooptri) * mr->tri_len, "MR_DATATYPE_LOOPTRI")); + if (mr->poly_normals != NULL) { + BKE_mesh_recalc_looptri_with_normals(me->mloop, + me->mpoly, + me->mvert, + me->totloop, + me->totpoly, + mr->mlooptri, + mr->poly_normals); + } + else { + BKE_mesh_recalc_looptri( + me->mloop, me->mpoly, me->mvert, me->totloop, me->totpoly, mr->mlooptri); + } + } + } + else { + /* #BMesh */ + if ((iter_type & MR_ITER_LOOPTRI) || (data_flag & MR_DATA_LOOPTRI)) { + /* Edit mode ensures this is valid, no need to calculate. */ + BLI_assert((mr->bm->totloop == 0) || (mr->edit_bmesh->looptris != NULL)); + } + } +} + +void mesh_render_data_update_normals(MeshRenderData *mr, const eMRDataType data_flag) +{ + Mesh *me = mr->me; + const bool is_auto_smooth = (me->flag & ME_AUTOSMOOTH) != 0; + const float split_angle = is_auto_smooth ? me->smoothresh : (float)M_PI; + + if (mr->extract_type != MR_EXTRACT_BMESH) { + /* Mesh */ + mr->vert_normals = BKE_mesh_vertex_normals_ensure(mr->me); + if (data_flag & (MR_DATA_POLY_NOR | MR_DATA_LOOP_NOR | MR_DATA_TAN_LOOP_NOR)) { + mr->poly_normals = BKE_mesh_poly_normals_ensure(mr->me); + } + if (((data_flag & MR_DATA_LOOP_NOR) && is_auto_smooth) || (data_flag & MR_DATA_TAN_LOOP_NOR)) { + mr->loop_normals = static_cast( + MEM_mallocN(sizeof(*mr->loop_normals) * mr->loop_len, __func__)); + short(*clnors)[2] = static_cast( + CustomData_get_layer(&mr->me->ldata, CD_CUSTOMLOOPNORMAL)); + BKE_mesh_normals_loop_split(mr->me->mvert, + mr->vert_normals, + mr->vert_len, + mr->me->medge, + mr->edge_len, + mr->me->mloop, + mr->loop_normals, + mr->loop_len, + mr->me->mpoly, + mr->poly_normals, + mr->poly_len, + is_auto_smooth, + split_angle, + NULL, + clnors, + NULL); + } + } + else { + /* #BMesh */ + if (data_flag & MR_DATA_POLY_NOR) { + /* Use #BMFace.no instead. */ + } + if (((data_flag & MR_DATA_LOOP_NOR) && is_auto_smooth) || (data_flag & MR_DATA_TAN_LOOP_NOR)) { + + const float(*vert_coords)[3] = NULL; + const float(*vert_normals)[3] = NULL; + const float(*poly_normals)[3] = NULL; + + if (mr->edit_data && mr->edit_data->vertexCos) { + vert_coords = mr->bm_vert_coords; + vert_normals = mr->bm_vert_normals; + poly_normals = mr->bm_poly_normals; + } + + mr->loop_normals = static_cast( + MEM_mallocN(sizeof(*mr->loop_normals) * mr->loop_len, __func__)); + const int clnors_offset = CustomData_get_offset(&mr->bm->ldata, CD_CUSTOMLOOPNORMAL); + BM_loops_calc_normal_vcos(mr->bm, + vert_coords, + vert_normals, + poly_normals, + is_auto_smooth, + split_angle, + mr->loop_normals, + NULL, + NULL, + clnors_offset, + false); + } + } +} + +MeshRenderData *mesh_render_data_create(Object *object, + Mesh *me, + const bool is_editmode, + const bool is_paint_mode, + const bool is_mode_active, + const float obmat[4][4], + const bool do_final, + const bool do_uvedit, + const ToolSettings *ts) +{ + MeshRenderData *mr = static_cast(MEM_callocN(sizeof(*mr), __func__)); + mr->toolsettings = ts; + mr->mat_len = mesh_render_mat_len_get(object, me); + + copy_m4_m4(mr->obmat, obmat); + + if (is_editmode) { + Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(object); + Mesh *editmesh_eval_cage = BKE_object_get_editmesh_eval_cage(object); + + BLI_assert(editmesh_eval_cage && editmesh_eval_final); + mr->bm = me->edit_mesh->bm; + mr->edit_bmesh = me->edit_mesh; + mr->me = (do_final) ? editmesh_eval_final : editmesh_eval_cage; + mr->edit_data = is_mode_active ? mr->me->runtime.edit_data : NULL; + + if (mr->edit_data) { + EditMeshData *emd = mr->edit_data; + if (emd->vertexCos) { + BKE_editmesh_cache_ensure_vert_normals(mr->edit_bmesh, emd); + BKE_editmesh_cache_ensure_poly_normals(mr->edit_bmesh, emd); + } + + mr->bm_vert_coords = mr->edit_data->vertexCos; + mr->bm_vert_normals = mr->edit_data->vertexNos; + mr->bm_poly_normals = mr->edit_data->polyNos; + mr->bm_poly_centers = mr->edit_data->polyCos; + } + + /* A subdivision wrapper may be created in edit mode when X-ray is turned on to ensure that the + * topology seen by the user matches the one used for the selection routines. This wrapper + * seemingly takes precedence over the MDATA one, however the mesh we use for rendering is not + * the subdivided one, but the one where the MDATA wrapper would have been added. So consider + * the subdivision wrapper as well for the `has_mdata` case. */ + bool has_mdata = is_mode_active && ELEM(mr->me->runtime.wrapper_type, + ME_WRAPPER_TYPE_MDATA, + ME_WRAPPER_TYPE_SUBD); + bool use_mapped = is_mode_active && + (has_mdata && !do_uvedit && mr->me && !mr->me->runtime.is_original); + + int bm_ensure_types = BM_VERT | BM_EDGE | BM_LOOP | BM_FACE; + + BM_mesh_elem_index_ensure(mr->bm, bm_ensure_types); + BM_mesh_elem_table_ensure(mr->bm, bm_ensure_types & ~BM_LOOP); + + mr->efa_act_uv = EDBM_uv_active_face_get(mr->edit_bmesh, false, false); + mr->efa_act = BM_mesh_active_face_get(mr->bm, false, true); + mr->eed_act = BM_mesh_active_edge_get(mr->bm); + mr->eve_act = BM_mesh_active_vert_get(mr->bm); + + mr->vert_crease_ofs = CustomData_get_offset(&mr->bm->vdata, CD_CREASE); + mr->edge_crease_ofs = CustomData_get_offset(&mr->bm->edata, CD_CREASE); + mr->bweight_ofs = CustomData_get_offset(&mr->bm->edata, CD_BWEIGHT); +#ifdef WITH_FREESTYLE + mr->freestyle_edge_ofs = CustomData_get_offset(&mr->bm->edata, CD_FREESTYLE_EDGE); + mr->freestyle_face_ofs = CustomData_get_offset(&mr->bm->pdata, CD_FREESTYLE_FACE); +#endif + + if (use_mapped) { + mr->v_origindex = static_cast( + CustomData_get_layer(&mr->me->vdata, CD_ORIGINDEX)); + mr->e_origindex = static_cast( + CustomData_get_layer(&mr->me->edata, CD_ORIGINDEX)); + mr->p_origindex = static_cast( + CustomData_get_layer(&mr->me->pdata, CD_ORIGINDEX)); + + use_mapped = (mr->v_origindex || mr->e_origindex || mr->p_origindex); + } + + mr->extract_type = use_mapped ? MR_EXTRACT_MAPPED : MR_EXTRACT_BMESH; + + /* Seems like the mesh_eval_final do not have the right origin indices. + * Force not mapped in this case. */ + if (has_mdata && do_final && editmesh_eval_final != editmesh_eval_cage) { + // mr->edit_bmesh = NULL; + mr->extract_type = MR_EXTRACT_MESH; + } + } + else { + mr->me = me; + mr->edit_bmesh = NULL; + + bool use_mapped = is_paint_mode && mr->me && !mr->me->runtime.is_original; + if (use_mapped) { + mr->v_origindex = static_cast( + CustomData_get_layer(&mr->me->vdata, CD_ORIGINDEX)); + mr->e_origindex = static_cast( + CustomData_get_layer(&mr->me->edata, CD_ORIGINDEX)); + mr->p_origindex = static_cast( + CustomData_get_layer(&mr->me->pdata, CD_ORIGINDEX)); + + use_mapped = (mr->v_origindex || mr->e_origindex || mr->p_origindex); + } + + mr->extract_type = use_mapped ? MR_EXTRACT_MAPPED : MR_EXTRACT_MESH; + } + + if (mr->extract_type != MR_EXTRACT_BMESH) { + /* Mesh */ + mr->vert_len = mr->me->totvert; + mr->edge_len = mr->me->totedge; + mr->loop_len = mr->me->totloop; + mr->poly_len = mr->me->totpoly; + mr->tri_len = poly_to_tri_count(mr->poly_len, mr->loop_len); + + mr->mvert = static_cast(CustomData_get_layer(&mr->me->vdata, CD_MVERT)); + mr->medge = static_cast(CustomData_get_layer(&mr->me->edata, CD_MEDGE)); + mr->mloop = static_cast(CustomData_get_layer(&mr->me->ldata, CD_MLOOP)); + mr->mpoly = static_cast(CustomData_get_layer(&mr->me->pdata, CD_MPOLY)); + + mr->v_origindex = static_cast(CustomData_get_layer(&mr->me->vdata, CD_ORIGINDEX)); + mr->e_origindex = static_cast(CustomData_get_layer(&mr->me->edata, CD_ORIGINDEX)); + mr->p_origindex = static_cast(CustomData_get_layer(&mr->me->pdata, CD_ORIGINDEX)); + } + else { + /* #BMesh */ + BMesh *bm = mr->bm; + + mr->vert_len = bm->totvert; + mr->edge_len = bm->totedge; + mr->loop_len = bm->totloop; + mr->poly_len = bm->totface; + mr->tri_len = poly_to_tri_count(mr->poly_len, mr->loop_len); + } + + return mr; +} + +void mesh_render_data_free(MeshRenderData *mr) +{ + MEM_SAFE_FREE(mr->mlooptri); + MEM_SAFE_FREE(mr->loop_normals); + + /* Loose geometry are owned by #MeshBufferCache. */ + mr->ledges = NULL; + mr->lverts = NULL; + + MEM_freeN(mr); +} + +/** \} */ diff --git a/source/blender/draw/intern/draw_cache_impl_curves.cc b/source/blender/draw/intern/draw_cache_impl_curves.cc index 68f210105b0..22b843650ca 100644 --- a/source/blender/draw/intern/draw_cache_impl_curves.cc +++ b/source/blender/draw/intern/draw_cache_impl_curves.cc @@ -512,7 +512,7 @@ static bool curves_ensure_attributes(const Curves &curves, ListBase gpu_attrs = GPU_material_attributes(gpu_material); LISTBASE_FOREACH (GPUMaterialAttribute *, gpu_attr, &gpu_attrs) { const char *name = gpu_attr->name; - int type = gpu_attr->type; + eCustomDataType type = static_cast(gpu_attr->type); int layer = -1; eAttrDomain domain; diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.c b/source/blender/draw/intern/draw_cache_impl_mesh.c deleted file mode 100644 index a7fd484c72f..00000000000 --- a/source/blender/draw/intern/draw_cache_impl_mesh.c +++ /dev/null @@ -1,2103 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later - * Copyright 2017 Blender Foundation. All rights reserved. */ - -/** \file - * \ingroup draw - * - * \brief Mesh API for render engines - */ - -#include "MEM_guardedalloc.h" - -#include "BLI_alloca.h" -#include "BLI_bitmap.h" -#include "BLI_buffer.h" -#include "BLI_edgehash.h" -#include "BLI_listbase.h" -#include "BLI_math_bits.h" -#include "BLI_math_vector.h" -#include "BLI_string.h" -#include "BLI_task.h" -#include "BLI_utildefines.h" - -#include "DNA_mesh_types.h" -#include "DNA_meshdata_types.h" -#include "DNA_object_types.h" -#include "DNA_scene_types.h" - -#include "BKE_attribute.h" -#include "BKE_customdata.h" -#include "BKE_deform.h" -#include "BKE_editmesh.h" -#include "BKE_editmesh_cache.h" -#include "BKE_editmesh_tangent.h" -#include "BKE_mesh.h" -#include "BKE_mesh_runtime.h" -#include "BKE_mesh_tangent.h" -#include "BKE_modifier.h" -#include "BKE_object_deform.h" -#include "BKE_paint.h" -#include "BKE_pbvh.h" -#include "BKE_subdiv_modifier.h" - -#include "atomic_ops.h" - -#include "bmesh.h" - -#include "GPU_batch.h" -#include "GPU_material.h" - -#include "DRW_render.h" - -#include "ED_mesh.h" -#include "ED_uvedit.h" - -#include "draw_cache_extract.h" -#include "draw_cache_inline.h" -#include "draw_subdivision.h" - -#include "draw_cache_impl.h" /* own include */ - -#include "mesh_extractors/extract_mesh.h" - -/* ---------------------------------------------------------------------- */ -/** \name Dependencies between buffer and batch - * \{ */ - -/* clang-format off */ - -#define BUFFER_INDEX(buff_name) ((offsetof(MeshBufferList, buff_name) - offsetof(MeshBufferList, vbo)) / sizeof(void *)) -#define BUFFER_LEN (sizeof(MeshBufferList) / sizeof(void *)) - -#define _BATCH_FLAG1(b) (1u << MBC_BATCH_INDEX(b)) -#define _BATCH_FLAG2(b1, b2) _BATCH_FLAG1(b1) | _BATCH_FLAG1(b2) -#define _BATCH_FLAG3(b1, b2, b3) _BATCH_FLAG2(b1, b2) | _BATCH_FLAG1(b3) -#define _BATCH_FLAG4(b1, b2, b3, b4) _BATCH_FLAG3(b1, b2, b3) | _BATCH_FLAG1(b4) -#define _BATCH_FLAG5(b1, b2, b3, b4, b5) _BATCH_FLAG4(b1, b2, b3, b4) | _BATCH_FLAG1(b5) -#define _BATCH_FLAG6(b1, b2, b3, b4, b5, b6) _BATCH_FLAG5(b1, b2, b3, b4, b5) | _BATCH_FLAG1(b6) -#define _BATCH_FLAG7(b1, b2, b3, b4, b5, b6, b7) _BATCH_FLAG6(b1, b2, b3, b4, b5, b6) | _BATCH_FLAG1(b7) -#define _BATCH_FLAG8(b1, b2, b3, b4, b5, b6, b7, b8) _BATCH_FLAG7(b1, b2, b3, b4, b5, b6, b7) | _BATCH_FLAG1(b8) -#define _BATCH_FLAG9(b1, b2, b3, b4, b5, b6, b7, b8, b9) _BATCH_FLAG8(b1, b2, b3, b4, b5, b6, b7, b8) | _BATCH_FLAG1(b9) -#define _BATCH_FLAG10(b1, b2, b3, b4, b5, b6, b7, b8, b9, b10) _BATCH_FLAG9(b1, b2, b3, b4, b5, b6, b7, b8, b9) | _BATCH_FLAG1(b10) -#define _BATCH_FLAG18(b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12, b13, b14, b15, b16, b17, b18) _BATCH_FLAG10(b1, b2, b3, b4, b5, b6, b7, b8, b9, b10) | _BATCH_FLAG8(b11, b12, b13, b14, b15, b16, b17, b18) - -#define BATCH_FLAG(...) VA_NARGS_CALL_OVERLOAD(_BATCH_FLAG, __VA_ARGS__) - -#define _BATCH_MAP1(a) g_buffer_deps[BUFFER_INDEX(a)] -#define _BATCH_MAP2(a, b) _BATCH_MAP1(a) | _BATCH_MAP1(b) -#define _BATCH_MAP3(a, b, c) _BATCH_MAP2(a, b) | _BATCH_MAP1(c) -#define _BATCH_MAP4(a, b, c, d) _BATCH_MAP3(a, b, c) | _BATCH_MAP1(d) -#define _BATCH_MAP5(a, b, c, d, e) _BATCH_MAP4(a, b, c, d) | _BATCH_MAP1(e) -#define _BATCH_MAP6(a, b, c, d, e, f) _BATCH_MAP5(a, b, c, d, e) | _BATCH_MAP1(f) -#define _BATCH_MAP7(a, b, c, d, e, f, g) _BATCH_MAP6(a, b, c, d, e, f) | _BATCH_MAP1(g) -#define _BATCH_MAP8(a, b, c, d, e, f, g, h) _BATCH_MAP7(a, b, c, d, e, f, g) | _BATCH_MAP1(h) -#define _BATCH_MAP9(a, b, c, d, e, f, g, h, i) _BATCH_MAP8(a, b, c, d, e, f, g, h) | _BATCH_MAP1(i) -#define _BATCH_MAP10(a, b, c, d, e, f, g, h, i, j) _BATCH_MAP9(a, b, c, d, e, f, g, h, i) | _BATCH_MAP1(j) - -#define BATCH_MAP(...) VA_NARGS_CALL_OVERLOAD(_BATCH_MAP, __VA_ARGS__) - -#ifndef NDEBUG -# define MDEPS_ASSERT_INDEX(buffer_index, batch_flag) \ - g_buffer_deps_d[buffer_index] |= batch_flag; \ - BLI_assert(g_buffer_deps[buffer_index] & batch_flag) - -# define _MDEPS_ASSERT2(b, n1) MDEPS_ASSERT_INDEX(BUFFER_INDEX(n1), b) -# define _MDEPS_ASSERT3(b, n1, n2) _MDEPS_ASSERT2(b, n1); _MDEPS_ASSERT2(b, n2) -# define _MDEPS_ASSERT4(b, n1, n2, n3) _MDEPS_ASSERT3(b, n1, n2); _MDEPS_ASSERT2(b, n3) -# define _MDEPS_ASSERT5(b, n1, n2, n3, n4) _MDEPS_ASSERT4(b, n1, n2, n3); _MDEPS_ASSERT2(b, n4) -# define _MDEPS_ASSERT6(b, n1, n2, n3, n4, n5) _MDEPS_ASSERT5(b, n1, n2, n3, n4); _MDEPS_ASSERT2(b, n5) -# define _MDEPS_ASSERT7(b, n1, n2, n3, n4, n5, n6) _MDEPS_ASSERT6(b, n1, n2, n3, n4, n5); _MDEPS_ASSERT2(b, n6) -# define _MDEPS_ASSERT8(b, n1, n2, n3, n4, n5, n6, n7) _MDEPS_ASSERT7(b, n1, n2, n3, n4, n5, n6); _MDEPS_ASSERT2(b, n7) -# define _MDEPS_ASSERT21(b, n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12, n13, n14, n15, n16, n17, n18, n19, n20) _MDEPS_ASSERT8(b, n1, n2, n3, n4, n5, n6, n7); _MDEPS_ASSERT8(b, n8, n9, n10, n11, n12, n13, n14); _MDEPS_ASSERT7(b, n15, n16, n17, n18, n19, n20) -# define _MDEPS_ASSERT22(b, n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12, n13, n14, n15, n16, n17, n18, n19, n20, n21) _MDEPS_ASSERT21(b, n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12, n13, n14, n15, n16, n17, n18, n19, n20); _MDEPS_ASSERT2(b, n21); - -# define MDEPS_ASSERT_FLAG(...) VA_NARGS_CALL_OVERLOAD(_MDEPS_ASSERT, __VA_ARGS__) -# define MDEPS_ASSERT(batch_name, ...) MDEPS_ASSERT_FLAG(BATCH_FLAG(batch_name), __VA_ARGS__) -# define MDEPS_ASSERT_MAP_INDEX(buff_index) BLI_assert(g_buffer_deps_d[buff_index] == g_buffer_deps[buff_index]) -# define MDEPS_ASSERT_MAP(buff_name) MDEPS_ASSERT_MAP_INDEX(BUFFER_INDEX(buff_name)) -#else -# define MDEPS_ASSERT_INDEX(buffer_index, batch_flag) -# define MDEPS_ASSERT_FLAG(...) -# define MDEPS_ASSERT(batch_name, ...) -# define MDEPS_ASSERT_MAP_INDEX(buff_index) -# define MDEPS_ASSERT_MAP(buff_name) -#endif - -/* clang-format on */ - -#define TRIS_PER_MAT_INDEX BUFFER_LEN -#define SURFACE_PER_MAT_FLAG (1u << MBC_BATCH_LEN) - -static const DRWBatchFlag g_buffer_deps[] = { - [BUFFER_INDEX(vbo.pos_nor)] = BATCH_FLAG(surface, - surface_weights, - edit_triangles, - edit_vertices, - edit_edges, - edit_vnor, - edit_lnor, - edit_mesh_analysis, - edit_selection_verts, - edit_selection_edges, - edit_selection_faces, - all_verts, - all_edges, - loose_edges, - edge_detection, - wire_edges, - wire_loops, - sculpt_overlays) | - SURFACE_PER_MAT_FLAG, - [BUFFER_INDEX(vbo.lnor)] = BATCH_FLAG(surface, edit_lnor, wire_loops) | SURFACE_PER_MAT_FLAG, - [BUFFER_INDEX(vbo.edge_fac)] = BATCH_FLAG(wire_edges), - [BUFFER_INDEX(vbo.weights)] = BATCH_FLAG(surface_weights), - [BUFFER_INDEX(vbo.uv)] = BATCH_FLAG(surface, - edituv_faces_stretch_area, - edituv_faces_stretch_angle, - edituv_faces, - edituv_edges, - edituv_verts, - wire_loops_uvs) | - SURFACE_PER_MAT_FLAG, - [BUFFER_INDEX(vbo.tan)] = SURFACE_PER_MAT_FLAG, - [BUFFER_INDEX(vbo.vcol)] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG, - [BUFFER_INDEX(vbo.sculpt_data)] = BATCH_FLAG(sculpt_overlays), - [BUFFER_INDEX(vbo.orco)] = SURFACE_PER_MAT_FLAG, - [BUFFER_INDEX(vbo.edit_data)] = BATCH_FLAG(edit_triangles, edit_edges, edit_vertices), - [BUFFER_INDEX(vbo.edituv_data)] = BATCH_FLAG(edituv_faces, - edituv_faces_stretch_area, - edituv_faces_stretch_angle, - edituv_edges, - edituv_verts), - [BUFFER_INDEX(vbo.edituv_stretch_area)] = BATCH_FLAG(edituv_faces_stretch_area), - [BUFFER_INDEX(vbo.edituv_stretch_angle)] = BATCH_FLAG(edituv_faces_stretch_angle), - [BUFFER_INDEX(vbo.mesh_analysis)] = BATCH_FLAG(edit_mesh_analysis), - [BUFFER_INDEX(vbo.fdots_pos)] = BATCH_FLAG(edit_fdots, edit_selection_fdots), - [BUFFER_INDEX(vbo.fdots_nor)] = BATCH_FLAG(edit_fdots), - [BUFFER_INDEX(vbo.fdots_uv)] = BATCH_FLAG(edituv_fdots), - [BUFFER_INDEX(vbo.fdots_edituv_data)] = BATCH_FLAG(edituv_fdots), - [BUFFER_INDEX(vbo.skin_roots)] = BATCH_FLAG(edit_skin_roots), - [BUFFER_INDEX(vbo.vert_idx)] = BATCH_FLAG(edit_selection_verts), - [BUFFER_INDEX(vbo.edge_idx)] = BATCH_FLAG(edit_selection_edges), - [BUFFER_INDEX(vbo.poly_idx)] = BATCH_FLAG(edit_selection_faces), - [BUFFER_INDEX(vbo.fdot_idx)] = BATCH_FLAG(edit_selection_fdots), - [BUFFER_INDEX(vbo.attr) + 0] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG, - [BUFFER_INDEX(vbo.attr) + 1] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG, - [BUFFER_INDEX(vbo.attr) + 2] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG, - [BUFFER_INDEX(vbo.attr) + 3] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG, - [BUFFER_INDEX(vbo.attr) + 4] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG, - [BUFFER_INDEX(vbo.attr) + 5] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG, - [BUFFER_INDEX(vbo.attr) + 6] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG, - [BUFFER_INDEX(vbo.attr) + 7] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG, - [BUFFER_INDEX(vbo.attr) + 8] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG, - [BUFFER_INDEX(vbo.attr) + 9] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG, - [BUFFER_INDEX(vbo.attr) + 10] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG, - [BUFFER_INDEX(vbo.attr) + 11] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG, - [BUFFER_INDEX(vbo.attr) + 12] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG, - [BUFFER_INDEX(vbo.attr) + 13] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG, - [BUFFER_INDEX(vbo.attr) + 14] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG, - - [BUFFER_INDEX(ibo.tris)] = BATCH_FLAG(surface, - surface_weights, - edit_triangles, - edit_lnor, - edit_mesh_analysis, - edit_selection_faces, - sculpt_overlays), - [BUFFER_INDEX(ibo.lines)] = BATCH_FLAG( - edit_edges, edit_selection_edges, all_edges, wire_edges), - [BUFFER_INDEX(ibo.lines_loose)] = BATCH_FLAG(loose_edges), - [BUFFER_INDEX(ibo.points)] = BATCH_FLAG(edit_vnor, edit_vertices, edit_selection_verts), - [BUFFER_INDEX(ibo.fdots)] = BATCH_FLAG(edit_fdots, edit_selection_fdots), - [BUFFER_INDEX(ibo.lines_paint_mask)] = BATCH_FLAG(wire_loops), - [BUFFER_INDEX(ibo.lines_adjacency)] = BATCH_FLAG(edge_detection), - [BUFFER_INDEX(ibo.edituv_tris)] = BATCH_FLAG( - edituv_faces, edituv_faces_stretch_area, edituv_faces_stretch_angle), - [BUFFER_INDEX(ibo.edituv_lines)] = BATCH_FLAG(edituv_edges, wire_loops_uvs), - [BUFFER_INDEX(ibo.edituv_points)] = BATCH_FLAG(edituv_verts), - [BUFFER_INDEX(ibo.edituv_fdots)] = BATCH_FLAG(edituv_fdots), - [TRIS_PER_MAT_INDEX] = SURFACE_PER_MAT_FLAG, -}; - -#ifndef NDEBUG -static DRWBatchFlag g_buffer_deps_d[ARRAY_SIZE(g_buffer_deps)] = {0}; -#endif - -static void mesh_batch_cache_discard_surface_batches(MeshBatchCache *cache); -static void mesh_batch_cache_clear(Mesh *me); - -static void mesh_batch_cache_discard_batch(MeshBatchCache *cache, const DRWBatchFlag batch_map) -{ - for (int i = 0; i < MBC_BATCH_LEN; i++) { - DRWBatchFlag batch_requested = (1u << i); - if (batch_map & batch_requested) { - GPU_BATCH_DISCARD_SAFE(((GPUBatch **)&cache->batch)[i]); - cache->batch_ready &= ~batch_requested; - } - } - - if (batch_map & SURFACE_PER_MAT_FLAG) { - mesh_batch_cache_discard_surface_batches(cache); - } -} - -/* Return true is all layers in _b_ are inside _a_. */ -BLI_INLINE bool mesh_cd_layers_type_overlap(DRW_MeshCDMask a, DRW_MeshCDMask b) -{ - return (*((uint32_t *)&a) & *((uint32_t *)&b)) == *((uint32_t *)&b); -} - -BLI_INLINE bool mesh_cd_layers_type_equal(DRW_MeshCDMask a, DRW_MeshCDMask b) -{ - return *((uint32_t *)&a) == *((uint32_t *)&b); -} - -BLI_INLINE void mesh_cd_layers_type_merge(DRW_MeshCDMask *a, DRW_MeshCDMask b) -{ - uint32_t *a_p = (uint32_t *)a; - uint32_t *b_p = (uint32_t *)&b; - atomic_fetch_and_or_uint32(a_p, *b_p); -} - -BLI_INLINE void mesh_cd_layers_type_clear(DRW_MeshCDMask *a) -{ - *((uint32_t *)a) = 0; -} - -BLI_INLINE const Mesh *editmesh_final_or_this(const Object *object, const Mesh *me) -{ - if (me->edit_mesh != NULL) { - Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(object); - if (editmesh_eval_final != NULL) { - return editmesh_eval_final; - } - } - - return me; -} - -static void mesh_cd_calc_edit_uv_layer(const Mesh *UNUSED(me), DRW_MeshCDMask *cd_used) -{ - cd_used->edit_uv = 1; -} - -BLI_INLINE const CustomData *mesh_cd_ldata_get_from_mesh(const Mesh *me) -{ - switch ((eMeshWrapperType)me->runtime.wrapper_type) { - case ME_WRAPPER_TYPE_SUBD: - case ME_WRAPPER_TYPE_MDATA: - return &me->ldata; - break; - case ME_WRAPPER_TYPE_BMESH: - return &me->edit_mesh->bm->ldata; - break; - } - - BLI_assert(0); - return &me->ldata; -} - -BLI_INLINE const CustomData *mesh_cd_pdata_get_from_mesh(const Mesh *me) -{ - switch ((eMeshWrapperType)me->runtime.wrapper_type) { - case ME_WRAPPER_TYPE_SUBD: - case ME_WRAPPER_TYPE_MDATA: - return &me->pdata; - break; - case ME_WRAPPER_TYPE_BMESH: - return &me->edit_mesh->bm->pdata; - break; - } - - BLI_assert(0); - return &me->pdata; -} - -BLI_INLINE const CustomData *mesh_cd_edata_get_from_mesh(const Mesh *me) -{ - switch ((eMeshWrapperType)me->runtime.wrapper_type) { - case ME_WRAPPER_TYPE_SUBD: - case ME_WRAPPER_TYPE_MDATA: - return &me->edata; - break; - case ME_WRAPPER_TYPE_BMESH: - return &me->edit_mesh->bm->edata; - break; - } - - BLI_assert(0); - return &me->edata; -} - -BLI_INLINE const CustomData *mesh_cd_vdata_get_from_mesh(const Mesh *me) -{ - switch ((eMeshWrapperType)me->runtime.wrapper_type) { - case ME_WRAPPER_TYPE_SUBD: - case ME_WRAPPER_TYPE_MDATA: - return &me->vdata; - break; - case ME_WRAPPER_TYPE_BMESH: - return &me->edit_mesh->bm->vdata; - break; - } - - BLI_assert(0); - return &me->vdata; -} - -static void mesh_cd_calc_active_uv_layer(const Object *object, - const Mesh *me, - DRW_MeshCDMask *cd_used) -{ - const Mesh *me_final = editmesh_final_or_this(object, me); - const CustomData *cd_ldata = mesh_cd_ldata_get_from_mesh(me_final); - int layer = CustomData_get_active_layer(cd_ldata, CD_MLOOPUV); - if (layer != -1) { - cd_used->uv |= (1 << layer); - } -} - -static void mesh_cd_calc_active_mask_uv_layer(const Object *object, - const Mesh *me, - DRW_MeshCDMask *cd_used) -{ - const Mesh *me_final = editmesh_final_or_this(object, me); - const CustomData *cd_ldata = mesh_cd_ldata_get_from_mesh(me_final); - int layer = CustomData_get_stencil_layer(cd_ldata, CD_MLOOPUV); - if (layer != -1) { - cd_used->uv |= (1 << layer); - } -} - -static void mesh_cd_calc_active_mloopcol_layer(const Object *object, - const Mesh *me, - DRW_MeshCDMask *cd_used) -{ - const Mesh *me_final = editmesh_final_or_this(object, me); - Mesh me_query = {0}; - - const CustomData *cd_vdata = mesh_cd_vdata_get_from_mesh(me_final); - const CustomData *cd_ldata = mesh_cd_ldata_get_from_mesh(me_final); - - BKE_id_attribute_copy_domains_temp(ID_ME, cd_vdata, NULL, cd_ldata, NULL, NULL, &me_query.id); - - CustomDataLayer *layer = BKE_id_attributes_active_color_get(&me_query.id); - int layer_i = BKE_id_attribute_to_index( - &me_query.id, layer, ATTR_DOMAIN_MASK_COLOR, CD_MASK_COLOR_ALL); - - if (layer_i != -1) { - cd_used->vcol |= (1UL << (uint)layer_i); - } -} - -static uint mesh_cd_calc_gpu_layers_vcol_used(const Mesh *me_query, - const CustomData *cd_vdata, - const CustomData *cd_ldata, - const char name[]) -{ - CustomDataLayer *layer = NULL; - eAttrDomain domain; - - if (name[0]) { - int layer_i = 0; - - domain = ATTR_DOMAIN_POINT; - layer_i = CustomData_get_named_layer_index(cd_vdata, CD_PROP_COLOR, name); - layer_i = layer_i == -1 ? - CustomData_get_named_layer_index(cd_vdata, CD_PROP_BYTE_COLOR, name) : - layer_i; - - if (layer_i == -1) { - domain = ATTR_DOMAIN_CORNER; - layer_i = layer_i == -1 ? CustomData_get_named_layer_index(cd_ldata, CD_PROP_COLOR, name) : - layer_i; - layer_i = layer_i == -1 ? - CustomData_get_named_layer_index(cd_ldata, CD_PROP_BYTE_COLOR, name) : - layer_i; - } - - /* NOTE: this is not the same as the layer_i below. */ - if (layer_i != -1) { - layer = (domain == ATTR_DOMAIN_POINT ? cd_vdata : cd_ldata)->layers + layer_i; - } - } - else { - layer = BKE_id_attributes_render_color_get(&me_query->id); - } - - if (!layer) { - return -1; - } - - /* NOTE: this is the logical index into the color attribute list, - * not the customdata index. */ - int vcol_i = BKE_id_attribute_to_index( - (ID *)me_query, layer, ATTR_DOMAIN_MASK_COLOR, CD_MASK_COLOR_ALL); - - return vcol_i; -} - -static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Object *object, - const Mesh *me, - struct GPUMaterial **gpumat_array, - int gpumat_array_len, - DRW_Attributes *attributes) -{ - const Mesh *me_final = editmesh_final_or_this(object, me); - const CustomData *cd_ldata = mesh_cd_ldata_get_from_mesh(me_final); - const CustomData *cd_pdata = mesh_cd_pdata_get_from_mesh(me_final); - const CustomData *cd_vdata = mesh_cd_vdata_get_from_mesh(me_final); - const CustomData *cd_edata = mesh_cd_edata_get_from_mesh(me_final); - - /* Create a mesh with final customdata domains - * we can query with attribute API. */ - Mesh me_query = {0}; - - BKE_id_attribute_copy_domains_temp( - ID_ME, cd_vdata, cd_edata, cd_ldata, cd_pdata, NULL, &me_query.id); - - /* See: DM_vertex_attributes_from_gpu for similar logic */ - DRW_MeshCDMask cd_used; - mesh_cd_layers_type_clear(&cd_used); - - for (int i = 0; i < gpumat_array_len; i++) { - GPUMaterial *gpumat = gpumat_array[i]; - if (gpumat) { - ListBase gpu_attrs = GPU_material_attributes(gpumat); - LISTBASE_FOREACH (GPUMaterialAttribute *, gpu_attr, &gpu_attrs) { - const char *name = gpu_attr->name; - int type = gpu_attr->type; - int layer = -1; - /* ATTR_DOMAIN_NUM is standard for "invalid value". */ - eAttrDomain domain = ATTR_DOMAIN_NUM; - - if (type == CD_AUTO_FROM_NAME) { - /* We need to deduce what exact layer is used. - * - * We do it based on the specified name. - */ - if (name[0] != '\0') { - layer = CustomData_get_named_layer(cd_ldata, CD_MLOOPUV, name); - type = CD_MTFACE; - - if (layer == -1) { - layer = CustomData_get_named_layer(cd_vdata, CD_PROP_COLOR, name); - if (layer != -1) { - type = CD_PROP_COLOR; - domain = ATTR_DOMAIN_POINT; - } - } - - if (layer == -1) { - layer = CustomData_get_named_layer(cd_ldata, CD_PROP_COLOR, name); - if (layer != -1) { - type = CD_PROP_COLOR; - domain = ATTR_DOMAIN_CORNER; - } - } - - if (layer == -1) { - layer = CustomData_get_named_layer(cd_vdata, CD_PROP_BYTE_COLOR, name); - if (layer != -1) { - type = CD_PROP_BYTE_COLOR; - domain = ATTR_DOMAIN_POINT; - } - } - - if (layer == -1) { - layer = CustomData_get_named_layer(cd_ldata, CD_PROP_BYTE_COLOR, name); - if (layer != -1) { - type = CD_PROP_BYTE_COLOR; - domain = ATTR_DOMAIN_CORNER; - } - } - -#if 0 /* Tangents are always from UV's - this will never happen. */ - if (layer == -1) { - layer = CustomData_get_named_layer(cd_ldata, CD_TANGENT, name); - type = CD_TANGENT; - } -#endif - if (layer == -1) { - /* Try to match a generic attribute, we use the first attribute domain with a - * matching name. */ - if (drw_custom_data_match_attribute(cd_vdata, name, &layer, &type)) { - domain = ATTR_DOMAIN_POINT; - } - else if (drw_custom_data_match_attribute(cd_ldata, name, &layer, &type)) { - domain = ATTR_DOMAIN_CORNER; - } - else if (drw_custom_data_match_attribute(cd_pdata, name, &layer, &type)) { - domain = ATTR_DOMAIN_FACE; - } - else if (drw_custom_data_match_attribute(cd_edata, name, &layer, &type)) { - domain = ATTR_DOMAIN_EDGE; - } - else { - layer = -1; - domain = ATTR_DOMAIN_NUM; - } - } - - if (layer == -1) { - continue; - } - } - else { - /* Fall back to the UV layer, which matches old behavior. */ - type = CD_MTFACE; - } - } - - switch (type) { - case CD_MTFACE: { - if (layer == -1) { - layer = (name[0] != '\0') ? CustomData_get_named_layer(cd_ldata, CD_MLOOPUV, name) : - CustomData_get_render_layer(cd_ldata, CD_MLOOPUV); - } - if (layer != -1) { - cd_used.uv |= (1 << layer); - } - break; - } - case CD_TANGENT: { - if (layer == -1) { - layer = (name[0] != '\0') ? CustomData_get_named_layer(cd_ldata, CD_MLOOPUV, name) : - CustomData_get_render_layer(cd_ldata, CD_MLOOPUV); - - /* Only fallback to orco (below) when we have no UV layers, see: T56545 */ - if (layer == -1 && name[0] != '\0') { - layer = CustomData_get_render_layer(cd_ldata, CD_MLOOPUV); - } - } - if (layer != -1) { - cd_used.tan |= (1 << layer); - } - else { - /* no UV layers at all => requesting orco */ - cd_used.tan_orco = 1; - cd_used.orco = 1; - } - break; - } - - case CD_ORCO: { - cd_used.orco = 1; - break; - } - - /* NOTE: attr->type will always be CD_PROP_COLOR even for - * CD_PROP_BYTE_COLOR layers, see node_shader_gpu_vertex_color in - * node_shader_vertex_color.cc. - */ - case CD_MCOL: - case CD_PROP_BYTE_COLOR: - case CD_PROP_COLOR: { - /* First check Color attributes, when not found check mesh attributes. Geometry nodes - * can generate those layers. */ - int vcol_bit = mesh_cd_calc_gpu_layers_vcol_used(&me_query, cd_vdata, cd_ldata, name); - - if (vcol_bit != -1) { - cd_used.vcol |= 1UL << (uint)vcol_bit; - break; - } - - if (layer != -1 && domain != ATTR_DOMAIN_NUM) { - drw_attributes_add_request(attributes, type, layer, domain); - } - break; - } - case CD_PROP_FLOAT3: - case CD_PROP_BOOL: - case CD_PROP_INT8: - case CD_PROP_INT32: - case CD_PROP_FLOAT: - case CD_PROP_FLOAT2: { - if (layer != -1 && domain != ATTR_DOMAIN_NUM) { - drw_attributes_add_request(attributes, type, layer, domain); - } - break; - } - } - } - } - } - return cd_used; -} - -/** \} */ - -/* ---------------------------------------------------------------------- */ -/** \name Vertex Group Selection - * \{ */ - -/** Reset the selection structure, deallocating heap memory as appropriate. */ -static void drw_mesh_weight_state_clear(struct DRW_MeshWeightState *wstate) -{ - MEM_SAFE_FREE(wstate->defgroup_sel); - MEM_SAFE_FREE(wstate->defgroup_locked); - MEM_SAFE_FREE(wstate->defgroup_unlocked); - - memset(wstate, 0, sizeof(*wstate)); - - wstate->defgroup_active = -1; -} - -/** Copy selection data from one structure to another, including heap memory. */ -static void drw_mesh_weight_state_copy(struct DRW_MeshWeightState *wstate_dst, - const struct DRW_MeshWeightState *wstate_src) -{ - MEM_SAFE_FREE(wstate_dst->defgroup_sel); - MEM_SAFE_FREE(wstate_dst->defgroup_locked); - MEM_SAFE_FREE(wstate_dst->defgroup_unlocked); - - memcpy(wstate_dst, wstate_src, sizeof(*wstate_dst)); - - if (wstate_src->defgroup_sel) { - wstate_dst->defgroup_sel = MEM_dupallocN(wstate_src->defgroup_sel); - } - if (wstate_src->defgroup_locked) { - wstate_dst->defgroup_locked = MEM_dupallocN(wstate_src->defgroup_locked); - } - if (wstate_src->defgroup_unlocked) { - wstate_dst->defgroup_unlocked = MEM_dupallocN(wstate_src->defgroup_unlocked); - } -} - -static bool drw_mesh_flags_equal(const bool *array1, const bool *array2, int size) -{ - return ((!array1 && !array2) || - (array1 && array2 && memcmp(array1, array2, size * sizeof(bool)) == 0)); -} - -/** Compare two selection structures. */ -static bool drw_mesh_weight_state_compare(const struct DRW_MeshWeightState *a, - const struct DRW_MeshWeightState *b) -{ - return a->defgroup_active == b->defgroup_active && a->defgroup_len == b->defgroup_len && - a->flags == b->flags && a->alert_mode == b->alert_mode && - a->defgroup_sel_count == b->defgroup_sel_count && - drw_mesh_flags_equal(a->defgroup_sel, b->defgroup_sel, a->defgroup_len) && - drw_mesh_flags_equal(a->defgroup_locked, b->defgroup_locked, a->defgroup_len) && - drw_mesh_flags_equal(a->defgroup_unlocked, b->defgroup_unlocked, a->defgroup_len); -} - -static void drw_mesh_weight_state_extract(Object *ob, - Mesh *me, - const ToolSettings *ts, - bool paint_mode, - struct DRW_MeshWeightState *wstate) -{ - /* Extract complete vertex weight group selection state and mode flags. */ - memset(wstate, 0, sizeof(*wstate)); - - wstate->defgroup_active = me->vertex_group_active_index - 1; - wstate->defgroup_len = BLI_listbase_count(&me->vertex_group_names); - - wstate->alert_mode = ts->weightuser; - - if (paint_mode && ts->multipaint) { - /* Multi-paint needs to know all selected bones, not just the active group. - * This is actually a relatively expensive operation, but caching would be difficult. */ - wstate->defgroup_sel = BKE_object_defgroup_selected_get( - ob, wstate->defgroup_len, &wstate->defgroup_sel_count); - - if (wstate->defgroup_sel_count > 1) { - wstate->flags |= DRW_MESH_WEIGHT_STATE_MULTIPAINT | - (ts->auto_normalize ? DRW_MESH_WEIGHT_STATE_AUTO_NORMALIZE : 0); - - if (ME_USING_MIRROR_X_VERTEX_GROUPS(me)) { - BKE_object_defgroup_mirror_selection(ob, - wstate->defgroup_len, - wstate->defgroup_sel, - wstate->defgroup_sel, - &wstate->defgroup_sel_count); - } - } - /* With only one selected bone Multi-paint reverts to regular mode. */ - else { - wstate->defgroup_sel_count = 0; - MEM_SAFE_FREE(wstate->defgroup_sel); - } - } - - if (paint_mode && ts->wpaint_lock_relative) { - /* Set of locked vertex groups for the lock relative mode. */ - wstate->defgroup_locked = BKE_object_defgroup_lock_flags_get(ob, wstate->defgroup_len); - wstate->defgroup_unlocked = BKE_object_defgroup_validmap_get(ob, wstate->defgroup_len); - - /* Check that a deform group is active, and none of selected groups are locked. */ - if (BKE_object_defgroup_check_lock_relative( - wstate->defgroup_locked, wstate->defgroup_unlocked, wstate->defgroup_active) && - BKE_object_defgroup_check_lock_relative_multi(wstate->defgroup_len, - wstate->defgroup_locked, - wstate->defgroup_sel, - wstate->defgroup_sel_count)) { - wstate->flags |= DRW_MESH_WEIGHT_STATE_LOCK_RELATIVE; - - /* Compute the set of locked and unlocked deform vertex groups. */ - BKE_object_defgroup_split_locked_validmap(wstate->defgroup_len, - wstate->defgroup_locked, - wstate->defgroup_unlocked, - wstate->defgroup_locked, /* out */ - wstate->defgroup_unlocked); - } - else { - MEM_SAFE_FREE(wstate->defgroup_unlocked); - MEM_SAFE_FREE(wstate->defgroup_locked); - } - } -} - -/** \} */ - -/* ---------------------------------------------------------------------- */ -/** \name Mesh GPUBatch Cache - * \{ */ - -BLI_INLINE void mesh_batch_cache_add_request(MeshBatchCache *cache, DRWBatchFlag new_flag) -{ - atomic_fetch_and_or_uint32((uint32_t *)(&cache->batch_requested), *(uint32_t *)&new_flag); -} - -/* GPUBatch cache management. */ - -static bool mesh_batch_cache_valid(Object *object, Mesh *me) -{ - MeshBatchCache *cache = me->runtime.batch_cache; - - if (cache == NULL) { - return false; - } - - if (object->sculpt && object->sculpt->pbvh) { - if (cache->pbvh_is_drawing != BKE_pbvh_is_drawing(object->sculpt->pbvh)) { - return false; - } - - if (BKE_pbvh_is_drawing(object->sculpt->pbvh) && - BKE_pbvh_draw_cache_invalid(object->sculpt->pbvh)) { - return false; - } - } - - if (cache->is_editmode != (me->edit_mesh != NULL)) { - return false; - } - - if (cache->is_dirty) { - return false; - } - - if (cache->mat_len != mesh_render_mat_len_get(object, me)) { - return false; - } - - return true; -} - -static void mesh_batch_cache_init(Object *object, Mesh *me) -{ - MeshBatchCache *cache = me->runtime.batch_cache; - - if (!cache) { - cache = me->runtime.batch_cache = MEM_callocN(sizeof(*cache), __func__); - } - else { - memset(cache, 0, sizeof(*cache)); - } - - cache->is_editmode = me->edit_mesh != NULL; - - if (object->sculpt && object->sculpt->pbvh) { - cache->pbvh_is_drawing = BKE_pbvh_is_drawing(object->sculpt->pbvh); - } - - if (cache->is_editmode == false) { - // cache->edge_len = mesh_render_edges_len_get(me); - // cache->tri_len = mesh_render_looptri_len_get(me); - // cache->poly_len = mesh_render_polys_len_get(me); - // cache->vert_len = mesh_render_verts_len_get(me); - } - - cache->mat_len = mesh_render_mat_len_get(object, me); - cache->surface_per_mat = MEM_callocN(sizeof(*cache->surface_per_mat) * cache->mat_len, __func__); - cache->tris_per_mat = MEM_callocN(sizeof(*cache->tris_per_mat) * cache->mat_len, __func__); - - cache->is_dirty = false; - cache->batch_ready = 0; - cache->batch_requested = 0; - - drw_mesh_weight_state_clear(&cache->weight_state); -} - -void DRW_mesh_batch_cache_validate(Object *object, Mesh *me) -{ - if (!mesh_batch_cache_valid(object, me)) { - mesh_batch_cache_clear(me); - mesh_batch_cache_init(object, me); - } -} - -static MeshBatchCache *mesh_batch_cache_get(Mesh *me) -{ - return me->runtime.batch_cache; -} - -static void mesh_batch_cache_check_vertex_group(MeshBatchCache *cache, - const struct DRW_MeshWeightState *wstate) -{ - if (!drw_mesh_weight_state_compare(&cache->weight_state, wstate)) { - FOREACH_MESH_BUFFER_CACHE (cache, mbc) { - GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.weights); - } - GPU_BATCH_CLEAR_SAFE(cache->batch.surface_weights); - - cache->batch_ready &= ~MBC_SURFACE_WEIGHTS; - - drw_mesh_weight_state_clear(&cache->weight_state); - } -} - -static void mesh_batch_cache_request_surface_batches(MeshBatchCache *cache) -{ - mesh_batch_cache_add_request(cache, MBC_SURFACE); - DRW_batch_request(&cache->batch.surface); - for (int i = 0; i < cache->mat_len; i++) { - DRW_batch_request(&cache->surface_per_mat[i]); - } -} - -/* Free batches with material-mapped looptris. - * NOTE: The updating of the indices buffers (#tris_per_mat) is handled in the extractors. - * No need to discard they here. */ -static void mesh_batch_cache_discard_surface_batches(MeshBatchCache *cache) -{ - GPU_BATCH_DISCARD_SAFE(cache->batch.surface); - for (int i = 0; i < cache->mat_len; i++) { - GPU_BATCH_DISCARD_SAFE(cache->surface_per_mat[i]); - } - cache->batch_ready &= ~MBC_SURFACE; -} - -static void mesh_batch_cache_discard_shaded_tri(MeshBatchCache *cache) -{ - FOREACH_MESH_BUFFER_CACHE (cache, mbc) { - GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.uv); - GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.tan); - GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.vcol); - GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.orco); - } - DRWBatchFlag batch_map = BATCH_MAP(vbo.uv, vbo.tan, vbo.vcol, vbo.orco); - mesh_batch_cache_discard_batch(cache, batch_map); - mesh_cd_layers_type_clear(&cache->cd_used); -} - -static void mesh_batch_cache_discard_uvedit(MeshBatchCache *cache) -{ - FOREACH_MESH_BUFFER_CACHE (cache, mbc) { - GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.edituv_stretch_angle); - GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.edituv_stretch_area); - GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.uv); - GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.edituv_data); - GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.fdots_uv); - GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.fdots_edituv_data); - GPU_INDEXBUF_DISCARD_SAFE(mbc->buff.ibo.edituv_tris); - GPU_INDEXBUF_DISCARD_SAFE(mbc->buff.ibo.edituv_lines); - GPU_INDEXBUF_DISCARD_SAFE(mbc->buff.ibo.edituv_points); - GPU_INDEXBUF_DISCARD_SAFE(mbc->buff.ibo.edituv_fdots); - } - DRWBatchFlag batch_map = BATCH_MAP(vbo.edituv_stretch_angle, - vbo.edituv_stretch_area, - vbo.uv, - vbo.edituv_data, - vbo.fdots_uv, - vbo.fdots_edituv_data, - ibo.edituv_tris, - ibo.edituv_lines, - ibo.edituv_points, - ibo.edituv_fdots); - mesh_batch_cache_discard_batch(cache, batch_map); - - cache->tot_area = 0.0f; - cache->tot_uv_area = 0.0f; - - cache->batch_ready &= ~MBC_EDITUV; - - /* We discarded the vbo.uv so we need to reset the cd_used flag. */ - cache->cd_used.uv = 0; - cache->cd_used.edit_uv = 0; -} - -static void mesh_batch_cache_discard_uvedit_select(MeshBatchCache *cache) -{ - FOREACH_MESH_BUFFER_CACHE (cache, mbc) { - GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.edituv_data); - GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.fdots_edituv_data); - GPU_INDEXBUF_DISCARD_SAFE(mbc->buff.ibo.edituv_tris); - GPU_INDEXBUF_DISCARD_SAFE(mbc->buff.ibo.edituv_lines); - GPU_INDEXBUF_DISCARD_SAFE(mbc->buff.ibo.edituv_points); - GPU_INDEXBUF_DISCARD_SAFE(mbc->buff.ibo.edituv_fdots); - } - DRWBatchFlag batch_map = BATCH_MAP(vbo.edituv_data, - vbo.fdots_edituv_data, - ibo.edituv_tris, - ibo.edituv_lines, - ibo.edituv_points, - ibo.edituv_fdots); - mesh_batch_cache_discard_batch(cache, batch_map); -} - -void DRW_mesh_batch_cache_dirty_tag(Mesh *me, eMeshBatchDirtyMode mode) -{ - MeshBatchCache *cache = me->runtime.batch_cache; - if (cache == NULL) { - return; - } - DRWBatchFlag batch_map; - switch (mode) { - case BKE_MESH_BATCH_DIRTY_SELECT: - FOREACH_MESH_BUFFER_CACHE (cache, mbc) { - GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.edit_data); - GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.fdots_nor); - } - batch_map = BATCH_MAP(vbo.edit_data, vbo.fdots_nor); - mesh_batch_cache_discard_batch(cache, batch_map); - - /* Because visible UVs depends on edit mode selection, discard topology. */ - mesh_batch_cache_discard_uvedit_select(cache); - break; - case BKE_MESH_BATCH_DIRTY_SELECT_PAINT: - /* Paint mode selection flag is packed inside the nor attribute. - * Note that it can be slow if auto smooth is enabled. (see T63946) */ - FOREACH_MESH_BUFFER_CACHE (cache, mbc) { - GPU_INDEXBUF_DISCARD_SAFE(mbc->buff.ibo.lines_paint_mask); - GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.pos_nor); - GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.lnor); - } - batch_map = BATCH_MAP(ibo.lines_paint_mask, vbo.pos_nor, vbo.lnor); - mesh_batch_cache_discard_batch(cache, batch_map); - break; - case BKE_MESH_BATCH_DIRTY_ALL: - cache->is_dirty = true; - break; - case BKE_MESH_BATCH_DIRTY_SHADING: - mesh_batch_cache_discard_shaded_tri(cache); - mesh_batch_cache_discard_uvedit(cache); - break; - case BKE_MESH_BATCH_DIRTY_UVEDIT_ALL: - mesh_batch_cache_discard_uvedit(cache); - break; - case BKE_MESH_BATCH_DIRTY_UVEDIT_SELECT: - FOREACH_MESH_BUFFER_CACHE (cache, mbc) { - GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.edituv_data); - GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.fdots_edituv_data); - } - batch_map = BATCH_MAP(vbo.edituv_data, vbo.fdots_edituv_data); - mesh_batch_cache_discard_batch(cache, batch_map); - break; - default: - BLI_assert(0); - } -} - -static void mesh_buffer_list_clear(MeshBufferList *mbuflist) -{ - GPUVertBuf **vbos = (GPUVertBuf **)&mbuflist->vbo; - GPUIndexBuf **ibos = (GPUIndexBuf **)&mbuflist->ibo; - for (int i = 0; i < sizeof(mbuflist->vbo) / sizeof(void *); i++) { - GPU_VERTBUF_DISCARD_SAFE(vbos[i]); - } - for (int i = 0; i < sizeof(mbuflist->ibo) / sizeof(void *); i++) { - GPU_INDEXBUF_DISCARD_SAFE(ibos[i]); - } -} - -static void mesh_buffer_cache_clear(MeshBufferCache *mbc) -{ - mesh_buffer_list_clear(&mbc->buff); - - MEM_SAFE_FREE(mbc->loose_geom.verts); - MEM_SAFE_FREE(mbc->loose_geom.edges); - mbc->loose_geom.edge_len = 0; - mbc->loose_geom.vert_len = 0; - - MEM_SAFE_FREE(mbc->poly_sorted.tri_first_index); - MEM_SAFE_FREE(mbc->poly_sorted.mat_tri_len); - mbc->poly_sorted.visible_tri_len = 0; -} - -static void mesh_batch_cache_free_subdiv_cache(MeshBatchCache *cache) -{ - if (cache->subdiv_cache) { - draw_subdiv_cache_free(cache->subdiv_cache); - MEM_freeN(cache->subdiv_cache); - cache->subdiv_cache = NULL; - } -} - -static void mesh_batch_cache_clear(Mesh *me) -{ - MeshBatchCache *cache = me->runtime.batch_cache; - if (!cache) { - return; - } - FOREACH_MESH_BUFFER_CACHE (cache, mbc) { - mesh_buffer_cache_clear(mbc); - } - - for (int i = 0; i < cache->mat_len; i++) { - GPU_INDEXBUF_DISCARD_SAFE(cache->tris_per_mat[i]); - } - MEM_SAFE_FREE(cache->tris_per_mat); - - for (int i = 0; i < sizeof(cache->batch) / sizeof(void *); i++) { - GPUBatch **batch = (GPUBatch **)&cache->batch; - GPU_BATCH_DISCARD_SAFE(batch[i]); - } - - mesh_batch_cache_discard_shaded_tri(cache); - mesh_batch_cache_discard_uvedit(cache); - MEM_SAFE_FREE(cache->surface_per_mat); - cache->mat_len = 0; - - cache->batch_ready = 0; - drw_mesh_weight_state_clear(&cache->weight_state); - - mesh_batch_cache_free_subdiv_cache(cache); -} - -void DRW_mesh_batch_cache_free(Mesh *me) -{ - mesh_batch_cache_clear(me); - MEM_SAFE_FREE(me->runtime.batch_cache); -} - -/** \} */ - -/* ---------------------------------------------------------------------- */ -/** \name Public API - * \{ */ - -static void texpaint_request_active_uv(MeshBatchCache *cache, Object *object, Mesh *me) -{ - DRW_MeshCDMask cd_needed; - mesh_cd_layers_type_clear(&cd_needed); - mesh_cd_calc_active_uv_layer(object, me, &cd_needed); - - BLI_assert(cd_needed.uv != 0 && - "No uv layer available in texpaint, but batches requested anyway!"); - - mesh_cd_calc_active_mask_uv_layer(object, me, &cd_needed); - mesh_cd_layers_type_merge(&cache->cd_needed, cd_needed); -} - -static void texpaint_request_active_vcol(MeshBatchCache *cache, Object *object, Mesh *me) -{ - DRW_MeshCDMask cd_needed; - mesh_cd_layers_type_clear(&cd_needed); - mesh_cd_calc_active_mloopcol_layer(object, me, &cd_needed); - - BLI_assert(cd_needed.vcol != 0 && - "No MLOOPCOL layer available in vertpaint, but batches requested anyway!"); - - mesh_cd_layers_type_merge(&cache->cd_needed, cd_needed); -} - -static void sculpt_request_active_vcol(MeshBatchCache *cache, Object *object, Mesh *me) -{ - const Mesh *me_final = editmesh_final_or_this(object, me); - const CustomData *cd_vdata = mesh_cd_vdata_get_from_mesh(me_final); - const CustomData *cd_ldata = mesh_cd_ldata_get_from_mesh(me_final); - - Mesh me_query = {0}; - BKE_id_attribute_copy_domains_temp(ID_ME, cd_vdata, NULL, cd_ldata, NULL, NULL, &me_query.id); - - CustomDataLayer *active = BKE_id_attributes_active_color_get(&me_query.id); - CustomDataLayer *render = BKE_id_attributes_render_color_get(&me_query.id); - - int active_i = BKE_id_attribute_to_index( - &me_query.id, active, ATTR_DOMAIN_MASK_COLOR, CD_MASK_COLOR_ALL); - int render_i = BKE_id_attribute_to_index( - &me_query.id, render, ATTR_DOMAIN_MASK_COLOR, CD_MASK_COLOR_ALL); - - if (active_i >= 0) { - cache->cd_needed.vcol |= 1UL << (uint)active_i; - } - - if (render_i >= 0) { - cache->cd_needed.vcol |= 1UL << (uint)render_i; - } -} - -GPUBatch *DRW_mesh_batch_cache_get_all_verts(Mesh *me) -{ - MeshBatchCache *cache = mesh_batch_cache_get(me); - mesh_batch_cache_add_request(cache, MBC_ALL_VERTS); - return DRW_batch_request(&cache->batch.all_verts); -} - -GPUBatch *DRW_mesh_batch_cache_get_all_edges(Mesh *me) -{ - MeshBatchCache *cache = mesh_batch_cache_get(me); - mesh_batch_cache_add_request(cache, MBC_ALL_EDGES); - return DRW_batch_request(&cache->batch.all_edges); -} - -GPUBatch *DRW_mesh_batch_cache_get_surface(Mesh *me) -{ - MeshBatchCache *cache = mesh_batch_cache_get(me); - mesh_batch_cache_request_surface_batches(cache); - - return cache->batch.surface; -} - -GPUBatch *DRW_mesh_batch_cache_get_loose_edges(Mesh *me) -{ - MeshBatchCache *cache = mesh_batch_cache_get(me); - mesh_batch_cache_add_request(cache, MBC_LOOSE_EDGES); - if (cache->no_loose_wire) { - return NULL; - } - - return DRW_batch_request(&cache->batch.loose_edges); -} - -GPUBatch *DRW_mesh_batch_cache_get_surface_weights(Mesh *me) -{ - MeshBatchCache *cache = mesh_batch_cache_get(me); - mesh_batch_cache_add_request(cache, MBC_SURFACE_WEIGHTS); - return DRW_batch_request(&cache->batch.surface_weights); -} - -GPUBatch *DRW_mesh_batch_cache_get_edge_detection(Mesh *me, bool *r_is_manifold) -{ - MeshBatchCache *cache = mesh_batch_cache_get(me); - mesh_batch_cache_add_request(cache, MBC_EDGE_DETECTION); - /* Even if is_manifold is not correct (not updated), - * the default (not manifold) is just the worst case. */ - if (r_is_manifold) { - *r_is_manifold = cache->is_manifold; - } - return DRW_batch_request(&cache->batch.edge_detection); -} - -GPUBatch *DRW_mesh_batch_cache_get_wireframes_face(Mesh *me) -{ - MeshBatchCache *cache = mesh_batch_cache_get(me); - mesh_batch_cache_add_request(cache, MBC_WIRE_EDGES); - return DRW_batch_request(&cache->batch.wire_edges); -} - -GPUBatch *DRW_mesh_batch_cache_get_edit_mesh_analysis(Mesh *me) -{ - MeshBatchCache *cache = mesh_batch_cache_get(me); - mesh_batch_cache_add_request(cache, MBC_EDIT_MESH_ANALYSIS); - return DRW_batch_request(&cache->batch.edit_mesh_analysis); -} - -GPUBatch **DRW_mesh_batch_cache_get_surface_shaded(Object *object, - Mesh *me, - struct GPUMaterial **gpumat_array, - uint gpumat_array_len) -{ - MeshBatchCache *cache = mesh_batch_cache_get(me); - DRW_Attributes attrs_needed; - drw_attributes_clear(&attrs_needed); - DRW_MeshCDMask cd_needed = mesh_cd_calc_used_gpu_layers( - object, me, gpumat_array, gpumat_array_len, &attrs_needed); - - BLI_assert(gpumat_array_len == cache->mat_len); - - mesh_cd_layers_type_merge(&cache->cd_needed, cd_needed); - ThreadMutex *mesh_render_mutex = (ThreadMutex *)me->runtime.render_mutex; - drw_attributes_merge(&cache->attr_needed, &attrs_needed, mesh_render_mutex); - mesh_batch_cache_request_surface_batches(cache); - return cache->surface_per_mat; -} - -GPUBatch **DRW_mesh_batch_cache_get_surface_texpaint(Object *object, Mesh *me) -{ - MeshBatchCache *cache = mesh_batch_cache_get(me); - texpaint_request_active_uv(cache, object, me); - mesh_batch_cache_request_surface_batches(cache); - return cache->surface_per_mat; -} - -GPUBatch *DRW_mesh_batch_cache_get_surface_texpaint_single(Object *object, Mesh *me) -{ - MeshBatchCache *cache = mesh_batch_cache_get(me); - texpaint_request_active_uv(cache, object, me); - mesh_batch_cache_request_surface_batches(cache); - return cache->batch.surface; -} - -GPUBatch *DRW_mesh_batch_cache_get_surface_vertpaint(Object *object, Mesh *me) -{ - MeshBatchCache *cache = mesh_batch_cache_get(me); - texpaint_request_active_vcol(cache, object, me); - mesh_batch_cache_request_surface_batches(cache); - return cache->batch.surface; -} - -GPUBatch *DRW_mesh_batch_cache_get_surface_sculpt(Object *object, Mesh *me) -{ - MeshBatchCache *cache = mesh_batch_cache_get(me); - sculpt_request_active_vcol(cache, object, me); - mesh_batch_cache_request_surface_batches(cache); - return cache->batch.surface; -} - -int DRW_mesh_material_count_get(const Object *object, const Mesh *me) -{ - return mesh_render_mat_len_get(object, me); -} - -GPUBatch *DRW_mesh_batch_cache_get_sculpt_overlays(Mesh *me) -{ - MeshBatchCache *cache = mesh_batch_cache_get(me); - - cache->cd_needed.sculpt_overlays = 1; - mesh_batch_cache_add_request(cache, MBC_SCULPT_OVERLAYS); - DRW_batch_request(&cache->batch.sculpt_overlays); - - return cache->batch.sculpt_overlays; -} - -/** \} */ - -/* ---------------------------------------------------------------------- */ -/** \name Edit Mode API - * \{ */ - -GPUVertBuf *DRW_mesh_batch_cache_pos_vertbuf_get(Mesh *me) -{ - MeshBatchCache *cache = mesh_batch_cache_get(me); - /* Request surface to trigger the vbo filling. Otherwise it may do nothing. */ - mesh_batch_cache_request_surface_batches(cache); - - DRW_vbo_request(NULL, &cache->final.buff.vbo.pos_nor); - return cache->final.buff.vbo.pos_nor; -} - -/** \} */ - -/* ---------------------------------------------------------------------- */ -/** \name Edit Mode API - * \{ */ - -GPUBatch *DRW_mesh_batch_cache_get_edit_triangles(Mesh *me) -{ - MeshBatchCache *cache = mesh_batch_cache_get(me); - mesh_batch_cache_add_request(cache, MBC_EDIT_TRIANGLES); - return DRW_batch_request(&cache->batch.edit_triangles); -} - -GPUBatch *DRW_mesh_batch_cache_get_edit_edges(Mesh *me) -{ - MeshBatchCache *cache = mesh_batch_cache_get(me); - mesh_batch_cache_add_request(cache, MBC_EDIT_EDGES); - return DRW_batch_request(&cache->batch.edit_edges); -} - -GPUBatch *DRW_mesh_batch_cache_get_edit_vertices(Mesh *me) -{ - MeshBatchCache *cache = mesh_batch_cache_get(me); - mesh_batch_cache_add_request(cache, MBC_EDIT_VERTICES); - return DRW_batch_request(&cache->batch.edit_vertices); -} - -GPUBatch *DRW_mesh_batch_cache_get_edit_vnors(Mesh *me) -{ - MeshBatchCache *cache = mesh_batch_cache_get(me); - mesh_batch_cache_add_request(cache, MBC_EDIT_VNOR); - return DRW_batch_request(&cache->batch.edit_vnor); -} - -GPUBatch *DRW_mesh_batch_cache_get_edit_lnors(Mesh *me) -{ - MeshBatchCache *cache = mesh_batch_cache_get(me); - mesh_batch_cache_add_request(cache, MBC_EDIT_LNOR); - return DRW_batch_request(&cache->batch.edit_lnor); -} - -GPUBatch *DRW_mesh_batch_cache_get_edit_facedots(Mesh *me) -{ - MeshBatchCache *cache = mesh_batch_cache_get(me); - mesh_batch_cache_add_request(cache, MBC_EDIT_FACEDOTS); - return DRW_batch_request(&cache->batch.edit_fdots); -} - -GPUBatch *DRW_mesh_batch_cache_get_edit_skin_roots(Mesh *me) -{ - MeshBatchCache *cache = mesh_batch_cache_get(me); - mesh_batch_cache_add_request(cache, MBC_SKIN_ROOTS); - return DRW_batch_request(&cache->batch.edit_skin_roots); -} - -/** \} */ - -/* ---------------------------------------------------------------------- */ -/** \name Edit Mode selection API - * \{ */ - -GPUBatch *DRW_mesh_batch_cache_get_triangles_with_select_id(Mesh *me) -{ - MeshBatchCache *cache = mesh_batch_cache_get(me); - mesh_batch_cache_add_request(cache, MBC_EDIT_SELECTION_FACES); - return DRW_batch_request(&cache->batch.edit_selection_faces); -} - -GPUBatch *DRW_mesh_batch_cache_get_facedots_with_select_id(Mesh *me) -{ - MeshBatchCache *cache = mesh_batch_cache_get(me); - mesh_batch_cache_add_request(cache, MBC_EDIT_SELECTION_FACEDOTS); - return DRW_batch_request(&cache->batch.edit_selection_fdots); -} - -GPUBatch *DRW_mesh_batch_cache_get_edges_with_select_id(Mesh *me) -{ - MeshBatchCache *cache = mesh_batch_cache_get(me); - mesh_batch_cache_add_request(cache, MBC_EDIT_SELECTION_EDGES); - return DRW_batch_request(&cache->batch.edit_selection_edges); -} - -GPUBatch *DRW_mesh_batch_cache_get_verts_with_select_id(Mesh *me) -{ - MeshBatchCache *cache = mesh_batch_cache_get(me); - mesh_batch_cache_add_request(cache, MBC_EDIT_SELECTION_VERTS); - return DRW_batch_request(&cache->batch.edit_selection_verts); -} - -/** \} */ - -/* ---------------------------------------------------------------------- */ -/** \name UV Image editor API - * \{ */ - -static void edituv_request_active_uv(MeshBatchCache *cache, Object *object, Mesh *me) -{ - DRW_MeshCDMask cd_needed; - mesh_cd_layers_type_clear(&cd_needed); - mesh_cd_calc_active_uv_layer(object, me, &cd_needed); - mesh_cd_calc_edit_uv_layer(me, &cd_needed); - - BLI_assert(cd_needed.edit_uv != 0 && - "No uv layer available in edituv, but batches requested anyway!"); - - mesh_cd_calc_active_mask_uv_layer(object, me, &cd_needed); - mesh_cd_layers_type_merge(&cache->cd_needed, cd_needed); -} - -GPUBatch *DRW_mesh_batch_cache_get_edituv_faces_stretch_area(Object *object, - Mesh *me, - float **tot_area, - float **tot_uv_area) -{ - MeshBatchCache *cache = mesh_batch_cache_get(me); - edituv_request_active_uv(cache, object, me); - mesh_batch_cache_add_request(cache, MBC_EDITUV_FACES_STRETCH_AREA); - - if (tot_area != NULL) { - *tot_area = &cache->tot_area; - } - if (tot_uv_area != NULL) { - *tot_uv_area = &cache->tot_uv_area; - } - return DRW_batch_request(&cache->batch.edituv_faces_stretch_area); -} - -GPUBatch *DRW_mesh_batch_cache_get_edituv_faces_stretch_angle(Object *object, Mesh *me) -{ - MeshBatchCache *cache = mesh_batch_cache_get(me); - edituv_request_active_uv(cache, object, me); - mesh_batch_cache_add_request(cache, MBC_EDITUV_FACES_STRETCH_ANGLE); - return DRW_batch_request(&cache->batch.edituv_faces_stretch_angle); -} - -GPUBatch *DRW_mesh_batch_cache_get_edituv_faces(Object *object, Mesh *me) -{ - MeshBatchCache *cache = mesh_batch_cache_get(me); - edituv_request_active_uv(cache, object, me); - mesh_batch_cache_add_request(cache, MBC_EDITUV_FACES); - return DRW_batch_request(&cache->batch.edituv_faces); -} - -GPUBatch *DRW_mesh_batch_cache_get_edituv_edges(Object *object, Mesh *me) -{ - MeshBatchCache *cache = mesh_batch_cache_get(me); - edituv_request_active_uv(cache, object, me); - mesh_batch_cache_add_request(cache, MBC_EDITUV_EDGES); - return DRW_batch_request(&cache->batch.edituv_edges); -} - -GPUBatch *DRW_mesh_batch_cache_get_edituv_verts(Object *object, Mesh *me) -{ - MeshBatchCache *cache = mesh_batch_cache_get(me); - edituv_request_active_uv(cache, object, me); - mesh_batch_cache_add_request(cache, MBC_EDITUV_VERTS); - return DRW_batch_request(&cache->batch.edituv_verts); -} - -GPUBatch *DRW_mesh_batch_cache_get_edituv_facedots(Object *object, Mesh *me) -{ - MeshBatchCache *cache = mesh_batch_cache_get(me); - edituv_request_active_uv(cache, object, me); - mesh_batch_cache_add_request(cache, MBC_EDITUV_FACEDOTS); - return DRW_batch_request(&cache->batch.edituv_fdots); -} - -GPUBatch *DRW_mesh_batch_cache_get_uv_edges(Object *object, Mesh *me) -{ - MeshBatchCache *cache = mesh_batch_cache_get(me); - edituv_request_active_uv(cache, object, me); - mesh_batch_cache_add_request(cache, MBC_WIRE_LOOPS_UVS); - return DRW_batch_request(&cache->batch.wire_loops_uvs); -} - -GPUBatch *DRW_mesh_batch_cache_get_surface_edges(Object *object, Mesh *me) -{ - MeshBatchCache *cache = mesh_batch_cache_get(me); - texpaint_request_active_uv(cache, object, me); - mesh_batch_cache_add_request(cache, MBC_WIRE_LOOPS); - return DRW_batch_request(&cache->batch.wire_loops); -} - -/** \} */ - -/* ---------------------------------------------------------------------- */ -/** \name Grouped batch generation - * \{ */ - -void DRW_mesh_batch_cache_free_old(Mesh *me, int ctime) -{ - MeshBatchCache *cache = me->runtime.batch_cache; - - if (cache == NULL) { - return; - } - - if (mesh_cd_layers_type_equal(cache->cd_used_over_time, cache->cd_used)) { - cache->lastmatch = ctime; - } - - if (drw_attributes_overlap(&cache->attr_used_over_time, &cache->attr_used)) { - cache->lastmatch = ctime; - } - - if (ctime - cache->lastmatch > U.vbotimeout) { - mesh_batch_cache_discard_shaded_tri(cache); - } - - mesh_cd_layers_type_clear(&cache->cd_used_over_time); - drw_attributes_clear(&cache->attr_used_over_time); -} - -static void drw_add_attributes_vbo(GPUBatch *batch, - MeshBufferList *mbuflist, - DRW_Attributes *attr_used) -{ - for (int i = 0; i < attr_used->num_requests; i++) { - DRW_vbo_request(batch, &mbuflist->vbo.attr[i]); - } -} - -#ifdef DEBUG -/* Sanity check function to test if all requested batches are available. */ -static void drw_mesh_batch_cache_check_available(struct TaskGraph *task_graph, Mesh *me) -{ - MeshBatchCache *cache = mesh_batch_cache_get(me); - /* Make sure all requested batches have been setup. */ - /* NOTE: The next line creates a different scheduling than during release builds what can lead to - * some issues (See T77867 where we needed to disable this function in order to debug what was - * happening in release builds). */ - BLI_task_graph_work_and_wait(task_graph); - for (int i = 0; i < MBC_BATCH_LEN; i++) { - BLI_assert(!DRW_batch_requested(((GPUBatch **)&cache->batch)[i], 0)); - } - for (int i = 0; i < MBC_VBO_LEN; i++) { - BLI_assert(!DRW_vbo_requested(((GPUVertBuf **)&cache->final.buff.vbo)[i])); - } - for (int i = 0; i < MBC_IBO_LEN; i++) { - BLI_assert(!DRW_ibo_requested(((GPUIndexBuf **)&cache->final.buff.ibo)[i])); - } - for (int i = 0; i < MBC_VBO_LEN; i++) { - BLI_assert(!DRW_vbo_requested(((GPUVertBuf **)&cache->cage.buff.vbo)[i])); - } - for (int i = 0; i < MBC_IBO_LEN; i++) { - BLI_assert(!DRW_ibo_requested(((GPUIndexBuf **)&cache->cage.buff.ibo)[i])); - } - for (int i = 0; i < MBC_VBO_LEN; i++) { - BLI_assert(!DRW_vbo_requested(((GPUVertBuf **)&cache->uv_cage.buff.vbo)[i])); - } - for (int i = 0; i < MBC_IBO_LEN; i++) { - BLI_assert(!DRW_ibo_requested(((GPUIndexBuf **)&cache->uv_cage.buff.ibo)[i])); - } -} -#endif - -void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph, - Object *ob, - Mesh *me, - const Scene *scene, - const bool is_paint_mode, - const bool use_hide) -{ - BLI_assert(task_graph); - const ToolSettings *ts = NULL; - if (scene) { - ts = scene->toolsettings; - } - MeshBatchCache *cache = mesh_batch_cache_get(me); - bool cd_uv_update = false; - - /* Early out */ - if (cache->batch_requested == 0) { -#ifdef DEBUG - drw_mesh_batch_cache_check_available(task_graph, me); -#endif - return; - } - - /* Sanity check. */ - if ((me->edit_mesh != NULL) && (ob->mode & OB_MODE_EDIT)) { - BLI_assert(BKE_object_get_editmesh_eval_final(ob) != NULL); - } - - const bool is_editmode = (me->edit_mesh != NULL) && - (BKE_object_get_editmesh_eval_final(ob) != NULL) && - DRW_object_is_in_edit_mode(ob); - - /* This could be set for paint mode too, currently it's only used for edit-mode. */ - const bool is_mode_active = is_editmode && DRW_object_is_in_edit_mode(ob); - - DRWBatchFlag batch_requested = cache->batch_requested; - cache->batch_requested = 0; - - if (batch_requested & MBC_SURFACE_WEIGHTS) { - /* Check vertex weights. */ - if ((cache->batch.surface_weights != NULL) && (ts != NULL)) { - struct DRW_MeshWeightState wstate; - BLI_assert(ob->type == OB_MESH); - drw_mesh_weight_state_extract(ob, me, ts, is_paint_mode, &wstate); - mesh_batch_cache_check_vertex_group(cache, &wstate); - drw_mesh_weight_state_copy(&cache->weight_state, &wstate); - drw_mesh_weight_state_clear(&wstate); - } - } - - if (batch_requested & - (MBC_SURFACE | MBC_WIRE_LOOPS_UVS | MBC_EDITUV_FACES_STRETCH_AREA | - MBC_EDITUV_FACES_STRETCH_ANGLE | MBC_EDITUV_FACES | MBC_EDITUV_EDGES | MBC_EDITUV_VERTS)) { - /* Modifiers will only generate an orco layer if the mesh is deformed. */ - if (cache->cd_needed.orco != 0) { - /* Orco is always extracted from final mesh. */ - Mesh *me_final = (me->edit_mesh) ? BKE_object_get_editmesh_eval_final(ob) : me; - if (CustomData_get_layer(&me_final->vdata, CD_ORCO) == NULL) { - /* Skip orco calculation */ - cache->cd_needed.orco = 0; - } - } - - ThreadMutex *mesh_render_mutex = (ThreadMutex *)me->runtime.render_mutex; - - /* Verify that all surface batches have needed attribute layers. - */ - /* TODO(fclem): We could be a bit smarter here and only do it per - * material. */ - bool cd_overlap = mesh_cd_layers_type_overlap(cache->cd_used, cache->cd_needed); - bool attr_overlap = drw_attributes_overlap(&cache->attr_used, &cache->attr_needed); - if (cd_overlap == false || attr_overlap == false) { - FOREACH_MESH_BUFFER_CACHE (cache, mbc) { - if ((cache->cd_used.uv & cache->cd_needed.uv) != cache->cd_needed.uv) { - GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.uv); - cd_uv_update = true; - } - if ((cache->cd_used.tan & cache->cd_needed.tan) != cache->cd_needed.tan || - cache->cd_used.tan_orco != cache->cd_needed.tan_orco) { - GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.tan); - } - if (cache->cd_used.orco != cache->cd_needed.orco) { - GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.orco); - } - if (cache->cd_used.sculpt_overlays != cache->cd_needed.sculpt_overlays) { - GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.sculpt_data); - } - if ((cache->cd_used.vcol & cache->cd_needed.vcol) != cache->cd_needed.vcol) { - GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.vcol); - } - if (!drw_attributes_overlap(&cache->attr_used, &cache->attr_needed)) { - for (int i = 0; i < GPU_MAX_ATTR; i++) { - GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.attr[i]); - } - } - } - /* We can't discard batches at this point as they have been - * referenced for drawing. Just clear them in place. */ - for (int i = 0; i < cache->mat_len; i++) { - GPU_BATCH_CLEAR_SAFE(cache->surface_per_mat[i]); - } - GPU_BATCH_CLEAR_SAFE(cache->batch.surface); - cache->batch_ready &= ~(MBC_SURFACE); - - mesh_cd_layers_type_merge(&cache->cd_used, cache->cd_needed); - drw_attributes_merge(&cache->attr_used, &cache->attr_needed, mesh_render_mutex); - } - mesh_cd_layers_type_merge(&cache->cd_used_over_time, cache->cd_needed); - mesh_cd_layers_type_clear(&cache->cd_needed); - - drw_attributes_merge(&cache->attr_used_over_time, &cache->attr_needed, mesh_render_mutex); - drw_attributes_clear(&cache->attr_needed); - } - - if (batch_requested & MBC_EDITUV) { - /* Discard UV batches if sync_selection changes */ - const bool is_uvsyncsel = ts && (ts->uv_flag & UV_SYNC_SELECTION); - if (cd_uv_update || (cache->is_uvsyncsel != is_uvsyncsel)) { - cache->is_uvsyncsel = is_uvsyncsel; - FOREACH_MESH_BUFFER_CACHE (cache, mbc) { - GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.edituv_data); - GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.fdots_uv); - GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.fdots_edituv_data); - GPU_INDEXBUF_DISCARD_SAFE(mbc->buff.ibo.edituv_tris); - GPU_INDEXBUF_DISCARD_SAFE(mbc->buff.ibo.edituv_lines); - GPU_INDEXBUF_DISCARD_SAFE(mbc->buff.ibo.edituv_points); - GPU_INDEXBUF_DISCARD_SAFE(mbc->buff.ibo.edituv_fdots); - } - /* We only clear the batches as they may already have been - * referenced. */ - GPU_BATCH_CLEAR_SAFE(cache->batch.wire_loops_uvs); - GPU_BATCH_CLEAR_SAFE(cache->batch.edituv_faces_stretch_area); - GPU_BATCH_CLEAR_SAFE(cache->batch.edituv_faces_stretch_angle); - GPU_BATCH_CLEAR_SAFE(cache->batch.edituv_faces); - GPU_BATCH_CLEAR_SAFE(cache->batch.edituv_edges); - GPU_BATCH_CLEAR_SAFE(cache->batch.edituv_verts); - GPU_BATCH_CLEAR_SAFE(cache->batch.edituv_fdots); - cache->batch_ready &= ~MBC_EDITUV; - } - } - - /* Second chance to early out */ - if ((batch_requested & ~cache->batch_ready) == 0) { -#ifdef DEBUG - drw_mesh_batch_cache_check_available(task_graph, me); -#endif - return; - } - - /* TODO(pablodp606): This always updates the sculpt normals for regular drawing (non-PBVH). - * This makes tools that sample the surface per step get wrong normals until a redraw happens. - * Normal updates should be part of the brush loop and only run during the stroke when the - * brush needs to sample the surface. The drawing code should only update the normals - * per redraw when smooth shading is enabled. */ - const bool do_update_sculpt_normals = ob->sculpt && ob->sculpt->pbvh; - if (do_update_sculpt_normals) { - Mesh *mesh = ob->data; - BKE_pbvh_update_normals(ob->sculpt->pbvh, mesh->runtime.subdiv_ccg); - } - - cache->batch_ready |= batch_requested; - - bool do_cage = false, do_uvcage = false; - if (is_editmode) { - Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(ob); - Mesh *editmesh_eval_cage = BKE_object_get_editmesh_eval_cage(ob); - - do_cage = editmesh_eval_final != editmesh_eval_cage; - do_uvcage = !editmesh_eval_final->runtime.is_original; - } - - const bool do_subdivision = BKE_subsurf_modifier_has_gpu_subdiv(me); - - MeshBufferList *mbuflist = &cache->final.buff; - - /* Initialize batches and request VBO's & IBO's. */ - MDEPS_ASSERT(surface, - ibo.tris, - vbo.lnor, - vbo.pos_nor, - vbo.uv, - vbo.vcol, - vbo.attr[0], - vbo.attr[1], - vbo.attr[2], - vbo.attr[3], - vbo.attr[4], - vbo.attr[5], - vbo.attr[6], - vbo.attr[7], - vbo.attr[8], - vbo.attr[9], - vbo.attr[10], - vbo.attr[11], - vbo.attr[12], - vbo.attr[13], - vbo.attr[14]); - if (DRW_batch_requested(cache->batch.surface, GPU_PRIM_TRIS)) { - DRW_ibo_request(cache->batch.surface, &mbuflist->ibo.tris); - /* Order matters. First ones override latest VBO's attributes. */ - DRW_vbo_request(cache->batch.surface, &mbuflist->vbo.lnor); - DRW_vbo_request(cache->batch.surface, &mbuflist->vbo.pos_nor); - if (cache->cd_used.uv != 0) { - DRW_vbo_request(cache->batch.surface, &mbuflist->vbo.uv); - } - if (cache->cd_used.vcol != 0) { - DRW_vbo_request(cache->batch.surface, &mbuflist->vbo.vcol); - } - drw_add_attributes_vbo(cache->batch.surface, mbuflist, &cache->attr_used); - } - MDEPS_ASSERT(all_verts, vbo.pos_nor); - if (DRW_batch_requested(cache->batch.all_verts, GPU_PRIM_POINTS)) { - DRW_vbo_request(cache->batch.all_verts, &mbuflist->vbo.pos_nor); - } - MDEPS_ASSERT(sculpt_overlays, ibo.tris, vbo.pos_nor, vbo.sculpt_data); - if (DRW_batch_requested(cache->batch.sculpt_overlays, GPU_PRIM_TRIS)) { - DRW_ibo_request(cache->batch.sculpt_overlays, &mbuflist->ibo.tris); - DRW_vbo_request(cache->batch.sculpt_overlays, &mbuflist->vbo.pos_nor); - DRW_vbo_request(cache->batch.sculpt_overlays, &mbuflist->vbo.sculpt_data); - } - MDEPS_ASSERT(all_edges, ibo.lines, vbo.pos_nor); - if (DRW_batch_requested(cache->batch.all_edges, GPU_PRIM_LINES)) { - DRW_ibo_request(cache->batch.all_edges, &mbuflist->ibo.lines); - DRW_vbo_request(cache->batch.all_edges, &mbuflist->vbo.pos_nor); - } - MDEPS_ASSERT(loose_edges, ibo.lines_loose, vbo.pos_nor); - if (DRW_batch_requested(cache->batch.loose_edges, GPU_PRIM_LINES)) { - DRW_ibo_request(NULL, &mbuflist->ibo.lines); - DRW_ibo_request(cache->batch.loose_edges, &mbuflist->ibo.lines_loose); - DRW_vbo_request(cache->batch.loose_edges, &mbuflist->vbo.pos_nor); - } - MDEPS_ASSERT(edge_detection, ibo.lines_adjacency, vbo.pos_nor); - if (DRW_batch_requested(cache->batch.edge_detection, GPU_PRIM_LINES_ADJ)) { - DRW_ibo_request(cache->batch.edge_detection, &mbuflist->ibo.lines_adjacency); - DRW_vbo_request(cache->batch.edge_detection, &mbuflist->vbo.pos_nor); - } - MDEPS_ASSERT(surface_weights, ibo.tris, vbo.pos_nor, vbo.weights); - if (DRW_batch_requested(cache->batch.surface_weights, GPU_PRIM_TRIS)) { - DRW_ibo_request(cache->batch.surface_weights, &mbuflist->ibo.tris); - DRW_vbo_request(cache->batch.surface_weights, &mbuflist->vbo.pos_nor); - DRW_vbo_request(cache->batch.surface_weights, &mbuflist->vbo.weights); - } - MDEPS_ASSERT(wire_loops, ibo.lines_paint_mask, vbo.lnor, vbo.pos_nor); - if (DRW_batch_requested(cache->batch.wire_loops, GPU_PRIM_LINES)) { - DRW_ibo_request(cache->batch.wire_loops, &mbuflist->ibo.lines_paint_mask); - /* Order matters. First ones override latest VBO's attributes. */ - DRW_vbo_request(cache->batch.wire_loops, &mbuflist->vbo.lnor); - DRW_vbo_request(cache->batch.wire_loops, &mbuflist->vbo.pos_nor); - } - MDEPS_ASSERT(wire_edges, ibo.lines, vbo.pos_nor, vbo.edge_fac); - if (DRW_batch_requested(cache->batch.wire_edges, GPU_PRIM_LINES)) { - DRW_ibo_request(cache->batch.wire_edges, &mbuflist->ibo.lines); - DRW_vbo_request(cache->batch.wire_edges, &mbuflist->vbo.pos_nor); - DRW_vbo_request(cache->batch.wire_edges, &mbuflist->vbo.edge_fac); - } - MDEPS_ASSERT(wire_loops_uvs, ibo.edituv_lines, vbo.uv); - if (DRW_batch_requested(cache->batch.wire_loops_uvs, GPU_PRIM_LINES)) { - DRW_ibo_request(cache->batch.wire_loops_uvs, &mbuflist->ibo.edituv_lines); - /* For paint overlay. Active layer should have been queried. */ - if (cache->cd_used.uv != 0) { - DRW_vbo_request(cache->batch.wire_loops_uvs, &mbuflist->vbo.uv); - } - } - MDEPS_ASSERT(edit_mesh_analysis, ibo.tris, vbo.pos_nor, vbo.mesh_analysis); - if (DRW_batch_requested(cache->batch.edit_mesh_analysis, GPU_PRIM_TRIS)) { - DRW_ibo_request(cache->batch.edit_mesh_analysis, &mbuflist->ibo.tris); - DRW_vbo_request(cache->batch.edit_mesh_analysis, &mbuflist->vbo.pos_nor); - DRW_vbo_request(cache->batch.edit_mesh_analysis, &mbuflist->vbo.mesh_analysis); - } - - /* Per Material */ - MDEPS_ASSERT_FLAG(SURFACE_PER_MAT_FLAG, - vbo.lnor, - vbo.pos_nor, - vbo.uv, - vbo.tan, - vbo.vcol, - vbo.orco, - vbo.attr[0], - vbo.attr[1], - vbo.attr[2], - vbo.attr[3], - vbo.attr[4], - vbo.attr[5], - vbo.attr[6], - vbo.attr[7], - vbo.attr[8], - vbo.attr[9], - vbo.attr[10], - vbo.attr[11], - vbo.attr[12], - vbo.attr[13], - vbo.attr[14]); - MDEPS_ASSERT_INDEX(TRIS_PER_MAT_INDEX, SURFACE_PER_MAT_FLAG); - for (int i = 0; i < cache->mat_len; i++) { - if (DRW_batch_requested(cache->surface_per_mat[i], GPU_PRIM_TRIS)) { - DRW_ibo_request(cache->surface_per_mat[i], &cache->tris_per_mat[i]); - /* Order matters. First ones override latest VBO's attributes. */ - DRW_vbo_request(cache->surface_per_mat[i], &mbuflist->vbo.lnor); - DRW_vbo_request(cache->surface_per_mat[i], &mbuflist->vbo.pos_nor); - if (cache->cd_used.uv != 0) { - DRW_vbo_request(cache->surface_per_mat[i], &mbuflist->vbo.uv); - } - if ((cache->cd_used.tan != 0) || (cache->cd_used.tan_orco != 0)) { - DRW_vbo_request(cache->surface_per_mat[i], &mbuflist->vbo.tan); - } - if (cache->cd_used.vcol != 0) { - DRW_vbo_request(cache->surface_per_mat[i], &mbuflist->vbo.vcol); - } - if (cache->cd_used.orco != 0) { - DRW_vbo_request(cache->surface_per_mat[i], &mbuflist->vbo.orco); - } - drw_add_attributes_vbo(cache->surface_per_mat[i], mbuflist, &cache->attr_used); - } - } - - mbuflist = (do_cage) ? &cache->cage.buff : &cache->final.buff; - - /* Edit Mesh */ - MDEPS_ASSERT(edit_triangles, ibo.tris, vbo.pos_nor, vbo.edit_data); - if (DRW_batch_requested(cache->batch.edit_triangles, GPU_PRIM_TRIS)) { - DRW_ibo_request(cache->batch.edit_triangles, &mbuflist->ibo.tris); - DRW_vbo_request(cache->batch.edit_triangles, &mbuflist->vbo.pos_nor); - DRW_vbo_request(cache->batch.edit_triangles, &mbuflist->vbo.edit_data); - } - MDEPS_ASSERT(edit_vertices, ibo.points, vbo.pos_nor, vbo.edit_data); - if (DRW_batch_requested(cache->batch.edit_vertices, GPU_PRIM_POINTS)) { - DRW_ibo_request(cache->batch.edit_vertices, &mbuflist->ibo.points); - DRW_vbo_request(cache->batch.edit_vertices, &mbuflist->vbo.pos_nor); - DRW_vbo_request(cache->batch.edit_vertices, &mbuflist->vbo.edit_data); - } - MDEPS_ASSERT(edit_edges, ibo.lines, vbo.pos_nor, vbo.edit_data); - if (DRW_batch_requested(cache->batch.edit_edges, GPU_PRIM_LINES)) { - DRW_ibo_request(cache->batch.edit_edges, &mbuflist->ibo.lines); - DRW_vbo_request(cache->batch.edit_edges, &mbuflist->vbo.pos_nor); - DRW_vbo_request(cache->batch.edit_edges, &mbuflist->vbo.edit_data); - } - MDEPS_ASSERT(edit_vnor, ibo.points, vbo.pos_nor); - if (DRW_batch_requested(cache->batch.edit_vnor, GPU_PRIM_POINTS)) { - DRW_ibo_request(cache->batch.edit_vnor, &mbuflist->ibo.points); - DRW_vbo_request(cache->batch.edit_vnor, &mbuflist->vbo.pos_nor); - } - MDEPS_ASSERT(edit_lnor, ibo.tris, vbo.pos_nor, vbo.lnor); - if (DRW_batch_requested(cache->batch.edit_lnor, GPU_PRIM_POINTS)) { - DRW_ibo_request(cache->batch.edit_lnor, &mbuflist->ibo.tris); - DRW_vbo_request(cache->batch.edit_lnor, &mbuflist->vbo.pos_nor); - DRW_vbo_request(cache->batch.edit_lnor, &mbuflist->vbo.lnor); - } - MDEPS_ASSERT(edit_fdots, ibo.fdots, vbo.fdots_pos, vbo.fdots_nor); - if (DRW_batch_requested(cache->batch.edit_fdots, GPU_PRIM_POINTS)) { - DRW_ibo_request(cache->batch.edit_fdots, &mbuflist->ibo.fdots); - DRW_vbo_request(cache->batch.edit_fdots, &mbuflist->vbo.fdots_pos); - DRW_vbo_request(cache->batch.edit_fdots, &mbuflist->vbo.fdots_nor); - } - MDEPS_ASSERT(edit_skin_roots, vbo.skin_roots); - if (DRW_batch_requested(cache->batch.edit_skin_roots, GPU_PRIM_POINTS)) { - DRW_vbo_request(cache->batch.edit_skin_roots, &mbuflist->vbo.skin_roots); - } - - /* Selection */ - MDEPS_ASSERT(edit_selection_verts, ibo.points, vbo.pos_nor, vbo.vert_idx); - if (DRW_batch_requested(cache->batch.edit_selection_verts, GPU_PRIM_POINTS)) { - DRW_ibo_request(cache->batch.edit_selection_verts, &mbuflist->ibo.points); - DRW_vbo_request(cache->batch.edit_selection_verts, &mbuflist->vbo.pos_nor); - DRW_vbo_request(cache->batch.edit_selection_verts, &mbuflist->vbo.vert_idx); - } - MDEPS_ASSERT(edit_selection_edges, ibo.lines, vbo.pos_nor, vbo.edge_idx); - if (DRW_batch_requested(cache->batch.edit_selection_edges, GPU_PRIM_LINES)) { - DRW_ibo_request(cache->batch.edit_selection_edges, &mbuflist->ibo.lines); - DRW_vbo_request(cache->batch.edit_selection_edges, &mbuflist->vbo.pos_nor); - DRW_vbo_request(cache->batch.edit_selection_edges, &mbuflist->vbo.edge_idx); - } - MDEPS_ASSERT(edit_selection_faces, ibo.tris, vbo.pos_nor, vbo.poly_idx); - if (DRW_batch_requested(cache->batch.edit_selection_faces, GPU_PRIM_TRIS)) { - DRW_ibo_request(cache->batch.edit_selection_faces, &mbuflist->ibo.tris); - DRW_vbo_request(cache->batch.edit_selection_faces, &mbuflist->vbo.pos_nor); - DRW_vbo_request(cache->batch.edit_selection_faces, &mbuflist->vbo.poly_idx); - } - MDEPS_ASSERT(edit_selection_fdots, ibo.fdots, vbo.fdots_pos, vbo.fdot_idx); - if (DRW_batch_requested(cache->batch.edit_selection_fdots, GPU_PRIM_POINTS)) { - DRW_ibo_request(cache->batch.edit_selection_fdots, &mbuflist->ibo.fdots); - DRW_vbo_request(cache->batch.edit_selection_fdots, &mbuflist->vbo.fdots_pos); - DRW_vbo_request(cache->batch.edit_selection_fdots, &mbuflist->vbo.fdot_idx); - } - - /** - * TODO: The code and data structure is ready to support modified UV display - * but the selection code for UVs needs to support it first. So for now, only - * display the cage in all cases. - */ - mbuflist = (do_uvcage) ? &cache->uv_cage.buff : &cache->final.buff; - - /* Edit UV */ - MDEPS_ASSERT(edituv_faces, ibo.edituv_tris, vbo.uv, vbo.edituv_data); - if (DRW_batch_requested(cache->batch.edituv_faces, GPU_PRIM_TRIS)) { - DRW_ibo_request(cache->batch.edituv_faces, &mbuflist->ibo.edituv_tris); - DRW_vbo_request(cache->batch.edituv_faces, &mbuflist->vbo.uv); - DRW_vbo_request(cache->batch.edituv_faces, &mbuflist->vbo.edituv_data); - } - MDEPS_ASSERT(edituv_faces_stretch_area, - ibo.edituv_tris, - vbo.uv, - vbo.edituv_data, - vbo.edituv_stretch_area); - if (DRW_batch_requested(cache->batch.edituv_faces_stretch_area, GPU_PRIM_TRIS)) { - DRW_ibo_request(cache->batch.edituv_faces_stretch_area, &mbuflist->ibo.edituv_tris); - DRW_vbo_request(cache->batch.edituv_faces_stretch_area, &mbuflist->vbo.uv); - DRW_vbo_request(cache->batch.edituv_faces_stretch_area, &mbuflist->vbo.edituv_data); - DRW_vbo_request(cache->batch.edituv_faces_stretch_area, &mbuflist->vbo.edituv_stretch_area); - } - MDEPS_ASSERT(edituv_faces_stretch_angle, - ibo.edituv_tris, - vbo.uv, - vbo.edituv_data, - vbo.edituv_stretch_angle); - if (DRW_batch_requested(cache->batch.edituv_faces_stretch_angle, GPU_PRIM_TRIS)) { - DRW_ibo_request(cache->batch.edituv_faces_stretch_angle, &mbuflist->ibo.edituv_tris); - DRW_vbo_request(cache->batch.edituv_faces_stretch_angle, &mbuflist->vbo.uv); - DRW_vbo_request(cache->batch.edituv_faces_stretch_angle, &mbuflist->vbo.edituv_data); - DRW_vbo_request(cache->batch.edituv_faces_stretch_angle, &mbuflist->vbo.edituv_stretch_angle); - } - MDEPS_ASSERT(edituv_edges, ibo.edituv_lines, vbo.uv, vbo.edituv_data); - if (DRW_batch_requested(cache->batch.edituv_edges, GPU_PRIM_LINES)) { - DRW_ibo_request(cache->batch.edituv_edges, &mbuflist->ibo.edituv_lines); - DRW_vbo_request(cache->batch.edituv_edges, &mbuflist->vbo.uv); - DRW_vbo_request(cache->batch.edituv_edges, &mbuflist->vbo.edituv_data); - } - MDEPS_ASSERT(edituv_verts, ibo.edituv_points, vbo.uv, vbo.edituv_data); - if (DRW_batch_requested(cache->batch.edituv_verts, GPU_PRIM_POINTS)) { - DRW_ibo_request(cache->batch.edituv_verts, &mbuflist->ibo.edituv_points); - DRW_vbo_request(cache->batch.edituv_verts, &mbuflist->vbo.uv); - DRW_vbo_request(cache->batch.edituv_verts, &mbuflist->vbo.edituv_data); - } - MDEPS_ASSERT(edituv_fdots, ibo.edituv_fdots, vbo.fdots_uv, vbo.fdots_edituv_data); - if (DRW_batch_requested(cache->batch.edituv_fdots, GPU_PRIM_POINTS)) { - DRW_ibo_request(cache->batch.edituv_fdots, &mbuflist->ibo.edituv_fdots); - DRW_vbo_request(cache->batch.edituv_fdots, &mbuflist->vbo.fdots_uv); - DRW_vbo_request(cache->batch.edituv_fdots, &mbuflist->vbo.fdots_edituv_data); - } - - MDEPS_ASSERT_MAP(vbo.lnor); - MDEPS_ASSERT_MAP(vbo.pos_nor); - MDEPS_ASSERT_MAP(vbo.uv); - MDEPS_ASSERT_MAP(vbo.vcol); - MDEPS_ASSERT_MAP(vbo.sculpt_data); - MDEPS_ASSERT_MAP(vbo.weights); - MDEPS_ASSERT_MAP(vbo.edge_fac); - MDEPS_ASSERT_MAP(vbo.mesh_analysis); - MDEPS_ASSERT_MAP(vbo.tan); - MDEPS_ASSERT_MAP(vbo.orco); - MDEPS_ASSERT_MAP(vbo.edit_data); - MDEPS_ASSERT_MAP(vbo.fdots_pos); - MDEPS_ASSERT_MAP(vbo.fdots_nor); - MDEPS_ASSERT_MAP(vbo.skin_roots); - MDEPS_ASSERT_MAP(vbo.vert_idx); - MDEPS_ASSERT_MAP(vbo.edge_idx); - MDEPS_ASSERT_MAP(vbo.poly_idx); - MDEPS_ASSERT_MAP(vbo.fdot_idx); - MDEPS_ASSERT_MAP(vbo.edituv_data); - MDEPS_ASSERT_MAP(vbo.edituv_stretch_area); - MDEPS_ASSERT_MAP(vbo.edituv_stretch_angle); - MDEPS_ASSERT_MAP(vbo.fdots_uv); - MDEPS_ASSERT_MAP(vbo.fdots_edituv_data); - for (int i = 0; i < GPU_MAX_ATTR; i++) { - MDEPS_ASSERT_MAP(vbo.attr[i]); - } - - MDEPS_ASSERT_MAP(ibo.tris); - MDEPS_ASSERT_MAP(ibo.lines); - MDEPS_ASSERT_MAP(ibo.lines_loose); - MDEPS_ASSERT_MAP(ibo.lines_adjacency); - MDEPS_ASSERT_MAP(ibo.lines_paint_mask); - MDEPS_ASSERT_MAP(ibo.points); - MDEPS_ASSERT_MAP(ibo.fdots); - MDEPS_ASSERT_MAP(ibo.edituv_tris); - MDEPS_ASSERT_MAP(ibo.edituv_lines); - MDEPS_ASSERT_MAP(ibo.edituv_points); - MDEPS_ASSERT_MAP(ibo.edituv_fdots); - - MDEPS_ASSERT_MAP_INDEX(TRIS_PER_MAT_INDEX); - - if (do_uvcage) { - mesh_buffer_cache_create_requested(task_graph, - cache, - &cache->uv_cage, - ob, - me, - is_editmode, - is_paint_mode, - is_mode_active, - ob->obmat, - false, - true, - scene, - ts, - true); - } - - if (do_cage) { - mesh_buffer_cache_create_requested(task_graph, - cache, - &cache->cage, - ob, - me, - is_editmode, - is_paint_mode, - is_mode_active, - ob->obmat, - false, - false, - scene, - ts, - true); - } - - if (do_subdivision) { - DRW_create_subdivision(scene, - ob, - me, - cache, - &cache->final, - is_editmode, - is_paint_mode, - is_mode_active, - ob->obmat, - true, - false, - ts, - use_hide); - } - else { - /* The subsurf modifier may have been recently removed, or another modifier was added after it, - * so free any potential subdivision cache as it is not needed anymore. */ - mesh_batch_cache_free_subdiv_cache(cache); - } - - mesh_buffer_cache_create_requested(task_graph, - cache, - &cache->final, - ob, - me, - is_editmode, - is_paint_mode, - is_mode_active, - ob->obmat, - true, - false, - scene, - ts, - use_hide); - - /* Ensure that all requested batches have finished. - * Ideally we want to remove this sync, but there are cases where this doesn't work. - * See T79038 for example. - * - * An idea to improve this is to separate the Object mode from the edit mode draw caches. And - * based on the mode the correct one will be updated. Other option is to look into using - * drw_batch_cache_generate_requested_delayed. */ - BLI_task_graph_work_and_wait(task_graph); -#ifdef DEBUG - drw_mesh_batch_cache_check_available(task_graph, me); -#endif -} - -/** \} */ diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.cc b/source/blender/draw/intern/draw_cache_impl_mesh.cc new file mode 100644 index 00000000000..1f83e0e3fce --- /dev/null +++ b/source/blender/draw/intern/draw_cache_impl_mesh.cc @@ -0,0 +1,2116 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2017 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup draw + * + * \brief Mesh API for render engines + */ + +#include + +#include "MEM_guardedalloc.h" + +#include "BLI_bitmap.h" +#include "BLI_buffer.h" +#include "BLI_edgehash.h" +#include "BLI_index_range.hh" +#include "BLI_listbase.h" +#include "BLI_map.hh" +#include "BLI_math_bits.h" +#include "BLI_math_vector.h" +#include "BLI_span.hh" +#include "BLI_string.h" +#include "BLI_task.h" +#include "BLI_utildefines.h" + +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" + +#include "BKE_attribute.h" +#include "BKE_customdata.h" +#include "BKE_deform.h" +#include "BKE_editmesh.h" +#include "BKE_editmesh_cache.h" +#include "BKE_editmesh_tangent.h" +#include "BKE_mesh.h" +#include "BKE_mesh_runtime.h" +#include "BKE_mesh_tangent.h" +#include "BKE_modifier.h" +#include "BKE_object_deform.h" +#include "BKE_paint.h" +#include "BKE_pbvh.h" +#include "BKE_subdiv_modifier.h" + +#include "atomic_ops.h" + +#include "bmesh.h" + +#include "GPU_batch.h" +#include "GPU_material.h" + +#include "DRW_render.h" + +#include "ED_mesh.h" +#include "ED_uvedit.h" + +#include "draw_cache_extract.hh" +#include "draw_cache_inline.h" +#include "draw_subdivision.h" + +#include "draw_cache_impl.h" /* own include */ + +#include "mesh_extractors/extract_mesh.hh" + +using blender::IndexRange; +using blender::Map; +using blender::Span; + +/* ---------------------------------------------------------------------- */ +/** \name Dependencies between buffer and batch + * \{ */ + +/* clang-format off */ + +#define BUFFER_INDEX(buff_name) ((offsetof(MeshBufferList, buff_name) - offsetof(MeshBufferList, vbo)) / sizeof(void *)) +#define BUFFER_LEN (sizeof(MeshBufferList) / sizeof(void *)) + +#define _BATCH_MAP1(a) batches_that_use_buffer(BUFFER_INDEX(a)) +#define _BATCH_MAP2(a, b) _BATCH_MAP1(a) | _BATCH_MAP1(b) +#define _BATCH_MAP3(a, b, c) _BATCH_MAP2(a, b) | _BATCH_MAP1(c) +#define _BATCH_MAP4(a, b, c, d) _BATCH_MAP3(a, b, c) | _BATCH_MAP1(d) +#define _BATCH_MAP5(a, b, c, d, e) _BATCH_MAP4(a, b, c, d) | _BATCH_MAP1(e) +#define _BATCH_MAP6(a, b, c, d, e, f) _BATCH_MAP5(a, b, c, d, e) | _BATCH_MAP1(f) +#define _BATCH_MAP7(a, b, c, d, e, f, g) _BATCH_MAP6(a, b, c, d, e, f) | _BATCH_MAP1(g) +#define _BATCH_MAP8(a, b, c, d, e, f, g, h) _BATCH_MAP7(a, b, c, d, e, f, g) | _BATCH_MAP1(h) +#define _BATCH_MAP9(a, b, c, d, e, f, g, h, i) _BATCH_MAP8(a, b, c, d, e, f, g, h) | _BATCH_MAP1(i) +#define _BATCH_MAP10(a, b, c, d, e, f, g, h, i, j) _BATCH_MAP9(a, b, c, d, e, f, g, h, i) | _BATCH_MAP1(j) + +#define BATCH_MAP(...) VA_NARGS_CALL_OVERLOAD(_BATCH_MAP, __VA_ARGS__) + +/* clang-format on */ + +#define TRIS_PER_MAT_INDEX BUFFER_LEN + +static constexpr DRWBatchFlag batches_that_use_buffer(const int buffer_index) +{ + switch (buffer_index) { + case BUFFER_INDEX(vbo.pos_nor): + return MBC_SURFACE | MBC_SURFACE_WEIGHTS | MBC_EDIT_TRIANGLES | MBC_EDIT_VERTICES | + MBC_EDIT_EDGES | MBC_EDIT_VNOR | MBC_EDIT_LNOR | MBC_EDIT_MESH_ANALYSIS | + MBC_EDIT_SELECTION_VERTS | MBC_EDIT_SELECTION_EDGES | MBC_EDIT_SELECTION_FACES | + MBC_ALL_VERTS | MBC_ALL_EDGES | MBC_LOOSE_EDGES | MBC_EDGE_DETECTION | + MBC_WIRE_EDGES | MBC_WIRE_LOOPS | MBC_SCULPT_OVERLAYS | MBC_SURFACE_PER_MAT; + case BUFFER_INDEX(vbo.lnor): + return MBC_SURFACE | MBC_EDIT_LNOR | MBC_WIRE_LOOPS | MBC_SURFACE_PER_MAT; + case BUFFER_INDEX(vbo.edge_fac): + return MBC_WIRE_EDGES; + case BUFFER_INDEX(vbo.weights): + return MBC_SURFACE_WEIGHTS; + case BUFFER_INDEX(vbo.uv): + return MBC_SURFACE | MBC_EDITUV_FACES_STRETCH_AREA | MBC_EDITUV_FACES_STRETCH_ANGLE | + MBC_EDITUV_FACES | MBC_EDITUV_EDGES | MBC_EDITUV_VERTS | MBC_WIRE_LOOPS_UVS | + MBC_SURFACE_PER_MAT; + case BUFFER_INDEX(vbo.tan): + return MBC_SURFACE_PER_MAT; + case BUFFER_INDEX(vbo.vcol): + return MBC_SURFACE | MBC_SURFACE_PER_MAT; + case BUFFER_INDEX(vbo.sculpt_data): + return MBC_SCULPT_OVERLAYS; + case BUFFER_INDEX(vbo.orco): + return MBC_SURFACE_PER_MAT; + case BUFFER_INDEX(vbo.edit_data): + return MBC_EDIT_TRIANGLES | MBC_EDIT_EDGES | MBC_EDIT_VERTICES; + case BUFFER_INDEX(vbo.edituv_data): + return MBC_EDITUV_FACES | MBC_EDITUV_FACES_STRETCH_AREA | MBC_EDITUV_FACES_STRETCH_ANGLE | + MBC_EDITUV_EDGES | MBC_EDITUV_VERTS; + case BUFFER_INDEX(vbo.edituv_stretch_area): + return MBC_EDITUV_FACES_STRETCH_AREA; + case BUFFER_INDEX(vbo.edituv_stretch_angle): + return MBC_EDITUV_FACES_STRETCH_ANGLE; + case BUFFER_INDEX(vbo.mesh_analysis): + return MBC_EDIT_MESH_ANALYSIS; + case BUFFER_INDEX(vbo.fdots_pos): + return MBC_EDIT_FACEDOTS | MBC_EDIT_SELECTION_FACEDOTS; + case BUFFER_INDEX(vbo.fdots_nor): + return MBC_EDIT_FACEDOTS; + case BUFFER_INDEX(vbo.fdots_uv): + return MBC_EDITUV_FACEDOTS; + case BUFFER_INDEX(vbo.fdots_edituv_data): + return MBC_EDITUV_FACEDOTS; + case BUFFER_INDEX(vbo.skin_roots): + return MBC_SKIN_ROOTS; + case BUFFER_INDEX(vbo.vert_idx): + return MBC_EDIT_SELECTION_VERTS; + case BUFFER_INDEX(vbo.edge_idx): + return MBC_EDIT_SELECTION_EDGES; + case BUFFER_INDEX(vbo.poly_idx): + return MBC_EDIT_SELECTION_FACES; + case BUFFER_INDEX(vbo.fdot_idx): + return MBC_EDIT_SELECTION_FACEDOTS; + case BUFFER_INDEX(vbo.attr[0]): + case BUFFER_INDEX(vbo.attr[1]): + case BUFFER_INDEX(vbo.attr[2]): + case BUFFER_INDEX(vbo.attr[3]): + case BUFFER_INDEX(vbo.attr[4]): + case BUFFER_INDEX(vbo.attr[5]): + case BUFFER_INDEX(vbo.attr[6]): + case BUFFER_INDEX(vbo.attr[7]): + case BUFFER_INDEX(vbo.attr[8]): + case BUFFER_INDEX(vbo.attr[9]): + case BUFFER_INDEX(vbo.attr[10]): + case BUFFER_INDEX(vbo.attr[11]): + case BUFFER_INDEX(vbo.attr[12]): + case BUFFER_INDEX(vbo.attr[13]): + case BUFFER_INDEX(vbo.attr[14]): + return MBC_SURFACE | MBC_SURFACE_PER_MAT; + case BUFFER_INDEX(ibo.tris): + return MBC_SURFACE | MBC_SURFACE_WEIGHTS | MBC_EDIT_TRIANGLES | MBC_EDIT_LNOR | + MBC_EDIT_MESH_ANALYSIS | MBC_EDIT_SELECTION_FACES | MBC_SCULPT_OVERLAYS; + case BUFFER_INDEX(ibo.lines): + return MBC_EDIT_EDGES | MBC_EDIT_SELECTION_EDGES | MBC_ALL_EDGES | MBC_WIRE_EDGES; + case BUFFER_INDEX(ibo.lines_loose): + return MBC_LOOSE_EDGES; + case BUFFER_INDEX(ibo.points): + return MBC_EDIT_VNOR | MBC_EDIT_VERTICES | MBC_EDIT_SELECTION_VERTS; + case BUFFER_INDEX(ibo.fdots): + return MBC_EDIT_FACEDOTS | MBC_EDIT_SELECTION_FACEDOTS; + case BUFFER_INDEX(ibo.lines_paint_mask): + return MBC_WIRE_LOOPS; + case BUFFER_INDEX(ibo.lines_adjacency): + return MBC_EDGE_DETECTION; + case BUFFER_INDEX(ibo.edituv_tris): + return MBC_EDITUV_FACES | MBC_EDITUV_FACES_STRETCH_AREA | MBC_EDITUV_FACES_STRETCH_ANGLE; + case BUFFER_INDEX(ibo.edituv_lines): + return MBC_EDITUV_EDGES | MBC_WIRE_LOOPS_UVS; + case BUFFER_INDEX(ibo.edituv_points): + return MBC_EDITUV_VERTS; + case BUFFER_INDEX(ibo.edituv_fdots): + return MBC_EDITUV_FACEDOTS; + case TRIS_PER_MAT_INDEX: + return MBC_SURFACE_PER_MAT; + } + return (DRWBatchFlag)0; +} + +static void mesh_batch_cache_discard_surface_batches(MeshBatchCache *cache); +static void mesh_batch_cache_clear(Mesh *me); + +static void mesh_batch_cache_discard_batch(MeshBatchCache *cache, const DRWBatchFlag batch_map) +{ + for (int i = 0; i < MBC_BATCH_LEN; i++) { + DRWBatchFlag batch_requested = (DRWBatchFlag)(1u << i); + if (batch_map & batch_requested) { + GPU_BATCH_DISCARD_SAFE(((GPUBatch **)&cache->batch)[i]); + cache->batch_ready &= ~batch_requested; + } + } + + if (batch_map & MBC_SURFACE_PER_MAT) { + mesh_batch_cache_discard_surface_batches(cache); + } +} + +/* Return true is all layers in _b_ are inside _a_. */ +BLI_INLINE bool mesh_cd_layers_type_overlap(DRW_MeshCDMask a, DRW_MeshCDMask b) +{ + return (*((uint32_t *)&a) & *((uint32_t *)&b)) == *((uint32_t *)&b); +} + +BLI_INLINE bool mesh_cd_layers_type_equal(DRW_MeshCDMask a, DRW_MeshCDMask b) +{ + return *((uint32_t *)&a) == *((uint32_t *)&b); +} + +BLI_INLINE void mesh_cd_layers_type_merge(DRW_MeshCDMask *a, DRW_MeshCDMask b) +{ + uint32_t *a_p = (uint32_t *)a; + uint32_t *b_p = (uint32_t *)&b; + atomic_fetch_and_or_uint32(a_p, *b_p); +} + +BLI_INLINE void mesh_cd_layers_type_clear(DRW_MeshCDMask *a) +{ + *((uint32_t *)a) = 0; +} + +BLI_INLINE const Mesh *editmesh_final_or_this(const Object *object, const Mesh *me) +{ + if (me->edit_mesh != NULL) { + Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(object); + if (editmesh_eval_final != NULL) { + return editmesh_eval_final; + } + } + + return me; +} + +static void mesh_cd_calc_edit_uv_layer(const Mesh *UNUSED(me), DRW_MeshCDMask *cd_used) +{ + cd_used->edit_uv = 1; +} + +BLI_INLINE const CustomData *mesh_cd_ldata_get_from_mesh(const Mesh *me) +{ + switch ((eMeshWrapperType)me->runtime.wrapper_type) { + case ME_WRAPPER_TYPE_SUBD: + case ME_WRAPPER_TYPE_MDATA: + return &me->ldata; + break; + case ME_WRAPPER_TYPE_BMESH: + return &me->edit_mesh->bm->ldata; + break; + } + + BLI_assert(0); + return &me->ldata; +} + +BLI_INLINE const CustomData *mesh_cd_pdata_get_from_mesh(const Mesh *me) +{ + switch ((eMeshWrapperType)me->runtime.wrapper_type) { + case ME_WRAPPER_TYPE_SUBD: + case ME_WRAPPER_TYPE_MDATA: + return &me->pdata; + break; + case ME_WRAPPER_TYPE_BMESH: + return &me->edit_mesh->bm->pdata; + break; + } + + BLI_assert(0); + return &me->pdata; +} + +BLI_INLINE const CustomData *mesh_cd_edata_get_from_mesh(const Mesh *me) +{ + switch ((eMeshWrapperType)me->runtime.wrapper_type) { + case ME_WRAPPER_TYPE_SUBD: + case ME_WRAPPER_TYPE_MDATA: + return &me->edata; + break; + case ME_WRAPPER_TYPE_BMESH: + return &me->edit_mesh->bm->edata; + break; + } + + BLI_assert(0); + return &me->edata; +} + +BLI_INLINE const CustomData *mesh_cd_vdata_get_from_mesh(const Mesh *me) +{ + switch ((eMeshWrapperType)me->runtime.wrapper_type) { + case ME_WRAPPER_TYPE_SUBD: + case ME_WRAPPER_TYPE_MDATA: + return &me->vdata; + break; + case ME_WRAPPER_TYPE_BMESH: + return &me->edit_mesh->bm->vdata; + break; + } + + BLI_assert(0); + return &me->vdata; +} + +static void mesh_cd_calc_active_uv_layer(const Object *object, + const Mesh *me, + DRW_MeshCDMask *cd_used) +{ + const Mesh *me_final = editmesh_final_or_this(object, me); + const CustomData *cd_ldata = mesh_cd_ldata_get_from_mesh(me_final); + int layer = CustomData_get_active_layer(cd_ldata, CD_MLOOPUV); + if (layer != -1) { + cd_used->uv |= (1 << layer); + } +} + +static void mesh_cd_calc_active_mask_uv_layer(const Object *object, + const Mesh *me, + DRW_MeshCDMask *cd_used) +{ + const Mesh *me_final = editmesh_final_or_this(object, me); + const CustomData *cd_ldata = mesh_cd_ldata_get_from_mesh(me_final); + int layer = CustomData_get_stencil_layer(cd_ldata, CD_MLOOPUV); + if (layer != -1) { + cd_used->uv |= (1 << layer); + } +} + +static void mesh_cd_calc_active_mloopcol_layer(const Object *object, + const Mesh *me, + DRW_MeshCDMask *cd_used) +{ + const Mesh *me_final = editmesh_final_or_this(object, me); + Mesh me_query = blender::dna::shallow_zero_initialize(); + + const CustomData *cd_vdata = mesh_cd_vdata_get_from_mesh(me_final); + const CustomData *cd_ldata = mesh_cd_ldata_get_from_mesh(me_final); + + BKE_id_attribute_copy_domains_temp(ID_ME, cd_vdata, NULL, cd_ldata, NULL, NULL, &me_query.id); + + CustomDataLayer *layer = BKE_id_attributes_active_color_get(&me_query.id); + int layer_i = BKE_id_attribute_to_index( + &me_query.id, layer, ATTR_DOMAIN_MASK_COLOR, CD_MASK_COLOR_ALL); + + if (layer_i != -1) { + cd_used->vcol |= (1UL << (uint)layer_i); + } +} + +static uint mesh_cd_calc_gpu_layers_vcol_used(const Mesh *me_query, + const CustomData *cd_vdata, + const CustomData *cd_ldata, + const char name[]) +{ + CustomDataLayer *layer = NULL; + eAttrDomain domain; + + if (name[0]) { + int layer_i = 0; + + domain = ATTR_DOMAIN_POINT; + layer_i = CustomData_get_named_layer_index(cd_vdata, CD_PROP_COLOR, name); + layer_i = layer_i == -1 ? + CustomData_get_named_layer_index(cd_vdata, CD_PROP_BYTE_COLOR, name) : + layer_i; + + if (layer_i == -1) { + domain = ATTR_DOMAIN_CORNER; + layer_i = layer_i == -1 ? CustomData_get_named_layer_index(cd_ldata, CD_PROP_COLOR, name) : + layer_i; + layer_i = layer_i == -1 ? + CustomData_get_named_layer_index(cd_ldata, CD_PROP_BYTE_COLOR, name) : + layer_i; + } + + /* NOTE: this is not the same as the layer_i below. */ + if (layer_i != -1) { + layer = (domain == ATTR_DOMAIN_POINT ? cd_vdata : cd_ldata)->layers + layer_i; + } + } + else { + layer = BKE_id_attributes_render_color_get(&me_query->id); + } + + if (!layer) { + return -1; + } + + /* NOTE: this is the logical index into the color attribute list, + * not the customdata index. */ + int vcol_i = BKE_id_attribute_to_index( + (ID *)me_query, layer, ATTR_DOMAIN_MASK_COLOR, CD_MASK_COLOR_ALL); + + return vcol_i; +} + +static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Object *object, + const Mesh *me, + struct GPUMaterial **gpumat_array, + int gpumat_array_len, + DRW_Attributes *attributes) +{ + const Mesh *me_final = editmesh_final_or_this(object, me); + const CustomData *cd_ldata = mesh_cd_ldata_get_from_mesh(me_final); + const CustomData *cd_pdata = mesh_cd_pdata_get_from_mesh(me_final); + const CustomData *cd_vdata = mesh_cd_vdata_get_from_mesh(me_final); + const CustomData *cd_edata = mesh_cd_edata_get_from_mesh(me_final); + + /* Create a mesh with final customdata domains + * we can query with attribute API. */ + Mesh me_query = blender::dna::shallow_zero_initialize(); + + BKE_id_attribute_copy_domains_temp( + ID_ME, cd_vdata, cd_edata, cd_ldata, cd_pdata, NULL, &me_query.id); + + /* See: DM_vertex_attributes_from_gpu for similar logic */ + DRW_MeshCDMask cd_used; + mesh_cd_layers_type_clear(&cd_used); + + for (int i = 0; i < gpumat_array_len; i++) { + GPUMaterial *gpumat = gpumat_array[i]; + if (gpumat) { + ListBase gpu_attrs = GPU_material_attributes(gpumat); + LISTBASE_FOREACH (GPUMaterialAttribute *, gpu_attr, &gpu_attrs) { + const char *name = gpu_attr->name; + eCustomDataType type = static_cast(gpu_attr->type); + int layer = -1; + std::optional domain; + + if (type == CD_AUTO_FROM_NAME) { + /* We need to deduce what exact layer is used. + * + * We do it based on the specified name. + */ + if (name[0] != '\0') { + layer = CustomData_get_named_layer(cd_ldata, CD_MLOOPUV, name); + type = CD_MTFACE; + + if (layer == -1) { + layer = CustomData_get_named_layer(cd_vdata, CD_PROP_COLOR, name); + if (layer != -1) { + type = CD_PROP_COLOR; + domain = ATTR_DOMAIN_POINT; + } + } + + if (layer == -1) { + layer = CustomData_get_named_layer(cd_ldata, CD_PROP_COLOR, name); + if (layer != -1) { + type = CD_PROP_COLOR; + domain = ATTR_DOMAIN_CORNER; + } + } + + if (layer == -1) { + layer = CustomData_get_named_layer(cd_vdata, CD_PROP_BYTE_COLOR, name); + if (layer != -1) { + type = CD_PROP_BYTE_COLOR; + domain = ATTR_DOMAIN_POINT; + } + } + + if (layer == -1) { + layer = CustomData_get_named_layer(cd_ldata, CD_PROP_BYTE_COLOR, name); + if (layer != -1) { + type = CD_PROP_BYTE_COLOR; + domain = ATTR_DOMAIN_CORNER; + } + } + +#if 0 /* Tangents are always from UV's - this will never happen. */ + if (layer == -1) { + layer = CustomData_get_named_layer(cd_ldata, CD_TANGENT, name); + type = CD_TANGENT; + } +#endif + if (layer == -1) { + /* Try to match a generic attribute, we use the first attribute domain with a + * matching name. */ + if (drw_custom_data_match_attribute(cd_vdata, name, &layer, &type)) { + domain = ATTR_DOMAIN_POINT; + } + else if (drw_custom_data_match_attribute(cd_ldata, name, &layer, &type)) { + domain = ATTR_DOMAIN_CORNER; + } + else if (drw_custom_data_match_attribute(cd_pdata, name, &layer, &type)) { + domain = ATTR_DOMAIN_FACE; + } + else if (drw_custom_data_match_attribute(cd_edata, name, &layer, &type)) { + domain = ATTR_DOMAIN_EDGE; + } + else { + layer = -1; + } + } + + if (layer == -1) { + continue; + } + } + else { + /* Fall back to the UV layer, which matches old behavior. */ + type = CD_MTFACE; + } + } + + switch (type) { + case CD_MTFACE: { + if (layer == -1) { + layer = (name[0] != '\0') ? CustomData_get_named_layer(cd_ldata, CD_MLOOPUV, name) : + CustomData_get_render_layer(cd_ldata, CD_MLOOPUV); + } + if (layer != -1) { + cd_used.uv |= (1 << layer); + } + break; + } + case CD_TANGENT: { + if (layer == -1) { + layer = (name[0] != '\0') ? CustomData_get_named_layer(cd_ldata, CD_MLOOPUV, name) : + CustomData_get_render_layer(cd_ldata, CD_MLOOPUV); + + /* Only fallback to orco (below) when we have no UV layers, see: T56545 */ + if (layer == -1 && name[0] != '\0') { + layer = CustomData_get_render_layer(cd_ldata, CD_MLOOPUV); + } + } + if (layer != -1) { + cd_used.tan |= (1 << layer); + } + else { + /* no UV layers at all => requesting orco */ + cd_used.tan_orco = 1; + cd_used.orco = 1; + } + break; + } + + case CD_ORCO: { + cd_used.orco = 1; + break; + } + + /* NOTE: attr->type will always be CD_PROP_COLOR even for + * CD_PROP_BYTE_COLOR layers, see node_shader_gpu_vertex_color in + * node_shader_vertex_color.cc. + */ + case CD_MCOL: + case CD_PROP_BYTE_COLOR: + case CD_PROP_COLOR: { + /* First check Color attributes, when not found check mesh attributes. Geometry nodes + * can generate those layers. */ + int vcol_bit = mesh_cd_calc_gpu_layers_vcol_used(&me_query, cd_vdata, cd_ldata, name); + + if (vcol_bit != -1) { + cd_used.vcol |= 1UL << (uint)vcol_bit; + break; + } + + if (layer != -1 && domain.has_value()) { + drw_attributes_add_request(attributes, type, layer, *domain); + } + break; + } + case CD_PROP_FLOAT3: + case CD_PROP_BOOL: + case CD_PROP_INT8: + case CD_PROP_INT32: + case CD_PROP_FLOAT: + case CD_PROP_FLOAT2: { + if (layer != -1 && domain.has_value()) { + drw_attributes_add_request(attributes, type, layer, *domain); + } + break; + } + default: + break; + } + } + } + } + return cd_used; +} + +/** \} */ + +/* ---------------------------------------------------------------------- */ +/** \name Vertex Group Selection + * \{ */ + +/** Reset the selection structure, deallocating heap memory as appropriate. */ +static void drw_mesh_weight_state_clear(struct DRW_MeshWeightState *wstate) +{ + MEM_SAFE_FREE(wstate->defgroup_sel); + MEM_SAFE_FREE(wstate->defgroup_locked); + MEM_SAFE_FREE(wstate->defgroup_unlocked); + + memset(wstate, 0, sizeof(*wstate)); + + wstate->defgroup_active = -1; +} + +/** Copy selection data from one structure to another, including heap memory. */ +static void drw_mesh_weight_state_copy(struct DRW_MeshWeightState *wstate_dst, + const struct DRW_MeshWeightState *wstate_src) +{ + MEM_SAFE_FREE(wstate_dst->defgroup_sel); + MEM_SAFE_FREE(wstate_dst->defgroup_locked); + MEM_SAFE_FREE(wstate_dst->defgroup_unlocked); + + memcpy(wstate_dst, wstate_src, sizeof(*wstate_dst)); + + if (wstate_src->defgroup_sel) { + wstate_dst->defgroup_sel = static_cast(MEM_dupallocN(wstate_src->defgroup_sel)); + } + if (wstate_src->defgroup_locked) { + wstate_dst->defgroup_locked = static_cast(MEM_dupallocN(wstate_src->defgroup_locked)); + } + if (wstate_src->defgroup_unlocked) { + wstate_dst->defgroup_unlocked = static_cast( + MEM_dupallocN(wstate_src->defgroup_unlocked)); + } +} + +static bool drw_mesh_flags_equal(const bool *array1, const bool *array2, int size) +{ + return ((!array1 && !array2) || + (array1 && array2 && memcmp(array1, array2, size * sizeof(bool)) == 0)); +} + +/** Compare two selection structures. */ +static bool drw_mesh_weight_state_compare(const struct DRW_MeshWeightState *a, + const struct DRW_MeshWeightState *b) +{ + return a->defgroup_active == b->defgroup_active && a->defgroup_len == b->defgroup_len && + a->flags == b->flags && a->alert_mode == b->alert_mode && + a->defgroup_sel_count == b->defgroup_sel_count && + drw_mesh_flags_equal(a->defgroup_sel, b->defgroup_sel, a->defgroup_len) && + drw_mesh_flags_equal(a->defgroup_locked, b->defgroup_locked, a->defgroup_len) && + drw_mesh_flags_equal(a->defgroup_unlocked, b->defgroup_unlocked, a->defgroup_len); +} + +static void drw_mesh_weight_state_extract(Object *ob, + Mesh *me, + const ToolSettings *ts, + bool paint_mode, + struct DRW_MeshWeightState *wstate) +{ + /* Extract complete vertex weight group selection state and mode flags. */ + memset(wstate, 0, sizeof(*wstate)); + + wstate->defgroup_active = me->vertex_group_active_index - 1; + wstate->defgroup_len = BLI_listbase_count(&me->vertex_group_names); + + wstate->alert_mode = ts->weightuser; + + if (paint_mode && ts->multipaint) { + /* Multi-paint needs to know all selected bones, not just the active group. + * This is actually a relatively expensive operation, but caching would be difficult. */ + wstate->defgroup_sel = BKE_object_defgroup_selected_get( + ob, wstate->defgroup_len, &wstate->defgroup_sel_count); + + if (wstate->defgroup_sel_count > 1) { + wstate->flags |= DRW_MESH_WEIGHT_STATE_MULTIPAINT | + (ts->auto_normalize ? DRW_MESH_WEIGHT_STATE_AUTO_NORMALIZE : 0); + + if (ME_USING_MIRROR_X_VERTEX_GROUPS(me)) { + BKE_object_defgroup_mirror_selection(ob, + wstate->defgroup_len, + wstate->defgroup_sel, + wstate->defgroup_sel, + &wstate->defgroup_sel_count); + } + } + /* With only one selected bone Multi-paint reverts to regular mode. */ + else { + wstate->defgroup_sel_count = 0; + MEM_SAFE_FREE(wstate->defgroup_sel); + } + } + + if (paint_mode && ts->wpaint_lock_relative) { + /* Set of locked vertex groups for the lock relative mode. */ + wstate->defgroup_locked = BKE_object_defgroup_lock_flags_get(ob, wstate->defgroup_len); + wstate->defgroup_unlocked = BKE_object_defgroup_validmap_get(ob, wstate->defgroup_len); + + /* Check that a deform group is active, and none of selected groups are locked. */ + if (BKE_object_defgroup_check_lock_relative( + wstate->defgroup_locked, wstate->defgroup_unlocked, wstate->defgroup_active) && + BKE_object_defgroup_check_lock_relative_multi(wstate->defgroup_len, + wstate->defgroup_locked, + wstate->defgroup_sel, + wstate->defgroup_sel_count)) { + wstate->flags |= DRW_MESH_WEIGHT_STATE_LOCK_RELATIVE; + + /* Compute the set of locked and unlocked deform vertex groups. */ + BKE_object_defgroup_split_locked_validmap(wstate->defgroup_len, + wstate->defgroup_locked, + wstate->defgroup_unlocked, + wstate->defgroup_locked, /* out */ + wstate->defgroup_unlocked); + } + else { + MEM_SAFE_FREE(wstate->defgroup_unlocked); + MEM_SAFE_FREE(wstate->defgroup_locked); + } + } +} + +/** \} */ + +/* ---------------------------------------------------------------------- */ +/** \name Mesh GPUBatch Cache + * \{ */ + +BLI_INLINE void mesh_batch_cache_add_request(MeshBatchCache *cache, DRWBatchFlag new_flag) +{ + atomic_fetch_and_or_uint32((uint32_t *)(&cache->batch_requested), *(uint32_t *)&new_flag); +} + +/* GPUBatch cache management. */ + +static bool mesh_batch_cache_valid(Object *object, Mesh *me) +{ + MeshBatchCache *cache = static_cast(me->runtime.batch_cache); + + if (cache == NULL) { + return false; + } + + if (object->sculpt && object->sculpt->pbvh) { + if (cache->pbvh_is_drawing != BKE_pbvh_is_drawing(object->sculpt->pbvh)) { + return false; + } + + if (BKE_pbvh_is_drawing(object->sculpt->pbvh) && + BKE_pbvh_draw_cache_invalid(object->sculpt->pbvh)) { + return false; + } + } + + if (cache->is_editmode != (me->edit_mesh != NULL)) { + return false; + } + + if (cache->is_dirty) { + return false; + } + + if (cache->mat_len != mesh_render_mat_len_get(object, me)) { + return false; + } + + return true; +} + +static void mesh_batch_cache_init(Object *object, Mesh *me) +{ + MeshBatchCache *cache = static_cast(me->runtime.batch_cache); + + if (!cache) { + me->runtime.batch_cache = MEM_cnew(__func__); + cache = static_cast(me->runtime.batch_cache); + } + else { + memset(cache, 0, sizeof(*cache)); + } + + cache->is_editmode = me->edit_mesh != NULL; + + if (object->sculpt && object->sculpt->pbvh) { + cache->pbvh_is_drawing = BKE_pbvh_is_drawing(object->sculpt->pbvh); + } + + if (cache->is_editmode == false) { + // cache->edge_len = mesh_render_edges_len_get(me); + // cache->tri_len = mesh_render_looptri_len_get(me); + // cache->poly_len = mesh_render_polys_len_get(me); + // cache->vert_len = mesh_render_verts_len_get(me); + } + + cache->mat_len = mesh_render_mat_len_get(object, me); + cache->surface_per_mat = static_cast( + MEM_callocN(sizeof(*cache->surface_per_mat) * cache->mat_len, __func__)); + cache->tris_per_mat = static_cast( + MEM_callocN(sizeof(*cache->tris_per_mat) * cache->mat_len, __func__)); + + cache->is_dirty = false; + cache->batch_ready = (DRWBatchFlag)0; + cache->batch_requested = (DRWBatchFlag)0; + + drw_mesh_weight_state_clear(&cache->weight_state); +} + +void DRW_mesh_batch_cache_validate(Object *object, Mesh *me) +{ + if (!mesh_batch_cache_valid(object, me)) { + mesh_batch_cache_clear(me); + mesh_batch_cache_init(object, me); + } +} + +static MeshBatchCache *mesh_batch_cache_get(Mesh *me) +{ + return static_cast(me->runtime.batch_cache); +} + +static void mesh_batch_cache_check_vertex_group(MeshBatchCache *cache, + const struct DRW_MeshWeightState *wstate) +{ + if (!drw_mesh_weight_state_compare(&cache->weight_state, wstate)) { + FOREACH_MESH_BUFFER_CACHE (cache, mbc) { + GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.weights); + } + GPU_BATCH_CLEAR_SAFE(cache->batch.surface_weights); + + cache->batch_ready &= ~MBC_SURFACE_WEIGHTS; + + drw_mesh_weight_state_clear(&cache->weight_state); + } +} + +static void mesh_batch_cache_request_surface_batches(MeshBatchCache *cache) +{ + mesh_batch_cache_add_request(cache, MBC_SURFACE); + DRW_batch_request(&cache->batch.surface); + for (int i = 0; i < cache->mat_len; i++) { + DRW_batch_request(&cache->surface_per_mat[i]); + } +} + +/* Free batches with material-mapped looptris. + * NOTE: The updating of the indices buffers (#tris_per_mat) is handled in the extractors. + * No need to discard they here. */ +static void mesh_batch_cache_discard_surface_batches(MeshBatchCache *cache) +{ + GPU_BATCH_DISCARD_SAFE(cache->batch.surface); + for (int i = 0; i < cache->mat_len; i++) { + GPU_BATCH_DISCARD_SAFE(cache->surface_per_mat[i]); + } + cache->batch_ready &= ~MBC_SURFACE; +} + +static void mesh_batch_cache_discard_shaded_tri(MeshBatchCache *cache) +{ + FOREACH_MESH_BUFFER_CACHE (cache, mbc) { + GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.uv); + GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.tan); + GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.vcol); + GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.orco); + } + DRWBatchFlag batch_map = BATCH_MAP(vbo.uv, vbo.tan, vbo.vcol, vbo.orco); + mesh_batch_cache_discard_batch(cache, batch_map); + mesh_cd_layers_type_clear(&cache->cd_used); +} + +static void mesh_batch_cache_discard_uvedit(MeshBatchCache *cache) +{ + FOREACH_MESH_BUFFER_CACHE (cache, mbc) { + GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.edituv_stretch_angle); + GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.edituv_stretch_area); + GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.uv); + GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.edituv_data); + GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.fdots_uv); + GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.fdots_edituv_data); + GPU_INDEXBUF_DISCARD_SAFE(mbc->buff.ibo.edituv_tris); + GPU_INDEXBUF_DISCARD_SAFE(mbc->buff.ibo.edituv_lines); + GPU_INDEXBUF_DISCARD_SAFE(mbc->buff.ibo.edituv_points); + GPU_INDEXBUF_DISCARD_SAFE(mbc->buff.ibo.edituv_fdots); + } + DRWBatchFlag batch_map = BATCH_MAP(vbo.edituv_stretch_angle, + vbo.edituv_stretch_area, + vbo.uv, + vbo.edituv_data, + vbo.fdots_uv, + vbo.fdots_edituv_data, + ibo.edituv_tris, + ibo.edituv_lines, + ibo.edituv_points, + ibo.edituv_fdots); + mesh_batch_cache_discard_batch(cache, batch_map); + + cache->tot_area = 0.0f; + cache->tot_uv_area = 0.0f; + + cache->batch_ready &= ~MBC_EDITUV; + + /* We discarded the vbo.uv so we need to reset the cd_used flag. */ + cache->cd_used.uv = 0; + cache->cd_used.edit_uv = 0; +} + +static void mesh_batch_cache_discard_uvedit_select(MeshBatchCache *cache) +{ + FOREACH_MESH_BUFFER_CACHE (cache, mbc) { + GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.edituv_data); + GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.fdots_edituv_data); + GPU_INDEXBUF_DISCARD_SAFE(mbc->buff.ibo.edituv_tris); + GPU_INDEXBUF_DISCARD_SAFE(mbc->buff.ibo.edituv_lines); + GPU_INDEXBUF_DISCARD_SAFE(mbc->buff.ibo.edituv_points); + GPU_INDEXBUF_DISCARD_SAFE(mbc->buff.ibo.edituv_fdots); + } + DRWBatchFlag batch_map = BATCH_MAP(vbo.edituv_data, + vbo.fdots_edituv_data, + ibo.edituv_tris, + ibo.edituv_lines, + ibo.edituv_points, + ibo.edituv_fdots); + mesh_batch_cache_discard_batch(cache, batch_map); +} + +void DRW_mesh_batch_cache_dirty_tag(Mesh *me, eMeshBatchDirtyMode mode) +{ + MeshBatchCache *cache = static_cast(me->runtime.batch_cache); + if (cache == NULL) { + return; + } + DRWBatchFlag batch_map; + switch (mode) { + case BKE_MESH_BATCH_DIRTY_SELECT: + FOREACH_MESH_BUFFER_CACHE (cache, mbc) { + GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.edit_data); + GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.fdots_nor); + } + batch_map = BATCH_MAP(vbo.edit_data, vbo.fdots_nor); + mesh_batch_cache_discard_batch(cache, batch_map); + + /* Because visible UVs depends on edit mode selection, discard topology. */ + mesh_batch_cache_discard_uvedit_select(cache); + break; + case BKE_MESH_BATCH_DIRTY_SELECT_PAINT: + /* Paint mode selection flag is packed inside the nor attribute. + * Note that it can be slow if auto smooth is enabled. (see T63946) */ + FOREACH_MESH_BUFFER_CACHE (cache, mbc) { + GPU_INDEXBUF_DISCARD_SAFE(mbc->buff.ibo.lines_paint_mask); + GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.pos_nor); + GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.lnor); + } + batch_map = BATCH_MAP(ibo.lines_paint_mask, vbo.pos_nor, vbo.lnor); + mesh_batch_cache_discard_batch(cache, batch_map); + break; + case BKE_MESH_BATCH_DIRTY_ALL: + cache->is_dirty = true; + break; + case BKE_MESH_BATCH_DIRTY_SHADING: + mesh_batch_cache_discard_shaded_tri(cache); + mesh_batch_cache_discard_uvedit(cache); + break; + case BKE_MESH_BATCH_DIRTY_UVEDIT_ALL: + mesh_batch_cache_discard_uvedit(cache); + break; + case BKE_MESH_BATCH_DIRTY_UVEDIT_SELECT: + FOREACH_MESH_BUFFER_CACHE (cache, mbc) { + GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.edituv_data); + GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.fdots_edituv_data); + } + batch_map = BATCH_MAP(vbo.edituv_data, vbo.fdots_edituv_data); + mesh_batch_cache_discard_batch(cache, batch_map); + break; + default: + BLI_assert(0); + } +} + +static void mesh_buffer_list_clear(MeshBufferList *mbuflist) +{ + GPUVertBuf **vbos = (GPUVertBuf **)&mbuflist->vbo; + GPUIndexBuf **ibos = (GPUIndexBuf **)&mbuflist->ibo; + for (int i = 0; i < sizeof(mbuflist->vbo) / sizeof(void *); i++) { + GPU_VERTBUF_DISCARD_SAFE(vbos[i]); + } + for (int i = 0; i < sizeof(mbuflist->ibo) / sizeof(void *); i++) { + GPU_INDEXBUF_DISCARD_SAFE(ibos[i]); + } +} + +static void mesh_buffer_cache_clear(MeshBufferCache *mbc) +{ + mesh_buffer_list_clear(&mbc->buff); + + MEM_SAFE_FREE(mbc->loose_geom.verts); + MEM_SAFE_FREE(mbc->loose_geom.edges); + mbc->loose_geom.edge_len = 0; + mbc->loose_geom.vert_len = 0; + + MEM_SAFE_FREE(mbc->poly_sorted.tri_first_index); + MEM_SAFE_FREE(mbc->poly_sorted.mat_tri_len); + mbc->poly_sorted.visible_tri_len = 0; +} + +static void mesh_batch_cache_free_subdiv_cache(MeshBatchCache *cache) +{ + if (cache->subdiv_cache) { + draw_subdiv_cache_free(cache->subdiv_cache); + MEM_freeN(cache->subdiv_cache); + cache->subdiv_cache = NULL; + } +} + +static void mesh_batch_cache_clear(Mesh *me) +{ + MeshBatchCache *cache = static_cast(me->runtime.batch_cache); + if (!cache) { + return; + } + FOREACH_MESH_BUFFER_CACHE (cache, mbc) { + mesh_buffer_cache_clear(mbc); + } + + for (int i = 0; i < cache->mat_len; i++) { + GPU_INDEXBUF_DISCARD_SAFE(cache->tris_per_mat[i]); + } + MEM_SAFE_FREE(cache->tris_per_mat); + + for (int i = 0; i < sizeof(cache->batch) / sizeof(void *); i++) { + GPUBatch **batch = (GPUBatch **)&cache->batch; + GPU_BATCH_DISCARD_SAFE(batch[i]); + } + + mesh_batch_cache_discard_shaded_tri(cache); + mesh_batch_cache_discard_uvedit(cache); + MEM_SAFE_FREE(cache->surface_per_mat); + cache->mat_len = 0; + + cache->batch_ready = (DRWBatchFlag)0; + drw_mesh_weight_state_clear(&cache->weight_state); + + mesh_batch_cache_free_subdiv_cache(cache); +} + +void DRW_mesh_batch_cache_free(Mesh *me) +{ + mesh_batch_cache_clear(me); + MEM_SAFE_FREE(me->runtime.batch_cache); +} + +/** \} */ + +/* ---------------------------------------------------------------------- */ +/** \name Public API + * \{ */ + +static void texpaint_request_active_uv(MeshBatchCache *cache, Object *object, Mesh *me) +{ + DRW_MeshCDMask cd_needed; + mesh_cd_layers_type_clear(&cd_needed); + mesh_cd_calc_active_uv_layer(object, me, &cd_needed); + + BLI_assert(cd_needed.uv != 0 && + "No uv layer available in texpaint, but batches requested anyway!"); + + mesh_cd_calc_active_mask_uv_layer(object, me, &cd_needed); + mesh_cd_layers_type_merge(&cache->cd_needed, cd_needed); +} + +static void texpaint_request_active_vcol(MeshBatchCache *cache, Object *object, Mesh *me) +{ + DRW_MeshCDMask cd_needed; + mesh_cd_layers_type_clear(&cd_needed); + mesh_cd_calc_active_mloopcol_layer(object, me, &cd_needed); + + BLI_assert(cd_needed.vcol != 0 && + "No MLOOPCOL layer available in vertpaint, but batches requested anyway!"); + + mesh_cd_layers_type_merge(&cache->cd_needed, cd_needed); +} + +static void sculpt_request_active_vcol(MeshBatchCache *cache, Object *object, Mesh *me) +{ + const Mesh *me_final = editmesh_final_or_this(object, me); + const CustomData *cd_vdata = mesh_cd_vdata_get_from_mesh(me_final); + const CustomData *cd_ldata = mesh_cd_ldata_get_from_mesh(me_final); + + Mesh me_query = blender::dna::shallow_zero_initialize(); + BKE_id_attribute_copy_domains_temp(ID_ME, cd_vdata, NULL, cd_ldata, NULL, NULL, &me_query.id); + + CustomDataLayer *active = BKE_id_attributes_active_color_get(&me_query.id); + CustomDataLayer *render = BKE_id_attributes_render_color_get(&me_query.id); + + int active_i = BKE_id_attribute_to_index( + &me_query.id, active, ATTR_DOMAIN_MASK_COLOR, CD_MASK_COLOR_ALL); + int render_i = BKE_id_attribute_to_index( + &me_query.id, render, ATTR_DOMAIN_MASK_COLOR, CD_MASK_COLOR_ALL); + + if (active_i >= 0) { + cache->cd_needed.vcol |= 1UL << (uint)active_i; + } + + if (render_i >= 0) { + cache->cd_needed.vcol |= 1UL << (uint)render_i; + } +} + +GPUBatch *DRW_mesh_batch_cache_get_all_verts(Mesh *me) +{ + MeshBatchCache *cache = mesh_batch_cache_get(me); + mesh_batch_cache_add_request(cache, MBC_ALL_VERTS); + return DRW_batch_request(&cache->batch.all_verts); +} + +GPUBatch *DRW_mesh_batch_cache_get_all_edges(Mesh *me) +{ + MeshBatchCache *cache = mesh_batch_cache_get(me); + mesh_batch_cache_add_request(cache, MBC_ALL_EDGES); + return DRW_batch_request(&cache->batch.all_edges); +} + +GPUBatch *DRW_mesh_batch_cache_get_surface(Mesh *me) +{ + MeshBatchCache *cache = mesh_batch_cache_get(me); + mesh_batch_cache_request_surface_batches(cache); + + return cache->batch.surface; +} + +GPUBatch *DRW_mesh_batch_cache_get_loose_edges(Mesh *me) +{ + MeshBatchCache *cache = mesh_batch_cache_get(me); + mesh_batch_cache_add_request(cache, MBC_LOOSE_EDGES); + if (cache->no_loose_wire) { + return NULL; + } + + return DRW_batch_request(&cache->batch.loose_edges); +} + +GPUBatch *DRW_mesh_batch_cache_get_surface_weights(Mesh *me) +{ + MeshBatchCache *cache = mesh_batch_cache_get(me); + mesh_batch_cache_add_request(cache, MBC_SURFACE_WEIGHTS); + return DRW_batch_request(&cache->batch.surface_weights); +} + +GPUBatch *DRW_mesh_batch_cache_get_edge_detection(Mesh *me, bool *r_is_manifold) +{ + MeshBatchCache *cache = mesh_batch_cache_get(me); + mesh_batch_cache_add_request(cache, MBC_EDGE_DETECTION); + /* Even if is_manifold is not correct (not updated), + * the default (not manifold) is just the worst case. */ + if (r_is_manifold) { + *r_is_manifold = cache->is_manifold; + } + return DRW_batch_request(&cache->batch.edge_detection); +} + +GPUBatch *DRW_mesh_batch_cache_get_wireframes_face(Mesh *me) +{ + MeshBatchCache *cache = mesh_batch_cache_get(me); + mesh_batch_cache_add_request(cache, MBC_WIRE_EDGES); + return DRW_batch_request(&cache->batch.wire_edges); +} + +GPUBatch *DRW_mesh_batch_cache_get_edit_mesh_analysis(Mesh *me) +{ + MeshBatchCache *cache = mesh_batch_cache_get(me); + mesh_batch_cache_add_request(cache, MBC_EDIT_MESH_ANALYSIS); + return DRW_batch_request(&cache->batch.edit_mesh_analysis); +} + +GPUBatch **DRW_mesh_batch_cache_get_surface_shaded(Object *object, + Mesh *me, + struct GPUMaterial **gpumat_array, + uint gpumat_array_len) +{ + MeshBatchCache *cache = mesh_batch_cache_get(me); + DRW_Attributes attrs_needed; + drw_attributes_clear(&attrs_needed); + DRW_MeshCDMask cd_needed = mesh_cd_calc_used_gpu_layers( + object, me, gpumat_array, gpumat_array_len, &attrs_needed); + + BLI_assert(gpumat_array_len == cache->mat_len); + + mesh_cd_layers_type_merge(&cache->cd_needed, cd_needed); + ThreadMutex *mesh_render_mutex = (ThreadMutex *)me->runtime.render_mutex; + drw_attributes_merge(&cache->attr_needed, &attrs_needed, mesh_render_mutex); + mesh_batch_cache_request_surface_batches(cache); + return cache->surface_per_mat; +} + +GPUBatch **DRW_mesh_batch_cache_get_surface_texpaint(Object *object, Mesh *me) +{ + MeshBatchCache *cache = mesh_batch_cache_get(me); + texpaint_request_active_uv(cache, object, me); + mesh_batch_cache_request_surface_batches(cache); + return cache->surface_per_mat; +} + +GPUBatch *DRW_mesh_batch_cache_get_surface_texpaint_single(Object *object, Mesh *me) +{ + MeshBatchCache *cache = mesh_batch_cache_get(me); + texpaint_request_active_uv(cache, object, me); + mesh_batch_cache_request_surface_batches(cache); + return cache->batch.surface; +} + +GPUBatch *DRW_mesh_batch_cache_get_surface_vertpaint(Object *object, Mesh *me) +{ + MeshBatchCache *cache = mesh_batch_cache_get(me); + texpaint_request_active_vcol(cache, object, me); + mesh_batch_cache_request_surface_batches(cache); + return cache->batch.surface; +} + +GPUBatch *DRW_mesh_batch_cache_get_surface_sculpt(Object *object, Mesh *me) +{ + MeshBatchCache *cache = mesh_batch_cache_get(me); + sculpt_request_active_vcol(cache, object, me); + mesh_batch_cache_request_surface_batches(cache); + return cache->batch.surface; +} + +int DRW_mesh_material_count_get(const Object *object, const Mesh *me) +{ + return mesh_render_mat_len_get(object, me); +} + +GPUBatch *DRW_mesh_batch_cache_get_sculpt_overlays(Mesh *me) +{ + MeshBatchCache *cache = mesh_batch_cache_get(me); + + cache->cd_needed.sculpt_overlays = 1; + mesh_batch_cache_add_request(cache, MBC_SCULPT_OVERLAYS); + DRW_batch_request(&cache->batch.sculpt_overlays); + + return cache->batch.sculpt_overlays; +} + +/** \} */ + +/* ---------------------------------------------------------------------- */ +/** \name Edit Mode API + * \{ */ + +GPUVertBuf *DRW_mesh_batch_cache_pos_vertbuf_get(Mesh *me) +{ + MeshBatchCache *cache = mesh_batch_cache_get(me); + /* Request surface to trigger the vbo filling. Otherwise it may do nothing. */ + mesh_batch_cache_request_surface_batches(cache); + + DRW_vbo_request(NULL, &cache->final.buff.vbo.pos_nor); + return cache->final.buff.vbo.pos_nor; +} + +/** \} */ + +/* ---------------------------------------------------------------------- */ +/** \name Edit Mode API + * \{ */ + +GPUBatch *DRW_mesh_batch_cache_get_edit_triangles(Mesh *me) +{ + MeshBatchCache *cache = mesh_batch_cache_get(me); + mesh_batch_cache_add_request(cache, MBC_EDIT_TRIANGLES); + return DRW_batch_request(&cache->batch.edit_triangles); +} + +GPUBatch *DRW_mesh_batch_cache_get_edit_edges(Mesh *me) +{ + MeshBatchCache *cache = mesh_batch_cache_get(me); + mesh_batch_cache_add_request(cache, MBC_EDIT_EDGES); + return DRW_batch_request(&cache->batch.edit_edges); +} + +GPUBatch *DRW_mesh_batch_cache_get_edit_vertices(Mesh *me) +{ + MeshBatchCache *cache = mesh_batch_cache_get(me); + mesh_batch_cache_add_request(cache, MBC_EDIT_VERTICES); + return DRW_batch_request(&cache->batch.edit_vertices); +} + +GPUBatch *DRW_mesh_batch_cache_get_edit_vnors(Mesh *me) +{ + MeshBatchCache *cache = mesh_batch_cache_get(me); + mesh_batch_cache_add_request(cache, MBC_EDIT_VNOR); + return DRW_batch_request(&cache->batch.edit_vnor); +} + +GPUBatch *DRW_mesh_batch_cache_get_edit_lnors(Mesh *me) +{ + MeshBatchCache *cache = mesh_batch_cache_get(me); + mesh_batch_cache_add_request(cache, MBC_EDIT_LNOR); + return DRW_batch_request(&cache->batch.edit_lnor); +} + +GPUBatch *DRW_mesh_batch_cache_get_edit_facedots(Mesh *me) +{ + MeshBatchCache *cache = mesh_batch_cache_get(me); + mesh_batch_cache_add_request(cache, MBC_EDIT_FACEDOTS); + return DRW_batch_request(&cache->batch.edit_fdots); +} + +GPUBatch *DRW_mesh_batch_cache_get_edit_skin_roots(Mesh *me) +{ + MeshBatchCache *cache = mesh_batch_cache_get(me); + mesh_batch_cache_add_request(cache, MBC_SKIN_ROOTS); + return DRW_batch_request(&cache->batch.edit_skin_roots); +} + +/** \} */ + +/* ---------------------------------------------------------------------- */ +/** \name Edit Mode selection API + * \{ */ + +GPUBatch *DRW_mesh_batch_cache_get_triangles_with_select_id(Mesh *me) +{ + MeshBatchCache *cache = mesh_batch_cache_get(me); + mesh_batch_cache_add_request(cache, MBC_EDIT_SELECTION_FACES); + return DRW_batch_request(&cache->batch.edit_selection_faces); +} + +GPUBatch *DRW_mesh_batch_cache_get_facedots_with_select_id(Mesh *me) +{ + MeshBatchCache *cache = mesh_batch_cache_get(me); + mesh_batch_cache_add_request(cache, MBC_EDIT_SELECTION_FACEDOTS); + return DRW_batch_request(&cache->batch.edit_selection_fdots); +} + +GPUBatch *DRW_mesh_batch_cache_get_edges_with_select_id(Mesh *me) +{ + MeshBatchCache *cache = mesh_batch_cache_get(me); + mesh_batch_cache_add_request(cache, MBC_EDIT_SELECTION_EDGES); + return DRW_batch_request(&cache->batch.edit_selection_edges); +} + +GPUBatch *DRW_mesh_batch_cache_get_verts_with_select_id(Mesh *me) +{ + MeshBatchCache *cache = mesh_batch_cache_get(me); + mesh_batch_cache_add_request(cache, MBC_EDIT_SELECTION_VERTS); + return DRW_batch_request(&cache->batch.edit_selection_verts); +} + +/** \} */ + +/* ---------------------------------------------------------------------- */ +/** \name UV Image editor API + * \{ */ + +static void edituv_request_active_uv(MeshBatchCache *cache, Object *object, Mesh *me) +{ + DRW_MeshCDMask cd_needed; + mesh_cd_layers_type_clear(&cd_needed); + mesh_cd_calc_active_uv_layer(object, me, &cd_needed); + mesh_cd_calc_edit_uv_layer(me, &cd_needed); + + BLI_assert(cd_needed.edit_uv != 0 && + "No uv layer available in edituv, but batches requested anyway!"); + + mesh_cd_calc_active_mask_uv_layer(object, me, &cd_needed); + mesh_cd_layers_type_merge(&cache->cd_needed, cd_needed); +} + +GPUBatch *DRW_mesh_batch_cache_get_edituv_faces_stretch_area(Object *object, + Mesh *me, + float **tot_area, + float **tot_uv_area) +{ + MeshBatchCache *cache = mesh_batch_cache_get(me); + edituv_request_active_uv(cache, object, me); + mesh_batch_cache_add_request(cache, MBC_EDITUV_FACES_STRETCH_AREA); + + if (tot_area != NULL) { + *tot_area = &cache->tot_area; + } + if (tot_uv_area != NULL) { + *tot_uv_area = &cache->tot_uv_area; + } + return DRW_batch_request(&cache->batch.edituv_faces_stretch_area); +} + +GPUBatch *DRW_mesh_batch_cache_get_edituv_faces_stretch_angle(Object *object, Mesh *me) +{ + MeshBatchCache *cache = mesh_batch_cache_get(me); + edituv_request_active_uv(cache, object, me); + mesh_batch_cache_add_request(cache, MBC_EDITUV_FACES_STRETCH_ANGLE); + return DRW_batch_request(&cache->batch.edituv_faces_stretch_angle); +} + +GPUBatch *DRW_mesh_batch_cache_get_edituv_faces(Object *object, Mesh *me) +{ + MeshBatchCache *cache = mesh_batch_cache_get(me); + edituv_request_active_uv(cache, object, me); + mesh_batch_cache_add_request(cache, MBC_EDITUV_FACES); + return DRW_batch_request(&cache->batch.edituv_faces); +} + +GPUBatch *DRW_mesh_batch_cache_get_edituv_edges(Object *object, Mesh *me) +{ + MeshBatchCache *cache = mesh_batch_cache_get(me); + edituv_request_active_uv(cache, object, me); + mesh_batch_cache_add_request(cache, MBC_EDITUV_EDGES); + return DRW_batch_request(&cache->batch.edituv_edges); +} + +GPUBatch *DRW_mesh_batch_cache_get_edituv_verts(Object *object, Mesh *me) +{ + MeshBatchCache *cache = mesh_batch_cache_get(me); + edituv_request_active_uv(cache, object, me); + mesh_batch_cache_add_request(cache, MBC_EDITUV_VERTS); + return DRW_batch_request(&cache->batch.edituv_verts); +} + +GPUBatch *DRW_mesh_batch_cache_get_edituv_facedots(Object *object, Mesh *me) +{ + MeshBatchCache *cache = mesh_batch_cache_get(me); + edituv_request_active_uv(cache, object, me); + mesh_batch_cache_add_request(cache, MBC_EDITUV_FACEDOTS); + return DRW_batch_request(&cache->batch.edituv_fdots); +} + +GPUBatch *DRW_mesh_batch_cache_get_uv_edges(Object *object, Mesh *me) +{ + MeshBatchCache *cache = mesh_batch_cache_get(me); + edituv_request_active_uv(cache, object, me); + mesh_batch_cache_add_request(cache, MBC_WIRE_LOOPS_UVS); + return DRW_batch_request(&cache->batch.wire_loops_uvs); +} + +GPUBatch *DRW_mesh_batch_cache_get_surface_edges(Object *object, Mesh *me) +{ + MeshBatchCache *cache = mesh_batch_cache_get(me); + texpaint_request_active_uv(cache, object, me); + mesh_batch_cache_add_request(cache, MBC_WIRE_LOOPS); + return DRW_batch_request(&cache->batch.wire_loops); +} + +/** \} */ + +/* ---------------------------------------------------------------------- */ +/** \name Grouped batch generation + * \{ */ + +void DRW_mesh_batch_cache_free_old(Mesh *me, int ctime) +{ + MeshBatchCache *cache = static_cast(me->runtime.batch_cache); + + if (cache == NULL) { + return; + } + + if (mesh_cd_layers_type_equal(cache->cd_used_over_time, cache->cd_used)) { + cache->lastmatch = ctime; + } + + if (drw_attributes_overlap(&cache->attr_used_over_time, &cache->attr_used)) { + cache->lastmatch = ctime; + } + + if (ctime - cache->lastmatch > U.vbotimeout) { + mesh_batch_cache_discard_shaded_tri(cache); + } + + mesh_cd_layers_type_clear(&cache->cd_used_over_time); + drw_attributes_clear(&cache->attr_used_over_time); +} + +static void drw_add_attributes_vbo(GPUBatch *batch, + MeshBufferList *mbuflist, + DRW_Attributes *attr_used) +{ + for (int i = 0; i < attr_used->num_requests; i++) { + DRW_vbo_request(batch, &mbuflist->vbo.attr[i]); + } +} + +#ifdef DEBUG +/* Sanity check function to test if all requested batches are available. */ +static void drw_mesh_batch_cache_check_available(struct TaskGraph *task_graph, Mesh *me) +{ + MeshBatchCache *cache = mesh_batch_cache_get(me); + /* Make sure all requested batches have been setup. */ + /* NOTE: The next line creates a different scheduling than during release builds what can lead to + * some issues (See T77867 where we needed to disable this function in order to debug what was + * happening in release builds). */ + BLI_task_graph_work_and_wait(task_graph); + for (int i = 0; i < MBC_BATCH_LEN; i++) { + BLI_assert(!DRW_batch_requested(((GPUBatch **)&cache->batch)[i], (GPUPrimType)0)); + } + for (int i = 0; i < MBC_VBO_LEN; i++) { + BLI_assert(!DRW_vbo_requested(((GPUVertBuf **)&cache->final.buff.vbo)[i])); + } + for (int i = 0; i < MBC_IBO_LEN; i++) { + BLI_assert(!DRW_ibo_requested(((GPUIndexBuf **)&cache->final.buff.ibo)[i])); + } + for (int i = 0; i < MBC_VBO_LEN; i++) { + BLI_assert(!DRW_vbo_requested(((GPUVertBuf **)&cache->cage.buff.vbo)[i])); + } + for (int i = 0; i < MBC_IBO_LEN; i++) { + BLI_assert(!DRW_ibo_requested(((GPUIndexBuf **)&cache->cage.buff.ibo)[i])); + } + for (int i = 0; i < MBC_VBO_LEN; i++) { + BLI_assert(!DRW_vbo_requested(((GPUVertBuf **)&cache->uv_cage.buff.vbo)[i])); + } + for (int i = 0; i < MBC_IBO_LEN; i++) { + BLI_assert(!DRW_ibo_requested(((GPUIndexBuf **)&cache->uv_cage.buff.ibo)[i])); + } +} +#endif + +void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph, + Object *ob, + Mesh *me, + const Scene *scene, + const bool is_paint_mode, + const bool use_hide) +{ + BLI_assert(task_graph); + const ToolSettings *ts = NULL; + if (scene) { + ts = scene->toolsettings; + } + MeshBatchCache *cache = mesh_batch_cache_get(me); + bool cd_uv_update = false; + + /* Early out */ + if (cache->batch_requested == 0) { +#ifdef DEBUG + drw_mesh_batch_cache_check_available(task_graph, me); +#endif + return; + } + +#ifdef DEBUG + /* Map the index of a buffer to a flag containing all batches that use it. */ + Map batches_that_use_buffer_local; + + auto assert_deps_valid = [&](DRWBatchFlag batch_flag, Span used_buffer_indices) { + for (const int buffer_index : used_buffer_indices) { + batches_that_use_buffer_local.add_or_modify( + buffer_index, + [&](DRWBatchFlag *value) { *value = batch_flag; }, + [&](DRWBatchFlag *value) { *value |= batch_flag; }); + BLI_assert(batches_that_use_buffer(buffer_index) & batch_flag); + } + }; +#else + auto assert_deps_valid = [&](DRWBatchFlag UNUSED(batch_flag), + Span UNUSED(used_buffer_indices)) {}; + +#endif + + /* Sanity check. */ + if ((me->edit_mesh != NULL) && (ob->mode & OB_MODE_EDIT)) { + BLI_assert(BKE_object_get_editmesh_eval_final(ob) != NULL); + } + + const bool is_editmode = (me->edit_mesh != NULL) && + (BKE_object_get_editmesh_eval_final(ob) != NULL) && + DRW_object_is_in_edit_mode(ob); + + /* This could be set for paint mode too, currently it's only used for edit-mode. */ + const bool is_mode_active = is_editmode && DRW_object_is_in_edit_mode(ob); + + DRWBatchFlag batch_requested = cache->batch_requested; + cache->batch_requested = (DRWBatchFlag)0; + + if (batch_requested & MBC_SURFACE_WEIGHTS) { + /* Check vertex weights. */ + if ((cache->batch.surface_weights != NULL) && (ts != NULL)) { + struct DRW_MeshWeightState wstate; + BLI_assert(ob->type == OB_MESH); + drw_mesh_weight_state_extract(ob, me, ts, is_paint_mode, &wstate); + mesh_batch_cache_check_vertex_group(cache, &wstate); + drw_mesh_weight_state_copy(&cache->weight_state, &wstate); + drw_mesh_weight_state_clear(&wstate); + } + } + + if (batch_requested & + (MBC_SURFACE | MBC_WIRE_LOOPS_UVS | MBC_EDITUV_FACES_STRETCH_AREA | + MBC_EDITUV_FACES_STRETCH_ANGLE | MBC_EDITUV_FACES | MBC_EDITUV_EDGES | MBC_EDITUV_VERTS)) { + /* Modifiers will only generate an orco layer if the mesh is deformed. */ + if (cache->cd_needed.orco != 0) { + /* Orco is always extracted from final mesh. */ + Mesh *me_final = (me->edit_mesh) ? BKE_object_get_editmesh_eval_final(ob) : me; + if (CustomData_get_layer(&me_final->vdata, CD_ORCO) == NULL) { + /* Skip orco calculation */ + cache->cd_needed.orco = 0; + } + } + + ThreadMutex *mesh_render_mutex = (ThreadMutex *)me->runtime.render_mutex; + + /* Verify that all surface batches have needed attribute layers. + */ + /* TODO(fclem): We could be a bit smarter here and only do it per + * material. */ + bool cd_overlap = mesh_cd_layers_type_overlap(cache->cd_used, cache->cd_needed); + bool attr_overlap = drw_attributes_overlap(&cache->attr_used, &cache->attr_needed); + if (cd_overlap == false || attr_overlap == false) { + FOREACH_MESH_BUFFER_CACHE (cache, mbc) { + if ((cache->cd_used.uv & cache->cd_needed.uv) != cache->cd_needed.uv) { + GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.uv); + cd_uv_update = true; + } + if ((cache->cd_used.tan & cache->cd_needed.tan) != cache->cd_needed.tan || + cache->cd_used.tan_orco != cache->cd_needed.tan_orco) { + GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.tan); + } + if (cache->cd_used.orco != cache->cd_needed.orco) { + GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.orco); + } + if (cache->cd_used.sculpt_overlays != cache->cd_needed.sculpt_overlays) { + GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.sculpt_data); + } + if ((cache->cd_used.vcol & cache->cd_needed.vcol) != cache->cd_needed.vcol) { + GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.vcol); + } + if (!drw_attributes_overlap(&cache->attr_used, &cache->attr_needed)) { + for (int i = 0; i < GPU_MAX_ATTR; i++) { + GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.attr[i]); + } + } + } + /* We can't discard batches at this point as they have been + * referenced for drawing. Just clear them in place. */ + for (int i = 0; i < cache->mat_len; i++) { + GPU_BATCH_CLEAR_SAFE(cache->surface_per_mat[i]); + } + GPU_BATCH_CLEAR_SAFE(cache->batch.surface); + cache->batch_ready &= ~(MBC_SURFACE); + + mesh_cd_layers_type_merge(&cache->cd_used, cache->cd_needed); + drw_attributes_merge(&cache->attr_used, &cache->attr_needed, mesh_render_mutex); + } + mesh_cd_layers_type_merge(&cache->cd_used_over_time, cache->cd_needed); + mesh_cd_layers_type_clear(&cache->cd_needed); + + drw_attributes_merge(&cache->attr_used_over_time, &cache->attr_needed, mesh_render_mutex); + drw_attributes_clear(&cache->attr_needed); + } + + if (batch_requested & MBC_EDITUV) { + /* Discard UV batches if sync_selection changes */ + const bool is_uvsyncsel = ts && (ts->uv_flag & UV_SYNC_SELECTION); + if (cd_uv_update || (cache->is_uvsyncsel != is_uvsyncsel)) { + cache->is_uvsyncsel = is_uvsyncsel; + FOREACH_MESH_BUFFER_CACHE (cache, mbc) { + GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.edituv_data); + GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.fdots_uv); + GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.fdots_edituv_data); + GPU_INDEXBUF_DISCARD_SAFE(mbc->buff.ibo.edituv_tris); + GPU_INDEXBUF_DISCARD_SAFE(mbc->buff.ibo.edituv_lines); + GPU_INDEXBUF_DISCARD_SAFE(mbc->buff.ibo.edituv_points); + GPU_INDEXBUF_DISCARD_SAFE(mbc->buff.ibo.edituv_fdots); + } + /* We only clear the batches as they may already have been + * referenced. */ + GPU_BATCH_CLEAR_SAFE(cache->batch.wire_loops_uvs); + GPU_BATCH_CLEAR_SAFE(cache->batch.edituv_faces_stretch_area); + GPU_BATCH_CLEAR_SAFE(cache->batch.edituv_faces_stretch_angle); + GPU_BATCH_CLEAR_SAFE(cache->batch.edituv_faces); + GPU_BATCH_CLEAR_SAFE(cache->batch.edituv_edges); + GPU_BATCH_CLEAR_SAFE(cache->batch.edituv_verts); + GPU_BATCH_CLEAR_SAFE(cache->batch.edituv_fdots); + cache->batch_ready &= ~MBC_EDITUV; + } + } + + /* Second chance to early out */ + if ((batch_requested & ~cache->batch_ready) == 0) { +#ifdef DEBUG + drw_mesh_batch_cache_check_available(task_graph, me); +#endif + return; + } + + /* TODO(pablodp606): This always updates the sculpt normals for regular drawing (non-PBVH). + * This makes tools that sample the surface per step get wrong normals until a redraw happens. + * Normal updates should be part of the brush loop and only run during the stroke when the + * brush needs to sample the surface. The drawing code should only update the normals + * per redraw when smooth shading is enabled. */ + const bool do_update_sculpt_normals = ob->sculpt && ob->sculpt->pbvh; + if (do_update_sculpt_normals) { + Mesh *mesh = static_cast(ob->data); + BKE_pbvh_update_normals(ob->sculpt->pbvh, mesh->runtime.subdiv_ccg); + } + + cache->batch_ready |= batch_requested; + + bool do_cage = false, do_uvcage = false; + if (is_editmode) { + Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(ob); + Mesh *editmesh_eval_cage = BKE_object_get_editmesh_eval_cage(ob); + + do_cage = editmesh_eval_final != editmesh_eval_cage; + do_uvcage = !editmesh_eval_final->runtime.is_original; + } + + const bool do_subdivision = BKE_subsurf_modifier_has_gpu_subdiv(me); + + MeshBufferList *mbuflist = &cache->final.buff; + + /* Initialize batches and request VBO's & IBO's. */ + assert_deps_valid( + MBC_SURFACE, + {BUFFER_INDEX(ibo.tris), BUFFER_INDEX(vbo.lnor), BUFFER_INDEX(vbo.pos_nor), + BUFFER_INDEX(vbo.uv), BUFFER_INDEX(vbo.vcol), BUFFER_INDEX(vbo.attr[0]), + BUFFER_INDEX(vbo.attr[1]), BUFFER_INDEX(vbo.attr[2]), BUFFER_INDEX(vbo.attr[3]), + BUFFER_INDEX(vbo.attr[4]), BUFFER_INDEX(vbo.attr[5]), BUFFER_INDEX(vbo.attr[6]), + BUFFER_INDEX(vbo.attr[7]), BUFFER_INDEX(vbo.attr[8]), BUFFER_INDEX(vbo.attr[9]), + BUFFER_INDEX(vbo.attr[10]), BUFFER_INDEX(vbo.attr[11]), BUFFER_INDEX(vbo.attr[12]), + BUFFER_INDEX(vbo.attr[13]), BUFFER_INDEX(vbo.attr[14])}); + if (DRW_batch_requested(cache->batch.surface, GPU_PRIM_TRIS)) { + DRW_ibo_request(cache->batch.surface, &mbuflist->ibo.tris); + /* Order matters. First ones override latest VBO's attributes. */ + DRW_vbo_request(cache->batch.surface, &mbuflist->vbo.lnor); + DRW_vbo_request(cache->batch.surface, &mbuflist->vbo.pos_nor); + if (cache->cd_used.uv != 0) { + DRW_vbo_request(cache->batch.surface, &mbuflist->vbo.uv); + } + if (cache->cd_used.vcol != 0) { + DRW_vbo_request(cache->batch.surface, &mbuflist->vbo.vcol); + } + drw_add_attributes_vbo(cache->batch.surface, mbuflist, &cache->attr_used); + } + assert_deps_valid(MBC_ALL_VERTS, {BUFFER_INDEX(vbo.pos_nor)}); + if (DRW_batch_requested(cache->batch.all_verts, GPU_PRIM_POINTS)) { + DRW_vbo_request(cache->batch.all_verts, &mbuflist->vbo.pos_nor); + } + assert_deps_valid( + MBC_SCULPT_OVERLAYS, + {BUFFER_INDEX(ibo.tris), BUFFER_INDEX(vbo.pos_nor), BUFFER_INDEX(vbo.sculpt_data)}); + if (DRW_batch_requested(cache->batch.sculpt_overlays, GPU_PRIM_TRIS)) { + DRW_ibo_request(cache->batch.sculpt_overlays, &mbuflist->ibo.tris); + DRW_vbo_request(cache->batch.sculpt_overlays, &mbuflist->vbo.pos_nor); + DRW_vbo_request(cache->batch.sculpt_overlays, &mbuflist->vbo.sculpt_data); + } + assert_deps_valid(MBC_ALL_EDGES, {BUFFER_INDEX(ibo.lines), BUFFER_INDEX(vbo.pos_nor)}); + if (DRW_batch_requested(cache->batch.all_edges, GPU_PRIM_LINES)) { + DRW_ibo_request(cache->batch.all_edges, &mbuflist->ibo.lines); + DRW_vbo_request(cache->batch.all_edges, &mbuflist->vbo.pos_nor); + } + assert_deps_valid(MBC_LOOSE_EDGES, {BUFFER_INDEX(ibo.lines_loose), BUFFER_INDEX(vbo.pos_nor)}); + if (DRW_batch_requested(cache->batch.loose_edges, GPU_PRIM_LINES)) { + DRW_ibo_request(NULL, &mbuflist->ibo.lines); + DRW_ibo_request(cache->batch.loose_edges, &mbuflist->ibo.lines_loose); + DRW_vbo_request(cache->batch.loose_edges, &mbuflist->vbo.pos_nor); + } + assert_deps_valid(MBC_EDGE_DETECTION, + {BUFFER_INDEX(ibo.lines_adjacency), BUFFER_INDEX(vbo.pos_nor)}); + if (DRW_batch_requested(cache->batch.edge_detection, GPU_PRIM_LINES_ADJ)) { + DRW_ibo_request(cache->batch.edge_detection, &mbuflist->ibo.lines_adjacency); + DRW_vbo_request(cache->batch.edge_detection, &mbuflist->vbo.pos_nor); + } + assert_deps_valid( + MBC_SURFACE_WEIGHTS, + {BUFFER_INDEX(ibo.tris), BUFFER_INDEX(vbo.pos_nor), BUFFER_INDEX(vbo.weights)}); + if (DRW_batch_requested(cache->batch.surface_weights, GPU_PRIM_TRIS)) { + DRW_ibo_request(cache->batch.surface_weights, &mbuflist->ibo.tris); + DRW_vbo_request(cache->batch.surface_weights, &mbuflist->vbo.pos_nor); + DRW_vbo_request(cache->batch.surface_weights, &mbuflist->vbo.weights); + } + assert_deps_valid( + MBC_WIRE_LOOPS, + {BUFFER_INDEX(ibo.lines_paint_mask), BUFFER_INDEX(vbo.lnor), BUFFER_INDEX(vbo.pos_nor)}); + if (DRW_batch_requested(cache->batch.wire_loops, GPU_PRIM_LINES)) { + DRW_ibo_request(cache->batch.wire_loops, &mbuflist->ibo.lines_paint_mask); + /* Order matters. First ones override latest VBO's attributes. */ + DRW_vbo_request(cache->batch.wire_loops, &mbuflist->vbo.lnor); + DRW_vbo_request(cache->batch.wire_loops, &mbuflist->vbo.pos_nor); + } + assert_deps_valid( + MBC_WIRE_EDGES, + {BUFFER_INDEX(ibo.lines), BUFFER_INDEX(vbo.pos_nor), BUFFER_INDEX(vbo.edge_fac)}); + if (DRW_batch_requested(cache->batch.wire_edges, GPU_PRIM_LINES)) { + DRW_ibo_request(cache->batch.wire_edges, &mbuflist->ibo.lines); + DRW_vbo_request(cache->batch.wire_edges, &mbuflist->vbo.pos_nor); + DRW_vbo_request(cache->batch.wire_edges, &mbuflist->vbo.edge_fac); + } + assert_deps_valid(MBC_WIRE_LOOPS_UVS, {BUFFER_INDEX(ibo.edituv_lines), BUFFER_INDEX(vbo.uv)}); + if (DRW_batch_requested(cache->batch.wire_loops_uvs, GPU_PRIM_LINES)) { + DRW_ibo_request(cache->batch.wire_loops_uvs, &mbuflist->ibo.edituv_lines); + /* For paint overlay. Active layer should have been queried. */ + if (cache->cd_used.uv != 0) { + DRW_vbo_request(cache->batch.wire_loops_uvs, &mbuflist->vbo.uv); + } + } + assert_deps_valid( + MBC_EDIT_MESH_ANALYSIS, + {BUFFER_INDEX(ibo.tris), BUFFER_INDEX(vbo.pos_nor), BUFFER_INDEX(vbo.mesh_analysis)}); + if (DRW_batch_requested(cache->batch.edit_mesh_analysis, GPU_PRIM_TRIS)) { + DRW_ibo_request(cache->batch.edit_mesh_analysis, &mbuflist->ibo.tris); + DRW_vbo_request(cache->batch.edit_mesh_analysis, &mbuflist->vbo.pos_nor); + DRW_vbo_request(cache->batch.edit_mesh_analysis, &mbuflist->vbo.mesh_analysis); + } + + /* Per Material */ + assert_deps_valid( + MBC_SURFACE_PER_MAT, + {BUFFER_INDEX(vbo.lnor), BUFFER_INDEX(vbo.pos_nor), BUFFER_INDEX(vbo.uv), + BUFFER_INDEX(vbo.tan), BUFFER_INDEX(vbo.vcol), BUFFER_INDEX(vbo.orco), + BUFFER_INDEX(vbo.attr[0]), BUFFER_INDEX(vbo.attr[1]), BUFFER_INDEX(vbo.attr[2]), + BUFFER_INDEX(vbo.attr[3]), BUFFER_INDEX(vbo.attr[4]), BUFFER_INDEX(vbo.attr[5]), + BUFFER_INDEX(vbo.attr[6]), BUFFER_INDEX(vbo.attr[7]), BUFFER_INDEX(vbo.attr[8]), + BUFFER_INDEX(vbo.attr[9]), BUFFER_INDEX(vbo.attr[10]), BUFFER_INDEX(vbo.attr[11]), + BUFFER_INDEX(vbo.attr[12]), BUFFER_INDEX(vbo.attr[13]), BUFFER_INDEX(vbo.attr[14])}); + assert_deps_valid(MBC_SURFACE_PER_MAT, {TRIS_PER_MAT_INDEX}); + for (int i = 0; i < cache->mat_len; i++) { + if (DRW_batch_requested(cache->surface_per_mat[i], GPU_PRIM_TRIS)) { + DRW_ibo_request(cache->surface_per_mat[i], &cache->tris_per_mat[i]); + /* Order matters. First ones override latest VBO's attributes. */ + DRW_vbo_request(cache->surface_per_mat[i], &mbuflist->vbo.lnor); + DRW_vbo_request(cache->surface_per_mat[i], &mbuflist->vbo.pos_nor); + if (cache->cd_used.uv != 0) { + DRW_vbo_request(cache->surface_per_mat[i], &mbuflist->vbo.uv); + } + if ((cache->cd_used.tan != 0) || (cache->cd_used.tan_orco != 0)) { + DRW_vbo_request(cache->surface_per_mat[i], &mbuflist->vbo.tan); + } + if (cache->cd_used.vcol != 0) { + DRW_vbo_request(cache->surface_per_mat[i], &mbuflist->vbo.vcol); + } + if (cache->cd_used.orco != 0) { + DRW_vbo_request(cache->surface_per_mat[i], &mbuflist->vbo.orco); + } + drw_add_attributes_vbo(cache->surface_per_mat[i], mbuflist, &cache->attr_used); + } + } + + mbuflist = (do_cage) ? &cache->cage.buff : &cache->final.buff; + + /* Edit Mesh */ + assert_deps_valid( + MBC_EDIT_TRIANGLES, + {BUFFER_INDEX(ibo.tris), BUFFER_INDEX(vbo.pos_nor), BUFFER_INDEX(vbo.edit_data)}); + if (DRW_batch_requested(cache->batch.edit_triangles, GPU_PRIM_TRIS)) { + DRW_ibo_request(cache->batch.edit_triangles, &mbuflist->ibo.tris); + DRW_vbo_request(cache->batch.edit_triangles, &mbuflist->vbo.pos_nor); + DRW_vbo_request(cache->batch.edit_triangles, &mbuflist->vbo.edit_data); + } + assert_deps_valid( + MBC_EDIT_VERTICES, + {BUFFER_INDEX(ibo.points), BUFFER_INDEX(vbo.pos_nor), BUFFER_INDEX(vbo.edit_data)}); + if (DRW_batch_requested(cache->batch.edit_vertices, GPU_PRIM_POINTS)) { + DRW_ibo_request(cache->batch.edit_vertices, &mbuflist->ibo.points); + DRW_vbo_request(cache->batch.edit_vertices, &mbuflist->vbo.pos_nor); + DRW_vbo_request(cache->batch.edit_vertices, &mbuflist->vbo.edit_data); + } + assert_deps_valid( + MBC_EDIT_EDGES, + {BUFFER_INDEX(ibo.lines), BUFFER_INDEX(vbo.pos_nor), BUFFER_INDEX(vbo.edit_data)}); + if (DRW_batch_requested(cache->batch.edit_edges, GPU_PRIM_LINES)) { + DRW_ibo_request(cache->batch.edit_edges, &mbuflist->ibo.lines); + DRW_vbo_request(cache->batch.edit_edges, &mbuflist->vbo.pos_nor); + DRW_vbo_request(cache->batch.edit_edges, &mbuflist->vbo.edit_data); + } + assert_deps_valid(MBC_EDIT_VNOR, {BUFFER_INDEX(ibo.points), BUFFER_INDEX(vbo.pos_nor)}); + if (DRW_batch_requested(cache->batch.edit_vnor, GPU_PRIM_POINTS)) { + DRW_ibo_request(cache->batch.edit_vnor, &mbuflist->ibo.points); + DRW_vbo_request(cache->batch.edit_vnor, &mbuflist->vbo.pos_nor); + } + assert_deps_valid(MBC_EDIT_LNOR, + {BUFFER_INDEX(ibo.tris), BUFFER_INDEX(vbo.pos_nor), BUFFER_INDEX(vbo.lnor)}); + if (DRW_batch_requested(cache->batch.edit_lnor, GPU_PRIM_POINTS)) { + DRW_ibo_request(cache->batch.edit_lnor, &mbuflist->ibo.tris); + DRW_vbo_request(cache->batch.edit_lnor, &mbuflist->vbo.pos_nor); + DRW_vbo_request(cache->batch.edit_lnor, &mbuflist->vbo.lnor); + } + assert_deps_valid( + MBC_EDIT_FACEDOTS, + {BUFFER_INDEX(ibo.fdots), BUFFER_INDEX(vbo.fdots_pos), BUFFER_INDEX(vbo.fdots_nor)}); + if (DRW_batch_requested(cache->batch.edit_fdots, GPU_PRIM_POINTS)) { + DRW_ibo_request(cache->batch.edit_fdots, &mbuflist->ibo.fdots); + DRW_vbo_request(cache->batch.edit_fdots, &mbuflist->vbo.fdots_pos); + DRW_vbo_request(cache->batch.edit_fdots, &mbuflist->vbo.fdots_nor); + } + assert_deps_valid(MBC_SKIN_ROOTS, {BUFFER_INDEX(vbo.skin_roots)}); + if (DRW_batch_requested(cache->batch.edit_skin_roots, GPU_PRIM_POINTS)) { + DRW_vbo_request(cache->batch.edit_skin_roots, &mbuflist->vbo.skin_roots); + } + + /* Selection */ + assert_deps_valid( + MBC_EDIT_SELECTION_VERTS, + {BUFFER_INDEX(ibo.points), BUFFER_INDEX(vbo.pos_nor), BUFFER_INDEX(vbo.vert_idx)}); + if (DRW_batch_requested(cache->batch.edit_selection_verts, GPU_PRIM_POINTS)) { + DRW_ibo_request(cache->batch.edit_selection_verts, &mbuflist->ibo.points); + DRW_vbo_request(cache->batch.edit_selection_verts, &mbuflist->vbo.pos_nor); + DRW_vbo_request(cache->batch.edit_selection_verts, &mbuflist->vbo.vert_idx); + } + assert_deps_valid( + MBC_EDIT_SELECTION_EDGES, + {BUFFER_INDEX(ibo.lines), BUFFER_INDEX(vbo.pos_nor), BUFFER_INDEX(vbo.edge_idx)}); + if (DRW_batch_requested(cache->batch.edit_selection_edges, GPU_PRIM_LINES)) { + DRW_ibo_request(cache->batch.edit_selection_edges, &mbuflist->ibo.lines); + DRW_vbo_request(cache->batch.edit_selection_edges, &mbuflist->vbo.pos_nor); + DRW_vbo_request(cache->batch.edit_selection_edges, &mbuflist->vbo.edge_idx); + } + assert_deps_valid( + MBC_EDIT_SELECTION_FACES, + {BUFFER_INDEX(ibo.tris), BUFFER_INDEX(vbo.pos_nor), BUFFER_INDEX(vbo.poly_idx)}); + if (DRW_batch_requested(cache->batch.edit_selection_faces, GPU_PRIM_TRIS)) { + DRW_ibo_request(cache->batch.edit_selection_faces, &mbuflist->ibo.tris); + DRW_vbo_request(cache->batch.edit_selection_faces, &mbuflist->vbo.pos_nor); + DRW_vbo_request(cache->batch.edit_selection_faces, &mbuflist->vbo.poly_idx); + } + assert_deps_valid( + MBC_EDIT_SELECTION_FACEDOTS, + {BUFFER_INDEX(ibo.fdots), BUFFER_INDEX(vbo.fdots_pos), BUFFER_INDEX(vbo.fdot_idx)}); + if (DRW_batch_requested(cache->batch.edit_selection_fdots, GPU_PRIM_POINTS)) { + DRW_ibo_request(cache->batch.edit_selection_fdots, &mbuflist->ibo.fdots); + DRW_vbo_request(cache->batch.edit_selection_fdots, &mbuflist->vbo.fdots_pos); + DRW_vbo_request(cache->batch.edit_selection_fdots, &mbuflist->vbo.fdot_idx); + } + + /** + * TODO: The code and data structure is ready to support modified UV display + * but the selection code for UVs needs to support it first. So for now, only + * display the cage in all cases. + */ + mbuflist = (do_uvcage) ? &cache->uv_cage.buff : &cache->final.buff; + + /* Edit UV */ + assert_deps_valid( + MBC_EDITUV_FACES, + {BUFFER_INDEX(ibo.edituv_tris), BUFFER_INDEX(vbo.uv), BUFFER_INDEX(vbo.edituv_data)}); + if (DRW_batch_requested(cache->batch.edituv_faces, GPU_PRIM_TRIS)) { + DRW_ibo_request(cache->batch.edituv_faces, &mbuflist->ibo.edituv_tris); + DRW_vbo_request(cache->batch.edituv_faces, &mbuflist->vbo.uv); + DRW_vbo_request(cache->batch.edituv_faces, &mbuflist->vbo.edituv_data); + } + assert_deps_valid(MBC_EDITUV_FACES_STRETCH_AREA, + {BUFFER_INDEX(ibo.edituv_tris), + BUFFER_INDEX(vbo.uv), + BUFFER_INDEX(vbo.edituv_data), + BUFFER_INDEX(vbo.edituv_stretch_area)}); + if (DRW_batch_requested(cache->batch.edituv_faces_stretch_area, GPU_PRIM_TRIS)) { + DRW_ibo_request(cache->batch.edituv_faces_stretch_area, &mbuflist->ibo.edituv_tris); + DRW_vbo_request(cache->batch.edituv_faces_stretch_area, &mbuflist->vbo.uv); + DRW_vbo_request(cache->batch.edituv_faces_stretch_area, &mbuflist->vbo.edituv_data); + DRW_vbo_request(cache->batch.edituv_faces_stretch_area, &mbuflist->vbo.edituv_stretch_area); + } + assert_deps_valid(MBC_EDITUV_FACES_STRETCH_ANGLE, + {BUFFER_INDEX(ibo.edituv_tris), + BUFFER_INDEX(vbo.uv), + BUFFER_INDEX(vbo.edituv_data), + BUFFER_INDEX(vbo.edituv_stretch_angle)}); + if (DRW_batch_requested(cache->batch.edituv_faces_stretch_angle, GPU_PRIM_TRIS)) { + DRW_ibo_request(cache->batch.edituv_faces_stretch_angle, &mbuflist->ibo.edituv_tris); + DRW_vbo_request(cache->batch.edituv_faces_stretch_angle, &mbuflist->vbo.uv); + DRW_vbo_request(cache->batch.edituv_faces_stretch_angle, &mbuflist->vbo.edituv_data); + DRW_vbo_request(cache->batch.edituv_faces_stretch_angle, &mbuflist->vbo.edituv_stretch_angle); + } + assert_deps_valid( + MBC_EDITUV_EDGES, + {BUFFER_INDEX(ibo.edituv_lines), BUFFER_INDEX(vbo.uv), BUFFER_INDEX(vbo.edituv_data)}); + if (DRW_batch_requested(cache->batch.edituv_edges, GPU_PRIM_LINES)) { + DRW_ibo_request(cache->batch.edituv_edges, &mbuflist->ibo.edituv_lines); + DRW_vbo_request(cache->batch.edituv_edges, &mbuflist->vbo.uv); + DRW_vbo_request(cache->batch.edituv_edges, &mbuflist->vbo.edituv_data); + } + assert_deps_valid( + MBC_EDITUV_VERTS, + {BUFFER_INDEX(ibo.edituv_points), BUFFER_INDEX(vbo.uv), BUFFER_INDEX(vbo.edituv_data)}); + if (DRW_batch_requested(cache->batch.edituv_verts, GPU_PRIM_POINTS)) { + DRW_ibo_request(cache->batch.edituv_verts, &mbuflist->ibo.edituv_points); + DRW_vbo_request(cache->batch.edituv_verts, &mbuflist->vbo.uv); + DRW_vbo_request(cache->batch.edituv_verts, &mbuflist->vbo.edituv_data); + } + assert_deps_valid(MBC_EDITUV_FACEDOTS, + {BUFFER_INDEX(ibo.edituv_fdots), + BUFFER_INDEX(vbo.fdots_uv), + BUFFER_INDEX(vbo.fdots_edituv_data)}); + if (DRW_batch_requested(cache->batch.edituv_fdots, GPU_PRIM_POINTS)) { + DRW_ibo_request(cache->batch.edituv_fdots, &mbuflist->ibo.edituv_fdots); + DRW_vbo_request(cache->batch.edituv_fdots, &mbuflist->vbo.fdots_uv); + DRW_vbo_request(cache->batch.edituv_fdots, &mbuflist->vbo.fdots_edituv_data); + } + +#ifdef DEBUG + auto assert_final_deps_valid = [&](const int buffer_index) { + BLI_assert(batches_that_use_buffer(buffer_index) == + batches_that_use_buffer_local.lookup(buffer_index)); + }; + assert_final_deps_valid(BUFFER_INDEX(vbo.lnor)); + assert_final_deps_valid(BUFFER_INDEX(vbo.pos_nor)); + assert_final_deps_valid(BUFFER_INDEX(vbo.uv)); + assert_final_deps_valid(BUFFER_INDEX(vbo.vcol)); + assert_final_deps_valid(BUFFER_INDEX(vbo.sculpt_data)); + assert_final_deps_valid(BUFFER_INDEX(vbo.weights)); + assert_final_deps_valid(BUFFER_INDEX(vbo.edge_fac)); + assert_final_deps_valid(BUFFER_INDEX(vbo.mesh_analysis)); + assert_final_deps_valid(BUFFER_INDEX(vbo.tan)); + assert_final_deps_valid(BUFFER_INDEX(vbo.orco)); + assert_final_deps_valid(BUFFER_INDEX(vbo.edit_data)); + assert_final_deps_valid(BUFFER_INDEX(vbo.fdots_pos)); + assert_final_deps_valid(BUFFER_INDEX(vbo.fdots_nor)); + assert_final_deps_valid(BUFFER_INDEX(vbo.skin_roots)); + assert_final_deps_valid(BUFFER_INDEX(vbo.vert_idx)); + assert_final_deps_valid(BUFFER_INDEX(vbo.edge_idx)); + assert_final_deps_valid(BUFFER_INDEX(vbo.poly_idx)); + assert_final_deps_valid(BUFFER_INDEX(vbo.fdot_idx)); + assert_final_deps_valid(BUFFER_INDEX(vbo.edituv_data)); + assert_final_deps_valid(BUFFER_INDEX(vbo.edituv_stretch_area)); + assert_final_deps_valid(BUFFER_INDEX(vbo.edituv_stretch_angle)); + assert_final_deps_valid(BUFFER_INDEX(vbo.fdots_uv)); + assert_final_deps_valid(BUFFER_INDEX(vbo.fdots_edituv_data)); + for (const int i : IndexRange(GPU_MAX_ATTR)) { + assert_final_deps_valid(BUFFER_INDEX(vbo.attr[i])); + } + + assert_final_deps_valid(BUFFER_INDEX(ibo.tris)); + assert_final_deps_valid(BUFFER_INDEX(ibo.lines)); + assert_final_deps_valid(BUFFER_INDEX(ibo.lines_loose)); + assert_final_deps_valid(BUFFER_INDEX(ibo.lines_adjacency)); + assert_final_deps_valid(BUFFER_INDEX(ibo.lines_paint_mask)); + assert_final_deps_valid(BUFFER_INDEX(ibo.points)); + assert_final_deps_valid(BUFFER_INDEX(ibo.fdots)); + assert_final_deps_valid(BUFFER_INDEX(ibo.edituv_tris)); + assert_final_deps_valid(BUFFER_INDEX(ibo.edituv_lines)); + assert_final_deps_valid(BUFFER_INDEX(ibo.edituv_points)); + assert_final_deps_valid(BUFFER_INDEX(ibo.edituv_fdots)); + + assert_final_deps_valid(TRIS_PER_MAT_INDEX); +#endif + + if (do_uvcage) { + blender::draw::mesh_buffer_cache_create_requested(task_graph, + cache, + &cache->uv_cage, + ob, + me, + is_editmode, + is_paint_mode, + is_mode_active, + ob->obmat, + false, + true, + scene, + ts, + true); + } + + if (do_cage) { + blender::draw::mesh_buffer_cache_create_requested(task_graph, + cache, + &cache->cage, + ob, + me, + is_editmode, + is_paint_mode, + is_mode_active, + ob->obmat, + false, + false, + scene, + ts, + true); + } + + if (do_subdivision) { + DRW_create_subdivision(scene, + ob, + me, + cache, + &cache->final, + is_editmode, + is_paint_mode, + is_mode_active, + ob->obmat, + true, + false, + ts, + use_hide); + } + else { + /* The subsurf modifier may have been recently removed, or another modifier was added after it, + * so free any potential subdivision cache as it is not needed anymore. */ + mesh_batch_cache_free_subdiv_cache(cache); + } + + blender::draw::mesh_buffer_cache_create_requested(task_graph, + cache, + &cache->final, + ob, + me, + is_editmode, + is_paint_mode, + is_mode_active, + ob->obmat, + true, + false, + scene, + ts, + use_hide); + + /* Ensure that all requested batches have finished. + * Ideally we want to remove this sync, but there are cases where this doesn't work. + * See T79038 for example. + * + * An idea to improve this is to separate the Object mode from the edit mode draw caches. And + * based on the mode the correct one will be updated. Other option is to look into using + * drw_batch_cache_generate_requested_delayed. */ + BLI_task_graph_work_and_wait(task_graph); +#ifdef DEBUG + drw_mesh_batch_cache_check_available(task_graph, me); +#endif +} + +/** \} */ diff --git a/source/blender/draw/intern/draw_cache_impl_subdivision.cc b/source/blender/draw/intern/draw_cache_impl_subdivision.cc index b5cdbd3617e..e7726ff55ca 100644 --- a/source/blender/draw/intern/draw_cache_impl_subdivision.cc +++ b/source/blender/draw/intern/draw_cache_impl_subdivision.cc @@ -39,10 +39,10 @@ #include "opensubdiv_evaluator_capi.h" #include "opensubdiv_topology_refiner_capi.h" -#include "draw_cache_extract.h" +#include "draw_cache_extract.hh" #include "draw_cache_impl.h" #include "draw_cache_inline.h" -#include "mesh_extractors/extract_mesh.h" +#include "mesh_extractors/extract_mesh.hh" extern "C" char datatoc_common_subdiv_custom_data_interp_comp_glsl[]; extern "C" char datatoc_common_subdiv_ibo_lines_comp_glsl[]; @@ -2099,7 +2099,7 @@ static bool draw_subdiv_create_requested_buffers(const Scene *scene, draw_subdiv_cache_update_extra_coarse_face_data(draw_cache, mesh_eval, mr); - mesh_buffer_cache_create_requested_subdiv(batch_cache, mbc, draw_cache, mr); + blender::draw::mesh_buffer_cache_create_requested_subdiv(batch_cache, mbc, draw_cache, mr); mesh_render_data_free(mr); diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh.c b/source/blender/draw/intern/mesh_extractors/extract_mesh.c deleted file mode 100644 index 9dc82fa3d32..00000000000 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh.c +++ /dev/null @@ -1,153 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later - * Copyright 2021 Blender Foundation. All rights reserved. */ - -/** \file - * \ingroup draw - * - * \brief Extraction of Mesh data into VBO to feed to GPU. - */ - -#include "MEM_guardedalloc.h" - -#include "DNA_object_types.h" - -#include "ED_uvedit.h" - -#include "extract_mesh.h" - -#include "draw_cache_impl.h" - -void *mesh_extract_buffer_get(const MeshExtract *extractor, MeshBufferList *mbuflist) -{ - /* NOTE: POINTER_OFFSET on windows platforms casts internally to `void *`, but on GCC/CLANG to - * `MeshBufferList *`. What shows a different usage versus intent. */ - void **buffer_ptr = (void **)POINTER_OFFSET(mbuflist, extractor->mesh_buffer_offset); - void *buffer = *buffer_ptr; - BLI_assert(buffer); - return buffer; -} - -eMRIterType mesh_extract_iter_type(const MeshExtract *ext) -{ - eMRIterType type = 0; - SET_FLAG_FROM_TEST(type, (ext->iter_looptri_bm || ext->iter_looptri_mesh), MR_ITER_LOOPTRI); - SET_FLAG_FROM_TEST(type, (ext->iter_poly_bm || ext->iter_poly_mesh), MR_ITER_POLY); - SET_FLAG_FROM_TEST(type, (ext->iter_ledge_bm || ext->iter_ledge_mesh), MR_ITER_LEDGE); - SET_FLAG_FROM_TEST(type, (ext->iter_lvert_bm || ext->iter_lvert_mesh), MR_ITER_LVERT); - return type; -} - -/* ---------------------------------------------------------------------- */ -/** \name Override extractors - * Extractors can be overridden. When overridden a specialized version is used. The next functions - * would check for any needed overrides and usage of the specialized version. - * \{ */ - -static const MeshExtract *mesh_extract_override_hq_normals(const MeshExtract *extractor) -{ - if (extractor == &extract_pos_nor) { - return &extract_pos_nor_hq; - } - if (extractor == &extract_lnor) { - return &extract_lnor_hq; - } - if (extractor == &extract_tan) { - return &extract_tan_hq; - } - if (extractor == &extract_fdots_nor) { - return &extract_fdots_nor_hq; - } - return extractor; -} - -static const MeshExtract *mesh_extract_override_single_material(const MeshExtract *extractor) -{ - if (extractor == &extract_tris) { - return &extract_tris_single_mat; - } - return extractor; -} - -const MeshExtract *mesh_extract_override_get(const MeshExtract *extractor, - const bool do_hq_normals, - const bool do_single_mat) -{ - if (do_hq_normals) { - extractor = mesh_extract_override_hq_normals(extractor); - } - - if (do_single_mat) { - extractor = mesh_extract_override_single_material(extractor); - } - - return extractor; -} - -/** \} */ - -/* ---------------------------------------------------------------------- */ -/** \name Extract Edit Flag Utils - * \{ */ - -void mesh_render_data_face_flag(const MeshRenderData *mr, - const BMFace *efa, - const int cd_ofs, - EditLoopData *eattr) -{ - if (efa == mr->efa_act) { - eattr->v_flag |= VFLAG_FACE_ACTIVE; - } - if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) { - eattr->v_flag |= VFLAG_FACE_SELECTED; - } - - if (efa == mr->efa_act_uv) { - eattr->v_flag |= VFLAG_FACE_UV_ACTIVE; - } - if ((cd_ofs != -1) && uvedit_face_select_test_ex(mr->toolsettings, (BMFace *)efa, cd_ofs)) { - eattr->v_flag |= VFLAG_FACE_UV_SELECT; - } - -#ifdef WITH_FREESTYLE - if (mr->freestyle_face_ofs != -1) { - const FreestyleFace *ffa = (const FreestyleFace *)BM_ELEM_CD_GET_VOID_P( - efa, mr->freestyle_face_ofs); - if (ffa->flag & FREESTYLE_FACE_MARK) { - eattr->v_flag |= VFLAG_FACE_FREESTYLE; - } - } -#endif -} - -void mesh_render_data_loop_flag(const MeshRenderData *mr, - BMLoop *l, - const int cd_ofs, - EditLoopData *eattr) -{ - if (cd_ofs == -1) { - return; - } - MLoopUV *luv = (MLoopUV *)BM_ELEM_CD_GET_VOID_P(l, cd_ofs); - if (luv != NULL && (luv->flag & MLOOPUV_PINNED)) { - eattr->v_flag |= VFLAG_VERT_UV_PINNED; - } - if (uvedit_uv_select_test_ex(mr->toolsettings, l, cd_ofs)) { - eattr->v_flag |= VFLAG_VERT_UV_SELECT; - } -} - -void mesh_render_data_loop_edge_flag(const MeshRenderData *mr, - BMLoop *l, - const int cd_ofs, - EditLoopData *eattr) -{ - if (cd_ofs == -1) { - return; - } - if (uvedit_edge_select_test_ex(mr->toolsettings, l, cd_ofs)) { - eattr->v_flag |= VFLAG_EDGE_UV_SELECT; - eattr->v_flag |= VFLAG_VERT_UV_SELECT; - } -} - -/** \} */ diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh.cc new file mode 100644 index 00000000000..7e02fbbf7d0 --- /dev/null +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh.cc @@ -0,0 +1,153 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2021 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup draw + * + * \brief Extraction of Mesh data into VBO to feed to GPU. + */ + +#include "MEM_guardedalloc.h" + +#include "DNA_object_types.h" + +#include "ED_uvedit.h" + +#include "extract_mesh.hh" + +#include "draw_cache_impl.h" + +void *mesh_extract_buffer_get(const MeshExtract *extractor, MeshBufferList *mbuflist) +{ + /* NOTE: POINTER_OFFSET on windows platforms casts internally to `void *`, but on GCC/CLANG to + * `MeshBufferList *`. What shows a different usage versus intent. */ + void **buffer_ptr = (void **)POINTER_OFFSET(mbuflist, extractor->mesh_buffer_offset); + void *buffer = *buffer_ptr; + BLI_assert(buffer); + return buffer; +} + +eMRIterType mesh_extract_iter_type(const MeshExtract *ext) +{ + eMRIterType type = (eMRIterType)0; + SET_FLAG_FROM_TEST(type, (ext->iter_looptri_bm || ext->iter_looptri_mesh), MR_ITER_LOOPTRI); + SET_FLAG_FROM_TEST(type, (ext->iter_poly_bm || ext->iter_poly_mesh), MR_ITER_POLY); + SET_FLAG_FROM_TEST(type, (ext->iter_ledge_bm || ext->iter_ledge_mesh), MR_ITER_LEDGE); + SET_FLAG_FROM_TEST(type, (ext->iter_lvert_bm || ext->iter_lvert_mesh), MR_ITER_LVERT); + return type; +} + +/* ---------------------------------------------------------------------- */ +/** \name Override extractors + * Extractors can be overridden. When overridden a specialized version is used. The next functions + * would check for any needed overrides and usage of the specialized version. + * \{ */ + +static const MeshExtract *mesh_extract_override_hq_normals(const MeshExtract *extractor) +{ + if (extractor == &extract_pos_nor) { + return &extract_pos_nor_hq; + } + if (extractor == &extract_lnor) { + return &extract_lnor_hq; + } + if (extractor == &extract_tan) { + return &extract_tan_hq; + } + if (extractor == &extract_fdots_nor) { + return &extract_fdots_nor_hq; + } + return extractor; +} + +static const MeshExtract *mesh_extract_override_single_material(const MeshExtract *extractor) +{ + if (extractor == &extract_tris) { + return &extract_tris_single_mat; + } + return extractor; +} + +const MeshExtract *mesh_extract_override_get(const MeshExtract *extractor, + const bool do_hq_normals, + const bool do_single_mat) +{ + if (do_hq_normals) { + extractor = mesh_extract_override_hq_normals(extractor); + } + + if (do_single_mat) { + extractor = mesh_extract_override_single_material(extractor); + } + + return extractor; +} + +/** \} */ + +/* ---------------------------------------------------------------------- */ +/** \name Extract Edit Flag Utils + * \{ */ + +void mesh_render_data_face_flag(const MeshRenderData *mr, + const BMFace *efa, + const int cd_ofs, + EditLoopData *eattr) +{ + if (efa == mr->efa_act) { + eattr->v_flag |= VFLAG_FACE_ACTIVE; + } + if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) { + eattr->v_flag |= VFLAG_FACE_SELECTED; + } + + if (efa == mr->efa_act_uv) { + eattr->v_flag |= VFLAG_FACE_UV_ACTIVE; + } + if ((cd_ofs != -1) && uvedit_face_select_test_ex(mr->toolsettings, (BMFace *)efa, cd_ofs)) { + eattr->v_flag |= VFLAG_FACE_UV_SELECT; + } + +#ifdef WITH_FREESTYLE + if (mr->freestyle_face_ofs != -1) { + const FreestyleFace *ffa = (const FreestyleFace *)BM_ELEM_CD_GET_VOID_P( + efa, mr->freestyle_face_ofs); + if (ffa->flag & FREESTYLE_FACE_MARK) { + eattr->v_flag |= VFLAG_FACE_FREESTYLE; + } + } +#endif +} + +void mesh_render_data_loop_flag(const MeshRenderData *mr, + BMLoop *l, + const int cd_ofs, + EditLoopData *eattr) +{ + if (cd_ofs == -1) { + return; + } + MLoopUV *luv = (MLoopUV *)BM_ELEM_CD_GET_VOID_P(l, cd_ofs); + if (luv != NULL && (luv->flag & MLOOPUV_PINNED)) { + eattr->v_flag |= VFLAG_VERT_UV_PINNED; + } + if (uvedit_uv_select_test_ex(mr->toolsettings, l, cd_ofs)) { + eattr->v_flag |= VFLAG_VERT_UV_SELECT; + } +} + +void mesh_render_data_loop_edge_flag(const MeshRenderData *mr, + BMLoop *l, + const int cd_ofs, + EditLoopData *eattr) +{ + if (cd_ofs == -1) { + return; + } + if (uvedit_edge_select_test_ex(mr->toolsettings, l, cd_ofs)) { + eattr->v_flag |= VFLAG_EDGE_UV_SELECT; + eattr->v_flag |= VFLAG_VERT_UV_SELECT; + } +} + +/** \} */ diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh.h b/source/blender/draw/intern/mesh_extractors/extract_mesh.h deleted file mode 100644 index b88cd9e77d2..00000000000 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh.h +++ /dev/null @@ -1,365 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later - * Copyright 2021 Blender Foundation. All rights reserved. */ - -/** \file - * \ingroup draw - * - * \brief Extraction of Mesh data into VBO to feed to GPU. - */ - -#pragma once - -#include "DNA_mesh_types.h" -#include "DNA_meshdata_types.h" -#include "DNA_object_types.h" -#include "DNA_scene_types.h" - -#include "BKE_customdata.h" -#include "BKE_editmesh.h" - -#include "draw_cache_extract.h" - -#ifdef __cplusplus -extern "C" { -#endif - -struct DRWSubdivCache; - -#define MIN_RANGE_LEN 1024 - -/* ---------------------------------------------------------------------- */ -/** \name Mesh Render Data - * \{ */ - -typedef enum eMRExtractType { - MR_EXTRACT_BMESH, - MR_EXTRACT_MAPPED, - MR_EXTRACT_MESH, -} eMRExtractType; - -typedef struct MeshRenderData { - eMRExtractType extract_type; - - int poly_len, edge_len, vert_len, loop_len; - int edge_loose_len; - int vert_loose_len; - int loop_loose_len; - int tri_len; - int mat_len; - - bool use_hide; - bool use_subsurf_fdots; - bool use_final_mesh; - - /** Use for #MeshStatVis calculation which use world-space coords. */ - float obmat[4][4]; - - const ToolSettings *toolsettings; - /** Edit Mesh */ - BMEditMesh *edit_bmesh; - BMesh *bm; - EditMeshData *edit_data; - - /* For deformed edit-mesh data. */ - /* Use for #ME_WRAPPER_TYPE_BMESH. */ - const float (*bm_vert_coords)[3]; - const float (*bm_vert_normals)[3]; - const float (*bm_poly_normals)[3]; - const float (*bm_poly_centers)[3]; - - const int *v_origindex, *e_origindex, *p_origindex; - int edge_crease_ofs; - int vert_crease_ofs; - int bweight_ofs; - int freestyle_edge_ofs; - int freestyle_face_ofs; - /** Mesh */ - Mesh *me; - const MVert *mvert; - const MEdge *medge; - const MLoop *mloop; - const MPoly *mpoly; - BMVert *eve_act; - BMEdge *eed_act; - BMFace *efa_act; - BMFace *efa_act_uv; - /* Data created on-demand (usually not for #BMesh based data). */ - MLoopTri *mlooptri; - const float (*vert_normals)[3]; - const float (*poly_normals)[3]; - float (*loop_normals)[3]; - int *lverts, *ledges; - - struct { - int *tri_first_index; - int *mat_tri_len; - int visible_tri_len; - } poly_sorted; -} MeshRenderData; - -BLI_INLINE BMFace *bm_original_face_get(const MeshRenderData *mr, int idx) -{ - return ((mr->p_origindex != NULL) && (mr->p_origindex[idx] != ORIGINDEX_NONE) && mr->bm) ? - BM_face_at_index(mr->bm, mr->p_origindex[idx]) : - NULL; -} - -BLI_INLINE BMEdge *bm_original_edge_get(const MeshRenderData *mr, int idx) -{ - return ((mr->e_origindex != NULL) && (mr->e_origindex[idx] != ORIGINDEX_NONE) && mr->bm) ? - BM_edge_at_index(mr->bm, mr->e_origindex[idx]) : - NULL; -} - -BLI_INLINE BMVert *bm_original_vert_get(const MeshRenderData *mr, int idx) -{ - return ((mr->v_origindex != NULL) && (mr->v_origindex[idx] != ORIGINDEX_NONE) && mr->bm) ? - BM_vert_at_index(mr->bm, mr->v_origindex[idx]) : - NULL; -} - -BLI_INLINE const float *bm_vert_co_get(const MeshRenderData *mr, const BMVert *eve) -{ - const float(*vert_coords)[3] = mr->bm_vert_coords; - if (vert_coords != NULL) { - return vert_coords[BM_elem_index_get(eve)]; - } - - UNUSED_VARS(mr); - return eve->co; -} - -BLI_INLINE const float *bm_vert_no_get(const MeshRenderData *mr, const BMVert *eve) -{ - const float(*vert_normals)[3] = mr->bm_vert_normals; - if (vert_normals != NULL) { - return vert_normals[BM_elem_index_get(eve)]; - } - - UNUSED_VARS(mr); - return eve->no; -} - -BLI_INLINE const float *bm_face_no_get(const MeshRenderData *mr, const BMFace *efa) -{ - const float(*poly_normals)[3] = mr->bm_poly_normals; - if (poly_normals != NULL) { - return poly_normals[BM_elem_index_get(efa)]; - } - - UNUSED_VARS(mr); - return efa->no; -} - -/** \} */ - -/* ---------------------------------------------------------------------- */ -/** \name Mesh Elements Extract Struct - * \{ */ - -/* TODO(jbakker): move parameters inside a struct. */ - -typedef void(ExtractTriBMeshFn)(const MeshRenderData *mr, BMLoop **elt, int elt_index, void *data); -typedef void(ExtractTriMeshFn)(const MeshRenderData *mr, - const MLoopTri *mlt, - int elt_index, - void *data); -typedef void(ExtractPolyBMeshFn)(const MeshRenderData *mr, - const BMFace *f, - int f_index, - void *data); -typedef void(ExtractPolyMeshFn)(const MeshRenderData *mr, - const MPoly *mp, - int mp_index, - void *data); -typedef void(ExtractLEdgeBMeshFn)(const MeshRenderData *mr, - const BMEdge *eed, - int ledge_index, - void *data); -typedef void(ExtractLEdgeMeshFn)(const MeshRenderData *mr, - const MEdge *med, - int ledge_index, - void *data); -typedef void(ExtractLVertBMeshFn)(const MeshRenderData *mr, - const BMVert *eve, - int lvert_index, - void *data); -typedef void(ExtractLVertMeshFn)(const MeshRenderData *mr, - const MVert *mv, - int lvert_index, - void *data); -typedef void(ExtractLooseGeomSubdivFn)(const struct DRWSubdivCache *subdiv_cache, - const MeshRenderData *mr, - void *buffer, - void *data); -typedef void(ExtractInitFn)(const MeshRenderData *mr, - struct MeshBatchCache *cache, - void *buffer, - void *r_data); -typedef void(ExtractFinishFn)(const MeshRenderData *mr, - struct MeshBatchCache *cache, - void *buffer, - void *data); -typedef void(ExtractTaskReduceFn)(void *userdata, void *task_userdata); - -typedef void(ExtractInitSubdivFn)(const struct DRWSubdivCache *subdiv_cache, - const MeshRenderData *mr, - struct MeshBatchCache *cache, - void *buf, - void *data); -typedef void(ExtractIterSubdivBMeshFn)(const struct DRWSubdivCache *subdiv_cache, - const MeshRenderData *mr, - void *data, - uint subdiv_quad_index, - const BMFace *coarse_quad); -typedef void(ExtractIterSubdivMeshFn)(const struct DRWSubdivCache *subdiv_cache, - const MeshRenderData *mr, - void *data, - uint subdiv_quad_index, - const MPoly *coarse_quad); -typedef void(ExtractFinishSubdivFn)(const struct DRWSubdivCache *subdiv_cache, - const MeshRenderData *mr, - struct MeshBatchCache *cache, - void *buf, - void *data); - -typedef struct MeshExtract { - /** Executed on main thread and return user data for iteration functions. */ - ExtractInitFn *init; - /** Executed on one (or more if use_threading) worker thread(s). */ - ExtractTriBMeshFn *iter_looptri_bm; - ExtractTriMeshFn *iter_looptri_mesh; - ExtractPolyBMeshFn *iter_poly_bm; - ExtractPolyMeshFn *iter_poly_mesh; - ExtractLEdgeBMeshFn *iter_ledge_bm; - ExtractLEdgeMeshFn *iter_ledge_mesh; - ExtractLVertBMeshFn *iter_lvert_bm; - ExtractLVertMeshFn *iter_lvert_mesh; - ExtractLooseGeomSubdivFn *iter_loose_geom_subdiv; - /** Executed on one worker thread after all elements iterations. */ - ExtractTaskReduceFn *task_reduce; - ExtractFinishFn *finish; - /** Executed on main thread for subdivision evaluation. */ - ExtractInitSubdivFn *init_subdiv; - ExtractIterSubdivBMeshFn *iter_subdiv_bm; - ExtractIterSubdivMeshFn *iter_subdiv_mesh; - ExtractFinishSubdivFn *finish_subdiv; - /** Used to request common data. */ - eMRDataType data_type; - size_t data_size; - /** Used to know if the element callbacks are thread-safe and can be parallelized. */ - bool use_threading; - /** - * Offset in bytes of the buffer inside a MeshBufferList instance. Points to a vertex or index - * buffer. - */ - size_t mesh_buffer_offset; -} MeshExtract; - -/** \} */ - -/* draw_cache_extract_mesh_render_data.c */ - -/** - * \param is_mode_active: When true, use the modifiers from the edit-data, - * otherwise don't use modifiers as they are not from this object. - */ -MeshRenderData *mesh_render_data_create(Object *object, - Mesh *me, - bool is_editmode, - bool is_paint_mode, - bool is_mode_active, - const float obmat[4][4], - bool do_final, - bool do_uvedit, - const ToolSettings *ts); -void mesh_render_data_free(MeshRenderData *mr); -void mesh_render_data_update_normals(MeshRenderData *mr, eMRDataType data_flag); -void mesh_render_data_update_loose_geom(MeshRenderData *mr, - MeshBufferCache *cache, - eMRIterType iter_type, - eMRDataType data_flag); -void mesh_render_data_update_polys_sorted(MeshRenderData *mr, - MeshBufferCache *cache, - eMRDataType data_flag); -/** - * Part of the creation of the #MeshRenderData that happens in a thread. - */ -void mesh_render_data_update_looptris(MeshRenderData *mr, - eMRIterType iter_type, - eMRDataType data_flag); - -/* draw_cache_extract_mesh_extractors.c */ - -typedef struct EditLoopData { - uchar v_flag; - uchar e_flag; - /* This is used for both vertex and edge creases. The edge crease value is stored in the bottom 4 - * bits, while the vertex crease is stored in the upper 4 bits. */ - uchar crease; - uchar bweight; -} EditLoopData; - -void *mesh_extract_buffer_get(const MeshExtract *extractor, MeshBufferList *mbuflist); -eMRIterType mesh_extract_iter_type(const MeshExtract *ext); -const MeshExtract *mesh_extract_override_get(const MeshExtract *extractor, - bool do_hq_normals, - bool do_single_mat); -void mesh_render_data_face_flag(const MeshRenderData *mr, - const BMFace *efa, - int cd_ofs, - EditLoopData *eattr); -void mesh_render_data_loop_flag(const MeshRenderData *mr, - BMLoop *l, - int cd_ofs, - EditLoopData *eattr); -void mesh_render_data_loop_edge_flag(const MeshRenderData *mr, - BMLoop *l, - int cd_ofs, - EditLoopData *eattr); - -extern const MeshExtract extract_tris; -extern const MeshExtract extract_tris_single_mat; -extern const MeshExtract extract_lines; -extern const MeshExtract extract_lines_with_lines_loose; -extern const MeshExtract extract_lines_loose_only; -extern const MeshExtract extract_points; -extern const MeshExtract extract_fdots; -extern const MeshExtract extract_lines_paint_mask; -extern const MeshExtract extract_lines_adjacency; -extern const MeshExtract extract_edituv_tris; -extern const MeshExtract extract_edituv_lines; -extern const MeshExtract extract_edituv_points; -extern const MeshExtract extract_edituv_fdots; -extern const MeshExtract extract_pos_nor; -extern const MeshExtract extract_pos_nor_hq; -extern const MeshExtract extract_lnor_hq; -extern const MeshExtract extract_lnor; -extern const MeshExtract extract_uv; -extern const MeshExtract extract_tan; -extern const MeshExtract extract_tan_hq; -extern const MeshExtract extract_sculpt_data; -extern const MeshExtract extract_vcol; -extern const MeshExtract extract_orco; -extern const MeshExtract extract_edge_fac; -extern const MeshExtract extract_weights; -extern const MeshExtract extract_edit_data; -extern const MeshExtract extract_edituv_data; -extern const MeshExtract extract_edituv_stretch_area; -extern const MeshExtract extract_edituv_stretch_angle; -extern const MeshExtract extract_mesh_analysis; -extern const MeshExtract extract_fdots_pos; -extern const MeshExtract extract_fdots_nor; -extern const MeshExtract extract_fdots_nor_hq; -extern const MeshExtract extract_fdots_uv; -extern const MeshExtract extract_fdots_edituv_data; -extern const MeshExtract extract_skin_roots; -extern const MeshExtract extract_poly_idx; -extern const MeshExtract extract_edge_idx; -extern const MeshExtract extract_vert_idx; -extern const MeshExtract extract_fdot_idx; -extern const MeshExtract extract_attr[GPU_MAX_ATTR]; - -#ifdef __cplusplus -} -#endif diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh.hh b/source/blender/draw/intern/mesh_extractors/extract_mesh.hh new file mode 100644 index 00000000000..bc97a62e4b1 --- /dev/null +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh.hh @@ -0,0 +1,357 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2021 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup draw + * + * \brief Extraction of Mesh data into VBO to feed to GPU. + */ + +#pragma once + +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" + +#include "BKE_customdata.h" +#include "BKE_editmesh.h" + +#include "draw_cache_extract.hh" + +struct DRWSubdivCache; + +#define MIN_RANGE_LEN 1024 + +/* ---------------------------------------------------------------------- */ +/** \name Mesh Render Data + * \{ */ + +enum eMRExtractType { + MR_EXTRACT_BMESH, + MR_EXTRACT_MAPPED, + MR_EXTRACT_MESH, +}; + +struct MeshRenderData { + eMRExtractType extract_type; + + int poly_len, edge_len, vert_len, loop_len; + int edge_loose_len; + int vert_loose_len; + int loop_loose_len; + int tri_len; + int mat_len; + + bool use_hide; + bool use_subsurf_fdots; + bool use_final_mesh; + + /** Use for #MeshStatVis calculation which use world-space coords. */ + float obmat[4][4]; + + const ToolSettings *toolsettings; + /** Edit Mesh */ + BMEditMesh *edit_bmesh; + BMesh *bm; + EditMeshData *edit_data; + + /* For deformed edit-mesh data. */ + /* Use for #ME_WRAPPER_TYPE_BMESH. */ + const float (*bm_vert_coords)[3]; + const float (*bm_vert_normals)[3]; + const float (*bm_poly_normals)[3]; + const float (*bm_poly_centers)[3]; + + const int *v_origindex, *e_origindex, *p_origindex; + int edge_crease_ofs; + int vert_crease_ofs; + int bweight_ofs; + int freestyle_edge_ofs; + int freestyle_face_ofs; + /** Mesh */ + Mesh *me; + const MVert *mvert; + const MEdge *medge; + const MLoop *mloop; + const MPoly *mpoly; + BMVert *eve_act; + BMEdge *eed_act; + BMFace *efa_act; + BMFace *efa_act_uv; + /* Data created on-demand (usually not for #BMesh based data). */ + MLoopTri *mlooptri; + const float (*vert_normals)[3]; + const float (*poly_normals)[3]; + float (*loop_normals)[3]; + int *lverts, *ledges; + + struct { + int *tri_first_index; + int *mat_tri_len; + int visible_tri_len; + } poly_sorted; +}; + +BLI_INLINE BMFace *bm_original_face_get(const MeshRenderData *mr, int idx) +{ + return ((mr->p_origindex != NULL) && (mr->p_origindex[idx] != ORIGINDEX_NONE) && mr->bm) ? + BM_face_at_index(mr->bm, mr->p_origindex[idx]) : + NULL; +} + +BLI_INLINE BMEdge *bm_original_edge_get(const MeshRenderData *mr, int idx) +{ + return ((mr->e_origindex != NULL) && (mr->e_origindex[idx] != ORIGINDEX_NONE) && mr->bm) ? + BM_edge_at_index(mr->bm, mr->e_origindex[idx]) : + NULL; +} + +BLI_INLINE BMVert *bm_original_vert_get(const MeshRenderData *mr, int idx) +{ + return ((mr->v_origindex != NULL) && (mr->v_origindex[idx] != ORIGINDEX_NONE) && mr->bm) ? + BM_vert_at_index(mr->bm, mr->v_origindex[idx]) : + NULL; +} + +BLI_INLINE const float *bm_vert_co_get(const MeshRenderData *mr, const BMVert *eve) +{ + const float(*vert_coords)[3] = mr->bm_vert_coords; + if (vert_coords != NULL) { + return vert_coords[BM_elem_index_get(eve)]; + } + + UNUSED_VARS(mr); + return eve->co; +} + +BLI_INLINE const float *bm_vert_no_get(const MeshRenderData *mr, const BMVert *eve) +{ + const float(*vert_normals)[3] = mr->bm_vert_normals; + if (vert_normals != NULL) { + return vert_normals[BM_elem_index_get(eve)]; + } + + UNUSED_VARS(mr); + return eve->no; +} + +BLI_INLINE const float *bm_face_no_get(const MeshRenderData *mr, const BMFace *efa) +{ + const float(*poly_normals)[3] = mr->bm_poly_normals; + if (poly_normals != NULL) { + return poly_normals[BM_elem_index_get(efa)]; + } + + UNUSED_VARS(mr); + return efa->no; +} + +/** \} */ + +/* ---------------------------------------------------------------------- */ +/** \name Mesh Elements Extract Struct + * \{ */ + +/* TODO(jbakker): move parameters inside a struct. */ + +using ExtractTriBMeshFn = void(const MeshRenderData *mr, BMLoop **elt, int elt_index, void *data); +using ExtractTriMeshFn = void(const MeshRenderData *mr, + const MLoopTri *mlt, + int elt_index, + void *data); +using ExtractPolyBMeshFn = void(const MeshRenderData *mr, + const BMFace *f, + int f_index, + void *data); +using ExtractPolyMeshFn = void(const MeshRenderData *mr, + const MPoly *mp, + int mp_index, + void *data); +using ExtractLEdgeBMeshFn = void(const MeshRenderData *mr, + const BMEdge *eed, + int ledge_index, + void *data); +using ExtractLEdgeMeshFn = void(const MeshRenderData *mr, + const MEdge *med, + int ledge_index, + void *data); +using ExtractLVertBMeshFn = void(const MeshRenderData *mr, + const BMVert *eve, + int lvert_index, + void *data); +using ExtractLVertMeshFn = void(const MeshRenderData *mr, + const MVert *mv, + int lvert_index, + void *data); +using ExtractLooseGeomSubdivFn = void(const struct DRWSubdivCache *subdiv_cache, + const MeshRenderData *mr, + void *buffer, + void *data); +using ExtractInitFn = void(const MeshRenderData *mr, + struct MeshBatchCache *cache, + void *buffer, + void *r_data); +using ExtractFinishFn = void(const MeshRenderData *mr, + struct MeshBatchCache *cache, + void *buffer, + void *data); +using ExtractTaskReduceFn = void(void *userdata, void *task_userdata); + +using ExtractInitSubdivFn = void(const struct DRWSubdivCache *subdiv_cache, + const MeshRenderData *mr, + struct MeshBatchCache *cache, + void *buf, + void *data); +using ExtractIterSubdivBMeshFn = void(const struct DRWSubdivCache *subdiv_cache, + const MeshRenderData *mr, + void *data, + uint subdiv_quad_index, + const BMFace *coarse_quad); +using ExtractIterSubdivMeshFn = void(const struct DRWSubdivCache *subdiv_cache, + const MeshRenderData *mr, + void *data, + uint subdiv_quad_index, + const MPoly *coarse_quad); +using ExtractFinishSubdivFn = void(const struct DRWSubdivCache *subdiv_cache, + const MeshRenderData *mr, + struct MeshBatchCache *cache, + void *buf, + void *data); + +struct MeshExtract { + /** Executed on main thread and return user data for iteration functions. */ + ExtractInitFn *init; + /** Executed on one (or more if use_threading) worker thread(s). */ + ExtractTriBMeshFn *iter_looptri_bm; + ExtractTriMeshFn *iter_looptri_mesh; + ExtractPolyBMeshFn *iter_poly_bm; + ExtractPolyMeshFn *iter_poly_mesh; + ExtractLEdgeBMeshFn *iter_ledge_bm; + ExtractLEdgeMeshFn *iter_ledge_mesh; + ExtractLVertBMeshFn *iter_lvert_bm; + ExtractLVertMeshFn *iter_lvert_mesh; + ExtractLooseGeomSubdivFn *iter_loose_geom_subdiv; + /** Executed on one worker thread after all elements iterations. */ + ExtractTaskReduceFn *task_reduce; + ExtractFinishFn *finish; + /** Executed on main thread for subdivision evaluation. */ + ExtractInitSubdivFn *init_subdiv; + ExtractIterSubdivBMeshFn *iter_subdiv_bm; + ExtractIterSubdivMeshFn *iter_subdiv_mesh; + ExtractFinishSubdivFn *finish_subdiv; + /** Used to request common data. */ + eMRDataType data_type; + size_t data_size; + /** Used to know if the element callbacks are thread-safe and can be parallelized. */ + bool use_threading; + /** + * Offset in bytes of the buffer inside a MeshBufferList instance. Points to a vertex or index + * buffer. + */ + size_t mesh_buffer_offset; +}; + +/** \} */ + +/* draw_cache_extract_mesh_render_data.c */ + +/** + * \param is_mode_active: When true, use the modifiers from the edit-data, + * otherwise don't use modifiers as they are not from this object. + */ +MeshRenderData *mesh_render_data_create(Object *object, + Mesh *me, + bool is_editmode, + bool is_paint_mode, + bool is_mode_active, + const float obmat[4][4], + bool do_final, + bool do_uvedit, + const ToolSettings *ts); +void mesh_render_data_free(MeshRenderData *mr); +void mesh_render_data_update_normals(MeshRenderData *mr, eMRDataType data_flag); +void mesh_render_data_update_loose_geom(MeshRenderData *mr, + MeshBufferCache *cache, + eMRIterType iter_type, + eMRDataType data_flag); +void mesh_render_data_update_polys_sorted(MeshRenderData *mr, + MeshBufferCache *cache, + eMRDataType data_flag); +/** + * Part of the creation of the #MeshRenderData that happens in a thread. + */ +void mesh_render_data_update_looptris(MeshRenderData *mr, + eMRIterType iter_type, + eMRDataType data_flag); + +/* draw_cache_extract_mesh_extractors.c */ + +struct EditLoopData { + uchar v_flag; + uchar e_flag; + /* This is used for both vertex and edge creases. The edge crease value is stored in the bottom 4 + * bits, while the vertex crease is stored in the upper 4 bits. */ + uchar crease; + uchar bweight; +}; + +void *mesh_extract_buffer_get(const MeshExtract *extractor, MeshBufferList *mbuflist); +eMRIterType mesh_extract_iter_type(const MeshExtract *ext); +const MeshExtract *mesh_extract_override_get(const MeshExtract *extractor, + bool do_hq_normals, + bool do_single_mat); +void mesh_render_data_face_flag(const MeshRenderData *mr, + const BMFace *efa, + int cd_ofs, + EditLoopData *eattr); +void mesh_render_data_loop_flag(const MeshRenderData *mr, + BMLoop *l, + int cd_ofs, + EditLoopData *eattr); +void mesh_render_data_loop_edge_flag(const MeshRenderData *mr, + BMLoop *l, + int cd_ofs, + EditLoopData *eattr); + +extern const MeshExtract extract_tris; +extern const MeshExtract extract_tris_single_mat; +extern const MeshExtract extract_lines; +extern const MeshExtract extract_lines_with_lines_loose; +extern const MeshExtract extract_lines_loose_only; +extern const MeshExtract extract_points; +extern const MeshExtract extract_fdots; +extern const MeshExtract extract_lines_paint_mask; +extern const MeshExtract extract_lines_adjacency; +extern const MeshExtract extract_edituv_tris; +extern const MeshExtract extract_edituv_lines; +extern const MeshExtract extract_edituv_points; +extern const MeshExtract extract_edituv_fdots; +extern const MeshExtract extract_pos_nor; +extern const MeshExtract extract_pos_nor_hq; +extern const MeshExtract extract_lnor_hq; +extern const MeshExtract extract_lnor; +extern const MeshExtract extract_uv; +extern const MeshExtract extract_tan; +extern const MeshExtract extract_tan_hq; +extern const MeshExtract extract_sculpt_data; +extern const MeshExtract extract_vcol; +extern const MeshExtract extract_orco; +extern const MeshExtract extract_edge_fac; +extern const MeshExtract extract_weights; +extern const MeshExtract extract_edit_data; +extern const MeshExtract extract_edituv_data; +extern const MeshExtract extract_edituv_stretch_area; +extern const MeshExtract extract_edituv_stretch_angle; +extern const MeshExtract extract_mesh_analysis; +extern const MeshExtract extract_fdots_pos; +extern const MeshExtract extract_fdots_nor; +extern const MeshExtract extract_fdots_nor_hq; +extern const MeshExtract extract_fdots_uv; +extern const MeshExtract extract_fdots_edituv_data; +extern const MeshExtract extract_skin_roots; +extern const MeshExtract extract_poly_idx; +extern const MeshExtract extract_edge_idx; +extern const MeshExtract extract_vert_idx; +extern const MeshExtract extract_fdot_idx; +extern const MeshExtract extract_attr[GPU_MAX_ATTR]; diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_edituv.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_edituv.cc index 2c4e7bfa802..9824602b129 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_edituv.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_edituv.cc @@ -7,7 +7,7 @@ #include "BLI_bitmap.h" -#include "extract_mesh.h" +#include "extract_mesh.hh" #include "draw_subdivision.h" @@ -584,9 +584,7 @@ constexpr MeshExtract create_extractor_edituv_fdots() } // namespace blender::draw -extern "C" { const MeshExtract extract_edituv_tris = blender::draw::create_extractor_edituv_tris(); const MeshExtract extract_edituv_lines = blender::draw::create_extractor_edituv_lines(); const MeshExtract extract_edituv_points = blender::draw::create_extractor_edituv_points(); const MeshExtract extract_edituv_fdots = blender::draw::create_extractor_edituv_fdots(); -} diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_fdots.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_fdots.cc index 4bf732caf0a..4eebea1b79f 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_fdots.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_fdots.cc @@ -7,7 +7,7 @@ #include "BLI_bitmap.h" -#include "extract_mesh.h" +#include "extract_mesh.hh" namespace blender::draw { /* ---------------------------------------------------------------------- */ @@ -95,6 +95,4 @@ constexpr MeshExtract create_extractor_fdots() } // namespace blender::draw -extern "C" { const MeshExtract extract_fdots = blender::draw::create_extractor_fdots(); -} diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines.cc index 3cecaf81b8a..7d584824045 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines.cc @@ -7,7 +7,7 @@ #include "MEM_guardedalloc.h" -#include "extract_mesh.h" +#include "extract_mesh.hh" #include "draw_subdivision.h" @@ -320,9 +320,7 @@ constexpr MeshExtract create_extractor_lines_loose_only() } // namespace blender::draw -extern "C" { const MeshExtract extract_lines = blender::draw::create_extractor_lines(); const MeshExtract extract_lines_with_lines_loose = blender::draw::create_extractor_lines_with_lines_loose(); const MeshExtract extract_lines_loose_only = blender::draw::create_extractor_lines_loose_only(); -} diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_adjacency.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_adjacency.cc index de464fb286f..9ba9453dada 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_adjacency.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_adjacency.cc @@ -11,7 +11,7 @@ #include "MEM_guardedalloc.h" #include "draw_subdivision.h" -#include "extract_mesh.h" +#include "extract_mesh.hh" namespace blender::draw { @@ -253,6 +253,4 @@ constexpr MeshExtract create_extractor_lines_adjacency() } // namespace blender::draw -extern "C" { const MeshExtract extract_lines_adjacency = blender::draw::create_extractor_lines_adjacency(); -} diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_paint_mask.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_paint_mask.cc index 286c7ea9c43..713a533492f 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_paint_mask.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_paint_mask.cc @@ -12,7 +12,7 @@ #include "MEM_guardedalloc.h" #include "draw_subdivision.h" -#include "extract_mesh.h" +#include "extract_mesh.hh" namespace blender::draw { /* ---------------------------------------------------------------------- */ @@ -181,6 +181,4 @@ constexpr MeshExtract create_extractor_lines_paint_mask() } // namespace blender::draw -extern "C" { const MeshExtract extract_lines_paint_mask = blender::draw::create_extractor_lines_paint_mask(); -} diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_points.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_points.cc index 503ce0e79e9..e746b37fd30 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_points.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_points.cc @@ -10,7 +10,7 @@ #include "MEM_guardedalloc.h" #include "draw_subdivision.h" -#include "extract_mesh.h" +#include "extract_mesh.hh" namespace blender::draw { @@ -322,6 +322,4 @@ constexpr MeshExtract create_extractor_points() } // namespace blender::draw -extern "C" { const MeshExtract extract_points = blender::draw::create_extractor_points(); -} diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_tris.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_tris.cc index 6ca5692f387..4c8d1d0002a 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_tris.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_tris.cc @@ -7,7 +7,7 @@ #include "MEM_guardedalloc.h" -#include "extract_mesh.h" +#include "extract_mesh.hh" #include "draw_subdivision.h" @@ -243,7 +243,5 @@ constexpr MeshExtract create_extractor_tris_single_mat() } // namespace blender::draw -extern "C" { const MeshExtract extract_tris = blender::draw::create_extractor_tris(); const MeshExtract extract_tris_single_mat = blender::draw::create_extractor_tris_single_mat(); -} diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc index fa41facb751..5f07f8dfb72 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc @@ -16,7 +16,7 @@ #include "draw_attributes.h" #include "draw_subdivision.h" -#include "extract_mesh.h" +#include "extract_mesh.hh" namespace blender::draw { @@ -447,7 +447,6 @@ constexpr MeshExtract create_extractor_attr(ExtractInitFn fn, ExtractInitSubdivF } // namespace blender::draw -extern "C" { #define CREATE_EXTRACTOR_ATTR(index) \ blender::draw::create_extractor_attr(blender::draw::extract_attr_init##index, \ blender::draw::extract_attr_init_subdiv##index) @@ -469,4 +468,3 @@ const MeshExtract extract_attr[GPU_MAX_ATTR] = { CREATE_EXTRACTOR_ATTR(13), CREATE_EXTRACTOR_ATTR(14), }; -} diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edge_fac.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edge_fac.cc index f3b41efe1c3..a11f740239a 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edge_fac.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edge_fac.cc @@ -10,7 +10,7 @@ #include "GPU_capabilities.h" #include "draw_subdivision.h" -#include "extract_mesh.h" +#include "extract_mesh.hh" namespace blender::draw { @@ -303,6 +303,4 @@ constexpr MeshExtract create_extractor_edge_fac() } // namespace blender::draw -extern "C" { const MeshExtract extract_edge_fac = blender::draw::create_extractor_edge_fac(); -} diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edit_data.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edit_data.cc index 1e158a7e6d7..3bb706e82cd 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edit_data.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edit_data.cc @@ -5,7 +5,7 @@ * \ingroup draw */ -#include "extract_mesh.h" +#include "extract_mesh.hh" #include "draw_cache_impl.h" @@ -367,6 +367,4 @@ constexpr MeshExtract create_extractor_edit_data() } // namespace blender::draw -extern "C" { const MeshExtract extract_edit_data = blender::draw::create_extractor_edit_data(); -} diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_data.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_data.cc index f79fe345f5a..6d54fce2a0d 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_data.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_data.cc @@ -5,7 +5,7 @@ * \ingroup draw */ -#include "extract_mesh.h" +#include "extract_mesh.hh" #include "draw_cache_impl.h" @@ -199,6 +199,4 @@ constexpr MeshExtract create_extractor_edituv_data() } // namespace blender::draw -extern "C" { const MeshExtract extract_edituv_data = blender::draw::create_extractor_edituv_data(); -} diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_angle.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_angle.cc index fb4b95885fc..5d6dd14b57a 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_angle.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_angle.cc @@ -9,7 +9,7 @@ #include "BKE_mesh.h" -#include "extract_mesh.h" +#include "extract_mesh.hh" #include "draw_subdivision.h" @@ -292,7 +292,5 @@ constexpr MeshExtract create_extractor_edituv_edituv_stretch_angle() } // namespace blender::draw -extern "C" { const MeshExtract extract_edituv_stretch_angle = blender::draw::create_extractor_edituv_edituv_stretch_angle(); -} diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_area.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_area.cc index ab397cc1717..70dcc24f946 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_area.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_area.cc @@ -9,7 +9,7 @@ #include "BKE_mesh.h" -#include "extract_mesh.h" +#include "extract_mesh.hh" #include "draw_subdivision.h" @@ -180,7 +180,5 @@ constexpr MeshExtract create_extractor_edituv_stretch_area() } // namespace blender::draw -extern "C" { const MeshExtract extract_edituv_stretch_area = blender::draw::create_extractor_edituv_stretch_area(); -} diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_edituv_data.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_edituv_data.cc index 1c4f6112877..64bec0adad4 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_edituv_data.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_edituv_data.cc @@ -5,7 +5,7 @@ * \ingroup draw */ -#include "extract_mesh.h" +#include "extract_mesh.hh" #include "draw_cache_impl.h" @@ -81,6 +81,4 @@ constexpr MeshExtract create_extractor_fdots_edituv_data() } // namespace blender::draw -extern "C" { const MeshExtract extract_fdots_edituv_data = blender::draw::create_extractor_fdots_edituv_data(); -} diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_nor.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_nor.cc index 909c9ac2300..8d189db9f12 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_nor.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_nor.cc @@ -5,7 +5,7 @@ * \ingroup draw */ -#include "extract_mesh.h" +#include "extract_mesh.hh" namespace blender::draw { @@ -180,7 +180,5 @@ constexpr MeshExtract create_extractor_fdots_nor_hq() } // namespace blender::draw -extern "C" { const MeshExtract extract_fdots_nor = blender::draw::create_extractor_fdots_nor(); const MeshExtract extract_fdots_nor_hq = blender::draw::create_extractor_fdots_nor_hq(); -} diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_pos.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_pos.cc index 1671a1cd1e7..822b5928c49 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_pos.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_pos.cc @@ -7,7 +7,7 @@ #include "BLI_bitmap.h" -#include "extract_mesh.h" +#include "extract_mesh.hh" #include "draw_subdivision.h" @@ -139,6 +139,4 @@ constexpr MeshExtract create_extractor_fdots_pos() } // namespace blender::draw -extern "C" { const MeshExtract extract_fdots_pos = blender::draw::create_extractor_fdots_pos(); -} diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_uv.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_uv.cc index e7a3cb03903..de21c63e5fd 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_uv.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_uv.cc @@ -7,7 +7,7 @@ #include "BLI_bitmap.h" -#include "extract_mesh.h" +#include "extract_mesh.hh" namespace blender::draw { @@ -109,6 +109,4 @@ constexpr MeshExtract create_extractor_fdots_uv() } // namespace blender::draw -extern "C" { const MeshExtract extract_fdots_uv = blender::draw::create_extractor_fdots_uv(); -} diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_lnor.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_lnor.cc index 8bc8b32fdf3..42a9a58bbe4 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_lnor.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_lnor.cc @@ -5,7 +5,7 @@ * \ingroup draw */ -#include "extract_mesh.h" +#include "extract_mesh.hh" #include "draw_subdivision.h" @@ -234,7 +234,5 @@ constexpr MeshExtract create_extractor_lnor_hq() } // namespace blender::draw -extern "C" { const MeshExtract extract_lnor = blender::draw::create_extractor_lnor(); const MeshExtract extract_lnor_hq = blender::draw::create_extractor_lnor_hq(); -} diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_mesh_analysis.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_mesh_analysis.cc index 968c1f693fb..b57e2f6b807 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_mesh_analysis.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_mesh_analysis.cc @@ -14,7 +14,7 @@ #include "BKE_editmesh_bvh.h" #include "BKE_editmesh_cache.h" -#include "extract_mesh.h" +#include "extract_mesh.hh" namespace blender::draw { @@ -633,6 +633,4 @@ constexpr MeshExtract create_extractor_mesh_analysis() } // namespace blender::draw -extern "C" { const MeshExtract extract_mesh_analysis = blender::draw::create_extractor_mesh_analysis(); -} diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_orco.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_orco.cc index 94674a54f12..68d838e9e62 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_orco.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_orco.cc @@ -5,7 +5,7 @@ * \ingroup draw */ -#include "extract_mesh.h" +#include "extract_mesh.hh" namespace blender::draw { @@ -94,6 +94,4 @@ constexpr MeshExtract create_extractor_orco() } // namespace blender::draw -extern "C" { const MeshExtract extract_orco = blender::draw::create_extractor_orco(); -} diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_pos_nor.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_pos_nor.cc index 5c0116f08d7..313744bdd27 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_pos_nor.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_pos_nor.cc @@ -7,7 +7,7 @@ #include "MEM_guardedalloc.h" -#include "extract_mesh.h" +#include "extract_mesh.hh" #include "draw_subdivision.h" @@ -552,7 +552,5 @@ constexpr MeshExtract create_extractor_pos_nor_hq() } // namespace blender::draw -extern "C" { const MeshExtract extract_pos_nor = blender::draw::create_extractor_pos_nor(); const MeshExtract extract_pos_nor_hq = blender::draw::create_extractor_pos_nor_hq(); -} diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_sculpt_data.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_sculpt_data.cc index 5658ed85c8b..0d959e324f8 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_sculpt_data.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_sculpt_data.cc @@ -12,7 +12,7 @@ #include "BKE_paint.h" #include "draw_subdivision.h" -#include "extract_mesh.h" +#include "extract_mesh.hh" namespace blender::draw { @@ -215,6 +215,4 @@ constexpr MeshExtract create_extractor_sculpt_data() } // namespace blender::draw -extern "C" { const MeshExtract extract_sculpt_data = blender::draw::create_extractor_sculpt_data(); -} diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_select_idx.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_select_idx.cc index f4c54b2f881..6230e1974be 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_select_idx.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_select_idx.cc @@ -6,7 +6,7 @@ */ #include "draw_subdivision.h" -#include "extract_mesh.h" +#include "extract_mesh.hh" namespace blender::draw { @@ -411,9 +411,7 @@ constexpr MeshExtract create_extractor_fdot_idx() } // namespace blender::draw -extern "C" { const MeshExtract extract_poly_idx = blender::draw::create_extractor_poly_idx(); const MeshExtract extract_edge_idx = blender::draw::create_extractor_edge_idx(); const MeshExtract extract_vert_idx = blender::draw::create_extractor_vert_idx(); const MeshExtract extract_fdot_idx = blender::draw::create_extractor_fdot_idx(); -} diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_skin_roots.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_skin_roots.cc index bb6331dd377..a275f247cad 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_skin_roots.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_skin_roots.cc @@ -5,7 +5,7 @@ * \ingroup draw */ -#include "extract_mesh.h" +#include "extract_mesh.hh" namespace blender::draw { @@ -72,6 +72,4 @@ constexpr MeshExtract create_extractor_skin_roots() } // namespace blender::draw -extern "C" { const MeshExtract extract_skin_roots = blender::draw::create_extractor_skin_roots(); -} diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_tan.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_tan.cc index 91cd675d32f..83453d6ef38 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_tan.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_tan.cc @@ -14,7 +14,7 @@ #include "BKE_mesh.h" #include "BKE_mesh_tangent.h" -#include "extract_mesh.h" +#include "extract_mesh.hh" #include "draw_subdivision.h" @@ -367,7 +367,5 @@ constexpr MeshExtract create_extractor_tan_hq() } // namespace blender::draw -extern "C" { const MeshExtract extract_tan = blender::draw::create_extractor_tan(); const MeshExtract extract_tan_hq = blender::draw::create_extractor_tan_hq(); -} diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_uv.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_uv.cc index 2808a0a3a71..ddb8ed9b25b 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_uv.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_uv.cc @@ -8,7 +8,7 @@ #include "BLI_string.h" #include "draw_subdivision.h" -#include "extract_mesh.h" +#include "extract_mesh.hh" namespace blender::draw { @@ -168,6 +168,4 @@ constexpr MeshExtract create_extractor_uv() } // namespace blender::draw -extern "C" { const MeshExtract extract_uv = blender::draw::create_extractor_uv(); -} diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_vcol.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_vcol.cc index 91ac3f22617..0e192e34dff 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_vcol.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_vcol.cc @@ -12,7 +12,7 @@ #include "BLI_vector.hh" #include "draw_subdivision.h" -#include "extract_mesh.h" +#include "extract_mesh.hh" struct VColRef { const CustomDataLayer *layer; @@ -380,6 +380,4 @@ constexpr MeshExtract create_extractor_vcol() } // namespace blender::draw -extern "C" { const MeshExtract extract_vcol = blender::draw::create_extractor_vcol(); -} diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_weights.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_weights.cc index 89aa16ca0c7..c64cca4dff5 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_weights.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_weights.cc @@ -10,7 +10,7 @@ #include "BKE_deform.h" #include "draw_subdivision.h" -#include "extract_mesh.h" +#include "extract_mesh.hh" namespace blender::draw { @@ -208,6 +208,4 @@ constexpr MeshExtract create_extractor_weights() } // namespace blender::draw -extern "C" { const MeshExtract extract_weights = blender::draw::create_extractor_weights(); -} diff --git a/source/blender/gpu/intern/gpu_node_graph.c b/source/blender/gpu/intern/gpu_node_graph.c index cac6f7cb38b..3c6a03c56d3 100644 --- a/source/blender/gpu/intern/gpu_node_graph.c +++ b/source/blender/gpu/intern/gpu_node_graph.c @@ -347,7 +347,7 @@ static char attr_prefix_get(eCustomDataType type) static void attr_input_name(GPUMaterialAttribute *attr) { - /* NOTE: Replicate changes to mesh_render_data_create() in draw_cache_impl_mesh.c */ + /* NOTE: Replicate changes to mesh_render_data_create() in draw_cache_impl_mesh.cc */ if (attr->type == CD_ORCO) { /* OPTI: orco is computed from local positions, but only if no modifier is present. */ STRNCPY(attr->input_name, "orco"); diff --git a/source/blender/makesdna/DNA_mesh_types.h b/source/blender/makesdna/DNA_mesh_types.h index 4a57f60be26..a66badb4a68 100644 --- a/source/blender/makesdna/DNA_mesh_types.h +++ b/source/blender/makesdna/DNA_mesh_types.h @@ -83,7 +83,7 @@ typedef struct Mesh_Runtime { /** * Data used to efficiently draw the mesh in the viewport, especially useful when - * the same mesh is used in many objects or instances. See `draw_cache_impl_mesh.c`. + * the same mesh is used in many objects or instances. See `draw_cache_impl_mesh.cc`. */ void *batch_cache; -- cgit v1.2.3