diff --git a/source/blender/blenkernel/BKE_pbvh_api.hh b/source/blender/blenkernel/BKE_pbvh_api.hh index 66e9e4ebbe1..d2f76bb5b57 100644 --- a/source/blender/blenkernel/BKE_pbvh_api.hh +++ b/source/blender/blenkernel/BKE_pbvh_api.hh @@ -294,15 +294,14 @@ bool BKE_pbvh_node_find_nearest_to_ray(PBVH *pbvh, void BKE_pbvh_set_frustum_planes(PBVH *pbvh, PBVHFrustumPlanes *planes); void BKE_pbvh_get_frustum_planes(const PBVH *pbvh, PBVHFrustumPlanes *planes); -void BKE_pbvh_draw_cb(const Mesh &mesh, - PBVH *pbvh, - bool update_only_visible, - PBVHFrustumPlanes *update_frustum, - PBVHFrustumPlanes *draw_frustum, - void (*draw_fn)(void *user_data, - blender::draw::pbvh::PBVHBatches *batches, - const blender::draw::pbvh::PBVH_GPU_Args &args), - void *user_data); +void BKE_pbvh_draw_cb( + const Mesh &mesh, + PBVH *pbvh, + bool update_only_visible, + const PBVHFrustumPlanes &update_frustum, + const PBVHFrustumPlanes &draw_frustum, + blender::FunctionRef draw_fn); /* PBVH Access */ diff --git a/source/blender/blenkernel/intern/pbvh.cc b/source/blender/blenkernel/intern/pbvh.cc index e8f344966a7..1255c5cc6e3 100644 --- a/source/blender/blenkernel/intern/pbvh.cc +++ b/source/blender/blenkernel/intern/pbvh.cc @@ -1294,139 +1294,6 @@ bool BKE_pbvh_get_color_layer(Mesh *me, CustomDataLayer **r_layer, eAttrDomain * return *r_layer != nullptr; } -static blender::draw::pbvh::PBVH_GPU_Args pbvh_draw_args_init(const Mesh &mesh, - PBVH &pbvh, - const PBVHNode &node) -{ - blender::draw::pbvh::PBVH_GPU_Args args{}; - - args.pbvh_type = pbvh.header.type; - - args.face_sets_color_default = mesh.face_sets_color_default; - args.face_sets_color_seed = mesh.face_sets_color_seed; - - args.active_color = mesh.active_color_attribute; - args.render_color = mesh.default_color_attribute; - - switch (pbvh.header.type) { - case PBVH_FACES: - args.vert_data = &mesh.vert_data; - args.loop_data = &mesh.loop_data; - args.face_data = &mesh.face_data; - args.me = pbvh.mesh; - args.vert_positions = pbvh.vert_positions; - args.corner_verts = mesh.corner_verts(); - args.corner_edges = mesh.corner_edges(); - args.mlooptri = pbvh.looptri; - args.vert_normals = pbvh.vert_normals; - args.face_normals = pbvh.face_normals; - /* Retrieve data from the original mesh. Ideally that would be passed to this function to - * make it clearer when each is used. */ - args.hide_poly = static_cast( - CustomData_get_layer_named(&pbvh.mesh->face_data, CD_PROP_BOOL, ".hide_poly")); - - args.prim_indices = node.prim_indices; - args.looptri_faces = mesh.looptri_faces(); - break; - case PBVH_GRIDS: - args.vert_data = &pbvh.mesh->vert_data; - args.loop_data = &pbvh.mesh->loop_data; - args.face_data = &pbvh.mesh->face_data; - args.ccg_key = pbvh.gridkey; - args.me = pbvh.mesh; - args.grid_indices = node.prim_indices; - args.subdiv_ccg = pbvh.subdiv_ccg; - args.grids = pbvh.subdiv_ccg->grids; - args.vert_normals = pbvh.vert_normals; - break; - case PBVH_BMESH: - args.bm = pbvh.header.bm; - args.vert_data = &args.bm->vdata; - args.loop_data = &args.bm->ldata; - args.face_data = &args.bm->pdata; - args.bm_faces = &node.bm_faces; - args.cd_mask_layer = CustomData_get_offset_named( - &pbvh.header.bm->vdata, CD_PROP_FLOAT, ".sculpt_mask"); - - break; - } - - return args; -} - -static void node_update_draw_buffers(const Mesh &mesh, PBVH &pbvh, PBVHNode &node) -{ - /* Create and update draw buffers. The functions called here must not - * do any OpenGL calls. Flags are not cleared immediately, that happens - * after GPU_pbvh_buffer_flush() which does the final OpenGL calls. */ - if (node.flag & PBVH_RebuildDrawBuffers) { - const blender::draw::pbvh::PBVH_GPU_Args args = pbvh_draw_args_init(mesh, pbvh, node); - node.draw_batches = blender::draw::pbvh::node_create(args); - } - - if (node.flag & PBVH_UpdateDrawBuffers) { - node.debug_draw_gen++; - - if (node.draw_batches) { - const blender::draw::pbvh::PBVH_GPU_Args args = pbvh_draw_args_init(mesh, pbvh, node); - blender::draw::pbvh::node_update(node.draw_batches, args); - } - } -} - -void pbvh_free_draw_buffers(PBVH & /*pbvh*/, PBVHNode *node) -{ - if (node->draw_batches) { - blender::draw::pbvh::node_free(node->draw_batches); - node->draw_batches = nullptr; - } -} - -static void pbvh_update_draw_buffers(const Mesh &mesh, - PBVH &pbvh, - Span nodes, - int update_flag) -{ - using namespace blender; - if (pbvh.header.type == PBVH_BMESH && !pbvh.header.bm) { - /* BMesh hasn't been created yet */ - return; - } - - if ((update_flag & PBVH_RebuildDrawBuffers) || ELEM(pbvh.header.type, PBVH_GRIDS, PBVH_BMESH)) { - /* Free buffers uses OpenGL, so not in parallel. */ - for (PBVHNode *node : nodes) { - if (node->flag & PBVH_RebuildDrawBuffers) { - pbvh_free_draw_buffers(pbvh, node); - } - else if ((node->flag & PBVH_UpdateDrawBuffers) && node->draw_batches) { - const draw::pbvh::PBVH_GPU_Args args = pbvh_draw_args_init(mesh, pbvh, *node); - draw::pbvh::update_pre(node->draw_batches, args); - } - } - } - - /* Parallel creation and update of draw buffers. */ - - threading::parallel_for(nodes.index_range(), 1, [&](const IndexRange range) { - for (PBVHNode *node : nodes.slice(range)) { - node_update_draw_buffers(mesh, pbvh, *node); - } - }); - - /* Flush buffers uses OpenGL, so not in parallel. */ - for (PBVHNode *node : nodes) { - if (node->flag & PBVH_UpdateDrawBuffers) { - - if (node->draw_batches) { - draw::pbvh::node_gpu_flush(node->draw_batches); - } - } - - node->flag &= ~(PBVH_RebuildDrawBuffers | PBVH_UpdateDrawBuffers); - } -} - static int pbvh_flush_bb(PBVH *pbvh, PBVHNode *node, int flag) { int update = 0; @@ -2796,74 +2663,186 @@ void BKE_pbvh_update_normals(PBVH *pbvh, SubdivCCG *subdiv_ccg) } } -/** - * PBVH drawing, updating draw buffers as needed and culling any nodes outside - * the specified frustum. - */ -struct PBVHDrawSearchData { - PBVHFrustumPlanes *frustum; - int accum_update_flag; -}; - -static bool pbvh_draw_search(PBVHNode *node, PBVHDrawSearchData *data) +static blender::draw::pbvh::PBVH_GPU_Args pbvh_draw_args_init(const Mesh &mesh, + PBVH &pbvh, + const PBVHNode &node) { - if (data->frustum && !BKE_pbvh_node_frustum_contain_AABB(node, data->frustum)) { - return false; + blender::draw::pbvh::PBVH_GPU_Args args{}; + + args.pbvh_type = pbvh.header.type; + + args.face_sets_color_default = mesh.face_sets_color_default; + args.face_sets_color_seed = mesh.face_sets_color_seed; + + args.active_color = mesh.active_color_attribute; + args.render_color = mesh.default_color_attribute; + + switch (pbvh.header.type) { + case PBVH_FACES: + args.vert_data = &mesh.vert_data; + args.loop_data = &mesh.loop_data; + args.face_data = &mesh.face_data; + args.me = pbvh.mesh; + args.vert_positions = pbvh.vert_positions; + args.corner_verts = mesh.corner_verts(); + args.corner_edges = mesh.corner_edges(); + args.mlooptri = pbvh.looptri; + args.vert_normals = pbvh.vert_normals; + args.face_normals = pbvh.face_normals; + /* Retrieve data from the original mesh. Ideally that would be passed to this function to + * make it clearer when each is used. */ + args.hide_poly = static_cast( + CustomData_get_layer_named(&pbvh.mesh->face_data, CD_PROP_BOOL, ".hide_poly")); + + args.prim_indices = node.prim_indices; + args.looptri_faces = mesh.looptri_faces(); + break; + case PBVH_GRIDS: + args.vert_data = &pbvh.mesh->vert_data; + args.loop_data = &pbvh.mesh->loop_data; + args.face_data = &pbvh.mesh->face_data; + args.ccg_key = pbvh.gridkey; + args.me = pbvh.mesh; + args.grid_indices = node.prim_indices; + args.subdiv_ccg = pbvh.subdiv_ccg; + args.grids = pbvh.subdiv_ccg->grids; + args.vert_normals = pbvh.vert_normals; + break; + case PBVH_BMESH: + args.bm = pbvh.header.bm; + args.vert_data = &args.bm->vdata; + args.loop_data = &args.bm->ldata; + args.face_data = &args.bm->pdata; + args.bm_faces = &node.bm_faces; + args.cd_mask_layer = CustomData_get_offset_named( + &pbvh.header.bm->vdata, CD_PROP_FLOAT, ".sculpt_mask"); + + break; } - data->accum_update_flag |= node->flag; - return true; + return args; } -void BKE_pbvh_draw_cb(const Mesh &mesh, - PBVH *pbvh, - bool update_only_visible, - PBVHFrustumPlanes *update_frustum, - PBVHFrustumPlanes *draw_frustum, - void (*draw_fn)(void *user_data, - blender::draw::pbvh::PBVHBatches *batches, - const blender::draw::pbvh::PBVH_GPU_Args &args), - void *user_data) +static void node_update_draw_buffers(const Mesh &mesh, PBVH &pbvh, PBVHNode &node) +{ + /* Create and update draw buffers. The functions called here must not + * do any OpenGL calls. Flags are not cleared immediately, that happens + * after GPU_pbvh_buffer_flush() which does the final OpenGL calls. */ + if (node.flag & PBVH_RebuildDrawBuffers) { + const blender::draw::pbvh::PBVH_GPU_Args args = pbvh_draw_args_init(mesh, pbvh, node); + node.draw_batches = blender::draw::pbvh::node_create(args); + } + + if (node.flag & PBVH_UpdateDrawBuffers) { + node.debug_draw_gen++; + + if (node.draw_batches) { + const blender::draw::pbvh::PBVH_GPU_Args args = pbvh_draw_args_init(mesh, pbvh, node); + blender::draw::pbvh::node_update(node.draw_batches, args); + } + } +} + +void pbvh_free_draw_buffers(PBVH & /*pbvh*/, PBVHNode *node) +{ + if (node->draw_batches) { + blender::draw::pbvh::node_free(node->draw_batches); + node->draw_batches = nullptr; + } +} + +static void pbvh_update_draw_buffers(const Mesh &mesh, + PBVH &pbvh, + Span nodes, + int update_flag) +{ + using namespace blender; + if (pbvh.header.type == PBVH_BMESH && !pbvh.header.bm) { + /* BMesh hasn't been created yet */ + return; + } + + if ((update_flag & PBVH_RebuildDrawBuffers) || ELEM(pbvh.header.type, PBVH_GRIDS, PBVH_BMESH)) { + /* Free buffers uses OpenGL, so not in parallel. */ + for (PBVHNode *node : nodes) { + if (node->flag & PBVH_RebuildDrawBuffers) { + pbvh_free_draw_buffers(pbvh, node); + } + else if ((node->flag & PBVH_UpdateDrawBuffers) && node->draw_batches) { + const draw::pbvh::PBVH_GPU_Args args = pbvh_draw_args_init(mesh, pbvh, *node); + draw::pbvh::update_pre(node->draw_batches, args); + } + } + } + + /* Parallel creation and update of draw buffers. */ + threading::parallel_for(nodes.index_range(), 1, [&](const IndexRange range) { + for (PBVHNode *node : nodes.slice(range)) { + node_update_draw_buffers(mesh, pbvh, *node); + } + }); + + /* Flush buffers uses OpenGL, so not in parallel. */ + for (PBVHNode *node : nodes) { + if (node->flag & PBVH_UpdateDrawBuffers) { + + if (node->draw_batches) { + draw::pbvh::node_gpu_flush(node->draw_batches); + } + } + + node->flag &= ~(PBVH_RebuildDrawBuffers | PBVH_UpdateDrawBuffers); + } +} + +void BKE_pbvh_draw_cb( + const Mesh &mesh, + PBVH *pbvh, + bool update_only_visible, + const PBVHFrustumPlanes &update_frustum, + const PBVHFrustumPlanes &draw_frustum, + const blender::FunctionRef draw_fn) { using namespace blender; using namespace blender::bke::pbvh; - Vector nodes; - int update_flag = 0; - pbvh->draw_cache_invalid = false; - /* Search for nodes that need updates. */ if (update_only_visible) { - /* Get visible nodes with draw updates. */ - PBVHDrawSearchData data{}; - data.frustum = update_frustum; - data.accum_update_flag = 0; - nodes = search_gather(pbvh, [&](PBVHNode &node) { return pbvh_draw_search(&node, &data); }); - update_flag = data.accum_update_flag; + int update_flag = 0; + Vector nodes = search_gather(pbvh, [&](PBVHNode &node) { + if (!BKE_pbvh_node_frustum_contain_AABB(&node, &update_frustum)) { + return false; + } + update_flag |= node.flag; + return true; + }); + if (update_flag & (PBVH_RebuildDrawBuffers | PBVH_UpdateDrawBuffers)) { + pbvh_update_draw_buffers(mesh, *pbvh, nodes, update_flag); + } } else { /* Get all nodes with draw updates, also those outside the view. */ - const int search_flag = PBVH_RebuildDrawBuffers | PBVH_UpdateDrawBuffers; - nodes = search_gather(pbvh, [&](PBVHNode &node) { return update_search(&node, search_flag); }); - update_flag = PBVH_RebuildDrawBuffers | PBVH_UpdateDrawBuffers; - } - - /* Update draw buffers. */ - if (!nodes.is_empty() && (update_flag & (PBVH_RebuildDrawBuffers | PBVH_UpdateDrawBuffers))) { - pbvh_update_draw_buffers(mesh, *pbvh, nodes, update_flag); + Vector nodes = search_gather(pbvh, [&](PBVHNode &node) { + return update_search(&node, PBVH_RebuildDrawBuffers | PBVH_UpdateDrawBuffers); + }); + pbvh_update_draw_buffers(mesh, *pbvh, nodes, PBVH_RebuildDrawBuffers | PBVH_UpdateDrawBuffers); } /* Draw visible nodes. */ - PBVHDrawSearchData draw_data{}; - draw_data.frustum = draw_frustum; - draw_data.accum_update_flag = 0; - nodes = search_gather(pbvh, [&](PBVHNode &node) { return pbvh_draw_search(&node, &draw_data); }); + Vector nodes = search_gather(pbvh, [&](PBVHNode &node) { + return BKE_pbvh_node_frustum_contain_AABB(&node, &draw_frustum); + }); for (PBVHNode *node : nodes) { - if (!(node->flag & PBVH_FullyHidden)) { - const draw::pbvh::PBVH_GPU_Args args = pbvh_draw_args_init(mesh, *pbvh, *node); - draw_fn(user_data, node->draw_batches, args); + if (node->flag & PBVH_FullyHidden) { + continue; } + if (!node->draw_batches) { + continue; + } + const draw::pbvh::PBVH_GPU_Args args = pbvh_draw_args_init(mesh, *pbvh, *node); + draw_fn(node->draw_batches, args); } } diff --git a/source/blender/draw/intern/draw_manager_data.cc b/source/blender/draw/intern/draw_manager_data.cc index d9e6c748340..54263b63d92 100644 --- a/source/blender/draw/intern/draw_manager_data.cc +++ b/source/blender/draw/intern/draw_manager_data.cc @@ -1234,10 +1234,6 @@ static void sculpt_draw_cb(DRWSculptCallbackData *scd, const blender::draw::pbvh::PBVH_GPU_Args &pbvh_draw_args) { using namespace blender::draw; - if (!batches) { - return; - } - GPUBatch *geom; if (!scd->use_wire) { @@ -1369,15 +1365,14 @@ static void drw_sculpt_generate_calls(DRWSculptCallbackData *scd) Mesh *mesh = static_cast(scd->ob->data); BKE_pbvh_update_normals(pbvh, mesh->runtime->subdiv_ccg.get()); - BKE_pbvh_draw_cb(*mesh, - pbvh, - update_only_visible, - &update_frustum, - &draw_frustum, - (void (*)(void *, - blender::draw::pbvh::PBVHBatches *, - const blender::draw::pbvh::PBVH_GPU_Args &))sculpt_draw_cb, - scd); + BKE_pbvh_draw_cb( + *mesh, + pbvh, + update_only_visible, + update_frustum, + draw_frustum, + [&](blender::draw::pbvh::PBVHBatches *batches, + const blender::draw::pbvh::PBVH_GPU_Args &args) { sculpt_draw_cb(scd, batches, args); }); if (SCULPT_DEBUG_BUFFERS) { int debug_node_nr = 0; diff --git a/source/blender/draw/intern/draw_sculpt.cc b/source/blender/draw/intern/draw_sculpt.cc index 9c390c970bf..329ee957190 100644 --- a/source/blender/draw/intern/draw_sculpt.cc +++ b/source/blender/draw/intern/draw_sculpt.cc @@ -37,40 +37,8 @@ float3 SculptBatch::debug_color() return colors[debug_index % 9]; } -struct SculptCallbackData { - bool use_wire; - bool fast_mode; - - Span attrs; - - Vector batches; -}; - -static void sculpt_draw_cb(SculptCallbackData *data, - pbvh::PBVHBatches *batches, - const pbvh::PBVH_GPU_Args &pbvh_draw_args) -{ - if (!batches) { - return; - } - - SculptBatch batch = {}; - - if (data->use_wire) { - batch.batch = pbvh::lines_get(batches, data->attrs, pbvh_draw_args, data->fast_mode); - } - else { - batch.batch = pbvh::tris_get(batches, data->attrs, pbvh_draw_args, data->fast_mode); - } - - batch.material_slot = pbvh::material_index_get(batches); - batch.debug_index = data->batches.size(); - - data->batches.append(batch); -} - static Vector sculpt_batches_get_ex(const Object *ob, - bool use_wire, + const bool use_wire, const Span attrs) { /* PBVH should always exist for non-empty meshes, created by depsgraph eval. */ @@ -131,21 +99,25 @@ static Vector sculpt_batches_get_ex(const Object *ob, const Mesh *mesh = static_cast(ob->data); BKE_pbvh_update_normals(pbvh, mesh->runtime->subdiv_ccg.get()); - SculptCallbackData data; - data.use_wire = use_wire; - data.fast_mode = fast_mode; - data.attrs = attrs; - - BKE_pbvh_draw_cb( - *mesh, - pbvh, - update_only_visible, - &update_frustum, - &draw_frustum, - (void (*)(void *, pbvh::PBVHBatches *, const pbvh::PBVH_GPU_Args &))sculpt_draw_cb, - &data); - - return data.batches; + Vector result_batches; + BKE_pbvh_draw_cb(*mesh, + pbvh, + update_only_visible, + update_frustum, + draw_frustum, + [&](pbvh::PBVHBatches *batches, const pbvh::PBVH_GPU_Args &args) { + SculptBatch batch{}; + if (use_wire) { + batch.batch = pbvh::lines_get(batches, attrs, args, fast_mode); + } + else { + batch.batch = pbvh::tris_get(batches, attrs, args, fast_mode); + } + batch.material_slot = pbvh::material_index_get(batches); + batch.debug_index = result_batches.size(); + result_batches.append(batch); + }); + return result_batches; } Vector sculpt_batches_get(const Object *ob, SculptBatchFeature features)