diff options
author | Hans Goudey <h.goudey@me.com> | 2022-06-05 13:04:42 +0300 |
---|---|---|
committer | Hans Goudey <h.goudey@me.com> | 2022-06-05 13:04:58 +0300 |
commit | 176d7bcc2eb47b9820861037f90a7fb26de8c9a0 (patch) | |
tree | 6ca43f27d9ab8ad4a711a9d58214324c24dd7351 /source/blender/draw/intern/draw_cache_extract.hh | |
parent | 31da775ec292731790e79d09b76e92ae36ac34f3 (diff) |
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
Diffstat (limited to 'source/blender/draw/intern/draw_cache_extract.hh')
-rw-r--r-- | source/blender/draw/intern/draw_cache_extract.hh | 353 |
1 files changed, 353 insertions, 0 deletions
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 <algorithm> + +#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<int>(1, editmesh_eval_final->totcol); + } + } + return std::max<int>(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 |