[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [58277] branches/soc-2013-depsgraph_mt/ source/blender/gpu/intern/gpu_buffers.c: Make GPU buffers allocation/ freeing safe for threading

Sergey Sharybin sergey.vfx at gmail.com
Mon Jul 15 20:46:08 CEST 2013


Revision: 58277
          http://projects.blender.org/scm/viewvc.php?view=rev&root=bf-blender&revision=58277
Author:   nazgul
Date:     2013-07-15 18:46:08 +0000 (Mon, 15 Jul 2013)
Log Message:
-----------
Make GPU buffers allocation/freeing safe for threading

Code in GPU_buffers_free was already trying to be safe
for threading, by skipping OGL calls there, but in fact
it was still buggy.

Namely, freeing was doing buffers shift in a cycle, and
if two threads will call this function shifting will go
crazy.

Now made it so GPU_buffers_alloc and GPU_buffers_free
are using mutex lock, so they're completely safe for
threading. Same goes to gpu_buffer_setup function.

It required minor functions reshuffle, so there're no
locks happening from locked thread, but it's all very
straightforward change.

Modified Paths:
--------------
    branches/soc-2013-depsgraph_mt/source/blender/gpu/intern/gpu_buffers.c

Modified: branches/soc-2013-depsgraph_mt/source/blender/gpu/intern/gpu_buffers.c
===================================================================
--- branches/soc-2013-depsgraph_mt/source/blender/gpu/intern/gpu_buffers.c	2013-07-15 18:39:18 UTC (rev 58276)
+++ branches/soc-2013-depsgraph_mt/source/blender/gpu/intern/gpu_buffers.c	2013-07-15 18:46:08 UTC (rev 58277)
@@ -77,6 +77,8 @@
 static GPUBufferState GLStates = 0;
 static GPUAttrib attribData[MAX_GPU_ATTRIB_DATA] = { { -1, 0, 0 } };
 
+static ThreadMutex buffer_mutex = BLI_MUTEX_INITIALIZER;
+
 /* stores recently-deleted buffers so that new buffers won't have to
  * be recreated as often
  *
@@ -189,8 +191,11 @@
 }
 
 /* get a GPUBuffer of at least `size' bytes; uses one from the buffer
- * pool if possible, otherwise creates a new one */
-GPUBuffer *GPU_buffer_alloc(int size)
+ * pool if possible, otherwise creates a new one
+ *
+ * Thread-unsafe version for internal usage only.
+ */
+static GPUBuffer *gpu_buffer_alloc_intern(int size)
 {
 	GPUBufferPool *pool;
 	GPUBuffer *buf;
@@ -270,10 +275,30 @@
 	return buf;
 }
 
+/* Same as above, but safe for threading. */
+GPUBuffer *GPU_buffer_alloc(int size)
+{
+	GPUBuffer *buffer;
+
+	if (size == 0) {
+		/* Early out, no lock needed in this case. */
+		return NULL;
+	}
+
+	BLI_mutex_lock(&buffer_mutex);
+	buffer = gpu_buffer_alloc_intern(size);
+	BLI_mutex_unlock(&buffer_mutex);
+
+	return buffer;
+}
+
 /* release a GPUBuffer; does not free the actual buffer or its data,
  * but rather moves it to the pool of recently-freed buffers for
- * possible re-use*/
-void GPU_buffer_free(GPUBuffer *buffer)
+ * possible re-use
+ *
+ * Thread-unsafe version for internal usage only.
+ */
+static void gpu_buffer_free_intern(GPUBuffer *buffer)
 {
 	GPUBufferPool *pool;
 	int i;
@@ -312,6 +337,19 @@
 	pool->totbuf++;
 }
 
+/* Same as above, but safe for threading. */
+void GPU_buffer_free(GPUBuffer *buffer)
+{
+	if (!buffer) {
+		/* Early output, no need to lock in this case, */
+		return;
+	}
+
+	BLI_mutex_lock(&buffer_mutex);
+	gpu_buffer_free_intern(buffer);
+	BLI_mutex_unlock(&buffer_mutex);
+}
+
 typedef struct GPUVertPointLink {
 	struct GPUVertPointLink *next;
 	/* -1 means uninitialized */
@@ -496,13 +534,17 @@
 
 	pool = gpu_get_global_buffer_pool();
 
+	BLI_mutex_lock(&buffer_mutex);
+
 	/* alloc a GPUBuffer; fall back to legacy mode on failure */
-	if (!(buffer = GPU_buffer_alloc(size)))
+	if (!(buffer = gpu_buffer_alloc_intern(size)))
 		dm->drawObject->legacy = 1;
 
 	/* nothing to do for legacy mode */
-	if (dm->drawObject->legacy)
+	if (dm->drawObject->legacy) {
+		BLI_mutex_unlock(&buffer_mutex);
 		return NULL;
+	}
 
 	cur_index_per_mat = MEM_mallocN(sizeof(int) * object->totmaterial,
 	                                "GPU_buffer_setup.cur_index_per_mat");
@@ -527,7 +569,7 @@
 			/* attempt to map the buffer */
 			if (!(varray = glMapBufferARB(target, GL_WRITE_ONLY_ARB))) {
 				/* failed to map the buffer; delete it */
-				GPU_buffer_free(buffer);
+				gpu_buffer_free_intern(buffer);
 				gpu_buffer_pool_delete_last(pool);
 				buffer = NULL;
 
@@ -535,7 +577,7 @@
 				 * and reallocating the buffer */
 				if (pool->totbuf > 0) {
 					gpu_buffer_pool_delete_last(pool);
-					buffer = GPU_buffer_alloc(size);
+					buffer = gpu_buffer_alloc_intern(size);
 				}
 
 				/* allocation still failed; fall back
@@ -577,6 +619,8 @@
 
 	MEM_freeN(cur_index_per_mat);
 
+	BLI_mutex_unlock(&buffer_mutex);
+
 	return buffer;
 }
 




More information about the Bf-blender-cvs mailing list