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
8
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/* ---------------------------------------------------------------------- */
32
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>
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>) {
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) {
180 return &bm.vdata;
182 return &bm.ldata;
184 return &bm.pdata;
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
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);
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();
321 attr_name, bke::AttrDomain::Corner, {1.0f, 0.0f, 1.0f, 1.0f});
322 attribute.varray.materialize(vbo_data);
323}
324
326
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.
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block Image Sample an image file as a texture Gabor Generate Gabor noise Gradient Generate interpolated color and intensity values based on the input vector Magic Generate a psychedelic color texture Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a or normal between and object coordinate space Combine Create a color from its and value channels Color Retrieve a color attribute
#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
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.
bool DRW_vbo_requested(blender::gpu::VertBuf *vbo)
int len
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)
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
ColorSceneLinear4f< eAlpha::Premultiplied > ColorGeometry4f
Definition BLI_color.hh:337
unsigned int uint32_t
Definition stdint.h:80
BMHeader head
BMHeader head
void * data
BMHeader head
struct BMVert * v
struct BMEdge * e
struct BMLoop * next
BMHeader head
int corners_num