Fix #124292: GPU subdivision loose edges crash

There were two issues. One was that the normals VBO wasn't created
with the correct size. The other was that there were empty VBOs created
which can apparently also cause crashes.

Pull Request: https://projects.blender.org/blender/blender/pulls/126041
This commit is contained in:
Hans Goudey
2024-08-07 19:11:23 +02:00
committed by Hans Goudey
parent 998712ba2e
commit a9d318d2f3
5 changed files with 75 additions and 57 deletions

View File

@@ -792,7 +792,7 @@ void mesh_buffer_cache_create_requested_subdiv(MeshBatchCache &cache,
}
if (DRW_vbo_requested(buffers.vbo.nor)) {
/* The corner normals calculation uses positions and normals stored in the `pos` VBO. */
extract_normals_subdiv(subdiv_cache, *buffers.vbo.pos, *buffers.vbo.nor);
extract_normals_subdiv(mr, subdiv_cache, *buffers.vbo.pos, *buffers.vbo.nor);
}
if (DRW_vbo_requested(buffers.vbo.edge_fac)) {
extract_edge_factor_subdiv(subdiv_cache, mr, *buffers.vbo.pos, *buffers.vbo.edge_fac);

View File

@@ -926,48 +926,50 @@ static bool draw_subdiv_topology_info_cb(const bke::subdiv::ForeachContext *fore
/* Initialize cache buffers, prefer dynamic usage so we can reuse memory on the host even after
* it was sent to the device, since we may use the data while building other buffers on the CPU
* side. */
cache->patch_coords = GPU_vertbuf_calloc();
GPU_vertbuf_init_with_format_ex(
*cache->patch_coords, get_blender_patch_coords_format(), GPU_USAGE_DYNAMIC);
GPU_vertbuf_data_alloc(*cache->patch_coords, cache->num_subdiv_loops);
if (cache->num_subdiv_loops > 0) {
cache->patch_coords = GPU_vertbuf_calloc();
GPU_vertbuf_init_with_format_ex(
*cache->patch_coords, get_blender_patch_coords_format(), GPU_USAGE_DYNAMIC);
GPU_vertbuf_data_alloc(*cache->patch_coords, cache->num_subdiv_loops);
cache->corner_patch_coords = GPU_vertbuf_calloc();
GPU_vertbuf_init_with_format_ex(
*cache->corner_patch_coords, get_blender_patch_coords_format(), GPU_USAGE_DYNAMIC);
GPU_vertbuf_data_alloc(*cache->corner_patch_coords, cache->num_subdiv_loops);
cache->corner_patch_coords = GPU_vertbuf_calloc();
GPU_vertbuf_init_with_format_ex(
*cache->corner_patch_coords, get_blender_patch_coords_format(), GPU_USAGE_DYNAMIC);
GPU_vertbuf_data_alloc(*cache->corner_patch_coords, cache->num_subdiv_loops);
cache->verts_orig_index = GPU_vertbuf_calloc();
GPU_vertbuf_init_with_format_ex(
*cache->verts_orig_index, get_origindex_format(), GPU_USAGE_DYNAMIC);
GPU_vertbuf_data_alloc(*cache->verts_orig_index, cache->num_subdiv_loops);
cache->verts_orig_index = GPU_vertbuf_calloc();
GPU_vertbuf_init_with_format_ex(
*cache->verts_orig_index, get_origindex_format(), GPU_USAGE_DYNAMIC);
GPU_vertbuf_data_alloc(*cache->verts_orig_index, cache->num_subdiv_loops);
cache->edges_orig_index = GPU_vertbuf_calloc();
GPU_vertbuf_init_with_format_ex(
*cache->edges_orig_index, get_origindex_format(), GPU_USAGE_DYNAMIC);
GPU_vertbuf_data_alloc(*cache->edges_orig_index, cache->num_subdiv_loops);
cache->edges_orig_index = GPU_vertbuf_calloc();
GPU_vertbuf_init_with_format_ex(
*cache->edges_orig_index, get_origindex_format(), GPU_USAGE_DYNAMIC);
GPU_vertbuf_data_alloc(*cache->edges_orig_index, cache->num_subdiv_loops);
cache->edges_draw_flag = GPU_vertbuf_calloc();
GPU_vertbuf_init_with_format_ex(
*cache->edges_draw_flag, get_origindex_format(), GPU_USAGE_DYNAMIC);
GPU_vertbuf_data_alloc(*cache->edges_draw_flag, cache->num_subdiv_loops);
cache->edges_draw_flag = GPU_vertbuf_calloc();
GPU_vertbuf_init_with_format_ex(
*cache->edges_draw_flag, get_origindex_format(), GPU_USAGE_DYNAMIC);
GPU_vertbuf_data_alloc(*cache->edges_draw_flag, cache->num_subdiv_loops);
cache->subdiv_loop_subdiv_vert_index = static_cast<int *>(
MEM_mallocN(cache->num_subdiv_loops * sizeof(int), "subdiv_loop_subdiv_vert_index"));
cache->subdiv_loop_subdiv_vert_index = static_cast<int *>(
MEM_mallocN(cache->num_subdiv_loops * sizeof(int), "subdiv_loop_subdiv_vert_index"));
cache->subdiv_loop_subdiv_edge_index = static_cast<int *>(
MEM_mallocN(cache->num_subdiv_loops * sizeof(int), "subdiv_loop_subdiv_edge_index"));
cache->subdiv_loop_subdiv_edge_index = static_cast<int *>(
MEM_mallocN(cache->num_subdiv_loops * sizeof(int), "subdiv_loop_subdiv_edge_index"));
cache->subdiv_loop_face_index = static_cast<int *>(
MEM_mallocN(cache->num_subdiv_loops * sizeof(int), "subdiv_loop_face_index"));
cache->subdiv_loop_face_index = static_cast<int *>(
MEM_mallocN(cache->num_subdiv_loops * sizeof(int), "subdiv_loop_face_index"));
/* Initialize context pointers and temporary buffers. */
ctx->patch_coords = cache->patch_coords->data<CompressedPatchCoord>().data();
ctx->subdiv_loop_vert_index = cache->verts_orig_index->data<int>().data();
ctx->subdiv_loop_edge_index = cache->edges_orig_index->data<int>().data();
ctx->subdiv_loop_edge_draw_flag = cache->edges_draw_flag->data<int>().data();
ctx->subdiv_loop_subdiv_vert_index = cache->subdiv_loop_subdiv_vert_index;
ctx->subdiv_loop_subdiv_edge_index = cache->subdiv_loop_subdiv_edge_index;
ctx->subdiv_loop_face_index = cache->subdiv_loop_face_index;
/* Initialize context pointers and temporary buffers. */
ctx->patch_coords = cache->patch_coords->data<CompressedPatchCoord>().data();
ctx->subdiv_loop_vert_index = cache->verts_orig_index->data<int>().data();
ctx->subdiv_loop_edge_index = cache->edges_orig_index->data<int>().data();
ctx->subdiv_loop_edge_draw_flag = cache->edges_draw_flag->data<int>().data();
ctx->subdiv_loop_subdiv_vert_index = cache->subdiv_loop_subdiv_vert_index;
ctx->subdiv_loop_subdiv_edge_index = cache->subdiv_loop_subdiv_edge_index;
ctx->subdiv_loop_face_index = cache->subdiv_loop_face_index;
}
ctx->orig_index_vert = static_cast<const int *>(
CustomData_get_layer(&ctx->coarse_mesh->vert_data, CD_ORIGINDEX));
@@ -1243,22 +1245,24 @@ static bool draw_subdiv_build_cache(DRWSubdivCache &cache,
/* Save coordinates for corners, as attributes may vary for each loop connected to the same
* vertex. */
memcpy(cache.corner_patch_coords->data<CompressedPatchCoord>().data(),
cache_building_context.patch_coords,
sizeof(CompressedPatchCoord) * cache.num_subdiv_loops);
if (cache.num_subdiv_loops > 0) {
memcpy(cache.corner_patch_coords->data<CompressedPatchCoord>().data(),
cache_building_context.patch_coords,
sizeof(CompressedPatchCoord) * cache.num_subdiv_loops);
for (int i = 0; i < cache.num_subdiv_loops; i++) {
const int vertex = cache_building_context.subdiv_loop_subdiv_vert_index[i];
if (first_loop_index[vertex] != -1) {
continue;
for (int i = 0; i < cache.num_subdiv_loops; i++) {
const int vertex = cache_building_context.subdiv_loop_subdiv_vert_index[i];
if (first_loop_index[vertex] != -1) {
continue;
}
first_loop_index[vertex] = i;
}
first_loop_index[vertex] = i;
}
for (int i = 0; i < cache.num_subdiv_loops; i++) {
const int vertex = cache_building_context.subdiv_loop_subdiv_vert_index[i];
cache_building_context.patch_coords[i] =
cache_building_context.patch_coords[first_loop_index[vertex]];
for (int i = 0; i < cache.num_subdiv_loops; i++) {
const int vertex = cache_building_context.subdiv_loop_subdiv_vert_index[i];
cache_building_context.patch_coords[i] =
cache_building_context.patch_coords[first_loop_index[vertex]];
}
}
/* Cleanup. */

View File

@@ -270,7 +270,8 @@ void extract_face_dots_subdiv(const DRWSubdivCache &subdiv_cache,
gpu::IndexBuf &fdots);
void extract_normals(const MeshRenderData &mr, bool use_hq, gpu::VertBuf &vbo);
void extract_normals_subdiv(const DRWSubdivCache &subdiv_cache,
void extract_normals_subdiv(const MeshRenderData &mr,
const DRWSubdivCache &subdiv_cache,
gpu::VertBuf &pos_nor,
gpu::VertBuf &lnor);
void extract_vert_normals(const MeshRenderData &mr, gpu::VertBuf &vbo);

View File

@@ -231,12 +231,14 @@ void extract_edge_factor_subdiv(const DRWSubdivCache &subdiv_cache,
subdiv_cache.num_subdiv_loops +
subdiv_loose_edges_num(mr, subdiv_cache) * 2);
gpu::VertBuf *poly_other_map = build_poly_other_map_vbo(subdiv_cache);
if (mr.faces_num > 0) {
gpu::VertBuf *poly_other_map = build_poly_other_map_vbo(subdiv_cache);
draw_subdiv_build_edge_fac_buffer(
subdiv_cache, &pos_nor, subdiv_cache.edges_draw_flag, poly_other_map, &vbo);
draw_subdiv_build_edge_fac_buffer(
subdiv_cache, &pos_nor, subdiv_cache.edges_draw_flag, poly_other_map, &vbo);
GPU_vertbuf_discard(poly_other_map);
GPU_vertbuf_discard(poly_other_map);
}
const int loose_edges_num = subdiv_loose_edges_num(mr, subdiv_cache);
if (loose_edges_num == 0) {

View File

@@ -259,12 +259,23 @@ static const GPUVertFormat &get_subdiv_lnor_format()
return format;
}
void extract_normals_subdiv(const DRWSubdivCache &subdiv_cache,
void extract_normals_subdiv(const MeshRenderData &mr,
const DRWSubdivCache &subdiv_cache,
gpu::VertBuf &pos_nor,
gpu::VertBuf &lnor)
{
GPU_vertbuf_init_build_on_device(lnor, get_subdiv_lnor_format(), subdiv_cache.num_subdiv_loops);
draw_subdiv_build_lnor_buffer(subdiv_cache, &pos_nor, &lnor);
}
const int vbo_size = subdiv_full_vbo_size(mr, subdiv_cache);
const int loose_geom_start = subdiv_cache.num_subdiv_loops;
GPU_vertbuf_init_build_on_device(lnor, get_subdiv_lnor_format(), vbo_size);
draw_subdiv_build_lnor_buffer(subdiv_cache, &pos_nor, &lnor);
/* Push VBO content to the GPU and bind the VBO so that #GPU_vertbuf_update_sub can work. */
GPU_vertbuf_use(&lnor);
const float4 up(0.0f, 0.0f, 1.0f, 0.0f);
for (const int i : IndexRange::from_begin_end(loose_geom_start, vbo_size)) {
GPU_vertbuf_update_sub(&lnor, i * sizeof(float4), sizeof(float4), &up);
}
}
} // namespace blender::draw