[Bf-blender-cvs] [d8b00a3] master: Freestyle: memory consumption optimization in stroke rendering.

Tamito Kajiyama noreply at git.blender.org
Sat Jan 3 14:32:05 CET 2015


Commit: d8b00a3bf5c170c60e33a10c660820b35e2ec0a8
Author: Tamito Kajiyama
Date:   Fri Aug 8 22:29:02 2014 +0900
Branches: master
https://developer.blender.org/rBd8b00a3bf5c170c60e33a10c660820b35e2ec0a8

Freestyle: memory consumption optimization in stroke rendering.

Previously individual strokes were represented by distinct mesh objects
no matter how many vertices and materials each stroke has, although
the vertex and material counts can be quite small depending on the input
scene data.  Now stroke meshes are packed into a minimum number of
mesh objects, so as to reduce the overheads of Blender object creation.

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

M	source/blender/freestyle/intern/application/Controller.cpp
M	source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
M	source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.h
M	source/blender/freestyle/intern/stroke/Stroke.cpp
M	source/blender/freestyle/intern/stroke/Stroke.h

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

diff --git a/source/blender/freestyle/intern/application/Controller.cpp b/source/blender/freestyle/intern/application/Controller.cpp
index 7c8a0c9..f8931d3 100644
--- a/source/blender/freestyle/intern/application/Controller.cpp
+++ b/source/blender/freestyle/intern/application/Controller.cpp
@@ -882,10 +882,13 @@ void Controller::ResetRenderCount()
 
 Render *Controller::RenderStrokes(Render *re, bool render)
 {
+	int totmesh = 0;
 	_Chrono.start();
 	BlenderStrokeRenderer *blenderRenderer = new BlenderStrokeRenderer(re, ++_render_count);
-	if (render)
+	if (render) {
 		_Canvas->Render(blenderRenderer);
+		totmesh = blenderRenderer->GenerateScene();
+	}
 	real d = _Chrono.stop();
 	if (G.debug & G_DEBUG_FREESTYLE) {
 		cout << "Temporary scene generation: " << d << endl;
@@ -904,8 +907,8 @@ Render *Controller::RenderStrokes(Render *re, bool render)
 		float mmap_used_memory = (mmap_in_use) / (1024.0 * 1024.0);
 		float megs_peak_memory = (peak_memory) / (1024.0 * 1024.0);
 
-		printf("%d verts, %d faces, mem %.2fM (%.2fM, peak %.2fM)\n",
-		       freestyle_render->i.totvert, freestyle_render->i.totface,
+		printf("%d objs, %d verts, %d faces, mem %.2fM (%.2fM, peak %.2fM)\n",
+		       totmesh, freestyle_render->i.totvert, freestyle_render->i.totface,
 		       megs_used_memory, mmap_used_memory, megs_peak_memory);
 	}
 	delete blenderRenderer;
diff --git a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
index 09701ab..29f3bfe 100644
--- a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
+++ b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
@@ -66,6 +66,8 @@ extern "C" {
 
 namespace Freestyle {
 
+const char *BlenderStrokeRenderer::uvNames[] = {"along_stroke", "along_stroke_tips"};
+
 BlenderStrokeRenderer::BlenderStrokeRenderer(Render *re, int render_count) : StrokeRenderer()
 {
 	freestyle_bmain = re->freestyle_bmain;
@@ -208,6 +210,8 @@ BlenderStrokeRenderer::~BlenderStrokeRenderer()
 
 	if (_use_shading_nodes)
 		BLI_ghash_free(_nodetree_hash, NULL, NULL);
+
+	FreeStrokeGroups();
 }
 
 float BlenderStrokeRenderer::get_stroke_vertex_z(void) const
@@ -414,10 +418,10 @@ Material* BlenderStrokeRenderer::GetStrokeShader(Main *bmain, bNodeTree *iNodeTr
 				input_uvmap->locy = node->locy;
 				NodeShaderUVMap *storage = (NodeShaderUVMap *)input_uvmap->storage;
 				if (node->custom1 & 1) { // use_tips
-					BLI_strncpy(storage->uv_map, "along_stroke_tips", sizeof(storage->uv_map));
+					BLI_strncpy(storage->uv_map, uvNames[1], sizeof(storage->uv_map));
 				}
 				else {
-					BLI_strncpy(storage->uv_map, "along_stroke", sizeof(storage->uv_map));
+					BLI_strncpy(storage->uv_map, uvNames[0], sizeof(storage->uv_map));
 				}
 				fromsock = (bNodeSocket *)BLI_findlink(&input_uvmap->outputs, 0); // UV
 
@@ -440,6 +444,11 @@ Material* BlenderStrokeRenderer::GetStrokeShader(Main *bmain, bNodeTree *iNodeTr
 
 void BlenderStrokeRenderer::RenderStrokeRep(StrokeRep *iStrokeRep) const
 {
+	RenderStrokeRepBasic(iStrokeRep);
+}
+
+void BlenderStrokeRenderer::RenderStrokeRepBasic(StrokeRep *iStrokeRep) const
+{
 	if (_use_shading_nodes) {
 		bNodeTree *nt = iStrokeRep->getNodeTree();
 		Material *ma = (Material *)BLI_ghash_lookup(_nodetree_hash, nt);
@@ -509,10 +518,10 @@ void BlenderStrokeRenderer::RenderStrokeRep(StrokeRep *iStrokeRep) const
 				// We'll generate both with tips and without tips
 				// coordinates, on two different UV layers.
 				if (ma->mtex[a]->texflag & MTEX_TIPS)  {
-					BLI_strncpy(ma->mtex[a]->uvname, "along_stroke_tips", sizeof(ma->mtex[a]->uvname));
+					BLI_strncpy(ma->mtex[a]->uvname, uvNames[1], sizeof(ma->mtex[a]->uvname));
 				}
 				else {
-					BLI_strncpy(ma->mtex[a]->uvname, "along_stroke", sizeof(ma->mtex[a]->uvname));
+					BLI_strncpy(ma->mtex[a]->uvname, uvNames[0], sizeof(ma->mtex[a]->uvname));
 				}
 				a++;
 			}
@@ -521,7 +530,42 @@ void BlenderStrokeRenderer::RenderStrokeRep(StrokeRep *iStrokeRep) const
 		}
 	}
 
-	RenderStrokeRepBasic(iStrokeRep);
+	const vector<Strip*>& strips = iStrokeRep->getStrips();
+	const bool hasTex = iStrokeRep->hasTex();
+	int totvert = 0, totedge = 0, totpoly = 0, totloop = 0;
+	int visible_faces, visible_segments;
+	for (vector<Strip*>::const_iterator s = strips.begin(), send = strips.end(); s != send; ++s) {
+		Strip::vertex_container& strip_vertices = (*s)->vertices();
+
+		// count visible faces and strip segments
+		test_strip_visibility(strip_vertices, &visible_faces, &visible_segments);
+		if (visible_faces == 0)
+			continue;
+
+		totvert += visible_faces + visible_segments * 2;
+		totedge += visible_faces * 2 + visible_segments;
+		totpoly += visible_faces;
+		totloop += visible_faces * 3;
+	}
+
+	BlenderStrokeRenderer *self = const_cast<BlenderStrokeRenderer *>(this); // FIXME
+	vector<StrokeGroup*> *groups = hasTex ? &self->texturedStrokeGroups : &self->strokeGroups;
+	StrokeGroup *group;
+	if (groups->empty() || !(groups->back()->totvert + totvert < MESH_MAX_VERTS &&
+	    groups->back()->totcol + 1 < MAXMAT))
+	{
+		group = new StrokeGroup;
+		groups->push_back(group);
+	}
+	else {
+		group = groups->back();
+	}
+	group->strokes.push_back(iStrokeRep);
+	group->totvert += totvert;
+	group->totedge += totedge;
+	group->totpoly += totpoly;
+	group->totloop += totloop;
+	group->totcol++;
 }
 
 // Check if the triangle is visible (i.e., within the render image boundary)
@@ -578,127 +622,168 @@ void BlenderStrokeRenderer::test_strip_visibility(Strip::vertex_container& strip
 	}
 }
 
-// Build a mesh object representing a stroke
-void BlenderStrokeRenderer::RenderStrokeRepBasic(StrokeRep *iStrokeRep) const
+// Release allocated memory for stroke groups
+void BlenderStrokeRenderer::FreeStrokeGroups()
 {
-	vector<Strip*>& strips = iStrokeRep->getStrips();
-	const bool hasTex = iStrokeRep->hasTex();
-	Strip::vertex_container::iterator v[3];
-	StrokeVertexRep *svRep[3];
-	unsigned int vertex_index, edge_index, loop_index;
-	Vec2r p;
+	vector<StrokeGroup*>::const_iterator it, itend;
 
-	int totvert = 0, totedge = 0, totpoly = 0, totloop = 0;
-	int visible_faces, visible_segments;
-
-	bool visible;
-	for (vector<Strip*>::iterator s = strips.begin(), send = strips.end(); s != send; ++s) {
-		Strip::vertex_container& strip_vertices = (*s)->vertices();
+	for (it = strokeGroups.begin(), itend = strokeGroups.end();
+	     it != itend; ++it)
+	{
+		delete (*it);
+	}
+	for (it = texturedStrokeGroups.begin(), itend = texturedStrokeGroups.end();
+	     it != itend; ++it)
+	{
+		delete (*it);
+	}
+}
 
-		// count visible faces and strip segments
-		test_strip_visibility(strip_vertices, &visible_faces, &visible_segments);
-		if (visible_faces == 0)
-			continue;
+// Build a scene populated by mesh objects representing stylized strokes
+int BlenderStrokeRenderer::GenerateScene()
+{
+	vector<StrokeGroup*>::const_iterator it, itend;
 
-		totvert += visible_faces + visible_segments * 2;
-		totedge += visible_faces * 2 + visible_segments;
-		totpoly += visible_faces;
-		totloop += visible_faces * 3;
+	for (it = strokeGroups.begin(), itend = strokeGroups.end();
+	     it != itend; ++it)
+	{
+		GenerateStrokeMesh(*it, false);
+	}
+	for (it = texturedStrokeGroups.begin(), itend = texturedStrokeGroups.end();
+	     it != itend; ++it)
+	{
+		GenerateStrokeMesh(*it, true);
 	}
+	return strokeGroups.size() + texturedStrokeGroups.size();
+}
 
+// Build a mesh object representing a group of stylized strokes
+void BlenderStrokeRenderer::GenerateStrokeMesh(StrokeGroup *group, bool hasTex)
+{
 #if 0
 	Object *object_mesh = BKE_object_add(freestyle_bmain, freestyle_scene, OB_MESH);
 #else
 	Object *object_mesh = NewMesh();
 #endif
 	Mesh *mesh = (Mesh *)object_mesh->data;
-	mesh->mat = (Material **)MEM_mallocN(1 * sizeof(Material *), "MaterialList");
-	mesh->mat[0] = iStrokeRep->getMaterial();
-	mesh->totcol = 1;
-	test_object_materials(freestyle_bmain, (ID *)mesh);
 
-	// vertices allocation
-	mesh->totvert = totvert; // visible_faces + visible_segments * 2;
-	CustomData_add_layer(&mesh->vdata, CD_MVERT, CD_CALLOC, NULL, mesh->totvert);
+	mesh->totvert = group->totvert;
+	mesh->totedge = group->totedge;
+	mesh->totpoly = group->totpoly;
+	mesh->totloop = group->totloop;
+	mesh->totcol = group->totcol;
 
-	// edges allocation
-	mesh->totedge = totedge; // visible_faces * 2 + visible_segments;
-	CustomData_add_layer(&mesh->edata, CD_MEDGE, CD_CALLOC, NULL, mesh->totedge);
+	mesh->mvert = (MVert *)CustomData_add_layer(&mesh->vdata, CD_MVERT, CD_CALLOC, NULL, mesh->totvert);
+	mesh->medge = (MEdge *)CustomData_add_layer(&mesh->edata, CD_MEDGE, CD_CALLOC, NULL, mesh->totedge);
+	mesh->mpoly = (MPoly *)CustomData_add_layer(&mesh->pdata, CD_MPOLY, CD_CALLOC, NULL, mesh->totpoly);
+	mesh->mloop = (MLoop *)CustomData_add_layer(&mesh->ldata, CD_MLOOP, CD_CALLOC, NULL, mesh->totloop);
 
-	// faces allocation
-	mesh->totpoly = totpoly; // visible_faces;
-	CustomData_add_layer(&mesh->pdata, CD_MPOLY, CD_CALLOC, NULL, mesh->totpoly);
-
-	// loops allocation
-	mesh->totloop = totloop; // visible_faces * 3;
-	CustomData_add_layer(&mesh->ldata, CD_MLOOP, CD_CALLOC, NULL, mesh->totloop);
-
-	// uv maps
+	MVert *vertices = mesh->mvert;
+	MEdge *edges = mesh->medge;
+	MPoly *polys = mesh->mpoly;
+	MLoop *loops = mesh->mloop;
 	MLoopUV *loopsuv[2] = { NULL };
-	if (hasTex) {
-		loopsuv[0] = (MLoopUV *)CustomData_add_layer_named(&mesh->ldata, CD_MLOOPUV, CD_CALLOC, NULL, mesh->totloop, "along_stroke");
-		loopsuv[1] = (MLoopUV *)CustomData_add_layer_named(&mesh->ldata, CD_MLOOPUV, CD_CALLOC, NULL, mesh->totloop, "along_stroke_tips");
 
-		CustomData_add_layer_named(&mesh->pdata, CD_MTEXPOLY, CD_CALLOC, NULL, mesh->totpoly, "along_stroke");
-		CustomData_add_layer_named(&mesh->pdata, CD_MTEXPOLY, CD_CALLOC, NULL, mesh->totpoly, "along_stroke_tips");
+	if (hasTex) {
+		// First UV layer
+		CustomData_add_layer_named(&mesh->pdata, CD_MTEXPOLY, CD_CALLOC, NULL, mesh->totpoly, uvNames[0]);
+		CustomData_add_layer_named(&mesh->ldata, CD_MLOOPUV, CD_CALLOC, NULL, mesh->totloop, uvNames[0]);
+		CustomData_set_layer_active(&mesh->pdata, CD_MTEXPOLY, 0);
+		CustomData_set_l

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list