[Bf-blender-cvs] [b7558e3c9c1] master: Cycles: internal support for per-instance and per-geometry attributes

Alexander Gavrilov noreply at git.blender.org
Wed Oct 28 13:00:27 CET 2020


Commit: b7558e3c9c1478cb0d3a4881c73984d46a0c9603
Author: Alexander Gavrilov
Date:   Mon Oct 26 15:37:07 2020 +0100
Branches: master
https://developer.blender.org/rBb7558e3c9c1478cb0d3a4881c73984d46a0c9603

Cycles: internal support for per-instance and per-geometry attributes

The existing code for this was incomplete. Each instance can now have a set
of attributes stored separately from geometry attributes. Geometry attributes
take precedence over instance attributes.

Ref D2057

===================================================================

M	intern/cycles/kernel/geom/geom_attribute.h
M	intern/cycles/render/attribute.h
M	intern/cycles/render/geometry.cpp
M	intern/cycles/render/geometry.h
M	intern/cycles/render/object.cpp
M	intern/cycles/render/object.h

===================================================================

diff --git a/intern/cycles/kernel/geom/geom_attribute.h b/intern/cycles/kernel/geom/geom_attribute.h
index e1b0e6fb81c..b37797ac21b 100644
--- a/intern/cycles/kernel/geom/geom_attribute.h
+++ b/intern/cycles/kernel/geom/geom_attribute.h
@@ -66,9 +66,17 @@ ccl_device_inline AttributeDescriptor find_attribute(KernelGlobals *kg,
 
   while (attr_map.x != id) {
     if (UNLIKELY(attr_map.x == ATTR_STD_NONE)) {
-      return attribute_not_found();
+      if (UNLIKELY(attr_map.y == 0)) {
+        return attribute_not_found();
+      }
+      else {
+        /* Chain jump to a different part of the table. */
+        attr_offset = attr_map.z;
+      }
+    }
+    else {
+      attr_offset += ATTR_PRIM_TYPES;
     }
-    attr_offset += ATTR_PRIM_TYPES;
     attr_map = kernel_tex_fetch(__attributes_map, attr_offset);
   }
 
diff --git a/intern/cycles/render/attribute.h b/intern/cycles/render/attribute.h
index 5871fa04a31..9990a1325a7 100644
--- a/intern/cycles/render/attribute.h
+++ b/intern/cycles/render/attribute.h
@@ -177,6 +177,7 @@ class AttributeSet {
   list<Attribute> attributes;
 
   AttributeSet(Geometry *geometry, AttributePrimitive prim);
+  AttributeSet(AttributeSet &&) = default;
   ~AttributeSet();
 
   Attribute *add(ustring name, TypeDesc type, AttributeElement element);
diff --git a/intern/cycles/render/geometry.cpp b/intern/cycles/render/geometry.cpp
index 29ac35f3f1f..cbd5e7e83fb 100644
--- a/intern/cycles/render/geometry.cpp
+++ b/intern/cycles/render/geometry.cpp
@@ -116,6 +116,16 @@ bool Geometry::need_attribute(Scene * /*scene*/, ustring name)
   return false;
 }
 
+AttributeRequestSet Geometry::needed_attributes()
+{
+  AttributeRequestSet result;
+
+  foreach (Shader *shader, used_shaders)
+    result.add(shader->attributes);
+
+  return result;
+}
+
 float Geometry::motion_time(int step) const
 {
   return (motion_steps > 1) ? 2.0f * step / (motion_steps - 1) - 1.0f : 0.0f;
@@ -305,15 +315,12 @@ void GeometryManager::update_osl_attributes(Device *device,
     }
 
     /* find geometry attributes */
-    size_t j;
-
-    for (j = 0; j < scene->geometry.size(); j++)
-      if (scene->geometry[j] == object->geometry)
-        break;
+    size_t j = object->geometry->index;
+    assert(j < scene->geometry.size() && scene->geometry[j] == object->geometry);
 
     AttributeRequestSet &attributes = geom_attributes[j];
 
-    /* set object attributes */
+    /* set mesh attributes */
     foreach (AttributeRequest &req, attributes.requests) {
       OSLGlobals::Attribute osl_attr;
 
@@ -375,10 +382,68 @@ void GeometryManager::update_osl_attributes(Device *device,
 #endif
 }
 
+/* Generate a normal attribute map entry from an attribute descriptor. */
+static void emit_attribute_map_entry(
+    uint4 *attr_map, int index, uint id, TypeDesc type, const AttributeDescriptor &desc)
+{
+  attr_map[index].x = id;
+  attr_map[index].y = desc.element;
+  attr_map[index].z = as_uint(desc.offset);
+
+  if (type == TypeDesc::TypeFloat)
+    attr_map[index].w = NODE_ATTR_FLOAT;
+  else if (type == TypeDesc::TypeMatrix)
+    attr_map[index].w = NODE_ATTR_MATRIX;
+  else if (type == TypeFloat2)
+    attr_map[index].w = NODE_ATTR_FLOAT2;
+  else if (type == TypeFloat4)
+    attr_map[index].w = NODE_ATTR_FLOAT4;
+  else if (type == TypeRGBA)
+    attr_map[index].w = NODE_ATTR_RGBA;
+  else
+    attr_map[index].w = NODE_ATTR_FLOAT3;
+
+  attr_map[index].w |= desc.flags << 8;
+}
+
+/* Generate an attribute map end marker, optionally including a link to another map.
+ * Links are used to connect object attribute maps to mesh attribute maps. */
+static void emit_attribute_map_terminator(uint4 *attr_map, int index, bool chain, uint chain_link)
+{
+  for (int j = 0; j < ATTR_PRIM_TYPES; j++) {
+    attr_map[index + j].x = ATTR_STD_NONE;
+    attr_map[index + j].y = chain;                      /* link is valid flag */
+    attr_map[index + j].z = chain ? chain_link + j : 0; /* link to the correct sub-entry */
+    attr_map[index + j].w = 0;
+  }
+}
+
+/* Generate all necessary attribute map entries from the attribute request. */
+static void emit_attribute_mapping(
+    uint4 *attr_map, int index, Scene *scene, AttributeRequest &req, Geometry *geom)
+{
+  uint id;
+
+  if (req.std == ATTR_STD_NONE)
+    id = scene->shader_manager->get_attribute_id(req.name);
+  else
+    id = scene->shader_manager->get_attribute_id(req.std);
+
+  emit_attribute_map_entry(attr_map, index, id, req.type, req.desc);
+
+  if (geom->type == Geometry::MESH) {
+    Mesh *mesh = static_cast<Mesh *>(geom);
+    if (mesh->subd_faces.size()) {
+      emit_attribute_map_entry(attr_map, index + 1, id, req.subd_type, req.subd_desc);
+    }
+  }
+}
+
 void GeometryManager::update_svm_attributes(Device *,
                                             DeviceScene *dscene,
                                             Scene *scene,
-                                            vector<AttributeRequestSet> &geom_attributes)
+                                            vector<AttributeRequestSet> &geom_attributes,
+                                            vector<AttributeRequestSet> &object_attributes)
 {
   /* for SVM, the attributes_map table is used to lookup the offset of an
    * attribute, based on a unique shader attribute id. */
@@ -392,6 +457,19 @@ void GeometryManager::update_svm_attributes(Device *,
     attr_map_size += (geom_attributes[i].size() + 1) * ATTR_PRIM_TYPES;
   }
 
+  for (size_t i = 0; i < scene->objects.size(); i++) {
+    Object *object = scene->objects[i];
+
+    /* only allocate a table for the object if it actually has attributes */
+    if (object_attributes[i].size() == 0) {
+      object->attr_map_offset = 0;
+    }
+    else {
+      object->attr_map_offset = attr_map_size;
+      attr_map_size += (object_attributes[i].size() + 1) * ATTR_PRIM_TYPES;
+    }
+  }
+
   if (attr_map_size == 0)
     return;
 
@@ -403,73 +481,31 @@ void GeometryManager::update_svm_attributes(Device *,
     Geometry *geom = scene->geometry[i];
     AttributeRequestSet &attributes = geom_attributes[i];
 
-    /* set object attributes */
+    /* set geometry attributes */
     int index = geom->attr_map_offset;
 
     foreach (AttributeRequest &req, attributes.requests) {
-      uint id;
-
-      if (req.std == ATTR_STD_NONE)
-        id = scene->shader_manager->get_attribute_id(req.name);
-      else
-        id = scene->shader_manager->get_attribute_id(req.std);
-
-      attr_map[index].x = id;
-      attr_map[index].y = req.desc.element;
-      attr_map[index].z = as_uint(req.desc.offset);
-
-      if (req.type == TypeDesc::TypeFloat)
-        attr_map[index].w = NODE_ATTR_FLOAT;
-      else if (req.type == TypeDesc::TypeMatrix)
-        attr_map[index].w = NODE_ATTR_MATRIX;
-      else if (req.type == TypeFloat2)
-        attr_map[index].w = NODE_ATTR_FLOAT2;
-      else if (req.type == TypeRGBA)
-        attr_map[index].w = NODE_ATTR_RGBA;
-      else if (req.type == TypeFloat4)
-        attr_map[index].w = NODE_ATTR_FLOAT4;
-      else
-        attr_map[index].w = NODE_ATTR_FLOAT3;
-
-      attr_map[index].w |= req.desc.flags << 8;
-
-      index++;
+      emit_attribute_mapping(attr_map, index, scene, req, geom);
+      index += ATTR_PRIM_TYPES;
+    }
 
-      if (geom->type == Geometry::MESH) {
-        Mesh *mesh = static_cast<Mesh *>(geom);
-        if (mesh->subd_faces.size()) {
-          attr_map[index].x = id;
-          attr_map[index].y = req.subd_desc.element;
-          attr_map[index].z = as_uint(req.subd_desc.offset);
-
-          if (req.subd_type == TypeDesc::TypeFloat)
-            attr_map[index].w = NODE_ATTR_FLOAT;
-          else if (req.subd_type == TypeDesc::TypeMatrix)
-            attr_map[index].w = NODE_ATTR_MATRIX;
-          else if (req.subd_type == TypeFloat2)
-            attr_map[index].w = NODE_ATTR_FLOAT2;
-          else if (req.subd_type == TypeRGBA)
-            attr_map[index].w = NODE_ATTR_RGBA;
-          else if (req.subd_type == TypeFloat4)
-            attr_map[index].w = NODE_ATTR_FLOAT4;
-          else
-            attr_map[index].w = NODE_ATTR_FLOAT3;
-
-          attr_map[index].w |= req.subd_desc.flags << 8;
-        }
-      }
+    emit_attribute_map_terminator(attr_map, index, false, 0);
+  }
 
-      index++;
-    }
+  for (size_t i = 0; i < scene->objects.size(); i++) {
+    Object *object = scene->objects[i];
+    AttributeRequestSet &attributes = object_attributes[i];
 
-    /* terminator */
-    for (int j = 0; j < ATTR_PRIM_TYPES; j++) {
-      attr_map[index].x = ATTR_STD_NONE;
-      attr_map[index].y = 0;
-      attr_map[index].z = 0;
-      attr_map[index].w = 0;
+    /* set object attributes */
+    if (attributes.size() > 0) {
+      int index = object->attr_map_offset;
+
+      foreach (AttributeRequest &req, attributes.requests) {
+        emit_attribute_mapping(attr_map, index, scene, req, object->geometry);
+        index += ATTR_PRIM_TYPES;
+      }
 
-      index++;
+      emit_attribute_map_terminator(attr_map, index, true, object->geometry->attr_map_offset);
     }
   }
 
@@ -649,6 +685,7 @@ void GeometryManager::device_update_attributes(Device *device,
   for (size_t i = 0; i < scene->geometry.size(); i++) {
     Geometry *geom = scene->geometry[i];
 
+    geom->index = i;
     scene->need_global_attributes(geom_attributes[i]);
 
     foreach (Shader *shader, geom->used_shaders) {
@@ -656,6 +693,39 @@ void GeometryManager::device_update_attributes(Device *device,
     }
   }
 
+  /* convert object attributes to use the same data structures as geometry ones */
+  vector<AttributeRequestSet> object_attributes(scene->objects.size());
+  vector<AttributeSet> object_attribute_values;
+
+  object_attribute_values.reserve(scene->objects.size());
+
+  for (size_t i = 0; i < scene->objects.size(); i++) {
+    Object *object = scene->objects[i];
+    Geometry *geom = object->geometry;
+    size_t geom_idx = geom->index;
+
+    assert(geom_idx < scene->geometry.size() && scene->geometry[geom_idx] == geom);
+
+    object_attribute_values.push_back(AttributeSet(geom, ATTR_PRIM_GEOMETRY));
+
+    AttributeRequestSet &geom_requests = geom_attributes[geom_idx];
+    AttributeRequestSet &attributes = object_attributes[i];
+    

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list