Blender V5.0
extract_mesh_ibo_points.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
8
9#include "GPU_index_buffer.hh"
10
11#include "draw_subdivision.hh"
12#include "extract_mesh.hh"
13
14#include "BLI_timeit.hh"
15
16namespace blender::draw {
17
19 const IndexMask &mask,
20 IndexMaskMemory &memory)
21{
22 IndexMask visible = mask;
23 if (!mr.hide_vert.is_empty()) {
24 visible = IndexMask::from_bools_inverse(visible, mr.hide_vert, memory);
25 }
26 if (mr.orig_index_vert != nullptr) {
27 const int *orig_index = mr.orig_index_vert;
28 visible = IndexMask::from_predicate(visible, GrainSize(4096), memory, [&](const int64_t i) {
29 return orig_index[i] != ORIGINDEX_NONE;
30 });
31 }
32 return visible;
33}
34
40template<typename Fn>
41static void process_ibo_verts_mesh(const MeshRenderData &mr, const Fn &process_vert_fn)
42{
43 const Span<int> corner_verts = mr.corner_verts;
44 threading::parallel_for(corner_verts.index_range(), 2048, [&](const IndexRange range) {
45 for (const int corner : range) {
46 process_vert_fn(corner, corner_verts[corner]);
47 }
48 });
49
50 const int loose_edges_start = mr.corners_num;
51 const Span<int2> edges = mr.edges;
52 const Span<int> loose_edges = mr.loose_edges;
53 threading::parallel_for(loose_edges.index_range(), 2048, [&](const IndexRange range) {
54 for (const int i : range) {
55 const int2 edge = edges[loose_edges[i]];
56 process_vert_fn(loose_edges_start + i * 2 + 0, edge[0]);
57 process_vert_fn(loose_edges_start + i * 2 + 1, edge[1]);
58 }
59 });
60
61 const int loose_verts_start = mr.corners_num + loose_edges.size() * 2;
62 const Span<int> loose_verts = mr.loose_verts;
63 threading::parallel_for(loose_verts.index_range(), 2048, [&](const IndexRange range) {
64 for (const int i : range) {
65 process_vert_fn(loose_verts_start + i, loose_verts[i]);
66 }
67 });
68}
69
71{
72 IndexMaskMemory memory;
73 const IndexMask visible_verts = calc_vert_visibility_mesh(mr, IndexMask(mr.verts_num), memory);
74
75 const int max_index = mr.corners_num + mr.loose_edges.size() * 2 + mr.loose_verts.size();
76 GPUIndexBufBuilder builder;
77 GPU_indexbuf_init(&builder, GPU_PRIM_POINTS, visible_verts.size(), max_index);
79
81 if (visible_verts.size() == mr.verts_num) {
82 Array<bool> used(mr.verts_num, false);
83 process_ibo_verts_mesh(mr, [&](const int ibo_index, const int vert) {
84 if (!used[vert]) {
85 used[vert] = true;
86 data[vert] = ibo_index;
87 }
88 });
89 }
90 else {
91 /* Compress the vertex indices into the smaller range of visible vertices in the IBO. */
92 Array<int> map(mr.verts_num, -1);
93 index_mask::build_reverse_map(visible_verts, map.as_mutable_span());
94 process_ibo_verts_mesh(mr, [&](const int ibo_index, const int vert) {
95 const int index = map[vert];
96 if (index != -1) {
97 map[vert] = -1;
98 data[index] = ibo_index;
99 }
100 });
101 }
102 });
103
104 return gpu::IndexBufPtr(GPU_indexbuf_build_ex(&builder, 0, max_index, false));
105}
106
107template<typename Fn>
108static void process_ibo_verts_bm(const MeshRenderData &mr, const Fn &process_vert_fn)
109{
110 BMesh &bm = *mr.bm;
111
112 threading::parallel_for(IndexRange(mr.verts_num), 4096, [&](const IndexRange range) {
113 for (const int i : range) {
114 BMVert &vert = *BM_vert_at_index(&bm, i);
115 if (const BMLoop *loop = BM_vert_find_first_loop(&vert)) {
116 process_vert_fn(BM_elem_index_get(loop), i);
117 }
118 }
119 });
120
121 const int loose_edges_start = mr.corners_num;
122 const Span<int> loose_edges = mr.loose_edges;
123 threading::parallel_for(loose_edges.index_range(), 4096, [&](const IndexRange range) {
124 for (const int i : range) {
125 const BMEdge &edge = *BM_edge_at_index(&bm, loose_edges[i]);
126 process_vert_fn(loose_edges_start + i * 2 + 0, BM_elem_index_get(edge.v1));
127 process_vert_fn(loose_edges_start + i * 2 + 1, BM_elem_index_get(edge.v2));
128 }
129 });
130
131 const int loose_verts_start = mr.corners_num + loose_edges.size() * 2;
132 const Span<int> loose_verts = mr.loose_verts;
133 threading::parallel_for(loose_verts.index_range(), 4096, [&](const IndexRange range) {
134 for (const int i : range) {
135 process_vert_fn(loose_verts_start + i, loose_verts[i]);
136 }
137 });
138}
139
141{
142 BMesh &bm = *mr.bm;
143
144 IndexMaskMemory memory;
145 const IndexMask visible_verts = IndexMask::from_predicate(
146 IndexRange(bm.totvert), GrainSize(4096), memory, [&](const int i) {
147 return !BM_elem_flag_test_bool(BM_vert_at_index(&const_cast<BMesh &>(bm), i),
149 });
150
151 const int max_index = mr.corners_num + mr.loose_edges.size() * 2 + mr.loose_verts.size();
152 GPUIndexBufBuilder builder;
153 GPU_indexbuf_init(&builder, GPU_PRIM_POINTS, visible_verts.size(), max_index);
155
156 if (mr.loose_verts.is_empty() && mr.loose_edges.is_empty()) {
157 /* Make use of BMesh's vertex to loop topology knowledge to iterate over verts instead of
158 * iterating over faces and defining points implicitly as done in the #Mesh extraction. */
159 visible_verts.foreach_index(GrainSize(4096), [&](const int i, const int pos) {
160 BMVert &vert = *BM_vert_at_index(&bm, i);
162 });
163 }
164 else if (visible_verts.size() == bm.totvert) {
165 Array<bool> used(mr.verts_num, false);
166 process_ibo_verts_bm(mr, [&](const int ibo_index, const int vert) {
167 if (!used[vert]) {
168 used[vert] = true;
169 data[vert] = ibo_index;
170 }
171 });
172 }
173 else {
174 /* Compress the vertex indices into the smaller range of visible vertices in the IBO. */
175 Array<int> map(mr.verts_num, -1);
177 process_ibo_verts_bm(mr, [&](const int ibo_index, const int vert) {
178 const int index = map[vert];
179 if (index != -1) {
180 map[vert] = -1;
181 data[index] = ibo_index;
182 }
183 });
184 }
185
186 return gpu::IndexBufPtr(GPU_indexbuf_build_ex(&builder, 0, max_index, false));
187}
188
190{
192 return extract_points_mesh(mr);
193 }
194 return extract_points_bm(mr);
195}
196
198 const IndexMask &mask,
199 const Span<int> map,
200 IndexMaskMemory &memory)
201{
202 IndexMask visible = mask;
203 if (!mr.hide_vert.is_empty()) {
204 const Span<bool> hide_vert = mr.hide_vert;
206 visible, GrainSize(4096), memory, [&](const int i) { return !hide_vert[map[i]]; });
207 }
208 if (mr.orig_index_vert != nullptr) {
209 const int *orig_index = mr.orig_index_vert;
210 visible = IndexMask::from_predicate(visible, GrainSize(4096), memory, [&](const int i) {
211 return orig_index[map[i]] != ORIGINDEX_NONE;
212 });
213 }
214 return visible;
215}
216
218 const DRWSubdivCache &subdiv_cache)
219{
220 const Span<int2> coarse_edges = mr.edges;
221 const Span<int> loose_verts = mr.loose_verts;
222 const Span<int> loose_edges = mr.loose_edges;
223 const int verts_per_edge = subdiv_verts_per_coarse_edge(subdiv_cache);
224 const int loose_edge_verts_num = verts_per_edge * loose_edges.size();
225
226 const Span<bool> hide_vert = mr.hide_vert;
227 const Span<int> corner_orig_verts = subdiv_cache.verts_orig_index->data<int>();
228
229 IndexMaskMemory memory;
230 IndexMask visible_corners = IndexMask::from_predicate(
231 corner_orig_verts.index_range(), GrainSize(4096), memory, [&](const int i) {
232 return corner_orig_verts[i] != -1;
233 });
234 visible_corners = calc_vert_visibility_mapped_mesh(
235 mr, visible_corners, corner_orig_verts, memory);
236
237 const IndexMask visible_loose = calc_vert_visibility_mapped_mesh(
238 mr, IndexMask(loose_verts.size()), loose_verts, memory);
239
240 const int max_index = subdiv_cache.num_subdiv_loops + loose_edge_verts_num + loose_verts.size();
241 GPUIndexBufBuilder builder;
242 GPU_indexbuf_init(&builder,
244 visible_corners.size() + loose_edges.size() * 2 + visible_loose.size(),
245 max_index);
247
248 visible_corners.to_indices<int32_t>(data.take_front(visible_corners.size()).cast<int32_t>());
249
250 const auto show_vert = [&](const int vert) {
251 if (!hide_vert.is_empty() && hide_vert[vert]) {
252 return false;
253 }
254 if (mr.orig_index_vert && mr.orig_index_vert[vert] == ORIGINDEX_NONE) {
255 return false;
256 }
257 return true;
258 };
259
260 MutableSpan loose_edge_data = data.slice(visible_corners.size(), loose_edges.size() * 2);
261 const int loose_geom_start = subdiv_cache.num_subdiv_loops;
262 for (const int i : loose_edges.index_range()) {
263 const int2 edge = coarse_edges[loose_edges[i]];
264 const IndexRange edge_range(loose_geom_start + i * verts_per_edge, verts_per_edge);
265 loose_edge_data[i * 2 + 0] = show_vert(edge[0]) ? edge_range.first() : gpu::RESTART_INDEX;
266 loose_edge_data[i * 2 + 1] = show_vert(edge[1]) ? edge_range.last() : gpu::RESTART_INDEX;
267 }
268
269 MutableSpan loose_vert_data = data.take_back(visible_loose.size()).cast<int32_t>();
270 const int loose_verts_start = loose_geom_start + loose_edge_verts_num;
271 visible_loose.shift(loose_verts_start, memory).to_indices<int32_t>(loose_vert_data);
272
273 return gpu::IndexBufPtr(GPU_indexbuf_build_ex(&builder, 0, max_index, true));
274}
275
277 const DRWSubdivCache &subdiv_cache)
278{
279 const Span<int2> coarse_edges = mr.edges;
280 const Span<int> loose_verts = mr.loose_verts;
281 const Span<int> loose_edges = mr.loose_edges;
282 const int verts_per_edge = subdiv_verts_per_coarse_edge(subdiv_cache);
283 const int loose_edge_verts_num = verts_per_edge * loose_edges.size();
284
285 const Span<int> corner_orig_verts = subdiv_cache.verts_orig_index->data<int>();
286
287 const auto show_vert_bm = [&](const int vert_index) {
288 const BMVert *vert = mr.orig_index_vert ? bm_original_vert_get(mr, vert_index) :
289 BM_vert_at_index(mr.bm, vert_index);
291 };
292
293 IndexMaskMemory memory;
294 const IndexMask visible_corners = IndexMask::from_predicate(
295 corner_orig_verts.index_range(), GrainSize(4096), memory, [&](const int i) {
296 return corner_orig_verts[i] != -1 && show_vert_bm(corner_orig_verts[i]);
297 });
298
299 const IndexMask visible_loose = IndexMask::from_predicate(
300 loose_verts.index_range(), GrainSize(4096), memory, [&](const int vert) {
301 return show_vert_bm(vert);
302 });
303
304 const int max_index = subdiv_cache.num_subdiv_loops + loose_edge_verts_num + loose_verts.size();
305 GPUIndexBufBuilder builder;
306 GPU_indexbuf_init(&builder,
308 visible_corners.size() + loose_edges.size() * 2 + visible_loose.size(),
309 max_index);
311
312 visible_corners.to_indices<int32_t>(data.take_front(visible_corners.size()).cast<int32_t>());
313
314 MutableSpan loose_edge_data = data.slice(visible_corners.size(), loose_edges.size() * 2);
315 const int loose_geom_start = subdiv_cache.num_subdiv_loops;
316 for (const int i : loose_edges.index_range()) {
317 const int2 edge = coarse_edges[loose_edges[i]];
318 const IndexRange edge_range(loose_geom_start + i * verts_per_edge, verts_per_edge);
319 loose_edge_data[i * 2 + 0] = show_vert_bm(edge[0]) ? edge_range.first() : gpu::RESTART_INDEX;
320 loose_edge_data[i * 2 + 1] = show_vert_bm(edge[1]) ? edge_range.last() : gpu::RESTART_INDEX;
321 }
322
323 MutableSpan loose_vert_data = data.take_back(visible_loose.size()).cast<int32_t>();
324 const int loose_verts_start = loose_geom_start + loose_edge_verts_num;
325 visible_loose.shift(loose_verts_start, memory).to_indices<int32_t>(loose_vert_data);
326
327 return gpu::IndexBufPtr(GPU_indexbuf_build_ex(&builder, 0, max_index, true));
328}
329
331 const DRWSubdivCache &subdiv_cache)
332{
334 return extract_points_subdiv_mesh(mr, subdiv_cache);
335 }
336 return extract_points_subdiv_bm(mr, subdiv_cache);
337}
338
339} // namespace blender::draw
#define ORIGINDEX_NONE
blender::MutableSpan< uint32_t > GPU_indexbuf_get_data(GPUIndexBufBuilder *)
void GPU_indexbuf_init(GPUIndexBufBuilder *, GPUPrimType, uint prim_len, uint vertex_len)
blender::gpu::IndexBuf * GPU_indexbuf_build_ex(GPUIndexBufBuilder *builder, uint index_min, uint index_max, bool uses_restart_indices)
@ GPU_PRIM_POINTS
@ BM_ELEM_HIDDEN
#define BM_elem_index_get(ele)
#define BM_elem_flag_test_bool(ele, hflag)
BMesh const char void * data
BMesh * bm
BLI_INLINE BMVert * BM_vert_at_index(BMesh *bm, const int index)
BMLoop * BM_vert_find_first_loop(BMVert *v)
long long int int64_t
static IndexMask from_predicate(const IndexMask &universe, GrainSize grain_size, IndexMaskMemory &memory, Fn &&predicate)
constexpr int64_t size_in_bytes() const
Definition BLI_span.hh:268
constexpr int64_t size() const
Definition BLI_span.hh:252
constexpr IndexRange index_range() const
Definition BLI_span.hh:401
constexpr bool is_empty() const
Definition BLI_span.hh:260
MutableSpan< T > as_mutable_span()
Definition BLI_array.hh:248
static IndexMask from_predicate(const IndexMask &universe, GrainSize grain_size, IndexMaskMemory &memory, Fn &&predicate)
static IndexMask from_bools_inverse(const VArray< bool > &bools, IndexMaskMemory &memory)
constexpr int64_t first() const
constexpr int64_t last(const int64_t n=0) const
constexpr int64_t size() const
Definition BLI_span.hh:252
constexpr IndexRange index_range() const
Definition BLI_span.hh:401
constexpr bool is_empty() const
Definition BLI_span.hh:260
MutableSpan< T > data()
void to_indices(MutableSpan< T > r_indices) const
IndexMask shift(const int64_t offset, IndexMaskMemory &memory) const
void foreach_index(Fn &&fn) const
Extraction of Mesh data into VBO to feed to GPU.
uint pos
ccl_device_inline float2 mask(const MaskType mask, const float2 a)
BLI_INLINE BMVert * bm_original_vert_get(const MeshRenderData &mr, int idx)
static IndexMask calc_vert_visibility_mapped_mesh(const MeshRenderData &mr, const IndexMask &mask, const Span< int > map, IndexMaskMemory &memory)
int subdiv_verts_per_coarse_edge(const DRWSubdivCache &cache)
gpu::IndexBufPtr extract_points_subdiv(const MeshRenderData &mr, const DRWSubdivCache &subdiv_cache)
static void process_ibo_verts_mesh(const MeshRenderData &mr, const Fn &process_vert_fn)
static gpu::IndexBufPtr extract_points_subdiv_bm(const MeshRenderData &mr, const DRWSubdivCache &subdiv_cache)
static gpu::IndexBufPtr extract_points_bm(const MeshRenderData &mr)
static gpu::IndexBufPtr extract_points_mesh(const MeshRenderData &mr)
static void process_ibo_verts_bm(const MeshRenderData &mr, const Fn &process_vert_fn)
static IndexMask calc_vert_visibility_mesh(const MeshRenderData &mr, const IndexMask &mask, IndexMaskMemory &memory)
static gpu::IndexBufPtr extract_points_subdiv_mesh(const MeshRenderData &mr, const DRWSubdivCache &subdiv_cache)
gpu::IndexBufPtr extract_points(const MeshRenderData &mr)
std::unique_ptr< IndexBuf, IndexBufDeleter > IndexBufPtr
constexpr uint32_t RESTART_INDEX
void build_reverse_map(const IndexMask &mask, MutableSpan< T > r_map)
Definition index_mask.cc:34
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:93
void memory_bandwidth_bound_task(const int64_t approximate_bytes_touched, const Function &function)
Definition BLI_task.hh:265
VecBase< int32_t, 2 > int2
i
Definition text_draw.cc:230