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:
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
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue