Blender V4.3
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
9#include "BLI_array_utils.hh"
10
11#include "GPU_index_buffer.hh"
12
13#include "draw_subdivision.hh"
14#include "extract_mesh.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
70static void extract_points_mesh(const MeshRenderData &mr, gpu::IndexBuf &points)
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
80 threading::memory_bandwidth_bound_task(mr.corner_verts.size_in_bytes(), [&]() {
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 GPU_indexbuf_build_in_place_ex(&builder, 0, max_index, false, &points);
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
140static void extract_points_bm(const MeshRenderData &mr, gpu::IndexBuf &points)
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 data[vert] = ibo_index;
169 used[vert] = true;
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);
176 index_mask::build_reverse_map(visible_verts, map.as_mutable_span());
177 process_ibo_verts_bm(mr, [&](const int ibo_index, const int vert) {
178 if (map[vert] != -1) {
179 data[map[vert]] = ibo_index;
180 map[vert] = -1;
181 }
182 });
183 }
184
185 GPU_indexbuf_build_in_place_ex(&builder, 0, max_index, false, &points);
186}
187
189{
190 if (mr.extract_type == MR_EXTRACT_MESH) {
191 extract_points_mesh(mr, points);
192 }
193 else {
194 extract_points_bm(mr, points);
195 }
196}
197
199 const IndexMask &mask,
200 const Span<int> map,
201 IndexMaskMemory &memory)
202{
203 IndexMask visible = mask;
204 if (!mr.hide_vert.is_empty()) {
205 const Span<bool> hide_vert = mr.hide_vert;
206 visible = IndexMask::from_predicate(
207 visible, GrainSize(4096), memory, [&](const int i) { return !hide_vert[map[i]]; });
208 }
209 if (mr.orig_index_vert != nullptr) {
210 const int *orig_index = mr.orig_index_vert;
211 visible = IndexMask::from_predicate(visible, GrainSize(4096), memory, [&](const int i) {
212 return orig_index[map[i]] != ORIGINDEX_NONE;
213 });
214 }
215 return visible;
216}
217
219 const DRWSubdivCache &subdiv_cache,
220 gpu::IndexBuf &points)
221{
222 const Span<int2> coarse_edges = mr.edges;
223 const Span<int> loose_verts = mr.loose_verts;
224 const Span<int> loose_edges = mr.loose_edges;
225 const int verts_per_edge = subdiv_verts_per_coarse_edge(subdiv_cache);
226 const int loose_edge_verts_num = verts_per_edge * loose_edges.size();
227
228 const Span<bool> hide_vert = mr.hide_vert;
229 const Span<int> corner_orig_verts = subdiv_cache.verts_orig_index->data<int>();
230
231 IndexMaskMemory memory;
232 IndexMask visible_corners = IndexMask::from_predicate(
233 corner_orig_verts.index_range(), GrainSize(4096), memory, [&](const int i) {
234 return corner_orig_verts[i] != -1;
235 });
236 visible_corners = calc_vert_visibility_mapped_mesh(
237 mr, visible_corners, corner_orig_verts, memory);
238
239 const IndexMask visible_loose = calc_vert_visibility_mapped_mesh(
240 mr, IndexMask(loose_verts.size()), loose_verts, memory);
241
242 const int max_index = subdiv_cache.num_subdiv_loops + loose_edge_verts_num + loose_verts.size();
243 GPUIndexBufBuilder builder;
244 GPU_indexbuf_init(&builder,
246 visible_corners.size() + loose_edges.size() * 2 + visible_loose.size(),
247 max_index);
249
250 visible_corners.to_indices<int32_t>(data.take_front(visible_corners.size()).cast<int32_t>());
251
252 const auto show_vert = [&](const int vert) {
253 if (!hide_vert.is_empty() && hide_vert[vert]) {
254 return false;
255 }
256 if (mr.orig_index_vert && mr.orig_index_vert[vert] == ORIGINDEX_NONE) {
257 return false;
258 }
259 return true;
260 };
261
262 MutableSpan loose_edge_data = data.slice(visible_corners.size(), loose_edges.size() * 2);
263 const int loose_geom_start = subdiv_cache.num_subdiv_loops;
264 for (const int i : loose_edges.index_range()) {
265 const int2 edge = coarse_edges[loose_edges[i]];
266 const IndexRange edge_range(loose_geom_start + i * verts_per_edge, verts_per_edge);
267 loose_edge_data[i * 2 + 0] = show_vert(edge[0]) ? edge_range.first() : gpu::RESTART_INDEX;
268 loose_edge_data[i * 2 + 1] = show_vert(edge[1]) ? edge_range.last() : gpu::RESTART_INDEX;
269 }
270
271 MutableSpan loose_vert_data = data.take_back(visible_loose.size()).cast<int32_t>();
272 const int loose_verts_start = loose_geom_start + loose_edge_verts_num;
273 visible_loose.shift(loose_verts_start, memory).to_indices<int32_t>(loose_vert_data);
274
275 GPU_indexbuf_build_in_place_ex(&builder, 0, max_index, true, &points);
276}
277
279 const DRWSubdivCache &subdiv_cache,
280 gpu::IndexBuf &points)
281{
282 const Span<int2> coarse_edges = mr.edges;
283 const Span<int> loose_verts = mr.loose_verts;
284 const Span<int> loose_edges = mr.loose_edges;
285 const int verts_per_edge = subdiv_verts_per_coarse_edge(subdiv_cache);
286 const int loose_edge_verts_num = verts_per_edge * loose_edges.size();
287
288 const Span<int> corner_orig_verts = subdiv_cache.verts_orig_index->data<int>();
289
290 const auto show_vert_bm = [&](const int vert_index) {
291 const BMVert *vert = mr.orig_index_vert ? bm_original_vert_get(mr, vert_index) :
292 BM_vert_at_index(mr.bm, vert_index);
294 };
295
296 IndexMaskMemory memory;
297 const IndexMask visible_corners = IndexMask::from_predicate(
298 corner_orig_verts.index_range(), GrainSize(4096), memory, [&](const int i) {
299 return corner_orig_verts[i] != -1 && show_vert_bm(corner_orig_verts[i]);
300 });
301
302 const IndexMask visible_loose = IndexMask::from_predicate(
303 loose_verts.index_range(), GrainSize(4096), memory, [&](const int vert) {
304 return show_vert_bm(vert);
305 });
306
307 const int max_index = subdiv_cache.num_subdiv_loops + loose_edge_verts_num + loose_verts.size();
308 GPUIndexBufBuilder builder;
309 GPU_indexbuf_init(&builder,
311 visible_corners.size() + loose_edges.size() * 2 + visible_loose.size(),
312 max_index);
314
315 visible_corners.to_indices<int32_t>(data.take_front(visible_corners.size()).cast<int32_t>());
316
317 MutableSpan loose_edge_data = data.slice(visible_corners.size(), loose_edges.size() * 2);
318 const int loose_geom_start = subdiv_cache.num_subdiv_loops;
319 for (const int i : loose_edges.index_range()) {
320 const int2 edge = coarse_edges[loose_edges[i]];
321 const IndexRange edge_range(loose_geom_start + i * verts_per_edge, verts_per_edge);
322 loose_edge_data[i * 2 + 0] = show_vert_bm(edge[0]) ? edge_range.first() : gpu::RESTART_INDEX;
323 loose_edge_data[i * 2 + 1] = show_vert_bm(edge[1]) ? edge_range.last() : gpu::RESTART_INDEX;
324 }
325
326 MutableSpan loose_vert_data = data.take_back(visible_loose.size()).cast<int32_t>();
327 const int loose_verts_start = loose_geom_start + loose_edge_verts_num;
328 visible_loose.shift(loose_verts_start, memory).to_indices<int32_t>(loose_vert_data);
329
330 GPU_indexbuf_build_in_place_ex(&builder, 0, max_index, true, &points);
331}
332
334 const DRWSubdivCache &subdiv_cache,
335 gpu::IndexBuf &points)
336{
337 if (mr.extract_type == MR_EXTRACT_MESH) {
338 extract_points_subdiv_mesh(mr, subdiv_cache, points);
339 }
340 else {
341 extract_points_subdiv_bm(mr, subdiv_cache, points);
342 }
343}
344
345} // namespace blender::draw
#define ORIGINDEX_NONE
void GPU_indexbuf_build_in_place_ex(GPUIndexBufBuilder *builder, uint index_min, uint index_max, bool uses_restart_indices, blender::gpu::IndexBuf *elem)
blender::MutableSpan< uint32_t > GPU_indexbuf_get_data(GPUIndexBufBuilder *)
void GPU_indexbuf_init(GPUIndexBufBuilder *, GPUPrimType, uint prim_len, uint vertex_len)
@ GPU_PRIM_POINTS
@ BM_ELEM_HIDDEN
#define BM_elem_index_get(ele)
#define BM_elem_flag_test_bool(ele, hflag)
ATTR_WARN_UNUSED_RESULT BMesh * bm
BLI_INLINE BMVert * BM_vert_at_index(BMesh *bm, const int index)
BMLoop * BM_vert_find_first_loop(BMVert *v)
constexpr int64_t first() const
constexpr int64_t last(const int64_t n=0) const
constexpr MutableSpan slice(const int64_t start, const int64_t size) const
Definition BLI_span.hh:574
constexpr MutableSpan< NewT > cast() const
Definition BLI_span.hh:736
constexpr MutableSpan take_back(const int64_t n) const
Definition BLI_span.hh:641
constexpr int64_t size_in_bytes() const
Definition BLI_span.hh:269
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()
static IndexMask from_predicate(const IndexMask &universe, GrainSize grain_size, IndexMaskMemory &memory, Fn &&predicate)
static IndexMask from_bools_inverse(const IndexMask &universe, Span< bool > bools, IndexMaskMemory &memory)
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.
ccl_device_inline float4 mask(const int4 mask, const float4 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)
static void process_ibo_verts_mesh(const MeshRenderData &mr, const Fn &process_vert_fn)
void extract_points_subdiv(const MeshRenderData &mr, const DRWSubdivCache &subdiv_cache, gpu::IndexBuf &points)
static void process_ibo_verts_bm(const MeshRenderData &mr, const Fn &process_vert_fn)
static void extract_points_subdiv_mesh(const MeshRenderData &mr, const DRWSubdivCache &subdiv_cache, gpu::IndexBuf &points)
static IndexMask calc_vert_visibility_mesh(const MeshRenderData &mr, const IndexMask &mask, IndexMaskMemory &memory)
void extract_points(const MeshRenderData &mr, gpu::IndexBuf &points)
static void extract_points_bm(const MeshRenderData &mr, gpu::IndexBuf &points)
static void extract_points_mesh(const MeshRenderData &mr, gpu::IndexBuf &points)
static void extract_points_subdiv_bm(const MeshRenderData &mr, const DRWSubdivCache &subdiv_cache, gpu::IndexBuf &points)
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
__int64 int64_t
Definition stdint.h:89
signed int int32_t
Definition stdint.h:77
int totvert