Blender V4.5
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
8
9#include "BLI_array_utils.hh"
10#include "BLI_string.h"
11
12#include "BKE_attribute.hh"
13#include "BKE_attribute_math.hh"
14#include "BKE_mesh.hh"
15
16#include "attribute_convert.hh"
17#include "draw_attributes.hh"
18#include "draw_subdivision.hh"
19#include "extract_mesh.hh"
20
21#include "GPU_vertex_buffer.hh"
22
23namespace blender::draw {
24
25/* ---------------------------------------------------------------------- */
28
30 gpu::VertBuf &vbo,
31 const StringRef name,
32 const eCustomDataType type,
33 bool build_on_device,
34 uint32_t len)
35{
36 char attr_name[32], attr_safe_name[GPU_MAX_SAFE_ATTR_NAME];
38 /* Attributes use auto-name. */
39 SNPRINTF(attr_name, "a%s", attr_safe_name);
40
43
44 if (mr.active_color_name && name == mr.active_color_name) {
46 }
47 if (mr.default_color_name && name == mr.default_color_name) {
49 }
50
51 if (build_on_device) {
53 }
54 else {
57 }
58}
59
60template<typename T>
61static void extract_data_mesh_mapped_corner(const Span<T> attribute,
62 const Span<int> indices,
63 gpu::VertBuf &vbo)
64{
65 using Converter = AttributeConverter<T>;
66 using VBOType = typename Converter::VBOType;
68
69 if constexpr (std::is_same_v<T, VBOType>) {
70 array_utils::gather(attribute, indices, data);
71 }
72 else {
73 threading::parallel_for(indices.index_range(), 8192, [&](const IndexRange range) {
74 for (const int i : range) {
75 data[i] = Converter::convert(attribute[indices[i]]);
76 }
77 });
78 }
79}
80
81template<typename T>
83 const Span<T> attribute,
84 gpu::VertBuf &vbo)
85{
86 using Converter = AttributeConverter<T>;
87 using VBOType = typename Converter::VBOType;
89
90 threading::parallel_for(faces.index_range(), 2048, [&](const IndexRange range) {
91 for (const int i : range) {
92 data.slice(faces[i]).fill(Converter::convert(attribute[i]));
93 }
94 });
95}
96
97template<typename T>
98static void extract_data_bmesh_vert(const BMesh &bm, const int cd_offset, gpu::VertBuf &vbo)
99{
100 using Converter = AttributeConverter<T>;
101 using VBOType = typename Converter::VBOType;
102 VBOType *data = vbo.data<VBOType>().data();
103
104 const BMFace *face;
105 BMIter f_iter;
106 BM_ITER_MESH (face, &f_iter, &const_cast<BMesh &>(bm), BM_FACES_OF_MESH) {
107 const BMLoop *loop = BM_FACE_FIRST_LOOP(face);
108 for ([[maybe_unused]] const int i : IndexRange(face->len)) {
109 const T *src = static_cast<const T *>(POINTER_OFFSET(loop->v->head.data, cd_offset));
110 *data = Converter::convert(*src);
111 loop = loop->next;
112 data++;
113 }
114 }
115}
116
117template<typename T>
118static void extract_data_bmesh_edge(const BMesh &bm, const int cd_offset, gpu::VertBuf &vbo)
119{
120 using Converter = AttributeConverter<T>;
121 using VBOType = typename Converter::VBOType;
122 VBOType *data = vbo.data<VBOType>().data();
123
124 const BMFace *face;
125 BMIter f_iter;
126 BM_ITER_MESH (face, &f_iter, &const_cast<BMesh &>(bm), BM_FACES_OF_MESH) {
127 const BMLoop *loop = BM_FACE_FIRST_LOOP(face);
128 for ([[maybe_unused]] const int i : IndexRange(face->len)) {
129 const T &src = *static_cast<const T *>(POINTER_OFFSET(loop->e->head.data, cd_offset));
130 *data = Converter::convert(src);
131 loop = loop->next;
132 data++;
133 }
134 }
135}
136
137template<typename T>
138static void extract_data_bmesh_face(const BMesh &bm, const int cd_offset, gpu::VertBuf &vbo)
139{
140 using Converter = AttributeConverter<T>;
141 using VBOType = typename Converter::VBOType;
142 VBOType *data = vbo.data<VBOType>().data();
143
144 const BMFace *face;
145 BMIter f_iter;
146 BM_ITER_MESH (face, &f_iter, &const_cast<BMesh &>(bm), BM_FACES_OF_MESH) {
147 const T &src = *static_cast<const T *>(POINTER_OFFSET(face->head.data, cd_offset));
148 std::fill_n(data, face->len, Converter::convert(src));
149 data += face->len;
150 }
151}
152
153template<typename T>
154static void extract_data_bmesh_loop(const BMesh &bm, const int cd_offset, gpu::VertBuf &vbo)
155{
156 using Converter = AttributeConverter<T>;
157 using VBOType = typename Converter::VBOType;
158 VBOType *data = vbo.data<VBOType>().data();
159
160 const BMFace *face;
161 BMIter f_iter;
162 BM_ITER_MESH (face, &f_iter, &const_cast<BMesh &>(bm), BM_FACES_OF_MESH) {
163 const BMLoop *loop = BM_FACE_FIRST_LOOP(face);
164 for ([[maybe_unused]] const int i : IndexRange(face->len)) {
165 const T &src = *static_cast<const T *>(POINTER_OFFSET(loop->head.data, cd_offset));
166 *data = Converter::convert(src);
167 loop = loop->next;
168 data++;
169 }
170 }
171}
172
174 const int offset = -1;
177 operator bool() const
178 {
179 return offset != -1;
180 }
181};
182
184{
185 for (const CustomDataLayer &layer : Span(bm.vdata.layers, bm.vdata.totlayer)) {
186 if (layer.name == name) {
187 return {layer.offset, bke::AttrDomain::Point, eCustomDataType(layer.type)};
188 }
189 }
190 for (const CustomDataLayer &layer : Span(bm.edata.layers, bm.edata.totlayer)) {
191 if (layer.name == name) {
192 return {layer.offset, bke::AttrDomain::Edge, eCustomDataType(layer.type)};
193 }
194 }
195 for (const CustomDataLayer &layer : Span(bm.pdata.layers, bm.pdata.totlayer)) {
196 if (layer.name == name) {
197 return {layer.offset, bke::AttrDomain::Face, eCustomDataType(layer.type)};
198 }
199 }
200 for (const CustomDataLayer &layer : Span(bm.ldata.layers, bm.ldata.totlayer)) {
201 if (layer.name == name) {
202 return {layer.offset, bke::AttrDomain::Corner, eCustomDataType(layer.type)};
203 }
204 }
205 return {};
206}
207
209 const BMeshAttributeLookup &attr,
210 gpu::VertBuf &vbo)
211{
213 using T = decltype(dummy);
214 if constexpr (!std::is_void_v<typename AttributeConverter<T>::VBOType>) {
215 switch (attr.domain) {
216 case bke::AttrDomain::Point:
217 extract_data_bmesh_vert<T>(*mr.bm, attr.offset, vbo);
218 break;
219 case bke::AttrDomain::Edge:
220 extract_data_bmesh_edge<T>(*mr.bm, attr.offset, vbo);
221 break;
222 case bke::AttrDomain::Face:
223 extract_data_bmesh_face<T>(*mr.bm, attr.offset, vbo);
224 break;
225 case bke::AttrDomain::Corner:
226 extract_data_bmesh_loop<T>(*mr.bm, attr.offset, vbo);
227 break;
228 default:
229 BLI_assert_unreachable();
230 }
231 }
232 });
233}
234
236 const bke::GAttributeReader &attr,
237 gpu::VertBuf &vbo)
238{
240 using T = decltype(dummy);
241 if constexpr (!std::is_void_v<typename AttributeConverter<T>::VBOType>) {
242 switch (attr.domain) {
243 case bke::AttrDomain::Point:
244 extract_data_mesh_mapped_corner(GVArraySpan(*attr).typed<T>(), mr.corner_verts, vbo);
245 break;
246 case bke::AttrDomain::Edge:
247 extract_data_mesh_mapped_corner(GVArraySpan(*attr).typed<T>(), mr.corner_edges, vbo);
248 break;
249 case bke::AttrDomain::Face:
250 extract_data_mesh_face(mr.faces, GVArraySpan(*attr).typed<T>(), vbo);
251 break;
252 case bke::AttrDomain::Corner:
253 vertbuf_data_extract_direct(GVArraySpan(*attr).typed<T>(), vbo);
254 break;
255 default:
256 BLI_assert_unreachable();
257 }
258 }
259 });
260}
261
263{
266 const BMeshAttributeLookup attr = lookup_bmesh_attribute(*mr.bm, name);
267 if (!attr) {
268 return {};
269 }
270 const eCustomDataType type = attr.type;
271 init_vbo_for_attribute(mr, *vbo, name, type, false, uint32_t(mr.corners_num));
272 extract_attribute_data(mr, attr, *vbo);
273 }
274 else {
275 const bke::AttributeAccessor attributes = mr.mesh->attributes();
276 const bke::GAttributeReader attr = attributes.lookup(name);
277 if (!attr) {
278 return {};
279 }
281 init_vbo_for_attribute(mr, *vbo, name, type, false, uint32_t(mr.corners_num));
282 extract_attribute_data(mr, attr, *vbo);
283 }
284 return gpu::VertBufPtr(vbo);
285}
286
287static gpu::VertBufPtr init_coarse_data(const eCustomDataType type, const int coarse_corners_num)
288{
290 GPUVertFormat coarse_format = draw::init_format_for_attribute(type, "data");
292 GPU_vertbuf_data_alloc(*vbo, uint32_t(coarse_corners_num));
293 return gpu::VertBufPtr(vbo);
294}
295
297 const DRWSubdivCache &subdiv_cache,
298 const StringRef name)
299{
300
301 const Mesh *coarse_mesh = subdiv_cache.mesh;
302
303 /* Prepare VBO for coarse data. The compute shader only expects floats. */
304 gpu::VertBufPtr coarse_vbo;
305 eCustomDataType type;
307 const BMeshAttributeLookup attr = lookup_bmesh_attribute(*mr.bm, name);
308 if (!attr) {
309 return {};
310 }
311 type = attr.type;
312 coarse_vbo = init_coarse_data(type, coarse_mesh->corners_num);
313 extract_attribute_data(mr, attr, *coarse_vbo);
314 }
315 else {
316 const bke::AttributeAccessor attributes = mr.mesh->attributes();
317 const bke::GAttributeReader attr = attributes.lookup(name);
318 if (!attr) {
319 return {};
320 }
322 coarse_vbo = init_coarse_data(type, coarse_mesh->corners_num);
323 extract_attribute_data(mr, attr, *coarse_vbo);
324 }
325
327 init_vbo_for_attribute(mr, *vbo, name, type, true, subdiv_cache.num_subdiv_loops);
328
329 /* Ensure data is uploaded properly. */
330 GPU_vertbuf_tag_dirty(coarse_vbo.get());
331 bke::attribute_math::convert_to_static_type(type, [&](auto dummy) {
332 using T = decltype(dummy);
333 using Converter = AttributeConverter<T>;
334 if constexpr (!std::is_void_v<typename Converter::VBOType>) {
336 *coarse_vbo,
337 *vbo,
338 Converter::gpu_component_type,
339 Converter::gpu_component_len,
340 0);
341 }
342 });
343
344 return gpu::VertBufPtr(vbo);
345}
346
348{
350 "attribute_value", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
351
354 MutableSpan vbo_data = vbo->data<ColorGeometry4f>();
355
356 const StringRefNull attr_name = ".viewer";
357 const bke::AttributeAccessor attributes = mr.mesh->attributes();
358 const bke::AttributeReader attribute = attributes.lookup_or_default<ColorGeometry4f>(
359 attr_name, bke::AttrDomain::Corner, {1.0f, 0.0f, 1.0f, 1.0f});
360 attribute.varray.materialize(vbo_data);
361 return vbo;
362}
363
365
366} // namespace blender::draw
#define SNPRINTF(dst, format,...)
Definition BLI_string.h:599
#define POINTER_OFFSET(v, ofs)
void GPU_vertbuf_init_build_on_device(blender::gpu::VertBuf &verts, const GPUVertFormat &format, uint v_len)
#define GPU_vertbuf_create_with_format(format)
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)
@ GPU_USAGE_STATIC
@ GPU_FETCH_FLOAT
void GPU_vertformat_alias_add(GPUVertFormat *, blender::StringRef alias)
void GPU_vertformat_safe_attr_name(blender::StringRef attr_name, char *r_safe_name, uint max_len)
static constexpr int GPU_MAX_SAFE_ATTR_NAME
GPUVertFormat GPU_vertformat_from_attribute(blender::StringRef name, const GPUVertCompType comp_type, const uint comp_len, const GPUVertFetchMode fetch_mode)
void GPU_vertformat_deinterleave(GPUVertFormat *format)
@ GPU_COMP_F32
#define BM_FACE_FIRST_LOOP(p)
#define BM_ITER_MESH(ele, iter, bm, itype)
@ BM_FACES_OF_MESH
BMesh const char void * data
BMesh * bm
AttributeSet attributes
constexpr T * data() const
Definition BLI_span.hh:539
GAttributeReader lookup(const StringRef attribute_id) const
GAttributeReader lookup_or_default(StringRef attribute_id, AttrDomain domain, eCustomDataType data_type, const void *default_value=nullptr) const
MutableSpan< T > data()
Utilities for rendering attributes.
Extraction of Mesh data into VBO to feed to GPU.
static ushort indices[]
format
#define T
static char faces[256]
void gather(const GVArray &src, const IndexMask &indices, GMutableSpan dst, int64_t grain_size=4096)
void convert_to_static_type(const CPPType &cpp_type, const Func &func)
eCustomDataType cpp_type_to_custom_data_type(const CPPType &type)
static void extract_data_bmesh_edge(const BMesh &bm, const int cd_offset, gpu::VertBuf &vbo)
gpu::VertBufPtr extract_attribute_subdiv(const MeshRenderData &mr, const DRWSubdivCache &subdiv_cache, StringRef name)
static void init_vbo_for_attribute(const MeshRenderData &mr, gpu::VertBuf &vbo, const StringRef name, const eCustomDataType type, bool build_on_device, uint32_t len)
static void extract_data_bmesh_vert(const BMesh &bm, const int cd_offset, gpu::VertBuf &vbo)
void draw_subdiv_interp_custom_data(const DRWSubdivCache &cache, gpu::VertBuf &src_data, gpu::VertBuf &dst_data, GPUVertCompType comp_type, int dimensions, int dst_offset)
gpu::VertBufPtr extract_attribute(const MeshRenderData &mr, StringRef name)
static gpu::VertBufPtr init_coarse_data(const eCustomDataType type, const int coarse_corners_num)
GPUVertFormat init_format_for_attribute(const eCustomDataType data_type, const StringRef vbo_name)
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_data(const MeshRenderData &mr, const BMeshAttributeLookup &attr, gpu::VertBuf &vbo)
static BMeshAttributeLookup lookup_bmesh_attribute(const BMesh &bm, const StringRef name)
static void extract_data_mesh_mapped_corner(const Span< T > attribute, const Span< int > indices, gpu::VertBuf &vbo)
gpu::VertBufPtr extract_attr_viewer(const MeshRenderData &mr)
std::unique_ptr< gpu::VertBuf, gpu::VertBufDeleter > VertBufPtr
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
ColorSceneLinear4f< eAlpha::Premultiplied > ColorGeometry4f
Definition BLI_color.hh:342
BMHeader head
BMHeader head
void * data
BMHeader head
struct BMVert * v
struct BMEdge * e
struct BMLoop * next
BMHeader head
int corners_num
i
Definition text_draw.cc:230
uint len