Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Sharybin <sergey.vfx@gmail.com>2013-08-19 14:06:05 +0400
committerSergey Sharybin <sergey.vfx@gmail.com>2013-08-19 14:06:05 +0400
commitb9ae749480aeeb7e77f16ebe667ddfcf8b63650e (patch)
tree88a43f1b3605e5e9ad03fd626bcc874bc32e05ac /source/blender/gpu
parent59dfb05c72a6cbbeed6e545488e3e4fe9f25d061 (diff)
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 -- svn merge -r58276:58277 ^/branches/soc-2013-depsgraph_mt
Diffstat (limited to 'source/blender/gpu')
-rw-r--r--source/blender/gpu/intern/gpu_buffers.c60
1 files changed, 52 insertions, 8 deletions
diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c
index c54f937f4a9..4420c260eed 100644
--- a/source/blender/gpu/intern/gpu_buffers.c
+++ b/source/blender/gpu/intern/gpu_buffers.c
@@ -77,6 +77,8 @@ static int useVBOs = -1;
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
*
@@ -203,8 +205,11 @@ void GPU_global_buffer_pool_free_unused(void)
}
/* 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;
@@ -284,10 +289,30 @@ GPUBuffer *GPU_buffer_alloc(int size)
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;
@@ -326,6 +351,19 @@ void GPU_buffer_free(GPUBuffer *buffer)
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 */
@@ -510,13 +548,17 @@ static GPUBuffer *gpu_buffer_setup(DerivedMesh *dm, GPUDrawObject *object,
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");
@@ -541,7 +583,7 @@ static GPUBuffer *gpu_buffer_setup(DerivedMesh *dm, GPUDrawObject *object,
/* 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;
@@ -549,7 +591,7 @@ static GPUBuffer *gpu_buffer_setup(DerivedMesh *dm, GPUDrawObject *object,
* 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
@@ -591,6 +633,8 @@ static GPUBuffer *gpu_buffer_setup(DerivedMesh *dm, GPUDrawObject *object,
MEM_freeN(cur_index_per_mat);
+ BLI_mutex_unlock(&buffer_mutex);
+
return buffer;
}