Fix T38024 crash when rebuilding sculpt mode buffers.

Main issue here is that glBuf* calls were invoked from threads different than
main thread. This caused a crash (since those do not have a GL context active).

Fix here is twofold:
* add an ID buffer in buffer pool that handles pbvh buffers and is freed
from main thread when gpu_buffer_pool_free_unused is called.

* do not create glbuffers in derivedmesh creation routine, rather tag nodes
for update and create those in the draw function
(guaranteed to be called from main thread)

Reviewed By: brecht

Differential Revision: https://developer.blender.org/D169
This commit is contained in:
Antonis Ryakiotakis 2014-01-05 04:58:27 +02:00
parent 0074eac1ed
commit d9697bc145
Notes: blender-bot 2023-02-14 11:25:07 +01:00
Referenced by issue #38024, Segfault on changing frame in sculpt mode with a ShapeKey
3 changed files with 57 additions and 21 deletions

View File

@ -330,15 +330,7 @@ static void build_mesh_leaf_node(PBVH *bvh, PBVHNode *node)
}
}
if (!G.background) {
node->draw_buffers =
GPU_build_pbvh_mesh_buffers(node->face_vert_indices,
bvh->faces, bvh->verts,
node->prim_indices,
node->totprim);
}
node->flag |= PBVH_UpdateDrawBuffers;
BKE_pbvh_node_mark_rebuild_draw(node);
BLI_ghash_free(map, NULL, NULL);
}

View File

@ -91,12 +91,9 @@ static void pbvh_bmesh_node_finalize(PBVH *bvh, int node_index)
n->orig_vb = n->vb;
/* Build GPU buffers */
if (!G.background) {
int smooth = bvh->flags & PBVH_DYNTOPO_SMOOTH_SHADING;
n->draw_buffers = GPU_build_bmesh_pbvh_buffers(smooth);
n->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateNormals;
}
/* Build GPU buffers for new node and update vertex normals */
BKE_pbvh_node_mark_rebuild_draw(n);
n->flag |= PBVH_UpdateNormals;
}
/* Recursively split the node if it exceeds the leaf_limit */

View File

@ -93,11 +93,15 @@ static ThreadMutex buffer_mutex = BLI_MUTEX_INITIALIZER;
typedef struct GPUBufferPool {
/* number of allocated buffers stored */
int totbuf;
/* actual allocated length of the array */
int totpbvhbufids;
/* actual allocated length of the arrays */
int maxsize;
int maxpbvhsize;
GPUBuffer **buffers;
GLuint *pbvhbufids;
} GPUBufferPool;
#define MAX_FREE_GPU_BUFFERS 8
#define MAX_FREE_GPU_BUFF_IDS 100
/* create a new GPUBufferPool */
static GPUBufferPool *gpu_buffer_pool_new(void)
@ -111,9 +115,11 @@ static GPUBufferPool *gpu_buffer_pool_new(void)
pool = MEM_callocN(sizeof(GPUBufferPool), "GPUBuffer_Pool");
pool->maxsize = MAX_FREE_GPU_BUFFERS;
pool->buffers = MEM_callocN(sizeof(GPUBuffer *) * pool->maxsize,
"GPUBuffer.buffers");
pool->maxpbvhsize = MAX_FREE_GPU_BUFF_IDS;
pool->buffers = MEM_callocN(sizeof(*pool->buffers) * pool->maxsize,
"GPUBufferPool.buffers");
pool->pbvhbufids = MEM_callocN(sizeof(*pool->pbvhbufids) * pool->maxpbvhsize,
"GPUBufferPool.pbvhbuffers");
return pool;
}
@ -171,6 +177,7 @@ static void gpu_buffer_pool_free(GPUBufferPool *pool)
gpu_buffer_pool_delete_last(pool);
MEM_freeN(pool->buffers);
MEM_freeN(pool->pbvhbufids);
MEM_freeN(pool);
}
@ -181,6 +188,9 @@ static void gpu_buffer_pool_free_unused(GPUBufferPool *pool)
while (pool->totbuf)
gpu_buffer_pool_delete_last(pool);
glDeleteBuffersARB(pool->totpbvhbufids, pool->pbvhbufids);
pool->totpbvhbufids = 0;
}
static GPUBufferPool *gpu_buffer_pool = NULL;
@ -2492,13 +2502,50 @@ int GPU_pbvh_buffers_diffuse_changed(GPU_PBVH_Buffers *buffers, int show_diffuse
diffuse_color[2] != buffers->diffuse_color[2];
}
/* release a GPU_PBVH_Buffers id;
*
* Thread-unsafe version for internal usage only.
*/
static void gpu_pbvh_buffer_free_intern(GLuint id)
{
GPUBufferPool *pool;
/* zero id is vertex buffers off */
if (!id)
return;
pool = gpu_get_global_buffer_pool();
/* free the buffers immediately if we are on main thread */
if (BLI_thread_is_main()) {
glDeleteBuffersARB(1, &id);
if (pool->totpbvhbufids > 0) {
glDeleteBuffersARB(pool->totpbvhbufids, pool->pbvhbufids);
pool->totpbvhbufids = 0;
}
return;
}
/* outside of main thread, can't safely delete the
* buffer, so increase pool size */
if (pool->maxpbvhsize == pool->totpbvhbufids) {
pool->maxpbvhsize += MAX_FREE_GPU_BUFF_IDS;
pool->pbvhbufids = MEM_reallocN(pool->pbvhbufids,
sizeof(*pool->pbvhbufids) * pool->maxpbvhsize);
}
/* insert the buffer into the beginning of the pool */
pool->pbvhbufids[pool->totpbvhbufids++] = id;
}
void GPU_free_pbvh_buffers(GPU_PBVH_Buffers *buffers)
{
if (buffers) {
if (buffers->vert_buf)
glDeleteBuffersARB(1, &buffers->vert_buf);
gpu_pbvh_buffer_free_intern(buffers->vert_buf);
if (buffers->index_buf && (buffers->tot_tri || buffers->has_hidden))
glDeleteBuffersARB(1, &buffers->index_buf);
gpu_pbvh_buffer_free_intern(buffers->index_buf);
MEM_freeN(buffers);
}