From 9503751c83345b2941a4fc41dcc979ef456b0c5f Mon Sep 17 00:00:00 2001 From: Joseph Eagar Date: Mon, 16 Aug 2021 20:50:02 -0700 Subject: Sculpt dyntopo * Added a limited "fast draw" mode to pbvh drawing that tries to limit data sent to the GPU. - Facesets and mask data are disabled. - Indexed mode is forced. - Does not work (at all) for multires. * Finally fixed some outstanding bmesh sculpt undo bugs: - Forgot to mark pbvh nodes to update their bounds, which produced a bug I had thought was caused by something else. - Hopefully fixed a long-standing occasional memory corruption bug. --- source/blender/blenkernel/BKE_paint.h | 2 + source/blender/blenkernel/BKE_pbvh.h | 15 +- source/blender/blenkernel/intern/paint.c | 10 +- source/blender/blenkernel/intern/pbvh.c | 59 +++-- source/blender/blenkernel/intern/pbvh_bmesh.c | 49 +++- source/blender/blenkernel/intern/pbvh_intern.h | 1 + .../blender/draw/engines/overlay/overlay_sculpt.c | 2 +- source/blender/editors/sculpt_paint/paint_mask.c | 9 +- source/blender/editors/sculpt_paint/sculpt_undo.c | 68 +++--- source/blender/gpu/GPU_buffers.h | 8 +- source/blender/gpu/intern/gpu_buffers.c | 266 +++++++++++++-------- source/blender/makesdna/DNA_scene_types.h | 19 +- source/blender/makesrna/intern/rna_sculpt_paint.c | 12 + 13 files changed, 346 insertions(+), 174 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h index 7314a2dc8ff..db091a8b878 100644 --- a/source/blender/blenkernel/BKE_paint.h +++ b/source/blender/blenkernel/BKE_paint.h @@ -655,6 +655,8 @@ typedef struct SculptSession { // id of current stroke, used to detect // if vertex original data needs to be updated int stroke_id; + + bool fast_draw; // hides facesets/masks and forces smooth to save GPU bandwidth } SculptSession; void BKE_sculptsession_free(struct Object *ob); diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h index 97d3c77fb50..2f87895b262 100644 --- a/source/blender/blenkernel/BKE_pbvh.h +++ b/source/blender/blenkernel/BKE_pbvh.h @@ -240,21 +240,24 @@ void BKE_pbvh_build_mesh(PBVH *pbvh, struct CustomData *ldata, struct CustomData *pdata, const struct MLoopTri *looptri, - int looptri_num); + int looptri_num, + bool fast_draw); void BKE_pbvh_build_grids(PBVH *pbvh, struct CCGElem **grids, int totgrid, struct CCGKey *key, void **gridfaces, struct DMFlagMat *flagmats, - unsigned int **grid_hidden); + unsigned int **grid_hidden, + bool fast_draw); void BKE_pbvh_build_bmesh(PBVH *pbvh, struct BMesh *bm, bool smooth_shading, struct BMLog *log, const int cd_vert_node_offset, const int cd_face_node_offset, - const int cd_dyn_vert); + const int cd_dyn_vert, + bool fast_draw); void BKE_pbvh_update_offsets(PBVH *pbvh, const int cd_vert_node_offset, const int cd_face_node_offset, @@ -682,10 +685,10 @@ bool BKE_pbvh_node_vert_update_check_any(PBVH *pbvh, PBVHNode *node); // void BKE_pbvh_node_BB_reset(PBVHNode *node); // void BKE_pbvh_node_BB_expand(PBVHNode *node, float co[3]); -bool pbvh_has_mask(const PBVH *pbvh); +bool BKE_pbvh_draw_mask(const PBVH *pbvh); void pbvh_show_mask_set(PBVH *pbvh, bool show_mask); -bool pbvh_has_face_sets(PBVH *pbvh); +bool BKE_pbvh_draw_face_sets(PBVH *pbvh); void pbvh_show_face_sets_set(PBVH *pbvh, bool show_face_sets); /* Parallelization */ @@ -740,6 +743,8 @@ void BKE_pbvh_update_vert_boundary(int cd_dyn_vert, int cd_faceset_offset, struc #define DYNTOPO_DYNAMIC_TESS +PBVHNode *BKE_pbvh_get_node_leaf_safe(PBVH *pbvh, int i); + #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c index 6463fcf8780..2cc5561000b 100644 --- a/source/blender/blenkernel/intern/paint.c +++ b/source/blender/blenkernel/intern/paint.c @@ -1701,6 +1701,7 @@ static void sculpt_update_object(Depsgraph *depsgraph, } ss->subdiv_ccg = me_eval->runtime.subdiv_ccg; + ss->fast_draw = (scene->toolsettings->sculpt->flags & SCULPT_FAST_DRAW) != 0; PBVH *pbvh = BKE_sculpt_object_pbvh_ensure(depsgraph, ob); BLI_assert(pbvh == ss->pbvh); @@ -2137,7 +2138,8 @@ static PBVH *build_pbvh_for_dynamic_topology(Object *ob) ob->sculpt->bm_log, ob->sculpt->cd_vert_node_offset, ob->sculpt->cd_face_node_offset, - ob->sculpt->cd_dyn_vert); + ob->sculpt->cd_dyn_vert, + ob->sculpt->fast_draw); pbvh_show_mask_set(pbvh, ob->sculpt->show_mask); pbvh_show_face_sets_set(pbvh, false); @@ -2167,7 +2169,8 @@ static PBVH *build_pbvh_from_regular_mesh(Object *ob, Mesh *me_eval_deform, bool &me->ldata, &me->pdata, looptri, - looptris_num); + looptris_num, + ob->sculpt->fast_draw); pbvh_show_mask_set(pbvh, ob->sculpt->show_mask); pbvh_show_face_sets_set(pbvh, ob->sculpt->show_face_sets); @@ -2199,7 +2202,8 @@ static PBVH *build_pbvh_from_ccg(Object *ob, SubdivCCG *subdiv_ccg, bool respect &key, (void **)subdiv_ccg->grid_faces, subdiv_ccg->grid_flag_mats, - subdiv_ccg->grid_hidden); + subdiv_ccg->grid_hidden, + ob->sculpt->fast_draw); pbvh_show_mask_set(pbvh, ob->sculpt->show_mask); pbvh_show_face_sets_set(pbvh, ob->sculpt->show_face_sets); return pbvh; diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c index abadab127a8..52058661da6 100644 --- a/source/blender/blenkernel/intern/pbvh.c +++ b/source/blender/blenkernel/intern/pbvh.c @@ -591,7 +591,8 @@ void BKE_pbvh_build_mesh(PBVH *pbvh, struct CustomData *ldata, struct CustomData *pdata, const MLoopTri *looptri, - int looptri_num) + int looptri_num, + bool fast_draw) { BBC *prim_bbc = NULL; BB cb; @@ -639,6 +640,10 @@ void BKE_pbvh_build_mesh(PBVH *pbvh, pbvh_build(pbvh, &cb, prim_bbc, looptri_num); } + if (fast_draw) { + pbvh->flags |= PBVH_FAST_DRAW; + } + MEM_freeN(prim_bbc); MEM_freeN(pbvh->vert_bitmap); } @@ -650,7 +655,8 @@ void BKE_pbvh_build_grids(PBVH *pbvh, CCGKey *key, void **gridfaces, DMFlagMat *flagmats, - BLI_bitmap **grid_hidden) + BLI_bitmap **grid_hidden, + bool fast_draw) { const int gridsize = key->grid_size; @@ -689,6 +695,10 @@ void BKE_pbvh_build_grids(PBVH *pbvh, pbvh_build(pbvh, &cb, prim_bbc, totgrid); } + if (fast_draw) { + pbvh->flags |= PBVH_FAST_DRAW; + } + MEM_freeN(prim_bbc); } @@ -1454,20 +1464,11 @@ void pbvh_update_free_all_draw_buffers(PBVH *pbvh, PBVHNode *node) } } -static void pbvh_update_draw_buffers(PBVH *pbvh, PBVHNode **nodes, int totnode, int update_flag) +ATTR_NO_OPT static void pbvh_update_draw_buffers(PBVH *pbvh, + PBVHNode **nodes, + int totnode, + int update_flag) { - if ((update_flag & PBVH_RebuildDrawBuffers) || ELEM(pbvh->type, PBVH_GRIDS, PBVH_BMESH)) { - /* Free buffers uses OpenGL, so not in parallel. */ - for (int n = 0; n < totnode; n++) { - PBVHNode *node = nodes[n]; - if (node->flag & PBVH_RebuildDrawBuffers) { - pbvh_free_all_draw_buffers(node); - } - else if ((node->flag & PBVH_UpdateDrawBuffers)) { - pbvh_update_free_all_draw_buffers(pbvh, node); - } - } - } CustomData *vdata; CustomData *ldata; @@ -1486,7 +1487,21 @@ static void pbvh_update_draw_buffers(PBVH *pbvh, PBVHNode **nodes, int totnode, ldata = pbvh->ldata; } - GPU_pbvh_update_attribute_names(vdata, ldata, GPU_pbvh_need_full_render_get()); + GPU_pbvh_update_attribute_names( + vdata, ldata, GPU_pbvh_need_full_render_get(), pbvh->flags & PBVH_FAST_DRAW); + + if ((update_flag & PBVH_RebuildDrawBuffers) || ELEM(pbvh->type, PBVH_GRIDS, PBVH_BMESH)) { + /* Free buffers uses OpenGL, so not in parallel. */ + for (int n = 0; n < totnode; n++) { + PBVHNode *node = nodes[n]; + if (node->flag & PBVH_RebuildDrawBuffers) { + pbvh_free_all_draw_buffers(node); + } + else if ((node->flag & PBVH_UpdateDrawBuffers)) { + pbvh_update_free_all_draw_buffers(pbvh, node); + } + } + } /* Parallel creation and update of draw buffers. */ PBVHUpdateData data = { @@ -3252,8 +3267,12 @@ void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int m } } -bool pbvh_has_mask(const PBVH *pbvh) +bool BKE_pbvh_draw_mask(const PBVH *pbvh) { + if (pbvh->flags & PBVH_FAST_DRAW) { + return false; + } + switch (pbvh->type) { case PBVH_GRIDS: return (pbvh->gridkey.has_mask != 0); @@ -3286,8 +3305,12 @@ SculptFaceRef BKE_pbvh_table_index_to_face(PBVH *pbvh, int idx) return BKE_pbvh_make_fref(idx); } -bool pbvh_has_face_sets(PBVH *pbvh) +bool BKE_pbvh_draw_face_sets(PBVH *pbvh) { + if (pbvh->flags & PBVH_FAST_DRAW) { + return false; + } + switch (pbvh->type) { case PBVH_GRIDS: return (pbvh->pdata && CustomData_get_layer(pbvh->pdata, CD_SCULPT_FACE_SETS)); diff --git a/source/blender/blenkernel/intern/pbvh_bmesh.c b/source/blender/blenkernel/intern/pbvh_bmesh.c index e2f926fa2f8..f8f3beaccaa 100644 --- a/source/blender/blenkernel/intern/pbvh_bmesh.c +++ b/source/blender/blenkernel/intern/pbvh_bmesh.c @@ -545,11 +545,13 @@ void bke_pbvh_insert_face(PBVH *pbvh, struct BMFace *f) static void pbvh_bmesh_regen_node_verts(PBVH *pbvh, PBVHNode *node) { - int usize = BLI_table_gset_len(node->bm_other_verts); + node->flag &= ~PBVH_RebuildNodeVerts; + + int usize = BLI_table_gset_len(node->bm_unique_verts); int osize = BLI_table_gset_len(node->bm_other_verts); - BLI_table_gset_free(node->bm_other_verts, NULL); BLI_table_gset_free(node->bm_unique_verts, NULL); + BLI_table_gset_free(node->bm_other_verts, NULL); node->bm_unique_verts = BLI_table_gset_new("bm_unique_verts"); node->bm_other_verts = BLI_table_gset_new("bm_other_verts"); @@ -557,11 +559,20 @@ static void pbvh_bmesh_regen_node_verts(PBVH *pbvh, PBVHNode *node) const int cd_vert_node = pbvh->cd_vert_node_offset; const int ni = (int)(node - pbvh->nodes); + bool update = false; + BMFace *f; TGSET_ITER (f, node->bm_faces) { BMLoop *l = f->l_first; do { int ni2 = BM_ELEM_CD_GET_INT(l->v, cd_vert_node); + + if (ni2 == DYNTOPO_NODE_NONE) { + BM_ELEM_CD_SET_INT(l->v, cd_vert_node, ni); + ni2 = ni; + update = true; + } + if (ni2 == ni) { BLI_table_gset_add(node->bm_unique_verts, l->v); } @@ -573,16 +584,25 @@ static void pbvh_bmesh_regen_node_verts(PBVH *pbvh, PBVHNode *node) TGSET_ITER_END; if (usize != BLI_table_gset_len(node->bm_unique_verts)) { + update = true; printf("possible pbvh error: bm_unique_verts might have had bad data. old: %d, new: %d\n", usize, BLI_table_gset_len(node->bm_unique_verts)); } if (osize != BLI_table_gset_len(node->bm_other_verts)) { + update = true; printf("possible pbvh error: bm_other_verts might have had bad data. old: %d, new: %d\n", osize, BLI_table_gset_len(node->bm_other_verts)); } + + if (update) { + node->flag |= PBVH_UpdateNormals | PBVH_UpdateDrawBuffers | PBVH_RebuildDrawBuffers | + PBVH_UpdateBB; + node->flag |= PBVH_UpdateOriginalBB | PBVH_UpdateRedraw | PBVH_UpdateColor | PBVH_UpdateTris | + PBVH_UpdateVisibility; + } } void BKE_pbvh_bmesh_mark_node_regen(PBVH *pbvh, PBVHNode *node) @@ -590,6 +610,18 @@ void BKE_pbvh_bmesh_mark_node_regen(PBVH *pbvh, PBVHNode *node) node->flag |= PBVH_RebuildNodeVerts; } +PBVHNode *BKE_pbvh_get_node_leaf_safe(PBVH *pbvh, int i) +{ + if (i >= 0 && i < pbvh->totnode) { + PBVHNode *node = pbvh->nodes + i; + if ((node->flag & PBVH_Leaf) && !(node->flag & PBVH_Delete)) { + return node; + } + } + + return NULL; +} + void BKE_pbvh_bmesh_regen_node_verts(PBVH *pbvh) { for (int i = 0; i < pbvh->totnode; i++) { @@ -1226,13 +1258,16 @@ void BKE_pbvh_build_bmesh(PBVH *pbvh, BMLog *log, const int cd_vert_node_offset, const int cd_face_node_offset, - const int cd_dyn_vert) + const int cd_dyn_vert, + bool fast_draw) { pbvh->cd_vert_node_offset = cd_vert_node_offset; pbvh->cd_face_node_offset = cd_face_node_offset; pbvh->cd_vert_mask_offset = CustomData_get_offset(&bm->vdata, CD_PAINT_MASK); pbvh->cd_dyn_vert = cd_dyn_vert; + smooth_shading |= fast_draw; + pbvh->bm = bm; BKE_pbvh_bmesh_detail_size_set(pbvh, 0.75f, 0.4f); @@ -1270,10 +1305,15 @@ void BKE_pbvh_build_bmesh(PBVH *pbvh, zero_v4(mv->origcolor); } } + if (smooth_shading) { pbvh->flags |= PBVH_DYNTOPO_SMOOTH_SHADING; } + if (fast_draw) { + pbvh->flags |= PBVH_FAST_DRAW; + } + /* bounding box array of all faces, no need to recalculate every time */ BBC *bbc_array = MEM_mallocN(sizeof(BBC) * bm->totface, "BBC"); BMFace **nodeinfo = MEM_mallocN(sizeof(*nodeinfo) * bm->totface, "nodeinfo"); @@ -1384,13 +1424,16 @@ static void pbvh_free_tribuf(PBVHTriBuf *tribuf) MEM_SAFE_FREE(tribuf->verts); MEM_SAFE_FREE(tribuf->tris); MEM_SAFE_FREE(tribuf->loops); + MEM_SAFE_FREE(tribuf->edges); tribuf->verts = NULL; tribuf->tris = NULL; tribuf->loops = NULL; + tribuf->edges = NULL; tribuf->verts_size = 0; tribuf->tris_size = 0; + tribuf->edges_size = 0; } PBVHTriBuf *BKE_pbvh_bmesh_get_tris(PBVH *pbvh, PBVHNode *node) diff --git a/source/blender/blenkernel/intern/pbvh_intern.h b/source/blender/blenkernel/intern/pbvh_intern.h index f06c95b1755..efe5c426e91 100644 --- a/source/blender/blenkernel/intern/pbvh_intern.h +++ b/source/blender/blenkernel/intern/pbvh_intern.h @@ -129,6 +129,7 @@ struct PBVHNode { typedef enum { PBVH_DYNTOPO_SMOOTH_SHADING = 1, + PBVH_FAST_DRAW = 2 // hides facesets/masks and forces smooth to save GPU bandwidth } PBVHFlags; typedef struct PBVHBMeshLog PBVHBMeshLog; diff --git a/source/blender/draw/engines/overlay/overlay_sculpt.c b/source/blender/draw/engines/overlay/overlay_sculpt.c index 24c52ec427d..24ff807bba8 100644 --- a/source/blender/draw/engines/overlay/overlay_sculpt.c +++ b/source/blender/draw/engines/overlay/overlay_sculpt.c @@ -60,7 +60,7 @@ void OVERLAY_sculpt_cache_populate(OVERLAY_Data *vedata, Object *ob) return; } - if (!pbvh_has_mask(pbvh) && !pbvh_has_face_sets(pbvh)) { + if (!BKE_pbvh_draw_mask(pbvh) && !BKE_pbvh_draw_face_sets(pbvh)) { /* The SculptSession and the PBVH can be created without a Mask data-layer or Face Set * data-layer. (masks data-layers are created after using a mask tool), so in these cases there * is nothing to draw. */ diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c index b3fcb9155f3..04db16d4516 100644 --- a/source/blender/editors/sculpt_paint/paint_mask.c +++ b/source/blender/editors/sculpt_paint/paint_mask.c @@ -1305,19 +1305,20 @@ static void sculpt_gesture_apply_trim(SculptGestureContext *sgcontext) MEM_freeN(looptris); - if (sgcontext->ss && sgcontext->ss->bm) { //rebuild pbvh + if (sgcontext->ss && sgcontext->ss->bm) { // rebuild pbvh BKE_pbvh_free(sgcontext->ss->pbvh); sgcontext->ss->pbvh = BKE_pbvh_new(); BKE_pbvh_build_bmesh(sgcontext->ss->pbvh, sgcontext->ss->bm, - false, + sgcontext->ss->bm_smooth_shading, sgcontext->ss->bm_log, sgcontext->ss->cd_vert_node_offset, sgcontext->ss->cd_face_node_offset, - sgcontext->ss->cd_dyn_vert); + sgcontext->ss->cd_dyn_vert, + sgcontext->ss->fast_draw); } - else { //save result to mesh + else { // save result to mesh Mesh *result = BKE_mesh_from_bmesh_nomain(bm, (&(struct BMeshToMeshParams){ .calc_object_remap = false, diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c index 3e5aa90a6ba..1cc928525ec 100644 --- a/source/blender/editors/sculpt_paint/sculpt_undo.c +++ b/source/blender/editors/sculpt_paint/sculpt_undo.c @@ -435,6 +435,8 @@ typedef struct BmeshUndoData { bool balance_pbvh; int cd_face_node_offset, cd_vert_node_offset; int cd_dyn_vert; + bool regen_all_unique_verts; + bool is_redo; } BmeshUndoData; static void bmesh_undo_on_vert_kill(BMVert *v, void *userdata) @@ -448,29 +450,17 @@ static void bmesh_undo_on_vert_kill(BMVert *v, void *userdata) data->do_full_recalc = true; return; } - else { - int ni = BM_ELEM_CD_GET_INT(v, data->cd_vert_node_offset); - - /* - regenerate bm_unique_verts, which can end up with - freed verts for some reason. I've run this through - ASAN and fixed one likely cause, but it still happens. - - joeedh - */ - if (ni >= 0) { - PBVHNode *node = BKE_pbvh_get_node(data->pbvh, ni); - BKE_pbvh_bmesh_mark_node_regen(data->pbvh, node); - } - } BKE_pbvh_bmesh_remove_vertex(data->pbvh, v, false); data->balance_pbvh = true; } + static void bmesh_undo_on_vert_add(BMVert *v, void *userdata) { BmeshUndoData *data = (BmeshUndoData *)userdata; BM_ELEM_CD_SET_INT(v, data->cd_vert_node_offset, -1); // data->do_full_recalc = true; + data->balance_pbvh = true; MDynTopoVert *mv = BKE_PBVH_DYNVERT(data->cd_dyn_vert, v); @@ -482,19 +472,13 @@ static void bmesh_undo_on_face_kill(BMFace *f, void *userdata) BmeshUndoData *data = (BmeshUndoData *)userdata; int ni = BM_ELEM_CD_GET_INT(f, data->cd_face_node_offset); - /* - regenerate bm_unique_verts, which can end up with - freed verts for some reason. I've run this through - ASAN and fixed one likely cause, but it still happens. - - joeedh - */ + BKE_pbvh_bmesh_remove_face(data->pbvh, f, false); + if (ni >= 0) { PBVHNode *node = BKE_pbvh_get_node(data->pbvh, ni); BKE_pbvh_bmesh_mark_node_regen(data->pbvh, node); } - BKE_pbvh_bmesh_remove_face(data->pbvh, f, false); - // data->do_full_recalc = true; data->balance_pbvh = true; } @@ -521,22 +505,36 @@ static void bmesh_undo_full_mesh(void *userdata) data->do_full_recalc = true; } -static void bmesh_undo_on_vert_change(BMVert *v, void *userdata, void *old_customdata) +ATTR_NO_OPT static void bmesh_undo_on_vert_change(BMVert *v, void *userdata, void *old_customdata) { BmeshUndoData *data = (BmeshUndoData *)userdata; if (!old_customdata) { BM_ELEM_CD_SET_INT(v, data->cd_vert_node_offset, -1); + data->regen_all_unique_verts = true; return; } - BM_ELEM_CD_SET_INT(v, data->cd_vert_node_offset, -1); + BMElem h; + h.head.data = old_customdata; + + int ni = BM_ELEM_CD_GET_INT(&h, data->cd_vert_node_offset); + + // attempt to find old node + PBVHNode *node = BKE_pbvh_get_node_leaf_safe(data->pbvh, ni); + if (node) { + // BKE_pbvh_bmesh_mark_node_regen(data->pbvh, node); + BKE_pbvh_node_mark_update(node); + // BM_ELEM_CD_SET_INT(v, data->cd_vert_node_offset, -1); + } + else { + BM_ELEM_CD_SET_INT(v, data->cd_vert_node_offset, -1); + data->regen_all_unique_verts = true; + } + return; // preserve pbvh node references - BMVert h; - h.head.data = old_customdata; - int oldnode_i = BM_ELEM_CD_GET_INT(&h, data->cd_vert_node_offset); BM_ELEM_CD_SET_INT(v, data->cd_vert_node_offset, oldnode_i); @@ -563,7 +561,9 @@ static void sculpt_undo_bmesh_restore_generic(SculptUndoNode *unode, Object *ob, false, ss->cd_face_node_offset, ss->cd_vert_node_offset, - ss->cd_dyn_vert}; + ss->cd_dyn_vert, + false, + !unode->applied}; BMLogCallbacks callbacks = {bmesh_undo_on_vert_add, bmesh_undo_on_vert_kill, @@ -589,11 +589,17 @@ static void sculpt_undo_bmesh_restore_generic(SculptUndoNode *unode, Object *ob, int totnode; PBVHNode **nodes; + BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode); + + if (data.regen_all_unique_verts) { + for (int i = 0; i < totnode; i++) { + BKE_pbvh_bmesh_mark_node_regen(ss->pbvh, nodes[i]); + } + } + BKE_pbvh_bmesh_regen_node_verts(ss->pbvh); pbvh_bmesh_check_nodes(ss->pbvh); - BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode); - TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, true, totnode); BLI_task_parallel_range( @@ -608,6 +614,8 @@ static void sculpt_undo_bmesh_restore_generic(SculptUndoNode *unode, Object *ob, if (data.balance_pbvh) { BKE_pbvh_bmesh_after_stroke(ss->pbvh); } + + BKE_pbvh_update_bounds(ss->pbvh, PBVH_UpdateBB | PBVH_UpdateOriginalBB | PBVH_UpdateRedraw); } else { SCULPT_pbvh_clear(ob); diff --git a/source/blender/gpu/GPU_buffers.h b/source/blender/gpu/GPU_buffers.h index cf0ba4b16bf..e2ccf8fe941 100644 --- a/source/blender/gpu/GPU_buffers.h +++ b/source/blender/gpu/GPU_buffers.h @@ -87,9 +87,11 @@ void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers, const struct MPropCol *vtcol, const int update_flags); -void GPU_pbvh_update_attribute_names(struct CustomData *vdata, - struct CustomData *ldata, - bool need_full_render); +void GPU_pbvh_update_attribute_names( + struct CustomData *vdata, + struct CustomData *ldata, + bool need_full_render, + bool fast_mode); // fast mode renders without vcol, uv, facesets, even mask, etc void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers, struct BMesh *bm, diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c index d6968dbc158..67e52b6c964 100644 --- a/source/blender/gpu/intern/gpu_buffers.c +++ b/source/blender/gpu/intern/gpu_buffers.c @@ -61,6 +61,8 @@ #include "bmesh.h" +//#define GPU_PERF_TEST // will disable vcol, uvs, mask, fset colors, etc + /* XXX: the rest of the code in this file is used for optimized PBVH * drawing and doesn't interact at all with the buffer code above */ @@ -116,6 +118,8 @@ struct GPU_PBVH_Buffers { * smooth-shaded or all faces are flat-shaded */ bool smooth; + void *last_tribuf_tris; // used to detect if we can reuse index buffers + bool show_overlay; #ifdef QUANTIZED_PERF_TEST float matrix[4][4]; @@ -157,6 +161,7 @@ static struct { bool active_vcol_only; bool need_full_render; + bool fast_mode; } g_vbo_id = {{0}}; #ifdef NEW_ATTR_SYSTEM @@ -355,7 +360,7 @@ static void free_cd_layers(CDAttrLayers *cdattr) void gpu_pbvh_init() { - GPU_pbvh_update_attribute_names(NULL, NULL, false); + GPU_pbvh_update_attribute_names(NULL, NULL, false, false); } void gpu_pbvh_exit() @@ -462,9 +467,11 @@ void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers, const MPropCol *vtcol, const int update_flags) { - const bool show_mask = vmask && (update_flags & GPU_PBVH_BUFFERS_SHOW_MASK) != 0; + const bool show_mask = vmask && (update_flags & GPU_PBVH_BUFFERS_SHOW_MASK) != 0 && + !g_vbo_id.fast_mode; const bool show_face_sets = sculpt_face_sets && - (update_flags & GPU_PBVH_BUFFERS_SHOW_SCULPT_FACE_SETS) != 0; + (update_flags & GPU_PBVH_BUFFERS_SHOW_SCULPT_FACE_SETS) != 0 && + !g_vbo_id.fast_mode; const bool show_vcol = (vcol || (vtcol && U.experimental.use_sculpt_vertex_colors)) && (update_flags & GPU_PBVH_BUFFERS_SHOW_VCOL) != 0; bool empty_mask = true; @@ -566,8 +573,11 @@ void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers, memcpy(GPU_vertbuf_raw_step(&col_step), scol, sizeof(scol)); } } - /* Face Sets. */ - memcpy(GPU_vertbuf_raw_step(&fset_step), face_set_color, sizeof(uchar[3])); + + if (!g_vbo_id.fast_mode) { + /* Face Sets. */ + memcpy(GPU_vertbuf_raw_step(&fset_step), face_set_color, sizeof(uchar[3])); + } } } } @@ -580,7 +590,7 @@ void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers, const MPoly *mp = &buffers->mpoly[lt->poly]; buffers->material_index = mp->mat_nr; - buffers->show_overlay = !empty_mask || !default_face_set; + buffers->show_overlay = (!empty_mask || !default_face_set) && !g_vbo_id.fast_mode; buffers->mvert = mvert; } @@ -601,7 +611,7 @@ GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const MPoly *mpoly, buffers = MEM_callocN(sizeof(GPU_PBVH_Buffers), "GPU_Buffers"); /* smooth or flat for all */ - buffers->smooth = mpoly[looptri[face_indices[0]].poly].flag & ME_SMOOTH; + buffers->smooth = (mpoly[looptri[face_indices[0]].poly].flag & ME_SMOOTH) || g_vbo_id.fast_mode; buffers->show_overlay = false; @@ -679,13 +689,13 @@ GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const MPoly *mpoly, /** \name Grid PBVH * \{ */ -static void gpu_pbvh_grid_fill_index_buffers(GPU_PBVH_Buffers *buffers, - SubdivCCG *UNUSED(subdiv_ccg), - const int *UNUSED(face_sets), - const int *grid_indices, - uint visible_quad_len, - int totgrid, - int gridsize) +ATTR_NO_OPT static void gpu_pbvh_grid_fill_index_buffers(GPU_PBVH_Buffers *buffers, + SubdivCCG *UNUSED(subdiv_ccg), + const int *UNUSED(face_sets), + const int *grid_indices, + uint visible_quad_len, + int totgrid, + int gridsize) { GPUIndexBufBuilder elb, elb_lines; GPUIndexBufBuilder elb_fast, elb_lines_fast; @@ -695,7 +705,7 @@ static void gpu_pbvh_grid_fill_index_buffers(GPU_PBVH_Buffers *buffers, GPU_indexbuf_init(&elb_lines, GPU_PRIM_LINES, 2 * totgrid * gridsize * (gridsize - 1), INT_MAX); GPU_indexbuf_init(&elb_lines_fast, GPU_PRIM_LINES, 4 * totgrid, INT_MAX); - if (buffers->smooth) { + if (buffers->smooth || g_vbo_id.fast_mode) { uint offset = 0; const uint grid_vert_len = gridsize * gridsize; for (int i = 0; i < totgrid; i++, offset += grid_vert_len) { @@ -815,7 +825,7 @@ void GPU_pbvh_grid_buffers_update_free(GPU_PBVH_Buffers *buffers, const struct DMFlagMat *grid_flag_mats, const int *grid_indices) { - const bool smooth = grid_flag_mats[grid_indices[0]].flag & ME_SMOOTH; + const bool smooth = (grid_flag_mats[grid_indices[0]].flag & ME_SMOOTH) || g_vbo_id.fast_mode; if (buffers->smooth != smooth) { buffers->smooth = smooth; @@ -832,22 +842,23 @@ void GPU_pbvh_grid_buffers_update_free(GPU_PBVH_Buffers *buffers, } /* Threaded - do not call any functions that use OpenGL calls! */ -void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers, - SubdivCCG *subdiv_ccg, - CCGElem **grids, - const struct DMFlagMat *grid_flag_mats, - int *grid_indices, - int totgrid, - const int *sculpt_face_sets, - const int face_sets_color_seed, - const int face_sets_color_default, - const struct CCGKey *key, - const int update_flags) +ATTR_NO_OPT void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers, + SubdivCCG *subdiv_ccg, + CCGElem **grids, + const struct DMFlagMat *grid_flag_mats, + int *grid_indices, + int totgrid, + const int *sculpt_face_sets, + const int face_sets_color_seed, + const int face_sets_color_default, + const struct CCGKey *key, + const int update_flags) { - const bool show_mask = (update_flags & GPU_PBVH_BUFFERS_SHOW_MASK) != 0; + const bool show_mask = (update_flags & GPU_PBVH_BUFFERS_SHOW_MASK) != 0 && !g_vbo_id.fast_mode; const bool show_vcol = (update_flags & GPU_PBVH_BUFFERS_SHOW_VCOL) != 0; const bool show_face_sets = sculpt_face_sets && - (update_flags & GPU_PBVH_BUFFERS_SHOW_SCULPT_FACE_SETS) != 0; + (update_flags & GPU_PBVH_BUFFERS_SHOW_SCULPT_FACE_SETS) != 0 && + !g_vbo_id.fast_mode; bool empty_mask = true; bool default_face_set = true; @@ -856,7 +867,13 @@ void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers, /* Build VBO */ const int has_mask = key->has_mask; - buffers->smooth = grid_flag_mats[grid_indices[0]].flag & ME_SMOOTH; + bool smooth = (grid_flag_mats[grid_indices[0]].flag & ME_SMOOTH) || g_vbo_id.fast_mode; + ; + if (smooth != buffers->smooth) { + GPU_pbvh_grid_buffers_update_free(buffers, grid_flag_mats, grid_indices); + } + + buffers->smooth = smooth; uint vert_per_grid = (buffers->smooth) ? key->grid_area : (square_i(key->grid_size - 1) * 4); uint vert_count = totgrid * vert_per_grid; @@ -906,7 +923,7 @@ void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers, } } - if (buffers->smooth) { + if (buffers->smooth || g_vbo_id.fast_mode) { for (y = 0; y < key->grid_size; y++) { for (x = 0; x < key->grid_size; x++) { CCGElem *elem = CCG_grid_elem(key, grid, x, y); @@ -929,7 +946,9 @@ void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers, GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.col[0], vbo_index, &vcol); } - GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.fset, vbo_index, &face_set_color); + if (!g_vbo_id.fast_mode) { + GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.fset, vbo_index, &face_set_color); + } vbo_index += 1; } @@ -980,15 +999,23 @@ void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers, } const ushort vcol[4] = {USHRT_MAX, USHRT_MAX, USHRT_MAX, USHRT_MAX}; - GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.col[0], vbo_index + 0, &vcol); - GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.col[0], vbo_index + 1, &vcol); - GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.col[0], vbo_index + 2, &vcol); - GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.col[0], vbo_index + 3, &vcol); + if (1) { // g_vbo_id.totcol > 0 || !g_vbo_id.fast_mode) { + GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.col[0], vbo_index + 0, &vcol); + GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.col[0], vbo_index + 1, &vcol); + GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.col[0], vbo_index + 2, &vcol); + GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.col[0], vbo_index + 3, &vcol); + } - GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.fset, vbo_index + 0, &face_set_color); - GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.fset, vbo_index + 1, &face_set_color); - GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.fset, vbo_index + 2, &face_set_color); - GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.fset, vbo_index + 3, &face_set_color); + if (!g_vbo_id.fast_mode) { + GPU_vertbuf_attr_set( + buffers->vert_buf, g_vbo_id.fset, vbo_index + 0, &face_set_color); + GPU_vertbuf_attr_set( + buffers->vert_buf, g_vbo_id.fset, vbo_index + 1, &face_set_color); + GPU_vertbuf_attr_set( + buffers->vert_buf, g_vbo_id.fset, vbo_index + 2, &face_set_color); + GPU_vertbuf_attr_set( + buffers->vert_buf, g_vbo_id.fset, vbo_index + 3, &face_set_color); + } vbo_index += 4; } @@ -1008,7 +1035,7 @@ void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers, buffers->totgrid = totgrid; buffers->grid_flag_mats = grid_flag_mats; buffers->gridkey = *key; - buffers->show_overlay = !empty_mask || !default_face_set; + buffers->show_overlay = (!empty_mask || !default_face_set) && !g_vbo_id.fast_mode; } /* Threaded - do not call any functions that use OpenGL calls! */ @@ -1061,9 +1088,11 @@ static void gpu_bmesh_vert_to_buffer_copy(BMVert *v, GPU_vertbuf_attr_set(vert_buf, g_vbo_id.pos, v_index, v->co); short no_short[3]; + normal_float_to_short_v3(no_short, fno ? fno : v->no); GPU_vertbuf_attr_set(vert_buf, g_vbo_id.nor, v_index, no_short); +#ifndef GPU_PERF_TEST if (show_mask) { float effective_mask = fmask ? *fmask : BM_ELEM_CD_GET_FLOAT(v, cd_vert_mask_offset); @@ -1078,7 +1107,7 @@ static void gpu_bmesh_vert_to_buffer_copy(BMVert *v, *empty_mask = *empty_mask && (cmask == 0); } -#ifndef NEW_ATTR_SYSTEM +# ifndef NEW_ATTR_SYSTEM if (show_vcol && totvcol > 0) { for (int i = 0; i < totvcol; i++) { ushort vcol[4] = {USHRT_MAX, USHRT_MAX, USHRT_MAX, USHRT_MAX}; @@ -1094,20 +1123,23 @@ static void gpu_bmesh_vert_to_buffer_copy(BMVert *v, GPU_vertbuf_attr_set(vert_buf, g_vbo_id.col[i], v_index, vcol); } } - else if (show_vcol) { // ensure first vcol attribute is not zero + else if (show_vcol && !g_vbo_id.fast_mode) { // ensure first vcol attribute is not zero const ushort vcol[4] = {USHRT_MAX, USHRT_MAX, USHRT_MAX, USHRT_MAX}; GPU_vertbuf_attr_set(vert_buf, g_vbo_id.col[0], v_index, vcol); } -#else +# else if (show_vcol && totvcol == 0) { // ensure first vcol attribute is not zero const ushort vcol[4] = {USHRT_MAX, USHRT_MAX, USHRT_MAX, USHRT_MAX}; GPU_vertbuf_attr_set(vert_buf, g_vbo_id.col[0], v_index, vcol); } -#endif +# endif - /* Add default face sets color to avoid artifacts. */ - const uchar face_set[3] = {UCHAR_MAX, UCHAR_MAX, UCHAR_MAX}; - GPU_vertbuf_attr_set(vert_buf, g_vbo_id.fset, v_index, &face_set); + if (!g_vbo_id.fast_mode) { + /* Add default face sets color to avoid artifacts. */ + const uchar face_set[3] = {UCHAR_MAX, UCHAR_MAX, UCHAR_MAX}; + GPU_vertbuf_attr_set(vert_buf, g_vbo_id.fset, v_index, &face_set); + } +#endif } /* Return the total number of vertices that don't have BM_ELEM_HIDDEN set */ @@ -1151,17 +1183,13 @@ static int gpu_bmesh_face_visible_count(TableGSet *bm_faces, int mat_nr) void GPU_pbvh_bmesh_buffers_update_free(GPU_PBVH_Buffers *buffers) { - if (buffers->smooth) { - /* Smooth needs to recreate index buffer, so we have to invalidate the batch. */ - GPU_BATCH_DISCARD_SAFE(buffers->triangles); - GPU_BATCH_DISCARD_SAFE(buffers->lines); - GPU_INDEXBUF_DISCARD_SAFE(buffers->index_lines_buf); - GPU_INDEXBUF_DISCARD_SAFE(buffers->index_buf); - } - else { - GPU_BATCH_DISCARD_SAFE(buffers->lines); - GPU_INDEXBUF_DISCARD_SAFE(buffers->index_lines_buf); + if (buffers->last_tribuf_tris) { + // bmesh indexed drawing frees buffers by itself + return; } + + GPU_BATCH_DISCARD_SAFE(buffers->lines); + GPU_INDEXBUF_DISCARD_SAFE(buffers->index_lines_buf); } static int gpu_pbvh_bmesh_make_vcol_offs(CustomData *vdata, @@ -1232,12 +1260,17 @@ bool GPU_pbvh_need_full_render_get() return g_vbo_id.need_full_render; } -void GPU_pbvh_update_attribute_names(CustomData *vdata, CustomData *ldata, bool need_full_render) +void GPU_pbvh_update_attribute_names(CustomData *vdata, + CustomData *ldata, + bool need_full_render, + bool fast_mode) { const bool active_only = !need_full_render; GPU_vertformat_clear(&g_vbo_id.format); + g_vbo_id.fast_mode = fast_mode; + // g_vbo_id.loop_attrs = build_cd_layers(vdata, ) /* Initialize vertex buffer (match 'VertexBufferFormat'). */ if (g_vbo_id.format.attr_len == 0) { @@ -1259,8 +1292,12 @@ void GPU_pbvh_update_attribute_names(CustomData *vdata, CustomData *ldata, bool return; #endif - g_vbo_id.msk = GPU_vertformat_attr_add( - &g_vbo_id.format, "msk", GPU_COMP_U8, 1, GPU_FETCH_INT_TO_FLOAT_UNIT); +#ifndef GPU_PERF_TEST + if (!fast_mode) { + g_vbo_id.msk = GPU_vertformat_attr_add( + &g_vbo_id.format, "msk", GPU_COMP_U8, 1, GPU_FETCH_INT_TO_FLOAT_UNIT); + } +#endif g_vbo_id.totcol = 0; @@ -1302,7 +1339,7 @@ void GPU_pbvh_update_attribute_names(CustomData *vdata, CustomData *ldata, bool g_vbo_id.loop_attrs_len = BLI_array_len(lattr); #endif -#ifndef NEW_ATTR_SYSTEM +#if !defined(NEW_ATTR_SYSTEM) && !defined(GPU_PERF_TEST) if (vdata && CustomData_has_layer(vdata, CD_PROP_COLOR)) { const int act = CustomData_get_active_layer_index(vdata, CD_PROP_COLOR); int ci = 0; @@ -1331,14 +1368,14 @@ void GPU_pbvh_update_attribute_names(CustomData *vdata, CustomData *ldata, bool } // ensure at least one vertex color layer - if (g_vbo_id.totcol == 0) { + if (!fast_mode && g_vbo_id.totcol == 0) { g_vbo_id.col[0] = GPU_vertformat_attr_add( &g_vbo_id.format, "c", GPU_COMP_U16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); g_vbo_id.totcol = 1; GPU_vertformat_alias_add(&g_vbo_id.format, "ac"); } -#else +#elif !defined(GPU_PERF_TEST) // ensure at least one vertex color layer if (!vdata || !CustomData_has_layer(vdata, CD_PROP_COLOR)) { g_vbo_id.col[0] = GPU_vertformat_attr_add( @@ -1349,20 +1386,25 @@ void GPU_pbvh_update_attribute_names(CustomData *vdata, CustomData *ldata, bool } #endif - g_vbo_id.fset = GPU_vertformat_attr_add( - &g_vbo_id.format, "fset", GPU_COMP_U8, 3, GPU_FETCH_INT_TO_FLOAT_UNIT); - g_vbo_id.uv = GPU_vertformat_attr_add( - &g_vbo_id.format, "uvs", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - GPU_vertformat_alias_add(&g_vbo_id.format, "u"); +#ifndef GPU_PERF_TEST + if (!fast_mode) { + g_vbo_id.fset = GPU_vertformat_attr_add( + &g_vbo_id.format, "fset", GPU_COMP_U8, 3, GPU_FETCH_INT_TO_FLOAT_UNIT); + } if (ldata && CustomData_has_layer(ldata, CD_MLOOPUV)) { + g_vbo_id.uv = GPU_vertformat_attr_add( + &g_vbo_id.format, "uvs", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + GPU_vertformat_alias_add(&g_vbo_id.format, "u"); + const int cd_uv_index = CustomData_get_layer_index(ldata, CD_MLOOPUV); CustomDataLayer *cl = ldata->layers + cd_uv_index; cl += cl->active; DRW_make_cdlayer_attr_aliases(&g_vbo_id.format, "u", ldata, cl); } +#endif } } @@ -1568,29 +1610,37 @@ static void GPU_pbvh_bmesh_buffers_update_flat_vcol(GPU_PBVH_Buffers *buffers, /* Get material index from the last face we iterated on. */ buffers->material_index = mat_nr; - buffers->show_overlay = !empty_mask || !default_face_set; + buffers->show_overlay = (!empty_mask || !default_face_set) && !g_vbo_id.fast_mode; gpu_pbvh_batch_init(buffers, GPU_PRIM_TRIS); } -static void GPU_pbvh_bmesh_buffers_update_indexed(GPU_PBVH_Buffers *buffers, - BMesh *bm, - TableGSet *bm_faces, - TableGSet *bm_unique_verts, - TableGSet *bm_other_verts, - PBVHTriBuf *tribuf, - const int update_flags, - const int cd_vert_node_offset, - int face_sets_color_seed, - int face_sets_color_default, - bool flat_vcol, - short mat_nr) +ATTR_NO_OPT static void GPU_pbvh_bmesh_buffers_update_indexed(GPU_PBVH_Buffers *buffers, + BMesh *bm, + TableGSet *bm_faces, + TableGSet *bm_unique_verts, + TableGSet *bm_other_verts, + PBVHTriBuf *tribuf, + const int update_flags, + const int cd_vert_node_offset, + int face_sets_color_seed, + int face_sets_color_default, + bool flat_vcol, + short mat_nr) { bool active_vcol_only = g_vbo_id.active_vcol_only; - const bool show_mask = (update_flags & GPU_PBVH_BUFFERS_SHOW_MASK) != 0; - const bool show_vcol = (update_flags & GPU_PBVH_BUFFERS_SHOW_VCOL) != 0; + const bool show_mask = (update_flags & GPU_PBVH_BUFFERS_SHOW_MASK) != 0 && !g_vbo_id.fast_mode; + bool show_vcol = (update_flags & GPU_PBVH_BUFFERS_SHOW_VCOL) != 0; + + if (g_vbo_id.totcol == 0 && g_vbo_id.fast_mode) { + show_vcol = false; + } + + bool need_indexed = buffers->last_tribuf_tris != tribuf->tris; + + buffers->last_tribuf_tris = tribuf->tris; int tottri, totvert; bool empty_mask = true; @@ -1629,11 +1679,6 @@ static void GPU_pbvh_bmesh_buffers_update_indexed(GPU_PBVH_Buffers *buffers, return; } - /* Fill the vertex and triangle buffer in one pass over faces. */ - GPUIndexBufBuilder elb, elb_lines; - GPU_indexbuf_init(&elb, GPU_PRIM_TRIS, tottri, totvert); - GPU_indexbuf_init(&elb_lines, GPU_PRIM_LINES, tottri * 3, totvert); - #ifdef QUANTIZED_PERF_TEST GPUVertBuf *vert_buf = buffers->vert_buf; @@ -1712,6 +1757,24 @@ static void GPU_pbvh_bmesh_buffers_update_indexed(GPU_PBVH_Buffers *buffers, #endif } + if (!need_indexed) { + buffers->material_index = mat_nr; + buffers->show_overlay = (!empty_mask || !default_face_set) && !g_vbo_id.fast_mode; + + gpu_pbvh_batch_init(buffers, GPU_PRIM_TRIS); + return; + } + + GPU_BATCH_DISCARD_SAFE(buffers->triangles); + GPU_BATCH_DISCARD_SAFE(buffers->lines); + GPU_INDEXBUF_DISCARD_SAFE(buffers->index_lines_buf); + GPU_INDEXBUF_DISCARD_SAFE(buffers->index_buf); + + /* Fill the vertex and triangle buffer in one pass over faces. */ + GPUIndexBufBuilder elb, elb_lines; + GPU_indexbuf_init(&elb, GPU_PRIM_TRIS, tottri, totvert); + GPU_indexbuf_init(&elb_lines, GPU_PRIM_LINES, tottri * 3, totvert); + for (int i = 0; i < tribuf->tottri; i++) { PBVHTri *tri = tribuf->tris + i; @@ -1735,7 +1798,7 @@ static void GPU_pbvh_bmesh_buffers_update_indexed(GPU_PBVH_Buffers *buffers, buffers->index_lines_buf = GPU_indexbuf_build(&elb_lines); buffers->material_index = mat_nr; - buffers->show_overlay = !empty_mask || !default_face_set; + buffers->show_overlay = (!empty_mask || !default_face_set) && !g_vbo_id.fast_mode; gpu_pbvh_batch_init(buffers, GPU_PRIM_TRIS); @@ -1779,9 +1842,10 @@ void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers, } const bool have_uv = CustomData_has_layer(&bm->ldata, CD_MLOOPUV); - const bool show_mask = (update_flags & GPU_PBVH_BUFFERS_SHOW_MASK) != 0; + const bool show_mask = (update_flags & GPU_PBVH_BUFFERS_SHOW_MASK) != 0 && !g_vbo_id.fast_mode; const bool show_face_sets = CustomData_has_layer(&bm->pdata, CD_SCULPT_FACE_SETS) && - (update_flags & GPU_PBVH_BUFFERS_SHOW_SCULPT_FACE_SETS) != 0; + (update_flags & GPU_PBVH_BUFFERS_SHOW_SCULPT_FACE_SETS) != 0 && + !g_vbo_id.fast_mode; int tottri, totvert; bool empty_mask = true; @@ -1810,6 +1874,8 @@ void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers, return; } + buffers->last_tribuf_tris = NULL; + /* TODO, make mask layer optional for bmesh buffer */ const int cd_vert_mask_offset = CustomData_get_offset(&bm->vdata, CD_PAINT_MASK); const int cd_mcol_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPCOL); @@ -1903,7 +1969,7 @@ void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers, &empty_mask, NULL, 0); - +# ifndef GPU_PERF_TEST if (cd_vcol_count >= 0) { for (int k = 0; k < cd_vcol_count; k++) { MPropCol *mp = BM_ELEM_CD_GET_VOID_P(l[j]->v, cd_vcols[k]); @@ -1938,8 +2004,10 @@ void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers, GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.uv, v_index, mu->uv); } - GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.fset, v_index, face_set_color); - + if (show_face_sets) { + GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.fset, v_index, face_set_color); + } +# endif v_index++; } } @@ -2068,7 +2136,7 @@ void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers, /* Get material index from the last face we iterated on. */ buffers->material_index = mat_nr; - buffers->show_overlay = !empty_mask || !default_face_set; + buffers->show_overlay = (!empty_mask || !default_face_set) && !g_vbo_id.fast_mode; gpu_pbvh_batch_init(buffers, GPU_PRIM_TRIS); } @@ -2084,8 +2152,8 @@ GPU_PBVH_Buffers *GPU_pbvh_bmesh_buffers_build(bool smooth_shading) buffers = MEM_callocN(sizeof(GPU_PBVH_Buffers), "GPU_Buffers"); buffers->use_bmesh = true; - buffers->smooth = smooth_shading; - buffers->show_overlay = true; + buffers->smooth = smooth_shading || g_vbo_id.fast_mode; + buffers->show_overlay = (!g_vbo_id.fast_mode) && !g_vbo_id.fast_mode; return buffers; } @@ -2101,7 +2169,7 @@ GPUBatch *GPU_pbvh_buffers_batch_get(GPU_PBVH_Buffers *buffers, bool fast, bool bool GPU_pbvh_buffers_has_overlays(GPU_PBVH_Buffers *buffers) { - return buffers->show_overlay; + return buffers->show_overlay && !g_vbo_id.fast_mode; } short GPU_pbvh_buffers_material_index_get(GPU_PBVH_Buffers *buffers) diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index 05a40f46977..3f3bc876126 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -484,7 +484,7 @@ typedef struct ImageFormatData { #define R_IMF_IMTYPE_INVALID 255 /** #ImageFormatData.flag */ -#define R_IMF_FLAG_ZBUF (1 << 0) /* was R_OPENEXR_ZBUF */ +#define R_IMF_FLAG_ZBUF (1 << 0) /* was R_OPENEXR_ZBUF */ #define R_IMF_FLAG_PREVIEW_JPG (1 << 1) /* was R_PREVIEW_JPG */ /* Return values from #BKE_imtype_valid_depths, note this is depths per channel. */ @@ -526,8 +526,8 @@ typedef enum eImageFormatDepth { /** #ImageFormatData.jp2_flag */ #define R_IMF_JP2_FLAG_YCC (1 << 0) /* when disabled use RGB */ /* was R_JPEG2K_YCC */ -#define R_IMF_JP2_FLAG_CINE_PRESET (1 << 1) /* was R_JPEG2K_CINE_PRESET */ -#define R_IMF_JP2_FLAG_CINE_48 (1 << 2) /* was R_JPEG2K_CINE_48FPS */ +#define R_IMF_JP2_FLAG_CINE_PRESET (1 << 1) /* was R_JPEG2K_CINE_PRESET */ +#define R_IMF_JP2_FLAG_CINE_48 (1 << 2) /* was R_JPEG2K_CINE_48FPS */ /** #ImageFormatData.jp2_codec */ #define R_IMF_JP2_CODEC_JP2 0 @@ -1842,12 +1842,12 @@ typedef struct Scene { #define R_MODE_UNUSED_20 (1 << 20) /* cleared */ #define R_MODE_UNUSED_21 (1 << 21) /* cleared */ -#define R_NO_OVERWRITE (1 << 22) /* skip existing files */ -#define R_TOUCH (1 << 23) /* touch files before rendering */ +#define R_NO_OVERWRITE (1 << 22) /* skip existing files */ +#define R_TOUCH (1 << 23) /* touch files before rendering */ #define R_SIMPLIFY (1 << 24) -#define R_EDGE_FRS (1 << 25) /* R_EDGE reserved for Freestyle */ +#define R_EDGE_FRS (1 << 25) /* R_EDGE reserved for Freestyle */ #define R_PERSISTENT_DATA (1 << 26) /* keep data around for re-render */ -#define R_MODE_UNUSED_27 (1 << 27) /* cleared */ +#define R_MODE_UNUSED_27 (1 << 27) /* cleared */ /** #RenderData.seq_flag */ enum { @@ -2237,8 +2237,11 @@ typedef enum eSculptFlags { /* Don't display face sets in viewport. */ SCULPT_HIDE_FACE_SETS = (1 << 17), - SCULPT_DYNTOPO_FLAT_VCOL_SHADING = (1<<18), + SCULPT_DYNTOPO_FLAT_VCOL_SHADING = (1 << 18), SCULPT_DYNTOPO_CLEANUP = (1 << 19), + + // hides facesets/masks and forces indexed mode to save GPU bandwidth + SCULPT_FAST_DRAW = (1 << 20), } eSculptFlags; /** #ImagePaintSettings.mode */ diff --git a/source/blender/makesrna/intern/rna_sculpt_paint.c b/source/blender/makesrna/intern/rna_sculpt_paint.c index 579dcf6aeb8..3d5e5ed8896 100644 --- a/source/blender/makesrna/intern/rna_sculpt_paint.c +++ b/source/blender/makesrna/intern/rna_sculpt_paint.c @@ -382,6 +382,7 @@ static void rna_Sculpt_update(bContext *C, PointerRNA *UNUSED(ptr)) ob->sculpt->bm_smooth_shading = ((scene->toolsettings->sculpt->flags & SCULPT_DYNTOPO_SMOOTH_SHADING) != 0); + ob->sculpt->fast_draw = ((scene->toolsettings->sculpt->flags & SCULPT_FAST_DRAW) != 0); } DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); @@ -831,6 +832,17 @@ static void rna_def_sculpt(BlenderRNA *brna) RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Sculpt_update"); + prop = RNA_def_property(srna, "use_fast_draw", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flags", SCULPT_FAST_DRAW); + RNA_def_property_ui_text(prop, + "Fast Draw Mode", + "Forces smooth shading" + "and disables drawing of masks and face sets" + "to speed up drawing. Useful for posing" + "high-poly meshes."); + RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); + RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Sculpt_update"); + prop = RNA_def_property(srna, "use_dyntopo_cleanup", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flags", SCULPT_DYNTOPO_CLEANUP); RNA_def_property_ui_text(prop, "Cleanup", "Removes verts surrounded by only 3 or 4 edges"); -- cgit v1.2.3