diff options
author | Brecht Van Lommel <brechtvanlommel@pandora.be> | 2010-07-13 17:31:43 +0400 |
---|---|---|
committer | Brecht Van Lommel <brechtvanlommel@pandora.be> | 2010-07-13 17:31:43 +0400 |
commit | ee03a99695a2eaff6dbc323dcabb44e759f64099 (patch) | |
tree | ab2affce3c6ee9f00bec7c9396daf55d4df615cb | |
parent | f533a70a4b80e0e347dc8284382c0d13359f4bb8 (diff) |
Fix #20461: deleting VBO's from threads used for rendering or baking would
crash, as OpenGL can't be called from these. Now deleting VBO's is delayed
until the next redraw in the main thread.
-rw-r--r-- | source/blender/gpu/gpu_buffers.h | 8 | ||||
-rw-r--r-- | source/blender/gpu/intern/gpu_buffers.c | 78 | ||||
-rw-r--r-- | source/blender/gpu/intern/gpu_draw.c | 4 |
3 files changed, 56 insertions, 34 deletions
diff --git a/source/blender/gpu/gpu_buffers.h b/source/blender/gpu/gpu_buffers.h index 98cefa7a696..983133a6d4b 100644 --- a/source/blender/gpu/gpu_buffers.h +++ b/source/blender/gpu/gpu_buffers.h @@ -69,8 +69,9 @@ typedef struct GPUBuffer typedef struct GPUBufferPool { - int size; /* number of allocated buffers stored */ - GPUBuffer* buffers[MAX_FREE_GPU_BUFFERS]; + int size; /* number of allocated buffers stored */ + int maxsize; /* size of the array */ + GPUBuffer **buffers; } GPUBufferPool; typedef struct GPUBufferMaterial @@ -119,7 +120,8 @@ typedef struct GPUAttrib } GPUAttrib; GPUBufferPool *GPU_buffer_pool_new(); -void GPU_buffer_pool_free( GPUBufferPool *pool ); /* TODO: Find a place where to call this function on exit */ +void GPU_buffer_pool_free( GPUBufferPool *pool ); +void GPU_buffer_pool_free_unused( GPUBufferPool *pool ); GPUBuffer *GPU_buffer_alloc( int size, GPUBufferPool *pool ); void GPU_buffer_free( GPUBuffer *buffer, GPUBufferPool *pool ); diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c index 1d615c8e67b..e0a47c0c5bc 100644 --- a/source/blender/gpu/intern/gpu_buffers.c +++ b/source/blender/gpu/intern/gpu_buffers.c @@ -38,8 +38,9 @@ #include "MEM_guardedalloc.h" -#include "BLI_math.h" #include "BLI_ghash.h" +#include "BLI_math.h" +#include "BLI_threads.h" #include "DNA_meshdata_types.h" @@ -82,37 +83,12 @@ GPUBufferPool *GPU_buffer_pool_new() } pool = MEM_callocN(sizeof(GPUBufferPool), "GPU_buffer_pool_new"); + pool->maxsize = MAX_FREE_GPU_BUFFERS; + pool->buffers = MEM_callocN(sizeof(GPUBuffer*)*pool->maxsize, "GPU_buffer_pool_new buffers"); return pool; } -void GPU_buffer_pool_free(GPUBufferPool *pool) -{ - int i; - - DEBUG_VBO("GPU_buffer_pool_free\n"); - - if( pool == 0 ) - pool = globalPool; - if( pool == 0 ) - return; - - for( i = 0; i < pool->size; i++ ) { - if( pool->buffers[i] != 0 ) { - if( useVBOs ) { - glDeleteBuffersARB( 1, &pool->buffers[i]->id ); - } - else { - MEM_freeN( pool->buffers[i]->pointer ); - } - MEM_freeN(pool->buffers[i]); - } else { - ERROR_VBO("Why are we accessing a null buffer in GPU_buffer_pool_free?\n"); - } - } - MEM_freeN(pool); -} - void GPU_buffer_pool_remove( int index, GPUBufferPool *pool ) { int i; @@ -159,6 +135,35 @@ void GPU_buffer_pool_delete_last( GPUBufferPool *pool ) pool->size--; } +void GPU_buffer_pool_free(GPUBufferPool *pool) +{ + DEBUG_VBO("GPU_buffer_pool_free\n"); + + if( pool == 0 ) + pool = globalPool; + if( pool == 0 ) + return; + + while( pool->size ) + GPU_buffer_pool_delete_last(pool); + + MEM_freeN(pool->buffers); + MEM_freeN(pool); +} + +void GPU_buffer_pool_free_unused(GPUBufferPool *pool) +{ + DEBUG_VBO("GPU_buffer_pool_free_unused\n"); + + if( pool == 0 ) + pool = globalPool; + if( pool == 0 ) + return; + + while( pool->size > MAX_FREE_GPU_BUFFERS ) + GPU_buffer_pool_delete_last(pool); +} + GPUBuffer *GPU_buffer_alloc( int size, GPUBufferPool *pool ) { char buffer[60]; @@ -226,6 +231,7 @@ GPUBuffer *GPU_buffer_alloc( int size, GPUBufferPool *pool ) void GPU_buffer_free( GPUBuffer *buffer, GPUBufferPool *pool ) { int i; + DEBUG_VBO("GPU_buffer_free\n"); if( buffer == 0 ) @@ -235,9 +241,19 @@ void GPU_buffer_free( GPUBuffer *buffer, GPUBufferPool *pool ) if( pool == 0 ) globalPool = GPU_buffer_pool_new(); - /* free the last used buffer in the queue if no more space */ - if( pool->size == MAX_FREE_GPU_BUFFERS ) { - GPU_buffer_pool_delete_last( pool ); + /* free the last used buffer in the queue if no more space, but only + if we are in the main thread. for e.g. rendering or baking it can + happen that we are in other thread and can't call OpenGL, in that + case cleanup will be done GPU_buffer_pool_free_unused */ + if( BLI_thread_is_main() ) { + while( pool->size >= MAX_FREE_GPU_BUFFERS ) + GPU_buffer_pool_delete_last( pool ); + } + else { + if( pool->maxsize == pool->size ) { + pool->maxsize += MAX_FREE_GPU_BUFFERS; + pool->buffers = MEM_reallocN(pool->buffers, sizeof(GPUBuffer*)*pool->maxsize); + } } for( i =pool->size; i > 0; i-- ) { diff --git a/source/blender/gpu/intern/gpu_draw.c b/source/blender/gpu/intern/gpu_draw.c index 9a5a6704428..506ce94b763 100644 --- a/source/blender/gpu/intern/gpu_draw.c +++ b/source/blender/gpu/intern/gpu_draw.c @@ -804,11 +804,15 @@ void GPU_free_unused_buffers(void) BLI_lock_thread(LOCK_OPENGL); + /* images */ for(ima=image_free_queue.first; ima; ima=ima->id.next) GPU_free_image(ima); BLI_freelistN(&image_free_queue); + /* vbo buffers */ + GPU_buffer_pool_free_unused(0); + BLI_unlock_thread(LOCK_OPENGL); } |