Fix #20461: deleting VBO's from threads used for rendering or baking would
authorBrecht Van Lommel <brechtvanlommel@pandora.be>
Tue, 13 Jul 2010 13:31:43 +0000 (13:31 +0000)
committerBrecht Van Lommel <brechtvanlommel@pandora.be>
Tue, 13 Jul 2010 13:31:43 +0000 (13:31 +0000)
crash, as OpenGL can't be called from these. Now deleting VBO's is delayed
until the next redraw in the main thread.

source/blender/gpu/gpu_buffers.h
source/blender/gpu/intern/gpu_buffers.c
source/blender/gpu/intern/gpu_draw.c

index 98cefa7a696cbd76e503acc4b0c9f2ee89421e63..983133a6d4b5ace385fa69e8ff9a9a9b8c2de391 100644 (file)
@@ -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 );
index 1d615c8e67bad7796ef23be181e973e3e81a2ee0..e0a47c0c5bcb6adedbb2f7b70a619d155426bf2d 100644 (file)
@@ -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-- ) {
index 9a5a670442835bc9ea3704a86f91bf3892dac592..506ce94b763ff42773115fc1d982d86fcf7cf41c 100644 (file)
@@ -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);
 }