Blender V4.3
extract_mesh_vbo_attributes.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 "MEM_guardedalloc.h"
10
11#include "BLI_array_utils.hh"
13#include "BLI_string.h"
14
15#include "BKE_attribute.hh"
16#include "BKE_attribute_math.hh"
17#include "BKE_mesh.hh"
18
19#include "attribute_convert.hh"
20#include "draw_attributes.hh"
21#include "draw_cache_inline.hh"
22#include "draw_subdivision.hh"
23#include "extract_mesh.hh"
24
25#include "GPU_vertex_buffer.hh"
26
27namespace blender::draw {
28
29/* ---------------------------------------------------------------------- */
34 gpu::VertBuf &vbo,
35 const DRW_AttributeRequest &request,
36 bool build_on_device,
38{
39 char attr_name[32], attr_safe_name[GPU_MAX_SAFE_ATTR_NAME];
41 /* Attributes use auto-name. */
42 SNPRINTF(attr_name, "a%s", attr_safe_name);
43
46
49 }
52 }
53
54 if (build_on_device) {
56 }
57 else {
60 }
61}
62
63template<typename T>
64static void extract_data_mesh_mapped_corner(const Span<T> attribute,
65 const Span<int> indices,
66 gpu::VertBuf &vbo)
67{
68 using Converter = AttributeConverter<T>;
69 using VBOType = typename Converter::VBOType;
70 MutableSpan data = vbo.data<VBOType>();
71
72 if constexpr (std::is_same_v<T, VBOType>) {
73 array_utils::gather(attribute, indices, data);
74 }
75 else {
76 threading::parallel_for(indices.index_range(), 8192, [&](const IndexRange range) {
77 for (const int i : range) {
78 data[i] = Converter::convert(attribute[indices[i]]);
79 }
80 });
81 }
82}
83
84template<typename T>
86 const Span<T> attribute,
87 gpu::VertBuf &vbo)
88{
89 using Converter = AttributeConverter<T>;
90 using VBOType = typename Converter::VBOType;
91 MutableSpan data = vbo.data<VBOType>();
92
93 threading::parallel_for(faces.index_range(), 2048, [&](const IndexRange range) {
94 for (const int i : range) {
95 data.slice(faces[i]).fill(Converter::convert(attribute[i]));
96 }
97 });
98}
99
100template<typename T>
101static void extract_data_bmesh_vert(const BMesh &bm, const int cd_offset, gpu::VertBuf &vbo)
102{
103 using Converter = AttributeConverter<T>;
104 using VBOType = typename Converter::VBOType;
105 VBOType *data = vbo.data<VBOType>().data();
106
107 const BMFace *face;
108 BMIter f_iter;
109 BM_ITER_MESH (face, &f_iter, &const_cast<BMesh &>(bm), BM_FACES_OF_MESH) {
110 const BMLoop *loop = BM_FACE_FIRST_LOOP(face);
111 for ([[maybe_unused]] const int i : IndexRange(face->len)) {
112 const T *src = static_cast<const T *>(POINTER_OFFSET(loop->v->head.data, cd_offset));
113 *data = Converter::convert(*src);
114 loop = loop->next;
115 data++;
116 }
117 }
118}
119
120template<typename T>
121static void extract_data_bmesh_edge(const BMesh &bm, const int cd_offset, gpu::VertBuf &vbo)
122{
123 using Converter = AttributeConverter<T>;
124 using VBOType = typename Converter::VBOType;
125 VBOType *data = vbo.data<VBOType>().data();
126
127 const BMFace *face;
128 BMIter f_iter;
129 BM_ITER_MESH (face, &f_iter, &const_cast<BMesh &>(bm), BM_FACES_OF_MESH) {
130 const BMLoop *loop = BM_FACE_FIRST_LOOP(face);
131 for ([[maybe_unused]] const int i : IndexRange(face->len)) {
132 const T &src = *static_cast<const T *>(POINTER_OFFSET(loop->e->head.data, cd_offset));
133 *data = Converter::convert(src);
134 loop = loop->next;
135 data++;
136 }
137 }
138}
139
140template<typename T>
141static void extract_data_bmesh_face(const BMesh &bm, const int cd_offset, gpu::VertBuf &vbo)
142{
143 using Converter = AttributeConverter<T>;
144 using VBOType = typename Converter::VBOType;
145 VBOType *data = vbo.data<VBOType>().data();
146
147 const BMFace *face;
148 BMIter f_iter;
149 BM_ITER_MESH (face, &f_iter, &const_cast<BMesh &>(bm), BM_FACES_OF_MESH) {
150 const T &src = *static_cast<const T *>(POINTER_OFFSET(face->head.data, cd_offset));
151 std::fill_n(data, face->len, Converter::convert(src));
152 data += face->len;
153 }
154}
155
156template<typename T>
157static void extract_data_bmesh_loop(const BMesh &bm, const int cd_offset, gpu::VertBuf &vbo)
158{
159 using Converter = AttributeConverter<T>;
160 using VBOType = typename Converter::VBOType;
161 VBOType *data = vbo.data<VBOType>().data();
162
163 const BMFace *face;
164 BMIter f_iter;
165 BM_ITER_MESH (face, &f_iter, &const_cast<BMesh &>(bm), BM_FACES_OF_MESH) {
166 const BMLoop *loop = BM_FACE_FIRST_LOOP(face);
167 for ([[maybe_unused]] const int i : IndexRange(face->len)) {
168 const T &src = *static_cast<const T *>(POINTER_OFFSET(loop->head.data, cd_offset));
169 *data = Converter::convert(src);
170 loop = loop->next;
171 data++;
172 }
173 }
174}
175
177{
178 switch (domain) {
179 case bke::AttrDomain::Point:
180 return &bm.vdata;
181 case bke::AttrDomain::Corner:
182 return &bm.ldata;
183 case bke::AttrDomain::Face:
184 return &bm.pdata;
185 case bke::AttrDomain::Edge:
186 return &bm.edata;
187 default:
188 return nullptr;
189 }
190}
191
192static void extract_attribute(const MeshRenderData &mr,
193 const DRW_AttributeRequest &request,
194 gpu::VertBuf &vbo)
195{
196 if (mr.extract_type == MR_EXTRACT_BMESH) {
197 const CustomData &custom_data = *get_custom_data_for_domain(*mr.bm, request.domain);
198 const char *name = request.attribute_name;
199 const int cd_offset = CustomData_get_offset_named(&custom_data, request.cd_type, name);
200
201 bke::attribute_math::convert_to_static_type(request.cd_type, [&](auto dummy) {
202 using T = decltype(dummy);
203 if constexpr (!std::is_void_v<typename AttributeConverter<T>::VBOType>) {
204 switch (request.domain) {
205 case bke::AttrDomain::Point:
206 extract_data_bmesh_vert<T>(*mr.bm, cd_offset, vbo);
207 break;
208 case bke::AttrDomain::Edge:
209 extract_data_bmesh_edge<T>(*mr.bm, cd_offset, vbo);
210 break;
211 case bke::AttrDomain::Face:
212 extract_data_bmesh_face<T>(*mr.bm, cd_offset, vbo);
213 break;
214 case bke::AttrDomain::Corner:
215 extract_data_bmesh_loop<T>(*mr.bm, cd_offset, vbo);
216 break;
217 default:
218 BLI_assert_unreachable();
219 }
220 }
221 });
222 }
223 else {
224 const bke::AttributeAccessor attributes = mr.mesh->attributes();
225 const StringRef name = request.attribute_name;
226 const eCustomDataType data_type = request.cd_type;
227 const GVArraySpan attribute = *attributes.lookup_or_default(name, request.domain, data_type);
228
229 bke::attribute_math::convert_to_static_type(request.cd_type, [&](auto dummy) {
230 using T = decltype(dummy);
231 if constexpr (!std::is_void_v<typename AttributeConverter<T>::VBOType>) {
232 switch (request.domain) {
233 case bke::AttrDomain::Point:
234 extract_data_mesh_mapped_corner(attribute.typed<T>(), mr.corner_verts, vbo);
235 break;
236 case bke::AttrDomain::Edge:
237 extract_data_mesh_mapped_corner(attribute.typed<T>(), mr.corner_edges, vbo);
238 break;
239 case bke::AttrDomain::Face:
240 extract_data_mesh_face(mr.faces, attribute.typed<T>(), vbo);
241 break;
242 case bke::AttrDomain::Corner:
243 vertbuf_data_extract_direct(attribute.typed<T>(), vbo);
244 break;
245 default:
246 BLI_assert_unreachable();
247 }
248 }
249 });
250 }
251}
252
254 const Span<DRW_AttributeRequest> requests,
255 const Span<gpu::VertBuf *> vbos)
256{
257 for (const int i : vbos.index_range()) {
258 if (DRW_vbo_requested(vbos[i])) {
259 init_vbo_for_attribute(mr, *vbos[i], requests[i], false, uint32_t(mr.corners_num));
260 extract_attribute(mr, requests[i], *vbos[i]);
261 }
262 }
263}
264
266 const DRWSubdivCache &subdiv_cache,
267 const Span<DRW_AttributeRequest> requests,
268 const Span<gpu::VertBuf *> vbos)
269{
270 for (const int i : vbos.index_range()) {
271 if (DRW_vbo_requested(vbos[i])) {
272 const DRW_AttributeRequest &request = requests[i];
273
274 const Mesh *coarse_mesh = subdiv_cache.mesh;
275
276 /* Prepare VBO for coarse data. The compute shader only expects floats. */
277 gpu::VertBuf *src_data = GPU_vertbuf_calloc();
278 GPUVertFormat coarse_format = draw::init_format_for_attribute(request.cd_type, "data");
279 GPU_vertbuf_init_with_format_ex(*src_data, coarse_format, GPU_USAGE_STATIC);
280 GPU_vertbuf_data_alloc(*src_data, uint32_t(coarse_mesh->corners_num));
281
282 extract_attribute(mr, request, *src_data);
283
284 gpu::VertBuf &dst_buffer = *vbos[i];
285 init_vbo_for_attribute(mr, dst_buffer, request, true, subdiv_cache.num_subdiv_loops);
286
287 /* Ensure data is uploaded properly. */
288 GPU_vertbuf_tag_dirty(src_data);
289 bke::attribute_math::convert_to_static_type(request.cd_type, [&](auto dummy) {
290 using T = decltype(dummy);
291 using Converter = AttributeConverter<T>;
292 if constexpr (!std::is_void_v<typename Converter::VBOType>) {
293 draw_subdiv_interp_custom_data(subdiv_cache,
294 *src_data,
295 dst_buffer,
296 Converter::gpu_component_type,
297 Converter::gpu_component_len,
298 0);
299 }
300 });
301
302 GPU_vertbuf_discard(src_data);
303 }
304 }
305}
306
308{
309 static GPUVertFormat format = {0};
310 if (format.attr_len == 0) {
312 }
313
316 MutableSpan vbo_data = vbo.data<ColorGeometry4f>();
317
318 const StringRefNull attr_name = ".viewer";
319 const bke::AttributeAccessor attributes = mr.mesh->attributes();
320 const bke::AttributeReader attribute = attributes.lookup_or_default<ColorGeometry4f>(
321 attr_name, bke::AttrDomain::Corner, {1.0f, 0.0f, 1.0f, 1.0f});
322 attribute.varray.materialize(vbo_data);
323}
324
327} // namespace blender::draw
int CustomData_get_offset_named(const CustomData *data, eCustomDataType type, blender::StringRef name)
#define SNPRINTF(dst, format,...)
Definition BLI_string.h:597
#define POINTER_OFFSET(v, ofs)
#define STREQ(a, b)
void GPU_vertbuf_init_build_on_device(blender::gpu::VertBuf &verts, const GPUVertFormat &format, uint v_len)
void GPU_vertbuf_tag_dirty(blender::gpu::VertBuf *verts)
#define GPU_vertbuf_init_with_format(verts, format)
blender::gpu::VertBuf * GPU_vertbuf_calloc()
void GPU_vertbuf_data_alloc(blender::gpu::VertBuf &verts, uint v_len)
void GPU_vertbuf_init_with_format_ex(blender::gpu::VertBuf &verts, const GPUVertFormat &format, GPUUsageType)
void GPU_vertbuf_discard(blender::gpu::VertBuf *)
@ GPU_USAGE_STATIC
void GPU_vertformat_safe_attr_name(const char *attr_name, char *r_safe_name, uint max_len)
@ GPU_FETCH_FLOAT
uint GPU_vertformat_attr_add(GPUVertFormat *, const char *name, GPUVertCompType, uint comp_len, GPUVertFetchMode)
#define GPU_MAX_SAFE_ATTR_NAME
void GPU_vertformat_alias_add(GPUVertFormat *, const char *alias)
void GPU_vertformat_deinterleave(GPUVertFormat *format)
@ GPU_COMP_F32
Read Guarded memory(de)allocation.
#define BM_FACE_FIRST_LOOP(p)
#define BM_ITER_MESH(ele, iter, bm, itype)
@ BM_FACES_OF_MESH
ATTR_WARN_UNUSED_RESULT BMesh * bm
AttributeSet attributes
constexpr IndexRange index_range() const
Definition BLI_span.hh:402
MutableSpan< T > data()
Utilities for rendering attributes.
bool DRW_vbo_requested(blender::gpu::VertBuf *vbo)
int len
Extraction of Mesh data into VBO to feed to GPU.
format
void gather(const GVArray &src, const IndexMask &indices, GMutableSpan dst, int64_t grain_size=4096)
GPUVertFormat init_format_for_attribute(const eCustomDataType data_type, const StringRefNull vbo_name)
static void extract_data_bmesh_edge(const BMesh &bm, const int cd_offset, gpu::VertBuf &vbo)
static void init_vbo_for_attribute(const MeshRenderData &mr, gpu::VertBuf &vbo, const DRW_AttributeRequest &request, bool build_on_device, uint32_t len)
void extract_attributes_subdiv(const MeshRenderData &mr, const DRWSubdivCache &subdiv_cache, const Span< DRW_AttributeRequest > requests, const Span< gpu::VertBuf * > vbos)
static void extract_data_bmesh_vert(const BMesh &bm, const int cd_offset, gpu::VertBuf &vbo)
static const CustomData * get_custom_data_for_domain(const BMesh &bm, bke::AttrDomain domain)
static void extract_data_bmesh_loop(const BMesh &bm, const int cd_offset, gpu::VertBuf &vbo)
static void extract_data_mesh_face(const OffsetIndices< int > faces, const Span< T > attribute, gpu::VertBuf &vbo)
static void extract_data_bmesh_face(const BMesh &bm, const int cd_offset, gpu::VertBuf &vbo)
static void extract_attribute(const MeshRenderData &mr, const DRW_AttributeRequest &request, gpu::VertBuf &vbo)
void extract_attr_viewer(const MeshRenderData &mr, gpu::VertBuf &vbo)
void extract_attributes(const MeshRenderData &mr, const Span< DRW_AttributeRequest > requests, const Span< gpu::VertBuf * > vbos)
static void extract_data_mesh_mapped_corner(const Span< T > attribute, const Span< int > indices, 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
unsigned int uint32_t
Definition stdint.h:80
BMHeader head
void * data
BMHeader head
struct BMVert * v
struct BMEdge * e
struct BMLoop * next
BMHeader head
CustomData vdata
CustomData edata
CustomData pdata
CustomData ldata
int corners_num