Blender V5.0
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 const bool use_osl = scene->shader_manager->use_osl();
147
148 /* compute array stride */
149 size_t attr_map_size = 0;
150
151 for (size_t i = 0; i < scene->geometry.size(); i++) {
152 Geometry *geom = scene->geometry[i];
153 geom->attr_map_offset = attr_map_size;
154
155 size_t attr_count = 0;
156 if (use_osl) {
157 for (const AttributeRequest &req : geom_attributes[i].requests) {
158 if (req.std != ATTR_STD_NONE &&
159 scene->shader_manager->get_attribute_id(req.std) != (uint64_t)req.std)
160 {
161 attr_count += 2;
162 }
163 else {
164 attr_count += 1;
165 }
166 }
167 }
168 else {
169 attr_count = geom_attributes[i].size();
170 }
171
172 attr_map_size += (attr_count + 1) * ATTR_PRIM_TYPES;
173 }
174
175 for (size_t i = 0; i < scene->objects.size(); i++) {
176 Object *object = scene->objects[i];
177
178 /* only allocate a table for the object if it actually has attributes */
179 if (object_attributes[i].size() == 0) {
180 object->attr_map_offset = 0;
181 }
182 else {
183 object->attr_map_offset = attr_map_size;
184 attr_map_size += (object_attributes[i].size() + 1) * ATTR_PRIM_TYPES;
185 }
186 }
187
188 if (attr_map_size == 0) {
189 return;
190 }
191
192 if (!dscene->attributes_map.need_realloc()) {
193 return;
194 }
195
196 /* create attribute map */
197 AttributeMap *attr_map = dscene->attributes_map.alloc(attr_map_size);
198 memset(attr_map, 0, dscene->attributes_map.size() * sizeof(*attr_map));
199
200 for (size_t i = 0; i < scene->geometry.size(); i++) {
201 Geometry *geom = scene->geometry[i];
202 AttributeRequestSet &attributes = geom_attributes[i];
203
204 /* set geometry attributes */
205 size_t index = geom->attr_map_offset;
206
207 for (AttributeRequest &req : attributes.requests) {
208 uint64_t id;
209 if (req.std == ATTR_STD_NONE) {
210 id = scene->shader_manager->get_attribute_id(req.name);
211 }
212 else {
213 id = scene->shader_manager->get_attribute_id(req.std);
214 }
215
216 emit_attribute_mapping(attr_map, index, id, req);
217 index += ATTR_PRIM_TYPES;
218
219 if (use_osl) {
220 /* Some standard attributes are explicitly referenced via their standard ID, so add those
221 * again in case they were added under a different attribute ID. */
222 if (req.std != ATTR_STD_NONE && id != (uint64_t)req.std) {
223 emit_attribute_mapping(attr_map, index, (uint64_t)req.std, req);
224 index += ATTR_PRIM_TYPES;
225 }
226 }
227 }
228
229 emit_attribute_map_terminator(attr_map, index, false, 0);
230 }
231
232 for (size_t i = 0; i < scene->objects.size(); i++) {
233 Object *object = scene->objects[i];
234 AttributeRequestSet &attributes = object_attributes[i];
235
236 /* set object attributes */
237 if (attributes.size() > 0) {
238 size_t index = object->attr_map_offset;
239
240 for (AttributeRequest &req : attributes.requests) {
241 uint64_t id;
242 if (req.std == ATTR_STD_NONE) {
243 id = scene->shader_manager->get_attribute_id(req.name);
244 }
245 else {
246 id = scene->shader_manager->get_attribute_id(req.std);
247 }
248
249 emit_attribute_mapping(attr_map, index, id, req);
250 index += ATTR_PRIM_TYPES;
251 }
252
253 emit_attribute_map_terminator(attr_map, index, true, object->geometry->attr_map_offset);
254 }
255 }
256
257 /* copy to device */
259}
260
261template<typename T> struct AttributeTableEntry {
263 size_t offset;
264 size_t size;
265
266 void reserve(const size_t attr_size)
267 {
268 size += attr_size;
269 }
270
271 /* Templated on U since we'll want to assign float3 values to a packed_float3 device_vector. */
272 template<typename U> size_t add(const U *attr_data, const size_t attr_size, const bool modified)
273 {
274 assert(data.size() >= offset + attr_size);
275 size_t start_offset = offset;
276 if (modified) {
277 for (size_t k = 0; k < attr_size; k++) {
278 data[offset + k] = attr_data[k];
279 }
280 data.tag_modified();
281 }
282 offset += attr_size;
283 return start_offset;
284 }
285
286 void alloc()
287 {
288 data.alloc(size);
289 }
290};
291
293 public:
295 : attr_float{dscene->attributes_float, 0, 0},
296 attr_float2{dscene->attributes_float2, 0, 0},
297 attr_float3{dscene->attributes_float3, 0, 0},
298 attr_float4{dscene->attributes_float4, 0, 0},
299 attr_uchar4{dscene->attributes_uchar4, 0, 0}
300 {
301 }
302
308
309 void add(Geometry *geom,
310 Attribute *mattr,
312 TypeDesc &type,
314 {
315 if (mattr == nullptr) {
316 /* attribute not found */
318 desc.offset = 0;
319 return;
320 }
321
322 /* store element and type */
323 desc.element = mattr->element;
324 type = mattr->type;
325
326 /* store attribute data in arrays */
327 const size_t size = mattr->element_size(geom, prim);
328
329 const AttributeElement &element = desc.element;
330 int &offset = desc.offset;
331
332 if (mattr->element == ATTR_ELEMENT_VOXEL) {
333 /* store slot in offset value */
334 const ImageHandle &handle = mattr->data_voxel();
335 offset = handle.svm_slot();
336 }
337 else if (mattr->element == ATTR_ELEMENT_CORNER_BYTE) {
338 offset = attr_uchar4.add(mattr->data_uchar4(), size, mattr->modified);
339 }
340 else if (mattr->type == TypeFloat) {
341 offset = attr_float.add(mattr->data_float(), size, mattr->modified);
342 }
343 else if (mattr->type == TypeFloat2) {
344 offset = attr_float2.add(mattr->data_float2(), size, mattr->modified);
345 }
346 else if (mattr->type == TypeMatrix) {
347 offset = attr_float4.add((float4 *)mattr->data_transform(), size * 3, mattr->modified);
348 }
349 else if (mattr->type == TypeFloat4 || mattr->type == TypeRGBA) {
350 offset = attr_float4.add(mattr->data_float4(), size, mattr->modified);
351 }
352 else {
353 offset = attr_float3.add(mattr->data_float3(), size, mattr->modified);
354 }
355
356 /* mesh vertex/curve index is global, not per object, so we sneak
357 * a correction for that in here */
358 if (geom->is_mesh()) {
359 Mesh *mesh = static_cast<Mesh *>(geom);
361 offset -= mesh->vert_offset;
362 }
364 offset -= mesh->vert_offset;
365 }
366 else if (element == ATTR_ELEMENT_FACE) {
367 offset -= mesh->prim_offset;
368 }
370 offset -= 3 * mesh->prim_offset;
371 }
372 }
373 else if (geom->is_hair()) {
374 Hair *hair = static_cast<Hair *>(geom);
376 offset -= hair->prim_offset;
377 }
378 else if (element == ATTR_ELEMENT_CURVE_KEY) {
379 offset -= hair->curve_key_offset;
380 }
382 offset -= hair->curve_key_offset;
383 }
384 }
385 else if (geom->is_pointcloud()) {
387 offset -= geom->prim_offset;
388 }
390 offset -= geom->prim_offset;
391 }
392 }
393 }
394
396 {
397 if (mattr == nullptr) {
398 return;
399 }
400
401 const size_t size = mattr->element_size(geom, prim);
402
403 if (mattr->element == ATTR_ELEMENT_VOXEL) {
404 /* pass */
405 }
406 else if (mattr->element == ATTR_ELEMENT_CORNER_BYTE) {
407 attr_uchar4.reserve(size);
408 }
409 else if (mattr->type == TypeFloat) {
410 attr_float.reserve(size);
411 }
412 else if (mattr->type == TypeFloat2) {
413 attr_float2.reserve(size);
414 }
415 else if (mattr->type == TypeMatrix) {
416 attr_float4.reserve(size * 3);
417 }
418 else if (mattr->type == TypeFloat4 || mattr->type == TypeRGBA) {
419 attr_float4.reserve(size);
420 }
421 else {
422 attr_float3.reserve(size);
423 }
424 }
425
426 void alloc()
427 {
428 attr_float.alloc();
429 attr_float2.alloc();
430 attr_float3.alloc();
431 attr_float4.alloc();
432 attr_uchar4.alloc();
433 }
434
436 {
437 attr_float.data.copy_to_device_if_modified();
438 attr_float2.data.copy_to_device_if_modified();
439 attr_float3.data.copy_to_device_if_modified();
440 attr_float4.data.copy_to_device_if_modified();
441 attr_uchar4.data.copy_to_device_if_modified();
442 }
443};
444
446 DeviceScene *dscene,
447 Scene *scene,
448 Progress &progress)
449{
450 progress.set_status("Updating Mesh", "Computing attributes");
451
452 /* gather per mesh requested attributes. as meshes may have multiple
453 * shaders assigned, this merges the requested attributes that have
454 * been set per shader by the shader manager */
455 vector<AttributeRequestSet> geom_attributes(scene->geometry.size());
456
457 for (size_t i = 0; i < scene->geometry.size(); i++) {
458 Geometry *geom = scene->geometry[i];
459
460 geom->index = i;
461 scene->need_global_attributes(geom_attributes[i]);
462
463 for (Node *node : geom->get_used_shaders()) {
464 Shader *shader = static_cast<Shader *>(node);
465 geom_attributes[i].add(shader->attributes);
466 }
467
468 if (geom->is_hair() && static_cast<Hair *>(geom)->need_shadow_transparency()) {
469 geom_attributes[i].add(ATTR_STD_SHADOW_TRANSPARENCY);
470 }
471 }
472
473 /* convert object attributes to use the same data structures as geometry ones */
474 vector<AttributeRequestSet> object_attributes(scene->objects.size());
475 vector<AttributeSet> object_attribute_values;
476
477 object_attribute_values.reserve(scene->objects.size());
478
479 for (size_t i = 0; i < scene->objects.size(); i++) {
480 Object *object = scene->objects[i];
481 Geometry *geom = object->geometry;
482 const size_t geom_idx = geom->index;
483
484 assert(geom_idx < scene->geometry.size() && scene->geometry[geom_idx] == geom);
485
486 object_attribute_values.push_back(AttributeSet(geom, ATTR_PRIM_GEOMETRY));
487
488 AttributeRequestSet &geom_requests = geom_attributes[geom_idx];
489 AttributeRequestSet &attributes = object_attributes[i];
490 AttributeSet &values = object_attribute_values[i];
491
492 for (size_t j = 0; j < object->attributes.size(); j++) {
493 const ParamValue &param = object->attributes[j];
494
495 /* add attributes that are requested and not already handled by the mesh */
496 if (geom_requests.find(param.name()) && !geom->attributes.find(param.name())) {
497 attributes.add(param.name());
498
499 Attribute *attr = values.add(param.name(), param.type(), ATTR_ELEMENT_OBJECT);
500 assert(param.datasize() == attr->buffer.size());
501 memcpy(attr->buffer.data(), param.data(), param.datasize());
502 }
503 }
504 }
505
506 /* mesh attribute are stored in a single array per data type. here we fill
507 * those arrays, and set the offset and element type to create attribute
508 * maps next */
509
510 /* Pre-allocate attributes to avoid arrays re-allocation which would
511 * take 2x of overall attribute memory usage.
512 */
513 AttributeTableBuilder builder(dscene);
514
515 for (size_t i = 0; i < scene->geometry.size(); i++) {
516 Geometry *geom = scene->geometry[i];
517 AttributeRequestSet &attributes = geom_attributes[i];
518 for (AttributeRequest &req : attributes.requests) {
519 Attribute *attr = geom->attributes.find(req);
520 builder.reserve(geom, attr, ATTR_PRIM_GEOMETRY);
521 }
522 }
523
524 for (size_t i = 0; i < scene->objects.size(); i++) {
525 Object *object = scene->objects[i];
526
527 for (Attribute &attr : object_attribute_values[i].attributes) {
528 builder.reserve(object->geometry, &attr, ATTR_PRIM_GEOMETRY);
529 }
530 }
531
532 builder.alloc();
533
534 /* The order of those flags needs to match that of AttrKernelDataType. */
535 const bool attributes_need_realloc[AttrKernelDataType::NUM] = {
541 };
542
543 /* Fill in attributes. */
544 for (size_t i = 0; i < scene->geometry.size(); i++) {
545 Geometry *geom = scene->geometry[i];
546 AttributeRequestSet &attributes = geom_attributes[i];
547
548 /* todo: we now store std and name attributes from requests even if
549 * they actually refer to the same mesh attributes, optimize */
550 for (AttributeRequest &req : attributes.requests) {
551 Attribute *attr = geom->attributes.find(req);
552
553 if (attr) {
554 /* force a copy if we need to reallocate all the data */
555 attr->modified |= attributes_need_realloc[Attribute::kernel_type(*attr)];
556 }
557
558 builder.add(geom, attr, ATTR_PRIM_GEOMETRY, req.type, req.desc);
559
560 if (progress.get_cancel()) {
561 return;
562 }
563 }
564 }
565
566 for (size_t i = 0; i < scene->objects.size(); i++) {
567 Object *object = scene->objects[i];
568 AttributeRequestSet &attributes = object_attributes[i];
569 AttributeSet &values = object_attribute_values[i];
570
571 for (AttributeRequest &req : attributes.requests) {
572 Attribute *attr = values.find(req);
573
574 if (attr) {
575 attr->modified |= attributes_need_realloc[Attribute::kernel_type(*attr)];
576 }
577
578 builder.add(object->geometry, attr, ATTR_PRIM_GEOMETRY, req.type, req.desc);
579
580 if (progress.get_cancel()) {
581 return;
582 }
583 }
584 }
585
586 /* create attribute lookup maps */
587 if (scene->shader_manager->use_osl()) {
588 update_osl_globals(device, scene);
589 }
590
591 update_svm_attributes(device, dscene, scene, geom_attributes, object_attributes);
592
593 if (progress.get_cancel()) {
594 return;
595 }
596
597 /* copy to device */
598 progress.set_status("Updating Mesh", "Copying Attributes to device");
599
601
602 if (progress.get_cancel()) {
603 return;
604 }
605
606 /* After mesh attributes and patch tables have been copied to device memory,
607 * we need to update offsets in the objects. */
608 scene->object_manager->device_update_geom_offsets(device, dscene, scene);
609}
610
unsigned int uint
#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:55
device_vector< float2 > attributes_float2
Definition devicescene.h:53
device_vector< AttributeMap > attributes_map
Definition devicescene.h:51
device_vector< packed_float3 > attributes_float3
Definition devicescene.h:54
device_vector< float > attributes_float
Definition devicescene.h:52
device_vector< uchar4 > attributes_uchar4
Definition devicescene.h:56
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:585
size_t curve_key_offset
Definition hair.h:89
int svm_slot(const int slot_index=0) const
bool get_cancel() const
Definition progress.h:77
void set_status(const string &status_, const string &substatus_="")
Definition progress.h:248
AttributeRequestSet attributes
size_t size() const
T * alloc(const size_t width, const size_t height=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)
static uint attr_size(GPUVertCompType type, int len)
#define assert(assertion)
@ NODE_ATTR_FLOAT
@ NODE_ATTR_FLOAT3
@ NODE_ATTR_RGBA
@ NODE_ATTR_FLOAT2
@ NODE_ATTR_FLOAT4
@ NODE_ATTR_MATRIX
AttributeStandard
@ ATTR_STD_NONE
@ 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
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()
ImageHandle & data_voxel()
float3 * data_float3()
float4 * data_float4()
Transform * data_transform()
float2 * data_float2()
size_t vert_offset
Definition scene/mesh.h:177
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:429
void need_global_attributes(AttributeRequestSet &attributes)
Definition scene.cpp:449
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