[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [46328] trunk/blender/intern/cycles: Cycles: threading optimizations

Brecht Van Lommel brechtvanlommel at pandora.be
Sat May 5 21:44:33 CEST 2012


Revision: 46328
          http://projects.blender.org/scm/viewvc.php?view=rev&root=bf-blender&revision=46328
Author:   blendix
Date:     2012-05-05 19:44:33 +0000 (Sat, 05 May 2012)
Log Message:
-----------
Cycles: threading optimizations

* Multithreaded image loading, each thread can load a separate image.
* Better multithreading for multiple instanced meshes, different threads can now
  build BVH's for different meshes, rather than all cooperating on the same mesh.
  Especially noticeable for dynamic BVH building for the viewport, gave about
  2x faster build on 8 core in fairly complex scene with many objects.
* The main thread waiting for worker threads can now also work itself, so
  (num_cores + 1) threads will be working, this supposedly gives better
  performance on some operating systems, but did not measure performance for
  this very detailed yet.

Modified Paths:
--------------
    trunk/blender/intern/cycles/bvh/bvh_build.cpp
    trunk/blender/intern/cycles/bvh/bvh_build.h
    trunk/blender/intern/cycles/device/device_cpu.cpp
    trunk/blender/intern/cycles/render/image.cpp
    trunk/blender/intern/cycles/render/image.h
    trunk/blender/intern/cycles/render/mesh.cpp
    trunk/blender/intern/cycles/render/mesh.h
    trunk/blender/intern/cycles/util/util_task.cpp
    trunk/blender/intern/cycles/util/util_task.h

Modified: trunk/blender/intern/cycles/bvh/bvh_build.cpp
===================================================================
--- trunk/blender/intern/cycles/bvh/bvh_build.cpp	2012-05-05 19:44:28 UTC (rev 46327)
+++ trunk/blender/intern/cycles/bvh/bvh_build.cpp	2012-05-05 19:44:33 UTC (rev 46328)
@@ -36,12 +36,12 @@
 
 class BVHBuildTask : public Task {
 public:
-	BVHBuildTask(InnerNode *node_, int child_, BVHObjectBinning& range_, int level_)
-	: node(node_), child(child_), level(level_), range(range_) {}
+	BVHBuildTask(BVHBuild *build, InnerNode *node, int child, BVHObjectBinning& range_, int level)
+	: range(range_)
+	{
+		run = function_bind(&BVHBuild::thread_build_node, build, node, child, &range, level);
+	}
 
-	InnerNode *node;
-	int child;
-	int level;
 	BVHObjectBinning range;
 };
 
@@ -55,8 +55,7 @@
   prim_object(prim_object_),
   params(params_),
   progress(progress_),
-  progress_start_time(0.0),
-  task_pool(function_bind(&BVHBuild::thread_build_node, this, _1, _2))
+  progress_start_time(0.0)
 {
 	spatial_min_overlap = 0.0f;
 }
@@ -177,7 +176,7 @@
 		/* multithreaded binning build */
 		BVHObjectBinning rootbin(root, (references.size())? &references[0]: NULL);
 		rootnode = build_node(rootbin, 0);
-		task_pool.wait();
+		task_pool.wait_work();
 	}
 
 	/* delete if we cancelled */
@@ -210,25 +209,24 @@
 	progress_start_time = time_dt(); 
 }
 
-void BVHBuild::thread_build_node(Task *task_, int thread_id)
+void BVHBuild::thread_build_node(InnerNode *inner, int child, BVHObjectBinning *range, int level)
 {
 	if(progress.get_cancel())
 		return;
 
 	/* build nodes */
-	BVHBuildTask *task = (BVHBuildTask*)task_;
-	BVHNode *node = build_node(task->range, task->level);
+	BVHNode *node = build_node(*range, level);
 
 	/* set child in inner node */
-	task->node->children[task->child] = node;
+	inner->children[child] = node;
 
 	/* update progress */
-	if(task->range.size() < THREAD_TASK_SIZE) {
+	if(range->size() < THREAD_TASK_SIZE) {
 		/*rotate(node, INT_MAX, 5);*/
 
 		thread_scoped_lock lock(build_mutex);
 
-		progress_count += task->range.size();
+		progress_count += range->size();
 		progress_update();
 	}
 }
@@ -262,8 +260,8 @@
 		/* threaded build */
 		inner = new InnerNode(range.bounds());
 
-		task_pool.push(new BVHBuildTask(inner, 0, left, level + 1), true);
-		task_pool.push(new BVHBuildTask(inner, 1, right, level + 1), true);
+		task_pool.push(new BVHBuildTask(this, inner, 0, left, level + 1), true);
+		task_pool.push(new BVHBuildTask(this, inner, 1, right, level + 1), true);
 	}
 
 	return inner;

Modified: trunk/blender/intern/cycles/bvh/bvh_build.h
===================================================================
--- trunk/blender/intern/cycles/bvh/bvh_build.h	2012-05-05 19:44:28 UTC (rev 46327)
+++ trunk/blender/intern/cycles/bvh/bvh_build.h	2012-05-05 19:44:33 UTC (rev 46328)
@@ -29,7 +29,9 @@
 
 CCL_NAMESPACE_BEGIN
 
+class BVHBuildTask;
 class BVHParams;
+class InnerNode;
 class Mesh;
 class Object;
 class Progress;
@@ -54,6 +56,7 @@
 	friend class BVHMixedSplit;
 	friend class BVHObjectSplit;
 	friend class BVHSpatialSplit;
+	friend class BVHBuildTask;
 
 	/* adding references */
 	void add_reference_mesh(BoundBox& root, BoundBox& center, Mesh *mesh, int i);
@@ -68,7 +71,7 @@
 
 	/* threads */
 	enum { THREAD_TASK_SIZE = 4096 };
-	void thread_build_node(Task *task_, int thread_id);
+	void thread_build_node(InnerNode *node, int child, BVHObjectBinning *range, int level);
 	thread_mutex build_mutex;
 
 	/* progress */

Modified: trunk/blender/intern/cycles/device/device_cpu.cpp
===================================================================
--- trunk/blender/intern/cycles/device/device_cpu.cpp	2012-05-05 19:44:28 UTC (rev 46327)
+++ trunk/blender/intern/cycles/device/device_cpu.cpp	2012-05-05 19:44:33 UTC (rev 46328)
@@ -44,7 +44,6 @@
 	KernelGlobals *kg;
 	
 	CPUDevice(int threads_num)
-	: task_pool(function_bind(&CPUDevice::thread_run, this, _1, _2))
 	{
 		kg = kernel_globals_create();
 
@@ -113,10 +112,8 @@
 #endif
 	}
 
-	void thread_run(Task *task_, int thread_id)
+	void thread_run(DeviceTask *task)
 	{
-		DeviceTask *task = (DeviceTask*)task_;
-
 		if(task->type == DeviceTask::PATH_TRACE)
 			thread_path_trace(*task);
 		else if(task->type == DeviceTask::TONEMAP)
@@ -125,6 +122,15 @@
 			thread_shader(*task);
 	}
 
+	class CPUDeviceTask : public DeviceTask {
+	public:
+		CPUDeviceTask(CPUDevice *device, DeviceTask& task)
+		: DeviceTask(task)
+		{
+			run = function_bind(&CPUDevice::thread_run, device, this);
+		}
+	};
+
 	void thread_path_trace(DeviceTask& task)
 	{
 		if(task_pool.cancelled())
@@ -226,12 +232,12 @@
 		task.split(tasks, TaskScheduler::num_threads()*10);
 
 		foreach(DeviceTask& task, tasks)
-			task_pool.push(new DeviceTask(task));
+			task_pool.push(new CPUDeviceTask(this, task));
 	}
 
 	void task_wait()
 	{
-		task_pool.wait();
+		task_pool.wait_work();
 	}
 
 	void task_cancel()

Modified: trunk/blender/intern/cycles/render/image.cpp
===================================================================
--- trunk/blender/intern/cycles/render/image.cpp	2012-05-05 19:44:28 UTC (rev 46327)
+++ trunk/blender/intern/cycles/render/image.cpp	2012-05-05 19:44:33 UTC (rev 46328)
@@ -324,8 +324,10 @@
 	return true;
 }
 
-void ImageManager::device_load_image(Device *device, DeviceScene *dscene, int slot)
+void ImageManager::device_load_image(Device *device, DeviceScene *dscene, int slot, Progress *progress)
 {
+	if(progress->get_cancel())
+		return;
 	if(osl_texture_system)
 		return;
 
@@ -342,6 +344,9 @@
 	}
 
 	if(is_float) {
+		string filename = path_filename(float_images[slot]->filename);
+		progress->set_status("Updating Images", "Loading " + filename);
+
 		device_vector<float4>& tex_img = dscene->tex_float_image[slot - TEX_IMAGE_FLOAT_START];
 
 		if(tex_img.device_pointer)
@@ -365,6 +370,9 @@
 		device->tex_alloc(name.c_str(), tex_img, true, true);
 	}
 	else {
+		string filename = path_filename(images[slot]->filename);
+		progress->set_status("Updating Images", "Loading " + filename);
+
 		device_vector<uchar4>& tex_img = dscene->tex_image[slot];
 
 		if(tex_img.device_pointer)
@@ -387,6 +395,8 @@
 
 		device->tex_alloc(name.c_str(), tex_img, true, true);
 	}
+
+	img->need_load = false;
 }
 
 void ImageManager::device_free_image(Device *device, DeviceScene *dscene, int slot)
@@ -431,39 +441,37 @@
 {
 	if(!need_update)
 		return;
+	
+	TaskPool pool;
 
 	for(size_t slot = 0; slot < images.size(); slot++) {
-		if(images[slot]) {
-			if(images[slot]->users == 0) {
-				device_free_image(device, dscene, slot);
-			}
-			else if(images[slot]->need_load) {
-				string name = path_filename(images[slot]->filename);
-				progress.set_status("Updating Images", "Loading " + name);
-				device_load_image(device, dscene, slot);
-				images[slot]->need_load = false;
-			}
+		if(!images[slot])
+			continue;
 
-			if(progress.get_cancel()) return;
+		if(images[slot]->users == 0) {
+			device_free_image(device, dscene, slot);
 		}
+		else if(images[slot]->need_load) {
+			if(!osl_texture_system) 
+				pool.push(function_bind(&ImageManager::device_load_image, this, device, dscene, slot, &progress));
+		}
 	}
 
 	for(size_t slot = 0; slot < float_images.size(); slot++) {
-		if(float_images[slot]) {
-			if(float_images[slot]->users == 0) {
-				device_free_image(device, dscene, slot + TEX_IMAGE_FLOAT_START);
-			}
-			else if(float_images[slot]->need_load) {
-				string name = path_filename(float_images[slot]->filename);
-				progress.set_status("Updating Images", "Loading " + name);
-				device_load_image(device, dscene, slot + TEX_IMAGE_FLOAT_START);
-				float_images[slot]->need_load = false;
-			}
+		if(!float_images[slot])
+			continue;
 
-			if(progress.get_cancel()) return;
+		if(float_images[slot]->users == 0) {
+			device_free_image(device, dscene, slot + TEX_IMAGE_FLOAT_START);
 		}
+		else if(float_images[slot]->need_load) {
+			if(!osl_texture_system) 
+				pool.push(function_bind(&ImageManager::device_load_image, this, device, dscene, slot + TEX_IMAGE_FLOAT_START, &progress));
+		}
 	}
 
+	pool.wait_work();
+
 	need_update = false;
 }
 

Modified: trunk/blender/intern/cycles/render/image.h
===================================================================
--- trunk/blender/intern/cycles/render/image.h	2012-05-05 19:44:28 UTC (rev 46327)
+++ trunk/blender/intern/cycles/render/image.h	2012-05-05 19:44:33 UTC (rev 46328)
@@ -65,7 +65,7 @@
 	bool file_load_image(Image *img, device_vector<uchar4>& tex_img);
 	bool file_load_float_image(Image *img, device_vector<float4>& tex_img);
 
-	void device_load_image(Device *device, DeviceScene *dscene, int slot);
+	void device_load_image(Device *device, DeviceScene *dscene, int slot, Progress *progess);
 	void device_free_image(Device *device, DeviceScene *dscene, int slot);
 };
 

Modified: trunk/blender/intern/cycles/render/mesh.cpp
===================================================================
--- trunk/blender/intern/cycles/render/mesh.cpp	2012-05-05 19:44:28 UTC (rev 46327)
+++ trunk/blender/intern/cycles/render/mesh.cpp	2012-05-05 19:44:33 UTC (rev 46328)
@@ -242,31 +242,47 @@
 	}
 }
 
-void Mesh::compute_bvh(SceneParams *params, Progress& progress)
+void Mesh::compute_bvh(SceneParams *params, Progress *progress, int n, int total)
 {
-	Object object;
-	object.mesh = this;
+	if(progress->get_cancel())
+		return;
 
-	vector<Object*> objects;
-	objects.push_back(&object);
+	compute_bounds();
 
-	if(bvh && !need_update_rebuild) {
-		progress.set_substatus("Refitting BVH");
-		bvh->objects = objects;
-		bvh->refit(progress);
-	}
-	else {
-		progress.set_substatus("Building BVH");
+	if(!transform_applied) {
+		string msg = "Updating Mesh BVH ";
+		if(name == "")
+			msg += string_printf("%u/%u", (uint)(n+1), (uint)total);
+		else
+			msg += string_printf("%s %u/%u", name.c_str(), (uint)(n+1), (uint)total);
 
-		BVHParams bparams;
-		bparams.use_cache = params->use_bvh_cache;
-		bparams.use_spatial_split = params->use_bvh_spatial_split;
-		bparams.use_qbvh = params->use_qbvh;
+		Object object;
+		object.mesh = this;
 
-		delete bvh;
-		bvh = BVH::create(bparams, objects);
-		bvh->build(progress);
+		vector<Object*> objects;
+		objects.push_back(&object);
+
+		if(bvh && !need_update_rebuild) {
+			progress->set_status(msg, "Refitting BVH");
+			bvh->objects = objects;
+			bvh->refit(*progress);
+		}
+		else {
+			progress->set_status(msg, "Building BVH");
+
+			BVHParams bparams;
+			bparams.use_cache = params->use_bvh_cache;
+			bparams.use_spatial_split = params->use_bvh_spatial_split;

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list