diff --git a/release/scripts/startup/bl_ui/properties_paint_common.py b/release/scripts/startup/bl_ui/properties_paint_common.py index 8025b17cbed..51356824491 100644 --- a/release/scripts/startup/bl_ui/properties_paint_common.py +++ b/release/scripts/startup/bl_ui/properties_paint_common.py @@ -125,8 +125,9 @@ class UnifiedPaintPanel: row = layout.row(align=True) - typeprop = "float_value" + if ch.type == "FLOAT": + typeprop = "float_value" if "spacing" in ch.idname else "factor_value" if ch.type == "INT": typeprop = "int_value" elif ch.type == "BOOL": @@ -139,7 +140,7 @@ class UnifiedPaintPanel: typeprop = "color3_value" elif ch.type == "VEC4": typeprop = "color4_value" - + if text is None: s = prop_name.lower().replace("_", " ").split(" "); text = '' @@ -191,14 +192,14 @@ class UnifiedPaintPanel: #if unified_name and not header: # # NOTE: We don't draw UnifiedPaintSettings in the header to reduce clutter. D5928#136281 # row.prop(ups, unified_name, text="", icon='BRUSHES_ALL') - if not header and ch.type != "BOOL": + if not header: # and ch.type != "BOOL": if ch.type == "BITMASK" and not toolsettings_only and ch == finalch: row.prop(ch, "inherit_if_unset", text="Combine With Defaults") if not toolsettings_only: row.prop(ch, "inherit", text="", icon='BRUSHES_ALL') - if ch.type == "BITMASK": + if ch.type == "BITMASK" or ch.type == "BOOL": return row.prop(ch, "ui_expanded", text="", icon="TRIA_DOWN" if ch.ui_expanded else "TRIA_RIGHT") @@ -806,7 +807,16 @@ def brush_settings(layout, context, brush, popover=False): box.prop(brush, "ignore_falloff_for_topology_rake") if context.sculpt_object.use_dynamic_topology_sculpting: - layout.prop(brush.dyntopo, "disabled", text="Disable Dyntopo") + UnifiedPaintPanel.channel_unified( + layout, + context, + brush, + "dyntopo_disabled", + #text="Weight By Face Area", + slider=True, + header=True + ) + #layout.prop(brush.dyntopo, "disabled", text="Disable Dyntopo") # normal_weight if capabilities.has_normal_weight: @@ -1018,7 +1028,16 @@ def brush_settings(layout, context, brush, popover=False): col = layout.column() col.prop(brush, "boundary_smooth_factor") - col.prop(brush, "use_weighted_smooth") + UnifiedPaintPanel.channel_unified( + layout, + context, + brush, + "use_weighted_smooth", + #text="Weight By Face Area", + slider=True, + ) + + #col.prop(brush, "use_weighted_smooth") col.prop(brush, "preserve_faceset_boundary") if brush.preserve_faceset_boundary: col.prop(brush, "autosmooth_fset_slide") diff --git a/source/blender/blenkernel/intern/dyntopo.c b/source/blender/blenkernel/intern/dyntopo.c index 51757540ba3..af07f0ace81 100644 --- a/source/blender/blenkernel/intern/dyntopo.c +++ b/source/blender/blenkernel/intern/dyntopo.c @@ -1628,6 +1628,7 @@ typedef struct EdgeQueueThreadData { int totedge; int size; bool is_collapse; + int seed; } EdgeQueueThreadData; static void edge_thread_data_insert(EdgeQueueThreadData *tdata, BMEdge *e) @@ -1962,6 +1963,16 @@ static void long_edge_queue_edge_add_recursive_2(EdgeQueueThreadData *tdata, static int _long_edge_queue_task_cb_seed = 0; +BLI_INLINE int dyntopo_thread_rand(int seed) +{ + // glibc + const uint32_t multiplier = 1103515245; + const uint32_t addend = 12345; + const uint32_t mask = (1 << 31) - 1; + + return (seed * multiplier + addend) & mask; +} + static void long_edge_queue_task_cb(void *__restrict userdata, const int n, const TaskParallelTLS *__restrict tls) @@ -1973,18 +1984,43 @@ static void long_edge_queue_task_cb(void *__restrict userdata, BMVert **val34 = NULL; BLI_array_declare(val34); - BMFace *f; + int seed = tdata->seed + n; + + BMFace *f, **faces = NULL; + BLI_array_declare(faces); const int cd_dyn_vert = tdata->pbvh->cd_dyn_vert; +#if 1 +# if 0 + // try to be nice to branch predictor + int off = (seed = dyntopo_thread_rand(seed)); + int stepi = off & 65535; +# endif + /* + we care more about convergence to accurate results + then accuracy in any individual runs. profiling + has shown this loop overwhelms the L3 cache, + so randomly skip bits of it. + */ TGSET_ITER (f, node->bm_faces) { BMLoop *l = f->l_first; +# if 0 + if ((stepi++) & 3) { + continue; + } +# else + if ((seed = dyntopo_thread_rand(seed)) & 3) { + continue; + } +# endif do { l->e->head.hflag &= ~BM_ELEM_TAG; l = l->next; } while (l != f->l_first); } TGSET_ITER_END +#endif TGSET_ITER (f, node->bm_faces) { #ifdef USE_EDGEQUEUE_FRONTFACE @@ -2014,7 +2050,9 @@ static void long_edge_queue_task_cb(void *__restrict userdata, // try to improve convergence by applying a small amount of smoothing to topology, // but tangentially to surface. - if (BLI_rng_get_float(rng) > 0.5) { + int randval = (seed = dyntopo_thread_rand(seed)) & 255; + + if (randval > 127) { surface_smooth_v_safe(tdata->pbvh, l_iter->v, eq_ctx->surface_smooth_fac); } @@ -2040,6 +2078,7 @@ static void long_edge_queue_task_cb(void *__restrict userdata, TGSET_ITER_END BLI_rng_free(rng); + BLI_array_free(faces); tdata->val34_verts = val34; tdata->val34_verts_tot = BLI_array_len(val34); @@ -2055,15 +2094,23 @@ static void short_edge_queue_task_cb(void *__restrict userdata, BMFace *f; + int seed = tdata->seed + n; + + // see comment in similar loop in long_edge_queue_task_cb TGSET_ITER (f, node->bm_faces) { +#if 0 + if ((stepi++) & 3) { + continue; + } +#else + if ((seed = dyntopo_thread_rand(seed)) & 3) { + continue; + } +#endif + BMLoop *l = f->l_first; do { - if (!l->e) { - printf("bmesh error! %s\n", __func__); - continue; - } - l->e->head.hflag &= ~BM_ELEM_TAG; l = l->next; } while (l != f->l_first); @@ -2562,30 +2609,41 @@ static void long_edge_queue_create(EdgeQueueContext *eq_ctx, EdgeQueueThreadData *tdata = NULL; BLI_array_declare(tdata); + int totleaf = 0; + for (int n = 0; n < pbvh->totnode; n++) { PBVHNode *node = &pbvh->nodes[n]; - /* Check leaf nodes marked for topology update */ - if ((node->flag & PBVH_Leaf) && (node->flag & PBVH_UpdateTopology) && - !(node->flag & PBVH_FullyHidden)) { - EdgeQueueThreadData td; - - memset(&td, 0, sizeof(td)); - - td.pbvh = pbvh; - td.node = node; - td.eq_ctx = eq_ctx; - - BLI_array_append(tdata, td); - /* Check each face */ - /* - BMFace *f; - TGSET_ITER (f, node->bm_faces) { - long_edge_queue_face_add(eq_ctx, f); - } - TGSET_ITER_END - */ + if (node->flag & PBVH_Leaf) { + totleaf++; } + + /* Check leaf nodes marked for topology update */ + bool ok = ((node->flag & PBVH_Leaf) && (node->flag & PBVH_UpdateTopology) && + !(node->flag & PBVH_FullyHidden)); + + if (!ok) { + continue; + } + + EdgeQueueThreadData td; + + memset(&td, 0, sizeof(td)); + + td.seed = BLI_thread_rand(0); + td.pbvh = pbvh; + td.node = node; + td.eq_ctx = eq_ctx; + + BLI_array_append(tdata, td); + /* Check each face */ + /* + BMFace *f; + TGSET_ITER (f, node->bm_faces) { + long_edge_queue_face_add(eq_ctx, f); + } + TGSET_ITER_END + */ } int count = BLI_array_len(tdata); @@ -2953,9 +3011,11 @@ static void short_edge_queue_create(EdgeQueueContext *eq_ctx, if ((node->flag & PBVH_Leaf) && (node->flag & PBVH_UpdateTopology) && !(node->flag & PBVH_FullyHidden)) { memset(&td, 0, sizeof(td)); + td.pbvh = pbvh; td.node = node; td.eq_ctx = eq_ctx; + td.seed = BLI_thread_rand(0); BLI_array_append(tdata, td); } diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index 5feca19a698..df3afa42257 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -1158,22 +1158,35 @@ bool SCULPT_vertex_has_face_set(SculptSession *ss, SculptVertRef index, int face return false; } case PBVH_BMESH: { - BMIter iter; - BMLoop *l; + BMEdge *e; BMVert *v = (BMVert *)index.i; if (ss->cd_faceset_offset == -1) { return false; } - BM_ITER_ELEM (l, &iter, v, BM_LOOPS_OF_VERT) { - BMFace *f = l->f; + e = v->e; - if (abs(BM_ELEM_CD_GET_INT(f, ss->cd_faceset_offset)) == abs(face_set)) { - return true; - } + if (UNLIKELY(!e)) { + return false; } + do { + BMLoop *l = e->l; + + if (UNLIKELY(!l)) { + continue; + } + + do { + BMFace *f = l->f; + + if (abs(BM_ELEM_CD_GET_INT(f, ss->cd_faceset_offset)) == abs(face_set)) { + return true; + } + } while ((l = l->radial_next) != e->l); + } while ((e = BM_DISK_EDGE_NEXT(e, v)) != v->e); + return false; } case PBVH_GRIDS: { @@ -9321,7 +9334,8 @@ ATTR_NO_OPT static void SCULPT_run_command_list( break; case SCULPT_TOOL_DYNTOPO: if (has_dyntopo) { - do_symmetrical_brush_actions(sd, ob, sculpt_topology_update, ups); + sculpt_topology_update(sd, ob, brush, ups); + // do_symmetrical_brush_actions(sd, ob, sculpt_topology_update, ups); } break; } diff --git a/source/blender/editors/sculpt_paint/sculpt_automasking.c b/source/blender/editors/sculpt_paint/sculpt_automasking.c index 7167dd93f45..103787c76d0 100644 --- a/source/blender/editors/sculpt_paint/sculpt_automasking.c +++ b/source/blender/editors/sculpt_paint/sculpt_automasking.c @@ -193,7 +193,7 @@ float SCULPT_automasking_factor_get(AutomaskingCache *automasking, } if (automasking->settings.flags & BRUSH_AUTOMASKING_BOUNDARY_FACE_SETS) { - if (!SCULPT_vertex_has_unique_face_set(ss, vert)) { + if (SCULPT_vertex_is_boundary(ss, vert, SCULPT_BOUNDARY_FACE_SET)) { return 0.0f; } }