diff options
author | Sergey Sharybin <sergey.vfx@gmail.com> | 2013-08-19 14:06:05 +0400 |
---|---|---|
committer | Sergey Sharybin <sergey.vfx@gmail.com> | 2013-08-19 14:06:05 +0400 |
commit | b9ae749480aeeb7e77f16ebe667ddfcf8b63650e (patch) | |
tree | 88a43f1b3605e5e9ad03fd626bcc874bc32e05ac /source/blender | |
parent | 59dfb05c72a6cbbeed6e545488e3e4fe9f25d061 (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')
-rw-r--r-- | source/blender/gpu/intern/gpu_buffers.c | 60 |
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; } |