[Bf-blender-cvs] [1862fbf] master: Cycles: Optimize memory usage when creating mesh attributes

Sergey Sharybin noreply at git.blender.org
Sat Feb 14 22:08:53 CET 2015


Commit: 1862fbf203b84b622d80846bd6d2f76f3cada434
Author: Sergey Sharybin
Date:   Sat Feb 14 20:23:08 2015 +0500
Branches: master
https://developer.blender.org/rB1862fbf203b84b622d80846bd6d2f76f3cada434

Cycles: Optimize memory usage when creating mesh attributes

The idea behind the change is to pre-allocate attribute arrays in advance,
which avoids re-allocation of arrays later for each of meshes being handled.

This reduces peak memory used by Cycles database from 1.3G to 0.9G for
victor.blend from Gooseberry.

It doesn't mean every file will benefit from this change since peak memory
usage is happening in the different places of the rendering code.

Also, unfortunately, attributes export might not cause the peak of render
preparation stage. That said, it's actually object_to_mesh() which causes
the memory to peak in the same test file. So we really need to optimize that
part first in order to get visible results for artists. But in any case it's
now quite easy to track hotspots in Cycles itself which is good.

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

M	intern/cycles/render/mesh.cpp

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

diff --git a/intern/cycles/render/mesh.cpp b/intern/cycles/render/mesh.cpp
index 24d36a1..e672aab 100644
--- a/intern/cycles/render/mesh.cpp
+++ b/intern/cycles/render/mesh.cpp
@@ -750,8 +750,49 @@ void MeshManager::update_svm_attributes(Device *device, DeviceScene *dscene, Sce
 	device->tex_alloc("__attributes_map", dscene->attributes_map);
 }
 
-static void update_attribute_element_offset(Mesh *mesh, vector<float>& attr_float, vector<float4>& attr_float3, vector<uchar4>& attr_uchar4,
-	Attribute *mattr, TypeDesc& type, int& offset, AttributeElement& element)
+static void update_attribute_element_size(Mesh *mesh,
+                                          Attribute *mattr,
+                                          size_t *attr_float_size,
+                                          size_t *attr_float3_size,
+                                          size_t *attr_uchar4_size)
+{
+	if(mattr) {
+		size_t size = mattr->element_size(
+			mesh->verts.size(),
+			mesh->triangles.size(),
+			mesh->motion_steps,
+			mesh->curves.size(),
+			mesh->curve_keys.size());
+
+		if(mattr->element == ATTR_ELEMENT_VOXEL) {
+			/* pass */
+		}
+		else if(mattr->element == ATTR_ELEMENT_CORNER_BYTE) {
+			*attr_uchar4_size += size;
+		}
+		else if(mattr->type == TypeDesc::TypeFloat) {
+			*attr_float_size += size;
+		}
+		else if(mattr->type == TypeDesc::TypeMatrix) {
+			*attr_float3_size += size * 4;
+		}
+		else {
+			*attr_float3_size += size;
+		}
+	}
+}
+
+static void update_attribute_element_offset(Mesh *mesh,
+                                            vector<float>& attr_float,
+                                            size_t& attr_float_offset,
+                                            vector<float4>& attr_float3,
+                                            size_t& attr_float3_offset,
+                                            vector<uchar4>& attr_uchar4,
+                                            size_t& attr_uchar4_offset,
+                                            Attribute *mattr,
+                                            TypeDesc& type,
+                                            int& offset,
+                                            AttributeElement& element)
 {
 	if(mattr) {
 		/* store element and type */
@@ -773,39 +814,43 @@ static void update_attribute_element_offset(Mesh *mesh, vector<float>& attr_floa
 		}
 		else if(mattr->element == ATTR_ELEMENT_CORNER_BYTE) {
 			uchar4 *data = mattr->data_uchar4();
-			offset = attr_uchar4.size();
-
-			attr_uchar4.resize(attr_uchar4.size() + size);
+			offset = attr_uchar4_offset;
 
-			for(size_t k = 0; k < size; k++)
+			assert(attr_uchar4.capacity() >= offset + size);
+			for(size_t k = 0; k < size; k++) {
 				attr_uchar4[offset+k] = data[k];
+			}
+			attr_uchar4_offset += size;
 		}
 		else if(mattr->type == TypeDesc::TypeFloat) {
 			float *data = mattr->data_float();
-			offset = attr_float.size();
+			offset = attr_float_offset;
 
-			attr_float.resize(attr_float.size() + size);
-
-			for(size_t k = 0; k < size; k++)
+			assert(attr_float.capacity() >= offset + size);
+			for(size_t k = 0; k < size; k++) {
 				attr_float[offset+k] = data[k];
+			}
+			attr_float_offset += size;
 		}
 		else if(mattr->type == TypeDesc::TypeMatrix) {
 			Transform *tfm = mattr->data_transform();
-			offset = attr_float3.size();
-
-			attr_float3.resize(attr_float3.size() + size*4);
+			offset = attr_float3_offset;
 
-			for(size_t k = 0; k < size*4; k++)
+			assert(attr_float3.capacity() >= offset + size * 4);
+			for(size_t k = 0; k < size*4; k++) {
 				attr_float3[offset+k] = (&tfm->x)[k];
+			}
+			attr_float3_offset += size * 4;
 		}
 		else {
 			float4 *data = mattr->data_float4();
-			offset = attr_float3.size();
-
-			attr_float3.resize(attr_float3.size() + size);
+			offset = attr_float3_offset;
 
-			for(size_t k = 0; k < size; k++)
+			assert(attr_float3.capacity() >= offset + size);
+			for(size_t k = 0; k < size; k++) {
 				attr_float3[offset+k] = data[k];
+			}
+			attr_float3_offset += size;
 		}
 
 		/* mesh vertex/curve index is global, not per object, so we sneak
@@ -855,10 +900,41 @@ void MeshManager::device_update_attributes(Device *device, DeviceScene *dscene,
 	/* mesh attribute are stored in a single array per data type. here we fill
 	 * those arrays, and set the offset and element type to create attribute
 	 * maps next */
-	vector<float> attr_float;
-	vector<float4> attr_float3;
-	vector<uchar4> attr_uchar4;
 
+	/* Pre-allocate attributes to avoid arrays re-allocation which would
+	 * take 2x of overall attribute memory usage.
+	 */
+	size_t attr_float_size = 0;
+	size_t attr_float3_size = 0;
+	size_t attr_uchar4_size = 0;
+	for(size_t i = 0; i < scene->meshes.size(); i++) {
+		Mesh *mesh = scene->meshes[i];
+		AttributeRequestSet& attributes = mesh_attributes[i];
+		foreach(AttributeRequest& req, attributes.requests) {
+			Attribute *triangle_mattr = mesh->attributes.find(req);
+			Attribute *curve_mattr = mesh->curve_attributes.find(req);
+			update_attribute_element_size(mesh,
+			                              triangle_mattr,
+			                              &attr_float_size,
+			                              &attr_float3_size,
+			                              &attr_uchar4_size);
+			update_attribute_element_size(mesh,
+			                              curve_mattr,
+			                              &attr_float_size,
+			                              &attr_float3_size,
+			                              &attr_uchar4_size);
+		}
+	}
+
+	vector<float> attr_float(attr_float_size);
+	vector<float4> attr_float3(attr_float3_size);
+	vector<uchar4> attr_uchar4(attr_uchar4_size);
+
+	size_t attr_float_offset = 0;
+	size_t attr_float3_offset = 0;
+	size_t attr_uchar4_offset = 0;
+
+	/* Fill in attributes. */
 	for(size_t i = 0; i < scene->meshes.size(); i++) {
 		Mesh *mesh = scene->meshes[i];
 		AttributeRequestSet& attributes = mesh_attributes[i];
@@ -878,12 +954,24 @@ void MeshManager::device_update_attributes(Device *device, DeviceScene *dscene,
 					memcpy(triangle_mattr->data_float3(), &mesh->verts[0], sizeof(float3)*mesh->verts.size());
 			}
 
-			update_attribute_element_offset(mesh, attr_float, attr_float3, attr_uchar4, triangle_mattr,
-				req.triangle_type, req.triangle_offset, req.triangle_element);
+			update_attribute_element_offset(mesh,
+			                                attr_float, attr_float_offset,
+			                                attr_float3, attr_float3_offset,
+			                                attr_uchar4, attr_uchar4_offset,
+			                                triangle_mattr,
+			                                req.triangle_type,
+			                                req.triangle_offset,
+			                                req.triangle_element);
+
+			update_attribute_element_offset(mesh,
+			                                attr_float, attr_float_offset,
+			                                attr_float3, attr_float3_offset,
+			                                attr_uchar4, attr_uchar4_offset,
+			                                curve_mattr,
+			                                req.curve_type,
+			                                req.curve_offset,
+			                                req.curve_element);
 
-			update_attribute_element_offset(mesh, attr_float, attr_float3, attr_uchar4, curve_mattr,
-				req.curve_type, req.curve_offset, req.curve_element);
-	
 			if(progress.get_cancel()) return;
 		}
 	}




More information about the Bf-blender-cvs mailing list