Blender V5.0
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"
14#include "BKE_attribute_math.hh"
15#include "BKE_mesh.hh"
16
17#include "attribute_convert.hh"
18#include "draw_attributes.hh"
19#include "draw_subdivision.hh"
20#include "extract_mesh.hh"
21
22#include "GPU_vertex_buffer.hh"
23
24namespace blender::draw {
25
26/* ---------------------------------------------------------------------- */
29
31 gpu::VertBuf &vbo,
32 const StringRef name,
33 const bke::AttrType type,
34 bool build_on_device,
35 uint32_t len)
36{
37 char attr_name[32], attr_safe_name[GPU_MAX_SAFE_ATTR_NAME];
39 /* Attributes use auto-name. */
40 SNPRINTF(attr_name, "a%s", attr_safe_name);
41
44
47 }
50 }
51
52 if (build_on_device) {
54 }
55 else {
58 }
59}
60
61template<typename T>
62static void extract_data_mesh_mapped_corner(const Span<T> attribute,
63 const Span<int> indices,
64 gpu::VertBuf &vbo)
65{
66 using Converter = AttributeConverter<T>;
67 using VBOType = typename Converter::VBOType;
69
70 if constexpr (std::is_same_v<T, VBOType>) {
71 array_utils::gather(attribute, indices, data);
72 }
73 else {
74 threading::parallel_for(indices.index_range(), 8192, [&](const IndexRange range) {
75 for (const int i : range) {
76 data[i] = Converter::convert(attribute[indices[i]]);
77 }
78 });
79 }
80}
81
82template<typename T>
84 const Span<T> attribute,
85 gpu::VertBuf &vbo)
86{
87 using Converter = AttributeConverter<T>;
88 using VBOType = typename Converter::VBOType;
90
91 threading::parallel_for(faces.index_range(), 2048, [&](const IndexRange range) {
92 for (const int i : range) {
93 data.slice(faces[i]).fill(Converter::convert(attribute[i]));
94 }
95 });
96}
97
98template<typename T>
99static void extract_data_bmesh_vert(const BMesh &bm, const int cd_offset, gpu::VertBuf &vbo)
100{
101 using Converter = AttributeConverter<T>;
102 using VBOType = typename Converter::VBOType;
103 VBOType *data = vbo.data<VBOType>().data();
104
105 const BMFace *face;
106 BMIter f_iter;
107 BM_ITER_MESH (face, &f_iter, &const_cast<BMesh &>(bm), BM_FACES_OF_MESH) {
108 const BMLoop *loop = BM_FACE_FIRST_LOOP(face);
109 for ([[maybe_unused]] const int i : IndexRange(face->len)) {
110 const T *src = static_cast<const T *>(POINTER_OFFSET(loop->v->head.data, cd_offset));
111 *data = Converter::convert(*src);
112 loop = loop->next;
113 data++;
114 }
115 }
116}
117
118template<typename T>
119static void extract_data_bmesh_edge(const BMesh &bm, const int cd_offset, gpu::VertBuf &vbo)
120{
121 using Converter = AttributeConverter<T>;
122 using VBOType = typename Converter::VBOType;
123 VBOType *data = vbo.data<VBOType>().data();
124
125 const BMFace *face;
126 BMIter f_iter;
127 BM_ITER_MESH (face, &f_iter, &const_cast<BMesh &>(bm), BM_FACES_OF_MESH) {
128 const BMLoop *loop = BM_FACE_FIRST_LOOP(face);
129 for ([[maybe_unused]] const int i : IndexRange(face->len)) {
130 const T &src = *static_cast<const T *>(POINTER_OFFSET(loop->e->head.data, cd_offset));
131 *data = Converter::convert(src);
132 loop = loop->next;
133 data++;
134 }
135 }
136}
137
138template<typename T>
139static void extract_data_bmesh_face(const BMesh &bm, const int cd_offset, gpu::VertBuf &vbo)
140{
141 using Converter = AttributeConverter<T>;
142 using VBOType = typename Converter::VBOType;
143 VBOType *data = vbo.data<VBOType>().data();
144
145 const BMFace *face;
146 BMIter f_iter;
147 BM_ITER_MESH (face, &f_iter, &const_cast<BMesh &>(bm), BM_FACES_OF_MESH) {
148 const T &src = *static_cast<const T *>(POINTER_OFFSET(face->head.data, cd_offset));
149 std::fill_n(data, face->len, Converter::convert(src));
150 data += face->len;
151 }
152}
153
154template<typename T>
155static void extract_data_bmesh_loop(const BMesh &bm, const int cd_offset, gpu::VertBuf &vbo)
156{
157 using Converter = AttributeConverter<T>;
158 using VBOType = typename Converter::VBOType;
159 VBOType *data = vbo.data<VBOType>().data();
160
161 const BMFace *face;
162 BMIter f_iter;
163 BM_ITER_MESH (face, &f_iter, &const_cast<BMesh &>(bm), BM_FACES_OF_MESH) {
164 const BMLoop *loop = BM_FACE_FIRST_LOOP(face);
165 for ([[maybe_unused]] const int i : IndexRange(face->len)) {
166 const T &src = *static_cast<const T *>(POINTER_OFFSET(loop->head.data, cd_offset));
167 *data = Converter::convert(src);
168 loop = loop->next;
169 data++;
170 }
171 }
172}
173
175 const BMDataLayerLookup &attr,
176 gpu::VertBuf &vbo)
177{
179 using T = decltype(dummy);
180 if constexpr (!std::is_void_v<typename AttributeConverter<T>::VBOType>) {
181 switch (attr.domain) {
182 case bke::AttrDomain::Point:
183 extract_data_bmesh_vert<T>(*mr.bm, attr.offset, vbo);
184 break;
185 case bke::AttrDomain::Edge:
186 extract_data_bmesh_edge<T>(*mr.bm, attr.offset, vbo);
187 break;
188 case bke::AttrDomain::Face:
189 extract_data_bmesh_face<T>(*mr.bm, attr.offset, vbo);
190 break;
191 case bke::AttrDomain::Corner:
192 extract_data_bmesh_loop<T>(*mr.bm, attr.offset, vbo);
193 break;
194 default:
195 BLI_assert_unreachable();
196 }
197 }
198 });
199}
200
202 const bke::GAttributeReader &attr,
203 gpu::VertBuf &vbo)
204{
206 using T = decltype(dummy);
207 if constexpr (!std::is_void_v<typename AttributeConverter<T>::VBOType>) {
208 switch (attr.domain) {
209 case bke::AttrDomain::Point:
210 extract_data_mesh_mapped_corner(GVArraySpan(*attr).typed<T>(), mr.corner_verts, vbo);
211 break;
212 case bke::AttrDomain::Edge:
213 extract_data_mesh_mapped_corner(GVArraySpan(*attr).typed<T>(), mr.corner_edges, vbo);
214 break;
215 case bke::AttrDomain::Face:
216 extract_data_mesh_face(mr.faces, GVArraySpan(*attr).typed<T>(), vbo);
217 break;
218 case bke::AttrDomain::Corner:
219 vertbuf_data_extract_direct(GVArraySpan(*attr).typed<T>(), vbo);
220 break;
221 default:
222 BLI_assert_unreachable();
223 }
224 }
225 });
226}
227
229{
233 if (!attr) {
234 return {};
235 }
236 const bke::AttrType type = attr.type;
237 init_vbo_for_attribute(mr, *vbo, name, type, false, uint32_t(mr.corners_num));
238 extract_attribute_data(mr, attr, *vbo);
239 }
240 else {
241 const bke::AttributeAccessor attributes = mr.mesh->attributes();
242 const bke::GAttributeReader attr = attributes.lookup(name);
243 if (!attr) {
244 return {};
245 }
247 init_vbo_for_attribute(mr, *vbo, name, type, false, uint32_t(mr.corners_num));
248 extract_attribute_data(mr, attr, *vbo);
249 }
250 return gpu::VertBufPtr(vbo);
251}
252
253static gpu::VertBufPtr init_coarse_data(const bke::AttrType type, const int coarse_corners_num)
254{
256 GPUVertFormat coarse_format = draw::init_format_for_attribute(type, "data");
258 GPU_vertbuf_data_alloc(*vbo, uint32_t(coarse_corners_num));
259 return gpu::VertBufPtr(vbo);
260}
261
263 const DRWSubdivCache &subdiv_cache,
264 const StringRef name)
265{
266
267 const Mesh *coarse_mesh = subdiv_cache.mesh;
268
269 /* Prepare VBO for coarse data. The compute shader only expects floats. */
270 gpu::VertBufPtr coarse_vbo;
271 bke::AttrType type;
274 if (!attr) {
275 return {};
276 }
277 type = attr.type;
278 coarse_vbo = init_coarse_data(type, coarse_mesh->corners_num);
279 extract_attribute_data(mr, attr, *coarse_vbo);
280 }
281 else {
282 const bke::AttributeAccessor attributes = mr.mesh->attributes();
283 const bke::GAttributeReader attr = attributes.lookup(name);
284 if (!attr) {
285 return {};
286 }
288 coarse_vbo = init_coarse_data(type, coarse_mesh->corners_num);
289 extract_attribute_data(mr, attr, *coarse_vbo);
290 }
291
293 init_vbo_for_attribute(mr, *vbo, name, type, true, subdiv_cache.num_subdiv_loops);
294
295 /* Ensure data is uploaded properly. */
296 GPU_vertbuf_tag_dirty(coarse_vbo.get());
297 bke::attribute_math::convert_to_static_type(type, [&](auto dummy) {
298 using T = decltype(dummy);
299 using Converter = AttributeConverter<T>;
300 if constexpr (!std::is_void_v<typename Converter::VBOType>) {
302 *coarse_vbo,
303 *vbo,
304 Converter::gpu_component_type,
305 Converter::gpu_component_len,
306 0);
307 }
308 });
309
310 return gpu::VertBufPtr(vbo);
311}
312
314{
316 "attribute_value", gpu::VertAttrType::SFLOAT_32_32_32_32);
317
320 MutableSpan vbo_data = vbo->data<ColorGeometry4f>();
321
322 const StringRefNull attr_name = ".viewer";
323 const bke::AttributeAccessor attributes = mr.mesh->attributes();
324 const bke::AttributeReader attribute = attributes.lookup_or_default<ColorGeometry4f>(
325 attr_name, bke::AttrDomain::Corner, {1.0f, 0.0f, 1.0f, 1.0f});
326 attribute.varray.materialize(vbo_data);
327 return vbo;
328}
329
331
332} // namespace blender::draw
#define SNPRINTF(dst, format,...)
Definition BLI_string.h:604
#define POINTER_OFFSET(v, ofs)
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)
static blender::gpu::VertBuf * GPU_vertbuf_create_with_format(const GPUVertFormat &format)
#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
void GPU_vertformat_alias_add(GPUVertFormat *, blender::StringRef alias)
GPUVertFormat GPU_vertformat_from_attribute(blender::StringRef name, blender::gpu::VertAttrType type)
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
void GPU_vertformat_deinterleave(GPUVertFormat *format)
#define BM_FACE_FIRST_LOOP(p)
BMDataLayerLookup BM_data_layer_lookup(const BMesh &bm, const blender::StringRef name)
#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_or_default(StringRef attribute_id, AttrDomain domain, AttrType data_type, const void *default_value=nullptr) const
GAttributeReader lookup(const StringRef attribute_id) 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)
AttrType cpp_type_to_attribute_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 gpu::VertBufPtr init_coarse_data(const bke::AttrType type, const int coarse_corners_num)
static void extract_data_bmesh_vert(const BMesh &bm, const int cd_offset, gpu::VertBuf &vbo)
static void init_vbo_for_attribute(const MeshRenderData &mr, gpu::VertBuf &vbo, const StringRef name, const bke::AttrType type, bool build_on_device, uint32_t len)
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 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)
GPUVertFormat init_format_for_attribute(const bke::AttrType data_type, const StringRef vbo_name)
static void extract_attribute_data(const MeshRenderData &mr, const BMDataLayerLookup &attr, gpu::VertBuf &vbo)
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
const char * name
blender::bke::AttrType type
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