Blender V4.3
extract_mesh_vbo_select_idx.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2021 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include "BLI_array_utils.hh"
10
11#include "draw_subdivision.hh"
12#include "extract_mesh.hh"
13
14namespace blender::draw {
15
16static MutableSpan<int> init_vbo_data(gpu::VertBuf &vbo, const int size)
17{
18 static GPUVertFormat format = {0};
19 if (format.attr_len == 0) {
21 }
23 GPU_vertbuf_data_alloc(vbo, size);
24 return vbo.data<int>();
25}
26
27/* TODO: Use #glVertexID to get loop index and use the data structure on the CPU to retrieve the
28 * select element associated with this loop ID. This would remove the need for this separate
29 * index VBO's. We could upload the p/e/orig_index_vert as a buffer texture and sample it inside
30 * the shader to output original index. */
31
33{
34 MutableSpan corners_data = vbo_data.take_front(mr.corners_num);
35 MutableSpan loose_edge_data = vbo_data.slice(mr.corners_num, mr.loose_edges.size() * 2);
36 MutableSpan loose_vert_data = vbo_data.take_back(mr.loose_verts.size());
37
38 if (mr.orig_index_vert) {
39 const Span<int> orig_index_vert(mr.orig_index_vert, mr.verts_num);
40 array_utils::gather(orig_index_vert, mr.corner_verts, corners_data);
41 extract_mesh_loose_edge_data(orig_index_vert, mr.edges, mr.loose_edges, loose_edge_data);
42 array_utils::gather(orig_index_vert, mr.loose_verts, loose_vert_data);
43 }
44 else {
45 array_utils::copy(mr.corner_verts, corners_data);
46 const Span<int2> edges = mr.edges;
47 const Span<int> loose_edges = mr.loose_edges;
48 threading::parallel_for(loose_edges.index_range(), 4096, [&](const IndexRange range) {
49 for (const int i : range) {
50 loose_edge_data[i * 2 + 0] = edges[loose_edges[i]][0];
51 loose_edge_data[i * 2 + 1] = edges[loose_edges[i]][1];
52 }
53 });
54 array_utils::copy(mr.loose_verts, loose_vert_data);
55 }
56}
57
59{
60 MutableSpan corners_data = vbo_data.take_front(mr.corners_num);
61 MutableSpan loose_edge_data = vbo_data.slice(mr.corners_num, mr.loose_edges.size() * 2);
62 MutableSpan loose_vert_data = vbo_data.take_back(mr.loose_verts.size());
63
64 const BMesh &bm = *mr.bm;
65 threading::parallel_for(IndexRange(bm.totface), 2048, [&](const IndexRange range) {
66 for (const int face_index : range) {
67 const BMFace &face = *BM_face_at_index(&const_cast<BMesh &>(bm), face_index);
68 const BMLoop *loop = BM_FACE_FIRST_LOOP(&face);
69 for ([[maybe_unused]] const int i : IndexRange(face.len)) {
70 const int index = BM_elem_index_get(loop);
71 corners_data[index] = BM_elem_index_get(loop->v);
72 loop = loop->next;
73 }
74 }
75 });
76
77 const Span<int> loose_edges = mr.loose_edges;
78 threading::parallel_for(loose_edges.index_range(), 4096, [&](const IndexRange range) {
79 for (const int i : range) {
80 const BMEdge &edge = *BM_edge_at_index(&const_cast<BMesh &>(bm), loose_edges[i]);
81 loose_edge_data[i * 2 + 0] = BM_elem_index_get(edge.v1);
82 loose_edge_data[i * 2 + 1] = BM_elem_index_get(edge.v2);
83 }
84 });
85
86 array_utils::copy(mr.loose_verts, loose_vert_data);
87}
88
90{
92 if (mr.extract_type == MR_EXTRACT_MESH) {
93 extract_vert_index_mesh(mr, vbo_data);
94 }
95 else {
96 extract_vert_index_bm(mr, vbo_data);
97 }
98}
99
101{
102 MutableSpan corners_data = vbo_data.take_front(mr.corners_num);
103 MutableSpan loose_edge_data = vbo_data.slice(mr.corners_num, mr.loose_edges.size() * 2);
104
105 const Span<int> loose_edges = mr.loose_edges;
106 if (mr.orig_index_edge) {
107 const Span<int> orig_index_edge(mr.orig_index_edge, mr.edges_num);
108 array_utils::gather(orig_index_edge, mr.corner_edges, corners_data);
109 threading::parallel_for(loose_edges.index_range(), 4096, [&](const IndexRange range) {
110 for (const int i : range) {
111 loose_edge_data[i * 2 + 0] = orig_index_edge[loose_edges[i]];
112 loose_edge_data[i * 2 + 1] = orig_index_edge[loose_edges[i]];
113 }
114 });
115 }
116 else {
117 array_utils::copy(mr.corner_edges, corners_data);
118 threading::parallel_for(loose_edges.index_range(), 4096, [&](const IndexRange range) {
119 for (const int i : range) {
120 loose_edge_data[i * 2 + 0] = loose_edges[i];
121 loose_edge_data[i * 2 + 1] = loose_edges[i];
122 }
123 });
124 }
125}
126
128{
129 MutableSpan corners_data = vbo_data.take_front(mr.corners_num);
130 MutableSpan loose_edge_data = vbo_data.slice(mr.corners_num, mr.loose_edges.size() * 2);
131
132 const BMesh &bm = *mr.bm;
133 threading::parallel_for(IndexRange(bm.totface), 2048, [&](const IndexRange range) {
134 for (const int face_index : range) {
135 const BMFace &face = *BM_face_at_index(&const_cast<BMesh &>(bm), face_index);
136 const BMLoop *loop = BM_FACE_FIRST_LOOP(&face);
137 for ([[maybe_unused]] const int i : IndexRange(face.len)) {
138 const int index = BM_elem_index_get(loop);
139 corners_data[index] = BM_elem_index_get(loop->e);
140 loop = loop->next;
141 }
142 }
143 });
144
145 const Span<int> loose_edges = mr.loose_edges;
146 threading::parallel_for(loose_edges.index_range(), 4096, [&](const IndexRange range) {
147 for (const int i : range) {
148 loose_edge_data[i * 2 + 0] = loose_edges[i];
149 loose_edge_data[i * 2 + 1] = loose_edges[i];
150 }
151 });
152}
153
155{
156 MutableSpan<int> vbo_data = init_vbo_data(vbo, mr.corners_num + mr.loose_edges.size() * 2);
157 if (mr.extract_type == MR_EXTRACT_MESH) {
158 extract_edge_index_mesh(mr, vbo_data);
159 }
160 else {
161 extract_edge_index_bm(mr, vbo_data);
162 }
163}
164
166{
167 const OffsetIndices faces = mr.faces;
168 if (mr.orig_index_face) {
169 const Span<int> orig_index_face(mr.orig_index_face, mr.edges_num);
170 threading::parallel_for(faces.index_range(), 2048, [&](const IndexRange range) {
171 for (const int face : range) {
172 vbo_data.slice(faces[face]).fill(orig_index_face[face]);
173 }
174 });
175 }
176 else {
177 offset_indices::build_reverse_map(faces, vbo_data);
178 }
179}
180
182{
183 const BMesh &bm = *mr.bm;
184 threading::parallel_for(IndexRange(bm.totface), 2048, [&](const IndexRange range) {
185 for (const int face_index : range) {
186 const BMFace &face = *BM_face_at_index(&const_cast<BMesh &>(bm), face_index);
187 const IndexRange face_range(BM_elem_index_get(BM_FACE_FIRST_LOOP(&face)), face.len);
188 vbo_data.slice(face_range).fill(face_index);
189 }
190 });
191}
192
194{
195 MutableSpan<int> vbo_data = init_vbo_data(vbo, mr.corners_num);
196 if (mr.extract_type == MR_EXTRACT_MESH) {
197 extract_face_index_mesh(mr, vbo_data);
198 }
199 else {
200 extract_face_index_bm(mr, vbo_data);
201 }
202}
203
205 const MeshRenderData &mr,
206 gpu::VertBuf &vbo)
207{
208 const Span<int> loose_verts = mr.loose_verts;
209 const Span<int> loose_edges = mr.loose_edges;
210 if (loose_edges.is_empty() && loose_verts.is_empty()) {
211 return;
212 }
213
214 MutableSpan<int32_t> vbo_data = vbo.data<int32_t>();
215
216 const Span<int2> coarse_edges = mr.edges;
217 const int verts_per_edge = subdiv_verts_per_coarse_edge(subdiv_cache);
218 MutableSpan<int32_t> edge_data = vbo_data.slice(subdiv_cache.num_subdiv_loops,
219 loose_edges.size() * verts_per_edge);
220 for (const int i : loose_edges.index_range()) {
221 const int2 edge = coarse_edges[loose_edges[i]];
222 MutableSpan data = edge_data.slice(i * verts_per_edge, verts_per_edge);
223 data.first() = mr.orig_index_vert ? mr.orig_index_vert[edge[0]] : edge[0];
224 data.last() = mr.orig_index_vert ? mr.orig_index_vert[edge[1]] : edge[1];
225 }
226
227 MutableSpan<int32_t> loose_vert_data = vbo_data.take_back(loose_verts.size());
228 if (mr.orig_index_vert) {
229 array_utils::gather(Span(mr.orig_index_vert, mr.verts_num), loose_verts, loose_vert_data);
230 }
231 else {
232 array_utils::copy(loose_verts, loose_vert_data);
233 }
234}
235
237 const MeshRenderData &mr,
238 gpu::VertBuf &vbo)
239{
240 /* Each element points to an element in the `ibo.points`. */
242 subdiv_cache.verts_orig_index->data<int32_t>().data(),
243 subdiv_cache.num_subdiv_loops,
244 subdiv_full_vbo_size(mr, subdiv_cache));
245 if (!mr.orig_index_vert) {
246 return;
247 }
248
249 /* Remap the vertex indices to those pointed by the origin indices layer. At this point, the
250 * VBO data is a copy of #verts_orig_index which contains the coarse vertices indices, so
251 * the memory can both be accessed for lookup and immediately overwritten. */
252 int32_t *vbo_data = vbo.data<int32_t>().data();
253 for (int i = 0; i < subdiv_cache.num_subdiv_loops; i++) {
254 if (vbo_data[i] == -1) {
255 continue;
256 }
257 vbo_data[i] = mr.orig_index_vert[vbo_data[i]];
258 }
259 extract_vert_idx_loose_geom_subdiv(subdiv_cache, mr, vbo);
260}
261
263 const MeshRenderData &mr,
264 gpu::VertBuf &vbo)
265{
266 const Span<int> loose_edges = mr.loose_edges;
267 if (loose_edges.is_empty()) {
268 return;
269 }
270
271 MutableSpan<int32_t> vbo_data = vbo.data<int32_t>();
272
273 const int verts_per_edge = subdiv_verts_per_coarse_edge(subdiv_cache);
274 MutableSpan data = vbo_data.slice(subdiv_cache.num_subdiv_loops,
275 loose_edges.size() * verts_per_edge);
276 for (const int i : loose_edges.index_range()) {
277 const int edge = loose_edges[i];
278 const int index = mr.orig_index_edge ? mr.orig_index_edge[edge] : edge;
279 data.slice(i * verts_per_edge, verts_per_edge).fill(index);
280 }
281}
282
284 const MeshRenderData &mr,
285 gpu::VertBuf &vbo)
286{
288 subdiv_cache.edges_orig_index->data<int32_t>().data(),
289 subdiv_cache.num_subdiv_loops,
290 subdiv_loose_edges_num(mr, subdiv_cache) * 2);
291 extract_edge_idx_loose_geom_subdiv(subdiv_cache, mr, vbo);
292}
293
295 const MeshRenderData &mr,
296 gpu::VertBuf &vbo)
297{
299 vbo, subdiv_cache.subdiv_loop_face_index, subdiv_cache.num_subdiv_loops, 0);
300
301 if (!mr.orig_index_face) {
302 return;
303 }
304
305 /* Remap the face indices to those pointed by the origin indices layer. At this point, the
306 * VBO data is a copy of #subdiv_loop_face_index which contains the coarse face indices, so
307 * the memory can both be accessed for lookup and immediately overwritten. */
308 int32_t *vbo_data = vbo.data<int32_t>().data();
309 for (int i = 0; i < subdiv_cache.num_subdiv_loops; i++) {
310 vbo_data[i] = mr.orig_index_face[vbo_data[i]];
311 }
312}
313
315{
316 MutableSpan<int> vbo_data = init_vbo_data(vbo, mr.faces_num);
317 if (mr.extract_type == MR_EXTRACT_MESH) {
318 if (mr.orig_index_face) {
319 const Span<int> orig_index_face(mr.orig_index_face, mr.faces_num);
320 array_utils::copy(orig_index_face, vbo_data);
321 }
322 else {
323 array_utils::fill_index_range(vbo_data);
324 }
325 }
326 else {
327 array_utils::fill_index_range(vbo_data);
328 }
329}
330
331} // namespace blender::draw
#define GPU_vertbuf_init_with_format(verts, format)
void GPU_vertbuf_data_alloc(blender::gpu::VertBuf &verts, uint v_len)
@ GPU_FETCH_INT
uint GPU_vertformat_attr_add(GPUVertFormat *, const char *name, GPUVertCompType, uint comp_len, GPUVertFetchMode)
@ GPU_COMP_I32
ATTR_WARN_UNUSED_RESULT BMesh * bm
constexpr MutableSpan slice(const int64_t start, const int64_t size) const
Definition BLI_span.hh:574
constexpr MutableSpan take_back(const int64_t n) const
Definition BLI_span.hh:641
constexpr T & first() const
Definition BLI_span.hh:680
constexpr MutableSpan take_front(const int64_t n) const
Definition BLI_span.hh:630
constexpr int64_t size() const
Definition BLI_span.hh:253
constexpr IndexRange index_range() const
Definition BLI_span.hh:402
constexpr bool is_empty() const
Definition BLI_span.hh:261
MutableSpan< T > data()
Extraction of Mesh data into VBO to feed to GPU.
format
void copy(const GVArray &src, GMutableSpan dst, int64_t grain_size=4096)
void gather(const GVArray &src, const IndexMask &indices, GMutableSpan dst, int64_t grain_size=4096)
void extract_edge_index(const MeshRenderData &mr, gpu::VertBuf &vbo)
int subdiv_loose_edges_num(const MeshRenderData &mr, const DRWSubdivCache &cache)
static void extract_vert_idx_loose_geom_subdiv(const DRWSubdivCache &subdiv_cache, const MeshRenderData &mr, gpu::VertBuf &vbo)
static void extract_vert_index_bm(const MeshRenderData &mr, MutableSpan< int > vbo_data)
static void extract_face_index_bm(const MeshRenderData &mr, MutableSpan< int > vbo_data)
int subdiv_verts_per_coarse_edge(const DRWSubdivCache &cache)
static void extract_edge_idx_loose_geom_subdiv(const DRWSubdivCache &subdiv_cache, const MeshRenderData &mr, gpu::VertBuf &vbo)
void extract_face_dot_index(const MeshRenderData &mr, gpu::VertBuf &vbo)
static void extract_edge_index_bm(const MeshRenderData &mr, MutableSpan< int > vbo_data)
void extract_vert_index_subdiv(const DRWSubdivCache &subdiv_cache, const MeshRenderData &mr, gpu::VertBuf &vbo)
void extract_face_index_subdiv(const DRWSubdivCache &subdiv_cache, const MeshRenderData &mr, gpu::VertBuf &vbo)
int subdiv_full_vbo_size(const MeshRenderData &mr, const DRWSubdivCache &cache)
static void extract_vert_index_mesh(const MeshRenderData &mr, MutableSpan< int > vbo_data)
void extract_vert_index(const MeshRenderData &mr, gpu::VertBuf &vbo)
void extract_face_index(const MeshRenderData &mr, gpu::VertBuf &vbo)
static MutableSpan< int > init_vbo_data(gpu::VertBuf &vbo, const int size)
static void extract_edge_index_mesh(const MeshRenderData &mr, MutableSpan< int > vbo_data)
void extract_mesh_loose_edge_data(const Span< T > vert_data, const Span< int2 > edges, const Span< int > loose_edges, MutableSpan< T > gpu_data)
void draw_subdiv_init_origindex_buffer(gpu::VertBuf &buffer, int32_t *vert_origindex, uint num_loops, uint loose_len)
static void extract_face_index_mesh(const MeshRenderData &mr, MutableSpan< int > vbo_data)
void extract_edge_index_subdiv(const DRWSubdivCache &subdiv_cache, const MeshRenderData &mr, gpu::VertBuf &vbo)
void parallel_for(const IndexRange range, const int64_t grain_size, const Function &function, const TaskSizeHints &size_hints=detail::TaskSizeHints_Static(1))
Definition BLI_task.hh:95
signed int int32_t
Definition stdint.h:77
int totface
OffsetIndices< int > faces