Blender V4.5
geometry_attributes.cpp
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
2 *
3 * SPDX-License-Identifier: Apache-2.0 */
4
5#include "bvh/bvh.h"
6
7#include "device/device.h"
8
9#include "scene/attribute.h"
10#include "scene/camera.h"
11#include "scene/geometry.h"
12#include "scene/hair.h"
13#include "scene/light.h"
14#include "scene/mesh.h"
15#include "scene/object.h"
16#include "scene/scene.h"
17#include "scene/shader.h"
18#include "scene/shader_nodes.h"
19
20#include "util/progress.h"
21
23
25{
26 if (std == ATTR_STD_NONE) {
27 return false;
28 }
29
30 if (scene->need_global_attribute(std)) {
31 return true;
32 }
33
34 for (Node *node : used_shaders) {
35 Shader *shader = static_cast<Shader *>(node);
36 if (shader->attributes.find(std)) {
37 return true;
38 }
39 }
40
41 return false;
42}
43
44bool Geometry::need_attribute(Scene * /*scene*/, ustring name)
45{
46 if (name.empty()) {
47 return false;
48 }
49
50 for (Node *node : used_shaders) {
51 Shader *shader = static_cast<Shader *>(node);
52 if (shader->attributes.find(name)) {
53 return true;
54 }
55 }
56
57 return false;
58}
59
61{
63
64 for (Node *node : used_shaders) {
65 Shader *shader = static_cast<Shader *>(node);
66 result.add(shader->attributes);
67 }
68
69 return result;
70}
71
73{
74 for (const Attribute &attr : attributes.attributes) {
75 if (attr.element == ATTR_ELEMENT_VOXEL) {
76 return true;
77 }
78 }
79
80 return false;
81}
82
83/* Generate a normal attribute map entry from an attribute descriptor. */
85 const size_t index,
86 const uint64_t id,
87 const TypeDesc type,
88 const AttributeDescriptor &desc)
89{
90 attr_map[index].id = id;
91 attr_map[index].element = desc.element;
92 attr_map[index].offset = as_uint(desc.offset);
93
94 if (type == TypeFloat) {
95 attr_map[index].type = NODE_ATTR_FLOAT;
96 }
97 else if (type == TypeMatrix) {
98 attr_map[index].type = NODE_ATTR_MATRIX;
99 }
100 else if (type == TypeFloat2) {
101 attr_map[index].type = NODE_ATTR_FLOAT2;
102 }
103 else if (type == TypeFloat4) {
104 attr_map[index].type = NODE_ATTR_FLOAT4;
105 }
106 else if (type == TypeRGBA) {
107 attr_map[index].type = NODE_ATTR_RGBA;
108 }
109 else {
110 attr_map[index].type = NODE_ATTR_FLOAT3;
111 }
112}
113
114/* Generate an attribute map end marker, optionally including a link to another map.
115 * Links are used to connect object attribute maps to mesh attribute maps. */
117 const size_t index,
118 const bool chain,
119 const uint chain_link)
120{
121 for (int j = 0; j < ATTR_PRIM_TYPES; j++) {
122 attr_map[index + j].id = ATTR_STD_NONE;
123 attr_map[index + j].element = chain; /* link is valid flag */
124 attr_map[index + j].offset = chain ? chain_link + j : 0; /* link to the correct sub-entry */
125 attr_map[index + j].type = 0;
126 }
127}
128
129/* Generate all necessary attribute map entries from the attribute request. */
131 const size_t index,
132 const uint64_t id,
133 AttributeRequest &req)
134{
135 emit_attribute_map_entry(attr_map, index, id, req.type, req.desc);
136}
137
139 DeviceScene *dscene,
140 Scene *scene,
141 vector<AttributeRequestSet> &geom_attributes,
142 vector<AttributeRequestSet> &object_attributes)
143{
144 /* for SVM, the attributes_map table is used to lookup the offset of an
145 * attribute, based on a unique shader attribute id. */
146
147 /* compute array stride */
148 size_t attr_map_size = 0;
149
150 for (size_t i = 0; i < scene->geometry.size(); i++) {
151 Geometry *geom = scene->geometry[i];
152 geom->attr_map_offset = attr_map_size;
153
154#ifdef WITH_OSL
155 size_t attr_count = 0;
156 for (const AttributeRequest &req : geom_attributes[i].requests) {
157 if (req.std != ATTR_STD_NONE &&
158 scene->shader_manager->get_attribute_id(req.std) != (uint64_t)req.std)
159 {
160 attr_count += 2;
161 }
162 else {
163 attr_count += 1;
164 }
165 }
166#else
167 const size_t attr_count = geom_attributes[i].size();
168#endif
169
170 attr_map_size += (attr_count + 1) * ATTR_PRIM_TYPES;
171 }
172
173 for (size_t i = 0; i < scene->objects.size(); i++) {
174 Object *object = scene->objects[i];
175
176 /* only allocate a table for the object if it actually has attributes */
177 if (object_attributes[i].size() == 0) {
178 object->attr_map_offset = 0;
179 }
180 else {
181 object->attr_map_offset = attr_map_size;
182 attr_map_size += (object_attributes[i].size() + 1) * ATTR_PRIM_TYPES;
183 }
184 }
185
186 if (attr_map_size == 0) {
187 return;
188 }
189
190 if (!dscene->attributes_map.need_realloc()) {
191 return;
192 }
193
194 /* create attribute map */
195 AttributeMap *attr_map = dscene->attributes_map.alloc(attr_map_size);
196 memset(attr_map, 0, dscene->attributes_map.size() * sizeof(*attr_map));
197
198 for (size_t i = 0; i < scene->geometry.size(); i++) {
199 Geometry *geom = scene->geometry[i];
200 AttributeRequestSet &attributes = geom_attributes[i];
201
202 /* set geometry attributes */
203 size_t index = geom->attr_map_offset;
204
205 for (AttributeRequest &req : attributes.requests) {
206 uint64_t id;
207 if (req.std == ATTR_STD_NONE) {
208 id = scene->shader_manager->get_attribute_id(req.name);
209 }
210 else {
211 id = scene->shader_manager->get_attribute_id(req.std);
212 }
213
214 emit_attribute_mapping(attr_map, index, id, req);
215 index += ATTR_PRIM_TYPES;
216
217#ifdef WITH_OSL
218 /* Some standard attributes are explicitly referenced via their standard ID, so add those
219 * again in case they were added under a different attribute ID. */
220 if (req.std != ATTR_STD_NONE && id != (uint64_t)req.std) {
221 emit_attribute_mapping(attr_map, index, (uint64_t)req.std, req);
222 index += ATTR_PRIM_TYPES;
223 }
224#endif
225 }
226
227 emit_attribute_map_terminator(attr_map, index, false, 0);
228 }
229
230 for (size_t i = 0; i < scene->objects.size(); i++) {
231 Object *object = scene->objects[i];
232 AttributeRequestSet &attributes = object_attributes[i];
233
234 /* set object attributes */
235 if (attributes.size() > 0) {
236 size_t index = object->attr_map_offset;
237
238 for (AttributeRequest &req : attributes.requests) {
239 uint64_t id;
240 if (req.std == ATTR_STD_NONE) {
241 id = scene->shader_manager->get_attribute_id(req.name);
242 }
243 else {
244 id = scene->shader_manager->get_attribute_id(req.std);
245 }
246
247 emit_attribute_mapping(attr_map, index, id, req);
248 index += ATTR_PRIM_TYPES;
249 }
250
251 emit_attribute_map_terminator(attr_map, index, true, object->geometry->attr_map_offset);
252 }
253 }
254
255 /* copy to device */
257}
258
259template<typename T> struct AttributeTableEntry {
261 size_t offset;
262 size_t size;
263
264 void reserve(const size_t attr_size)
265 {
266 size += attr_size;
267 }
268
269 /* Templated on U since we'll want to assign float3 values to a packed_float3 device_vector. */
270 template<typename U> size_t add(const U *attr_data, const size_t attr_size, const bool modified)
271 {
272 assert(data.size() >= offset + attr_size);
273 size_t start_offset = offset;
274 if (modified) {
275 for (size_t k = 0; k < attr_size; k++) {
276 data[offset + k] = attr_data[k];
277 }
278 data.tag_modified();
279 }
280 offset += attr_size;
281 return start_offset;
282 }
283
284 void alloc()
285 {
286 data.alloc(size);
287 }
288};
289
291 public:
293 : attr_float{dscene->attributes_float, 0, 0},
294 attr_float2{dscene->attributes_float2, 0, 0},
295 attr_float3{dscene->attributes_float3, 0, 0},
296 attr_float4{dscene->attributes_float4, 0, 0},
297 attr_uchar4{dscene->attributes_uchar4, 0, 0}
298 {
299 }
300
306
307 void add(Geometry *geom,
308 Attribute *mattr,
310 TypeDesc &type,
312 {
313 if (mattr == nullptr) {
314 /* attribute not found */
316 desc.offset = 0;
317 return;
318 }
319
320 /* store element and type */
321 desc.element = mattr->element;
322 type = mattr->type;
323
324 /* store attribute data in arrays */
325 const size_t size = mattr->element_size(geom, prim);
326
327 const AttributeElement &element = desc.element;
328 int &offset = desc.offset;
329
330 if (mattr->element == ATTR_ELEMENT_VOXEL) {
331 /* store slot in offset value */
332 const ImageHandle &handle = mattr->data_voxel();
333 offset = handle.svm_slot();
334 }
335 else if (mattr->element == ATTR_ELEMENT_CORNER_BYTE) {
336 offset = attr_uchar4.add(mattr->data_uchar4(), size, mattr->modified);
337 }
338 else if (mattr->type == TypeFloat) {
339 offset = attr_float.add(mattr->data_float(), size, mattr->modified);
340 }
341 else if (mattr->type == TypeFloat2) {
342 offset = attr_float2.add(mattr->data_float2(), size, mattr->modified);
343 }
344 else if (mattr->type == TypeMatrix) {
345 offset = attr_float4.add((float4 *)mattr->data_transform(), size * 3, mattr->modified);
346 }
347 else if (mattr->type == TypeFloat4 || mattr->type == TypeRGBA) {
348 offset = attr_float4.add(mattr->data_float4(), size, mattr->modified);
349 }
350 else {
351 offset = attr_float3.add(mattr->data_float3(), size, mattr->modified);
352 }
353
354 /* mesh vertex/curve index is global, not per object, so we sneak
355 * a correction for that in here */
356 if (geom->is_mesh()) {
357 Mesh *mesh = static_cast<Mesh *>(geom);
359 offset -= mesh->vert_offset;
360 }
362 offset -= mesh->vert_offset;
363 }
364 else if (element == ATTR_ELEMENT_FACE) {
365 offset -= mesh->prim_offset;
366 }
368 offset -= 3 * mesh->prim_offset;
369 }
370 }
371 else if (geom->is_hair()) {
372 Hair *hair = static_cast<Hair *>(geom);
374 offset -= hair->prim_offset;
375 }
376 else if (element == ATTR_ELEMENT_CURVE_KEY) {
377 offset -= hair->curve_key_offset;
378 }
380 offset -= hair->curve_key_offset;
381 }
382 }
383 else if (geom->is_pointcloud()) {
385 offset -= geom->prim_offset;
386 }
388 offset -= geom->prim_offset;
389 }
390 }
391 }
392
394 {
395 if (mattr == nullptr) {
396 return;
397 }
398
399 const size_t size = mattr->element_size(geom, prim);
400
401 if (mattr->element == ATTR_ELEMENT_VOXEL) {
402 /* pass */
403 }
404 else if (mattr->element == ATTR_ELEMENT_CORNER_BYTE) {
405 attr_uchar4.reserve(size);
406 }
407 else if (mattr->type == TypeFloat) {
408 attr_float.reserve(size);
409 }
410 else if (mattr->type == TypeFloat2) {
411 attr_float2.reserve(size);
412 }
413 else if (mattr->type == TypeMatrix) {
414 attr_float4.reserve(size * 3);
415 }
416 else if (mattr->type == TypeFloat4 || mattr->type == TypeRGBA) {
417 attr_float4.reserve(size);
418 }
419 else {
420 attr_float3.reserve(size);
421 }
422 }
423
424 void alloc()
425 {
426 attr_float.alloc();
427 attr_float2.alloc();
428 attr_float3.alloc();
429 attr_float4.alloc();
430 attr_uchar4.alloc();
431 }
432
434 {
435 attr_float.data.copy_to_device_if_modified();
436 attr_float2.data.copy_to_device_if_modified();
437 attr_float3.data.copy_to_device_if_modified();
438 attr_float4.data.copy_to_device_if_modified();
439 attr_uchar4.data.copy_to_device_if_modified();
440 }
441};
442
444 DeviceScene *dscene,
445 Scene *scene,
447{
448 progress.set_status("Updating Mesh", "Computing attributes");
449
450 /* gather per mesh requested attributes. as meshes may have multiple
451 * shaders assigned, this merges the requested attributes that have
452 * been set per shader by the shader manager */
453 vector<AttributeRequestSet> geom_attributes(scene->geometry.size());
454
455 for (size_t i = 0; i < scene->geometry.size(); i++) {
456 Geometry *geom = scene->geometry[i];
457
458 geom->index = i;
459 scene->need_global_attributes(geom_attributes[i]);
460
461 for (Node *node : geom->get_used_shaders()) {
462 Shader *shader = static_cast<Shader *>(node);
463 geom_attributes[i].add(shader->attributes);
464 }
465
466 if (geom->is_hair() && static_cast<Hair *>(geom)->need_shadow_transparency()) {
467 geom_attributes[i].add(ATTR_STD_SHADOW_TRANSPARENCY);
468 }
469 }
470
471 /* convert object attributes to use the same data structures as geometry ones */
472 vector<AttributeRequestSet> object_attributes(scene->objects.size());
473 vector<AttributeSet> object_attribute_values;
474
475 object_attribute_values.reserve(scene->objects.size());
476
477 for (size_t i = 0; i < scene->objects.size(); i++) {
478 Object *object = scene->objects[i];
479 Geometry *geom = object->geometry;
480 const size_t geom_idx = geom->index;
481
482 assert(geom_idx < scene->geometry.size() && scene->geometry[geom_idx] == geom);
483
484 object_attribute_values.push_back(AttributeSet(geom, ATTR_PRIM_GEOMETRY));
485
486 AttributeRequestSet &geom_requests = geom_attributes[geom_idx];
487 AttributeRequestSet &attributes = object_attributes[i];
488 AttributeSet &values = object_attribute_values[i];
489
490 for (size_t j = 0; j < object->attributes.size(); j++) {
491 const ParamValue &param = object->attributes[j];
492
493 /* add attributes that are requested and not already handled by the mesh */
494 if (geom_requests.find(param.name()) && !geom->attributes.find(param.name())) {
495 attributes.add(param.name());
496
497 Attribute *attr = values.add(param.name(), param.type(), ATTR_ELEMENT_OBJECT);
498 assert(param.datasize() == attr->buffer.size());
499 memcpy(attr->buffer.data(), param.data(), param.datasize());
500 }
501 }
502 }
503
504 /* mesh attribute are stored in a single array per data type. here we fill
505 * those arrays, and set the offset and element type to create attribute
506 * maps next */
507
508 /* Pre-allocate attributes to avoid arrays re-allocation which would
509 * take 2x of overall attribute memory usage.
510 */
511 AttributeTableBuilder builder(dscene);
512
513 for (size_t i = 0; i < scene->geometry.size(); i++) {
514 Geometry *geom = scene->geometry[i];
515 AttributeRequestSet &attributes = geom_attributes[i];
516 for (AttributeRequest &req : attributes.requests) {
517 Attribute *attr = geom->attributes.find(req);
518 builder.reserve(geom, attr, ATTR_PRIM_GEOMETRY);
519 }
520 }
521
522 for (size_t i = 0; i < scene->objects.size(); i++) {
523 Object *object = scene->objects[i];
524
525 for (Attribute &attr : object_attribute_values[i].attributes) {
526 builder.reserve(object->geometry, &attr, ATTR_PRIM_GEOMETRY);
527 }
528 }
529
530 builder.alloc();
531
532 /* The order of those flags needs to match that of AttrKernelDataType. */
533 const bool attributes_need_realloc[AttrKernelDataType::NUM] = {
537 dscene->attributes_float4.need_realloc(),
539 };
540
541 /* Fill in attributes. */
542 for (size_t i = 0; i < scene->geometry.size(); i++) {
543 Geometry *geom = scene->geometry[i];
544 AttributeRequestSet &attributes = geom_attributes[i];
545
546 /* todo: we now store std and name attributes from requests even if
547 * they actually refer to the same mesh attributes, optimize */
548 for (AttributeRequest &req : attributes.requests) {
549 Attribute *attr = geom->attributes.find(req);
550
551 /* Keep "N" attribute undisplaced for backwards compatibility in Blender 4.5. */
552 if (attr && attr->std == ATTR_STD_VERTEX_NORMAL) {
553 if (Attribute *undisplaced_attr = geom->attributes.find(ATTR_STD_NORMAL_UNDISPLACED)) {
554 attr = undisplaced_attr;
555 }
556 }
557
558 if (attr) {
559 /* force a copy if we need to reallocate all the data */
560 attr->modified |= attributes_need_realloc[Attribute::kernel_type(*attr)];
561 }
562
563 builder.add(geom, attr, ATTR_PRIM_GEOMETRY, req.type, req.desc);
564
565 if (progress.get_cancel()) {
566 return;
567 }
568 }
569 }
570
571 for (size_t i = 0; i < scene->objects.size(); i++) {
572 Object *object = scene->objects[i];
573 AttributeRequestSet &attributes = object_attributes[i];
574 AttributeSet &values = object_attribute_values[i];
575
576 for (AttributeRequest &req : attributes.requests) {
577 Attribute *attr = values.find(req);
578
579 if (attr) {
580 attr->modified |= attributes_need_realloc[Attribute::kernel_type(*attr)];
581 }
582
583 builder.add(object->geometry, attr, ATTR_PRIM_GEOMETRY, req.type, req.desc);
584
585 if (progress.get_cancel()) {
586 return;
587 }
588 }
589 }
590
591 /* create attribute lookup maps */
592 if (scene->shader_manager->use_osl()) {
593 update_osl_globals(device, scene);
594 }
595
596 update_svm_attributes(device, dscene, scene, geom_attributes, object_attributes);
597
598 if (progress.get_cancel()) {
599 return;
600 }
601
602 /* copy to device */
603 progress.set_status("Updating Mesh", "Copying Attributes to device");
604
606
607 if (progress.get_cancel()) {
608 return;
609 }
610
611 /* After mesh attributes and patch tables have been copied to device memory,
612 * we need to update offsets in the objects. */
613 scene->object_manager->device_update_geom_offsets(device, dscene, scene);
614}
615
unsigned int uint
float progress
Definition WM_types.hh:1019
#define U
ATTR_WARN_UNUSED_RESULT const void * element
unsigned long long int uint64_t
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
vector< AttributeRequest > requests
bool find(ustring name)
void add(ustring name)
AttributeDescriptor desc
AttributeStandard std
Attribute * find(ustring name) const
Attribute * add(ustring name, const TypeDesc type, AttributeElement element)
void add(Geometry *geom, Attribute *mattr, AttributePrimitive prim, TypeDesc &type, AttributeDescriptor &desc)
AttributeTableEntry< packed_float3 > attr_float3
AttributeTableEntry< float2 > attr_float2
AttributeTableBuilder(DeviceScene *dscene)
void reserve(Geometry *geom, Attribute *mattr, AttributePrimitive prim)
AttributeTableEntry< uchar4 > attr_uchar4
AttributeTableEntry< float > attr_float
AttributeTableEntry< float4 > attr_float4
device_vector< float4 > attributes_float4
Definition devicescene.h:56
device_vector< float2 > attributes_float2
Definition devicescene.h:54
device_vector< AttributeMap > attributes_map
Definition devicescene.h:52
device_vector< packed_float3 > attributes_float3
Definition devicescene.h:55
device_vector< float > attributes_float
Definition devicescene.h:53
device_vector< uchar4 > attributes_uchar4
Definition devicescene.h:57
void device_update_attributes(Device *device, DeviceScene *dscene, Scene *scene, Progress &progress)
void update_osl_globals(Device *device, Scene *scene)
void update_svm_attributes(Device *device, DeviceScene *dscene, Scene *scene, vector< AttributeRequestSet > &geom_attributes, vector< AttributeRequestSet > &object_attributes)
bool has_voxel_attributes() const
bool is_pointcloud() const
bool is_hair() const
AttributeRequestSet needed_attributes()
size_t attr_map_offset
size_t prim_offset
bool need_attribute(Scene *scene, AttributeStandard std)
AttributeSet attributes
bool is_mesh() const
Definition hair.h:13
bool need_shadow_transparency()
Definition hair.cpp:582
size_t curve_key_offset
Definition hair.h:89
int svm_slot(const int slot_index=0) const
AttributeRequestSet attributes
size_t size() const
T * alloc(const size_t width, const size_t height=0, const size_t depth=0)
size_t size() const
#define CCL_NAMESPACE_END
static void emit_attribute_mapping(AttributeMap *attr_map, const size_t index, const uint64_t id, AttributeRequest &req)
static void emit_attribute_map_terminator(AttributeMap *attr_map, const size_t index, const bool chain, const uint chain_link)
static void emit_attribute_map_entry(AttributeMap *attr_map, const size_t index, const uint64_t id, const TypeDesc type, const AttributeDescriptor &desc)
VecBase< float, 4 > float4
#define assert(assertion)
static uint attr_size(const GPUVertAttr *a)
@ NODE_ATTR_FLOAT
@ NODE_ATTR_FLOAT3
@ NODE_ATTR_RGBA
@ NODE_ATTR_FLOAT2
@ NODE_ATTR_FLOAT4
@ NODE_ATTR_MATRIX
AttributeStandard
@ ATTR_STD_VERTEX_NORMAL
@ ATTR_STD_NONE
@ ATTR_STD_NORMAL_UNDISPLACED
@ ATTR_STD_SHADOW_TRANSPARENCY
AttributeElement
@ ATTR_ELEMENT_NONE
@ ATTR_ELEMENT_CORNER_BYTE
@ ATTR_ELEMENT_CURVE_KEY
@ ATTR_ELEMENT_CURVE_KEY_MOTION
@ ATTR_ELEMENT_VOXEL
@ ATTR_ELEMENT_CORNER
@ ATTR_ELEMENT_OBJECT
@ ATTR_ELEMENT_VERTEX_MOTION
@ ATTR_ELEMENT_VERTEX
@ ATTR_ELEMENT_FACE
@ ATTR_ELEMENT_CURVE
AttributePrimitive
@ ATTR_PRIM_TYPES
@ ATTR_PRIM_GEOMETRY
ccl_device_inline uint as_uint(const int i)
Definition math_base.h:236
static constexpr TypeDesc TypeRGBA(TypeDesc::FLOAT, TypeDesc::VEC4, TypeDesc::COLOR)
@ NUM
long long TypeDesc
AttributeElement element
uint16_t element
size_t add(const U *attr_data, const size_t attr_size, const bool modified)
void reserve(const size_t attr_size)
device_vector< T > & data
AttributeElement element
uchar4 * data_uchar4()
static AttrKernelDataType kernel_type(const Attribute &attr)
TypeDesc type
size_t element_size(Geometry *geom, AttributePrimitive prim) const
vector< char > buffer
float * data_float()
AttributeStandard std
ImageHandle & data_voxel()
float3 * data_float3()
float4 * data_float4()
Transform * data_transform()
float2 * data_float2()
size_t vert_offset
Definition scene/mesh.h:171
ustring name
Definition graph/node.h:177
Node(const NodeType *type, ustring name=ustring())
size_t attr_map_offset
unique_ptr< ObjectManager > object_manager
Definition scene.h:150
bool need_global_attribute(AttributeStandard std)
Definition scene.cpp:418
void need_global_attributes(AttributeRequestSet &attributes)
Definition scene.cpp:438
unique_ptr_vector< Geometry > geometry
Definition scene.h:140
unique_ptr< ShaderManager > shader_manager
Definition scene.h:148
unique_ptr_vector< Object > objects
Definition scene.h:141
i
Definition text_draw.cc:230