Cycles: fix inefficient attribute map storage, saves 615MB in victor scene.
authorBrecht Van Lommel <brechtvanlommel@gmail.com>
Sun, 5 Nov 2017 16:40:36 +0000 (17:40 +0100)
committerBrecht Van Lommel <brechtvanlommel@gmail.com>
Sun, 5 Nov 2017 17:00:48 +0000 (18:00 +0100)
intern/cycles/kernel/geom/geom_attribute.h
intern/cycles/kernel/geom/geom_motion_curve.h
intern/cycles/kernel/geom/geom_motion_triangle.h
intern/cycles/kernel/kernel_types.h
intern/cycles/render/mesh.cpp
intern/cycles/render/mesh.h
intern/cycles/render/object.cpp
intern/cycles/render/object.h

index cc62192..18f5c81 100644 (file)
@@ -51,14 +51,21 @@ ccl_device_inline AttributeDescriptor attribute_not_found()
 
 /* Find attribute based on ID */
 
+ccl_device_inline uint object_attribute_map_offset(KernelGlobals *kg, int object)
+{
+       int offset = object*OBJECT_SIZE + 11;
+       float4 f = kernel_tex_fetch(__objects, offset);
+       return __float_as_uint(f.y);
+}
+
 ccl_device_inline AttributeDescriptor find_attribute(KernelGlobals *kg, const ShaderData *sd, uint id)
 {
-       if(sd->object == PRIM_NONE) {
+       if(sd->object == OBJECT_NONE) {
                return attribute_not_found();
        }
 
        /* for SVM, find attribute by unique id */
-       uint attr_offset = sd->object*kernel_data.bvh.attributes_map_stride;
+       uint attr_offset = object_attribute_map_offset(kg, sd->object);
        attr_offset += attribute_primitive_type(kg, sd);
        uint4 attr_map = kernel_tex_fetch(__attributes_map, attr_offset);
        
index 119bdb2..fad29e4 100644 (file)
@@ -33,7 +33,7 @@ ccl_device_inline int find_attribute_curve_motion(KernelGlobals *kg, int object,
         * zero iterations and rendering is really slow with motion curves. For until other
         * areas are speed up it's probably not so crucial to optimize this out.
         */
-       uint attr_offset = object*kernel_data.bvh.attributes_map_stride + ATTR_PRIM_CURVE;
+       uint attr_offset = object_attribute_map_offset(kg, object) + ATTR_PRIM_CURVE;
        uint4 attr_map = kernel_tex_fetch(__attributes_map, attr_offset);
 
        while(attr_map.x != id) {
index 4e84aa9..cd28b75 100644 (file)
@@ -32,7 +32,7 @@ CCL_NAMESPACE_BEGIN
 ccl_device_inline int find_attribute_motion(KernelGlobals *kg, int object, uint id, AttributeElement *elem)
 {
        /* todo: find a better (faster) solution for this, maybe store offset per object */
-       uint attr_offset = object*kernel_data.bvh.attributes_map_stride;
+       uint attr_offset = object_attribute_map_offset(kg, object);
        uint4 attr_map = kernel_tex_fetch(__attributes_map, attr_offset);
        
        while(attr_map.x != id) {
index 49ec6d9..d1733d8 100644 (file)
@@ -1295,13 +1295,12 @@ static_assert_align(KernelIntegrator, 16);
 typedef struct KernelBVH {
        /* root node */
        int root;
-       int attributes_map_stride;
        int have_motion;
        int have_curves;
        int have_instancing;
        int use_qbvh;
        int use_bvh_steps;
-       int pad1;
+       int pad1, pad2;
 } KernelBVH;
 static_assert_align(KernelBVH, 16);
 
index 75bdf71..189ba80 100644 (file)
@@ -436,6 +436,8 @@ Mesh::Mesh()
        face_offset = 0;
        corner_offset = 0;
 
+       attr_map_offset = 0;
+
        num_subd_verts = 0;
 
        attributes.triangle_mesh = this;
@@ -1258,33 +1260,27 @@ void MeshManager::update_svm_attributes(Device *, DeviceScene *dscene, Scene *sc
         * attribute, based on a unique shader attribute id. */
 
        /* compute array stride */
-       int attr_map_stride = 0;
+       int attr_map_size = 0;
 
-       for(size_t i = 0; i < scene->meshes.size(); i++)
-               attr_map_stride = max(attr_map_stride, (mesh_attributes[i].size() + 1)*ATTR_PRIM_TYPES);
+       for(size_t i = 0; i < scene->meshes.size(); i++) {
+               Mesh *mesh = scene->meshes[i];
+               mesh->attr_map_offset = attr_map_size;
+               attr_map_size += (mesh_attributes[i].size() + 1)*ATTR_PRIM_TYPES;
+       }
 
-       if(attr_map_stride == 0)
+       if(attr_map_size == 0)
                return;
 
        /* create attribute map */
-       uint4 *attr_map = dscene->attributes_map.alloc(attr_map_stride*scene->objects.size());
+       uint4 *attr_map = dscene->attributes_map.alloc(attr_map_size*scene->meshes.size());
        memset(attr_map, 0, dscene->attributes_map.size()*sizeof(uint));
 
-       for(size_t i = 0; i < scene->objects.size(); i++) {
-               Object *object = scene->objects[i];
-               Mesh *mesh = object->mesh;
-
-               /* find mesh attributes */
-               size_t j;
-
-               for(j = 0; j < scene->meshes.size(); j++)
-                       if(scene->meshes[j] == mesh)
-                               break;
-
-               AttributeRequestSet& attributes = mesh_attributes[j];
+       for(size_t i = 0; i < scene->meshes.size(); i++) {
+               Mesh *mesh = scene->meshes[i];
+               AttributeRequestSet& attributes = mesh_attributes[i];
 
                /* set object attributes */
-               int index = i*attr_map_stride;
+               int index = mesh->attr_map_offset;
 
                foreach(AttributeRequest& req, attributes.requests) {
                        uint id;
@@ -1358,7 +1354,6 @@ void MeshManager::update_svm_attributes(Device *, DeviceScene *dscene, Scene *sc
        }
 
        /* copy to device */
-       dscene->data.bvh.attributes_map_stride = attr_map_stride;
        dscene->attributes_map.copy_to_device();
 }
 
@@ -1625,6 +1620,12 @@ void MeshManager::device_update_attributes(Device *device, DeviceScene *dscene,
        if(dscene->attributes_uchar4.size()) {
                dscene->attributes_uchar4.copy_to_device();
        }
+
+       if(progress.get_cancel()) return;
+
+       /* After mesh attributes and patch tables have been copied to device memory,
+        * we need to update offsets in the objects. */
+       scene->object_manager->device_update_mesh_offsets(device, dscene, scene);
 }
 
 void MeshManager::mesh_calc_offset(Scene *scene)
@@ -2042,10 +2043,6 @@ void MeshManager::device_update(Device *device, DeviceScene *dscene, Scene *scen
        }
        if(progress.get_cancel()) return;
 
-       /* after mesh data has been copied to device memory we need to update
-        * offsets for patch tables as this can't be known before hand */
-       scene->object_manager->device_update_patch_map_offsets(device, dscene, scene);
-
        device_update_attributes(device, dscene, scene, progress);
        if(progress.get_cancel()) return;
 
index 30f5e90..07d8bbd 100644 (file)
@@ -250,6 +250,8 @@ public:
        size_t face_offset;
        size_t corner_offset;
 
+       size_t attr_map_offset;
+
        size_t num_subd_verts;
 
        /* Functions */
index 3b93b0c..a12a0d2 100644 (file)
@@ -641,7 +641,7 @@ void ObjectManager::device_update_flags(Device *,
        dscene->object_flag.copy_to_device();
 }
 
-void ObjectManager::device_update_patch_map_offsets(Device *, DeviceScene *dscene, Scene *scene)
+void ObjectManager::device_update_mesh_offsets(Device *, DeviceScene *dscene, Scene *scene)
 {
        if(scene->objects.size() == 0) {
                return;
@@ -650,12 +650,11 @@ void ObjectManager::device_update_patch_map_offsets(Device *, DeviceScene *dscen
        uint4* objects = (uint4*)dscene->objects.data();
 
        bool update = false;
-
        int object_index = 0;
-       foreach(Object *object, scene->objects) {
-               int offset = object_index*OBJECT_SIZE + 11;
 
+       foreach(Object *object, scene->objects) {
                Mesh* mesh = object->mesh;
+               int offset = object_index*OBJECT_SIZE + 11;
 
                if(mesh->patch_table) {
                        uint patch_map_offset = 2*(mesh->patch_table_offset + mesh->patch_table->total_size() -
@@ -667,6 +666,11 @@ void ObjectManager::device_update_patch_map_offsets(Device *, DeviceScene *dscen
                        }
                }
 
+               if(objects[offset].y != mesh->attr_map_offset) {
+                       objects[offset].y = mesh->attr_map_offset;
+                       update = true;
+               }
+
                object_index++;
        }
 
index 6927bbf..9f86c34 100644 (file)
@@ -104,7 +104,7 @@ public:
                                 Scene *scene,
                                 Progress& progress,
                                 bool bounds_valid = true);
-       void device_update_patch_map_offsets(Device *device, DeviceScene *dscene, Scene *scene);
+       void device_update_mesh_offsets(Device *device, DeviceScene *dscene, Scene *scene);
 
        void device_free(Device *device, DeviceScene *dscene);