Implements another phase of #116901, this time for the `lines` and `lines_loose` index buffers that store indices for wireframe drawing. The key improvement is removing loose edge's dependency on the main edge index buffer. That means for the majority of meshes with no loose edges, edge index extraction can be completely skipped. Even when there are loose edges, only the loose edges need to be extracted with wireframe turned off. Besides that improvement, there are more changes to use data-oriented code with visible hot loops instead of the virtual function call design used for the existing mesh extractor system. For this step I completely replaced the `extract_lines` object, which is in line with the general plan for this area. Additionally, hidden edge filtering is done ahead of time using several `IndexMask` operations. This means only indices for visible edges need to be uploaded to the GPU, and no restart index stripping needs to be performed on macOS. On my usual test file with 1.9 million vertices, I observed an improvement from 26 to 33 FPS with wireframe off, and from 9.15 to 9.5 FPS with wireframe on. Pull Request: https://projects.blender.org/blender/blender/pulls/120720
313 lines
11 KiB
C++
313 lines
11 KiB
C++
/* SPDX-FileCopyrightText: 2021 Blender Authors
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
|
|
#pragma once
|
|
|
|
#include "BLI_math_matrix_types.hh"
|
|
#include "BLI_span.hh"
|
|
#include "BLI_sys_types.h"
|
|
|
|
struct BMesh;
|
|
struct GPUUniformBuf;
|
|
namespace blender::gpu {
|
|
class IndexBuf;
|
|
class VertBuf;
|
|
} // namespace blender::gpu
|
|
struct GPUVertFormat;
|
|
struct Mesh;
|
|
struct Object;
|
|
namespace blender::bke::subdiv {
|
|
struct Subdiv;
|
|
}
|
|
struct ToolSettings;
|
|
|
|
namespace blender::draw {
|
|
|
|
struct MeshBatchCache;
|
|
struct MeshBufferCache;
|
|
struct MeshRenderData;
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/** \name DRWPatchMap
|
|
*
|
|
* This is a GPU version of the OpenSubDiv PatchMap. The quad tree and the patch handles are copied
|
|
* to GPU buffers in order to lookup the right patch for a given set of patch coordinates.
|
|
* \{ */
|
|
|
|
struct DRWPatchMap {
|
|
gpu::VertBuf *patch_map_handles;
|
|
gpu::VertBuf *patch_map_quadtree;
|
|
int min_patch_face;
|
|
int max_patch_face;
|
|
int max_depth;
|
|
int patches_are_triangular;
|
|
};
|
|
|
|
/** \} */
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/** \name DRWSubdivLooseEdge
|
|
*
|
|
* This stores information about a subdivided loose edge.
|
|
* \{ */
|
|
|
|
struct DRWSubdivLooseEdge {
|
|
/* The corresponding coarse edge, this is always valid. */
|
|
int coarse_edge_index;
|
|
/* Pointers into #DRWSubdivLooseGeom.verts. */
|
|
int loose_subdiv_v1_index;
|
|
int loose_subdiv_v2_index;
|
|
};
|
|
|
|
/** \} */
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/** \name DRWSubdivLooseVertex
|
|
*
|
|
* This stores information about a subdivided loose vertex, that may or may not come from a loose
|
|
* edge.
|
|
* \{ */
|
|
|
|
struct DRWSubdivLooseVertex {
|
|
/* The corresponding coarse vertex, or -1 if this vertex is the result
|
|
* of subdivision. */
|
|
unsigned int coarse_vertex_index;
|
|
/* Position and normal of the vertex. */
|
|
float co[3];
|
|
float nor[3];
|
|
};
|
|
|
|
/** \} */
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/** \name DRWSubdivLooseGeom
|
|
*
|
|
* This stores the subdivided vertices and edges of loose geometry from #MeshExtractLooseGeom.
|
|
* \{ */
|
|
|
|
struct DRWSubdivLooseGeom {
|
|
DRWSubdivLooseEdge *edges;
|
|
DRWSubdivLooseVertex *verts;
|
|
int edge_len;
|
|
int vert_len;
|
|
int loop_len;
|
|
};
|
|
|
|
/** \} */
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/** \name DRWSubdivCache
|
|
*
|
|
* This holds the various buffers used to evaluate and render subdivision through OpenGL.
|
|
* \{ */
|
|
|
|
struct DRWSubdivCache {
|
|
const Mesh *mesh;
|
|
BMesh *bm;
|
|
bke::subdiv::Subdiv *subdiv;
|
|
bool optimal_display;
|
|
bool hide_unmapped_edges;
|
|
bool use_custom_loop_normals;
|
|
|
|
/* Coordinates used to evaluate patches for positions and normals. */
|
|
gpu::VertBuf *patch_coords;
|
|
/* Coordinates used to evaluate patches for attributes. */
|
|
gpu::VertBuf *corner_patch_coords;
|
|
/* Coordinates used to evaluate patches for the face centers (or face dots) in edit-mode. */
|
|
gpu::VertBuf *fdots_patch_coords;
|
|
|
|
/* Resolution used to generate the patch coordinates. */
|
|
int resolution;
|
|
|
|
/* Number of subdivided loops, also the number of patch coordinates since we have one coordinate
|
|
* but quad corner/vertex. */
|
|
uint num_subdiv_loops;
|
|
uint num_subdiv_edges;
|
|
uint num_subdiv_triangles;
|
|
uint num_subdiv_verts;
|
|
uint num_subdiv_quads;
|
|
|
|
/* We only do the subdivision traversal for full faces, however we may have geometries that only
|
|
* have loose edges (e.g. a custom bone shape). This flag is used to detect those cases, as the
|
|
* counters above will all be set to zero if we do not have subdivision loops. */
|
|
bool may_have_loose_geom;
|
|
|
|
/* Number of faces in the coarse mesh, notably used to compute a coarse face index given a
|
|
* subdivision loop index. */
|
|
int num_coarse_faces;
|
|
|
|
/* Maps subdivision loop to subdivided vertex index. */
|
|
int *subdiv_loop_subdiv_vert_index;
|
|
/* Maps subdivision loop to subdivided edge index. */
|
|
int *subdiv_loop_subdiv_edge_index;
|
|
/* Maps subdivision loop to original coarse face index. */
|
|
int *subdiv_loop_face_index;
|
|
|
|
/* Indices of faces adjacent to the vertices, ordered by vertex index, with no particular
|
|
* winding. */
|
|
gpu::VertBuf *subdiv_vertex_face_adjacency;
|
|
/* The difference between value (i + 1) and (i) gives the number of faces adjacent to vertex (i).
|
|
*/
|
|
gpu::VertBuf *subdiv_vertex_face_adjacency_offsets;
|
|
|
|
/* Maps subdivision loop to original coarse vertex index, only really useful for edit mode. */
|
|
gpu::VertBuf *verts_orig_index;
|
|
/* Maps subdivision loop to original coarse edge index, only really useful for edit mode. */
|
|
gpu::VertBuf *edges_orig_index;
|
|
/* Indicates if edge should be drawn in optimal display mode. */
|
|
gpu::VertBuf *edges_draw_flag;
|
|
|
|
/* Owned by #Subdiv. Indexed by coarse face index, difference between value (i + 1) and (i)
|
|
* gives the number of ptex faces for coarse face (i). */
|
|
int *face_ptex_offset;
|
|
/* Vertex buffer for face_ptex_offset. */
|
|
gpu::VertBuf *face_ptex_offset_buffer;
|
|
|
|
int *subdiv_face_offset;
|
|
gpu::VertBuf *subdiv_face_offset_buffer;
|
|
|
|
/* Contains the start loop index and the smooth flag for each coarse face. */
|
|
gpu::VertBuf *extra_coarse_face_data;
|
|
|
|
/* Computed for `ibo.points`, one value per subdivided vertex,
|
|
* mapping coarse vertices -> subdivided loop. */
|
|
int *point_indices;
|
|
|
|
/* Material offsets. */
|
|
int *mat_start;
|
|
int *mat_end;
|
|
gpu::VertBuf *face_mat_offset;
|
|
|
|
DRWPatchMap gpu_patch_map;
|
|
|
|
DRWSubdivLooseGeom loose_geom;
|
|
|
|
/* UBO to store settings for the various compute shaders. */
|
|
GPUUniformBuf *ubo;
|
|
|
|
/* Extra flags, passed to the UBO. */
|
|
bool is_edit_mode;
|
|
bool use_hide;
|
|
};
|
|
|
|
/* Only frees the data of the cache, caller is responsible to free the cache itself if necessary.
|
|
*/
|
|
void draw_subdiv_cache_free(DRWSubdivCache &cache);
|
|
|
|
/** \} */
|
|
|
|
void DRW_create_subdivision(Object *ob,
|
|
Mesh *mesh,
|
|
MeshBatchCache &batch_cache,
|
|
MeshBufferCache *mbc,
|
|
bool is_editmode,
|
|
bool is_paint_mode,
|
|
bool edit_mode_active,
|
|
const float4x4 &object_to_world,
|
|
bool do_final,
|
|
bool do_uvedit,
|
|
bool do_cage,
|
|
const ToolSettings *ts,
|
|
bool use_hide);
|
|
|
|
void DRW_subdivide_loose_geom(DRWSubdivCache *subdiv_cache, MeshBufferCache *cache);
|
|
|
|
void DRW_subdiv_cache_free(bke::subdiv::Subdiv *subdiv);
|
|
|
|
void draw_subdiv_init_origindex_buffer(gpu::VertBuf *buffer,
|
|
int32_t *vert_origindex,
|
|
uint num_loops,
|
|
uint loose_len);
|
|
|
|
gpu::VertBuf *draw_subdiv_build_origindex_buffer(int *vert_origindex, uint num_loops);
|
|
|
|
/* Compute shader functions. */
|
|
|
|
void draw_subdiv_build_sculpt_data_buffer(const DRWSubdivCache &cache,
|
|
gpu::VertBuf *mask_vbo,
|
|
gpu::VertBuf *face_set_vbo,
|
|
gpu::VertBuf *sculpt_data);
|
|
|
|
void draw_subdiv_accumulate_normals(const DRWSubdivCache &cache,
|
|
gpu::VertBuf *pos_nor,
|
|
gpu::VertBuf *face_adjacency_offsets,
|
|
gpu::VertBuf *face_adjacency_lists,
|
|
gpu::VertBuf *vertex_loop_map,
|
|
gpu::VertBuf *vert_normals);
|
|
|
|
void draw_subdiv_finalize_normals(const DRWSubdivCache &cache,
|
|
gpu::VertBuf *vert_normals,
|
|
gpu::VertBuf *subdiv_loop_subdiv_vert_index,
|
|
gpu::VertBuf *pos_nor);
|
|
|
|
void draw_subdiv_finalize_custom_normals(const DRWSubdivCache &cache,
|
|
gpu::VertBuf *src_custom_normals,
|
|
gpu::VertBuf *pos_nor);
|
|
|
|
void draw_subdiv_extract_pos_nor(const DRWSubdivCache &cache,
|
|
gpu::VertBuf *flags_buffer,
|
|
gpu::VertBuf *pos_nor,
|
|
gpu::VertBuf *orco);
|
|
|
|
void draw_subdiv_interp_custom_data(const DRWSubdivCache &cache,
|
|
gpu::VertBuf *src_data,
|
|
gpu::VertBuf *dst_data,
|
|
int comp_type, /*GPUVertCompType*/
|
|
int dimensions,
|
|
int dst_offset);
|
|
|
|
void draw_subdiv_extract_uvs(const DRWSubdivCache &cache,
|
|
gpu::VertBuf *uvs,
|
|
int face_varying_channel,
|
|
int dst_offset);
|
|
|
|
void draw_subdiv_build_edge_fac_buffer(const DRWSubdivCache &cache,
|
|
gpu::VertBuf *pos_nor,
|
|
gpu::VertBuf *edge_draw_flag,
|
|
gpu::VertBuf *poly_other_map,
|
|
gpu::VertBuf *edge_fac);
|
|
|
|
void draw_subdiv_build_tris_buffer(const DRWSubdivCache &cache,
|
|
gpu::IndexBuf *subdiv_tris,
|
|
int material_count);
|
|
|
|
void draw_subdiv_build_lines_buffer(const DRWSubdivCache &cache, gpu::IndexBuf *lines_indices);
|
|
|
|
void draw_subdiv_build_lines_loose_buffer(const DRWSubdivCache &cache,
|
|
gpu::IndexBuf *lines_indices,
|
|
gpu::VertBuf *lines_flags,
|
|
uint edge_loose_offset,
|
|
uint num_loose_edges);
|
|
|
|
void draw_subdiv_build_fdots_buffers(const DRWSubdivCache &cache,
|
|
gpu::VertBuf *fdots_pos,
|
|
gpu::VertBuf *fdots_nor,
|
|
gpu::IndexBuf *fdots_indices);
|
|
|
|
void draw_subdiv_build_lnor_buffer(const DRWSubdivCache &cache,
|
|
gpu::VertBuf *pos_nor,
|
|
gpu::VertBuf *lnor);
|
|
|
|
void draw_subdiv_build_edituv_stretch_area_buffer(const DRWSubdivCache &cache,
|
|
gpu::VertBuf *coarse_data,
|
|
gpu::VertBuf *subdiv_data);
|
|
|
|
void draw_subdiv_build_edituv_stretch_angle_buffer(const DRWSubdivCache &cache,
|
|
gpu::VertBuf *pos_nor,
|
|
gpu::VertBuf *uvs,
|
|
int uvs_offset,
|
|
gpu::VertBuf *stretch_angles);
|
|
|
|
/** Return the format used for the positions and normals VBO. */
|
|
GPUVertFormat *draw_subdiv_get_pos_nor_format();
|
|
|
|
/* Helper to access the loose edges. */
|
|
Span<DRWSubdivLooseEdge> draw_subdiv_cache_get_loose_edges(const DRWSubdivCache &cache);
|
|
|
|
/* Helper to access only the loose vertices, i.e. not the ones attached to loose edges. To access
|
|
* loose vertices of loose edges #draw_subdiv_cache_get_loose_edges should be used. */
|
|
Span<DRWSubdivLooseVertex> draw_subdiv_cache_get_loose_verts(const DRWSubdivCache &cache);
|
|
|
|
} // namespace blender::draw
|