Sculpt: Avoid expensive mask access in remaining cases

In the last couple places, avoid retrieving the mask attribute per
vertex. Use existing attribute data pointers instead. This also avoids
function calls and branches for every vertex, since there is no PBVH
type switch at the lowest level of the loop anymore.
This commit is contained in:
Hans Goudey 2023-12-28 16:36:11 -05:00
parent 27582ddb93
commit bd51bb7623
6 changed files with 89 additions and 70 deletions

View File

@ -372,14 +372,11 @@ static void fill_mask_bmesh(Object &object, const float value, const Span<PBVHNo
});
}
static void fill_mask(Main &bmain,
const Scene &scene,
Depsgraph &depsgraph,
Object &object,
const float value,
const Span<PBVHNode *> nodes)
static void fill_mask(
Main &bmain, const Scene &scene, Depsgraph &depsgraph, Object &object, const float value)
{
PBVH &pbvh = *object.sculpt->pbvh;
Vector<PBVHNode *> nodes = bke::pbvh::search_gather(&pbvh, {});
switch (BKE_pbvh_type(&pbvh)) {
case PBVH_FACES:
fill_mask_mesh(object, value, nodes);
@ -489,12 +486,9 @@ static void invert_mask_bmesh(Object &object, const Span<PBVHNode *> nodes)
});
}
static void invert_mask(Main &bmain,
const Scene &scene,
Depsgraph &depsgraph,
Object &object,
const Span<PBVHNode *> nodes)
static void invert_mask(Main &bmain, const Scene &scene, Depsgraph &depsgraph, Object &object)
{
Vector<PBVHNode *> nodes = bke::pbvh::search_gather(object.sculpt->pbvh, {});
switch (BKE_pbvh_type(object.sculpt->pbvh)) {
case PBVH_FACES:
invert_mask_mesh(object, nodes);
@ -521,16 +515,15 @@ static int mask_flood_fill_exec(bContext *C, wmOperator *op)
BKE_sculpt_update_object_for_edit(&depsgraph, &object, false);
undo::push_begin(&object, op);
Vector<PBVHNode *> nodes = bke::pbvh::search_gather(object.sculpt->pbvh, {});
switch (mode) {
case PAINT_MASK_FLOOD_VALUE:
fill_mask(bmain, scene, depsgraph, object, value, nodes);
fill_mask(bmain, scene, depsgraph, object, value);
break;
case PAINT_MASK_FLOOD_VALUE_INVERSE:
fill_mask(bmain, scene, depsgraph, object, 1.0f - value, nodes);
fill_mask(bmain, scene, depsgraph, object, 1.0f - value);
break;
case PAINT_MASK_INVERT:
invert_mask(bmain, scene, depsgraph, object, nodes);
invert_mask(bmain, scene, depsgraph, object);
break;
}

View File

@ -303,33 +303,6 @@ float SCULPT_mask_get_at_grids_vert_index(const SubdivCCG &subdiv_ccg,
return *CCG_elem_offset_mask(&key, elem, index_in_grid);
}
float SCULPT_vertex_mask_get(SculptSession *ss, PBVHVertRef vertex)
{
using namespace blender;
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES: {
const Mesh *mesh = BKE_pbvh_get_mesh(ss->pbvh);
const bke::AttributeAccessor attributes = mesh->attributes();
const VArray mask = *attributes.lookup_or_default<float>(
".sculpt_mask", bke::AttrDomain::Point, 0.0f);
return mask[vertex.i];
}
case PBVH_BMESH: {
BMVert *v;
int cd_mask = CustomData_get_offset_named(&ss->bm->vdata, CD_PROP_FLOAT, ".sculpt_mask");
v = (BMVert *)vertex.i;
return cd_mask != -1 ? BM_ELEM_CD_GET_FLOAT(v, cd_mask) : 0.0f;
}
case PBVH_GRIDS: {
return SCULPT_mask_get_at_grids_vert_index(
*ss->subdiv_ccg, *BKE_pbvh_get_grid_key(ss->pbvh), vertex.i);
}
}
return 0.0f;
}
PBVHVertRef SCULPT_active_vertex_get(SculptSession *ss)
{
if (ELEM(BKE_pbvh_type(ss->pbvh), PBVH_FACES, PBVH_BMESH, PBVH_GRIDS)) {

View File

@ -2105,6 +2105,54 @@ static void sculpt_expand_undo_push(Object *ob, Cache *expand_cache)
}
}
static bool any_nonzero_mask(const Object &object)
{
const SculptSession &ss = *object.sculpt;
switch (BKE_pbvh_type(ss.pbvh)) {
case PBVH_FACES: {
const Mesh &mesh = *static_cast<const Mesh *>(object.data);
const bke::AttributeAccessor attributes = mesh.attributes();
const VArraySpan mask = *attributes.lookup<float>(".sculpt_mask");
if (mask.is_empty()) {
return false;
}
return std::any_of(
mask.begin(), mask.end(), [&](const float value) { return value > 0.0f; });
}
case PBVH_GRIDS: {
const SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
if (!key.has_mask) {
return false;
}
return std::any_of(subdiv_ccg.grids.begin(), subdiv_ccg.grids.end(), [&](CCGElem *elem) {
for (const int i : IndexRange(key.grid_area)) {
if (*CCG_elem_offset_mask(&key, elem, i) > 0.0f) {
return true;
}
}
return false;
});
}
case PBVH_BMESH: {
BMesh &bm = *ss.bm;
const int offset = CustomData_get_offset_named(&bm.vdata, CD_PROP_FLOAT, ".sculpt_mask");
if (offset == -1) {
return false;
}
BMIter iter;
BMVert *vert;
BM_ITER_MESH (vert, &iter, &bm, BM_VERTS_OF_MESH) {
if (BM_ELEM_CD_GET_FLOAT(vert, offset) > 0.0f) {
return true;
}
}
return false;
}
}
return false;
}
static int sculpt_expand_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
@ -2134,19 +2182,7 @@ static int sculpt_expand_invoke(bContext *C, wmOperator *op, const wmEvent *even
BKE_sculpt_mask_layers_ensure(depsgraph, CTX_data_main(C), ob, mmd);
if (RNA_boolean_get(op->ptr, "use_auto_mask")) {
int verts_num = SCULPT_vertex_count_get(ss);
bool ok = true;
for (int i = 0; i < verts_num; i++) {
PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i);
if (SCULPT_vertex_mask_get(ss, vertex) != 0.0f) {
ok = false;
break;
}
}
if (ok) {
if (any_nonzero_mask(*ob)) {
write_mask_data(ss, Array<float>(SCULPT_vertex_count_get(ss), 1.0f));
}
}

View File

@ -91,7 +91,7 @@ static void mask_filter_task(SculptSession *ss,
switch (mode) {
case MASK_FILTER_SMOOTH:
case MASK_FILTER_SHARPEN: {
float val = smooth::neighbor_mask_average(ss, vd.vertex);
float val = smooth::neighbor_mask_average(ss, mask_write, vd.vertex);
val -= mask;

View File

@ -877,7 +877,6 @@ void SCULPT_vertex_normal_get(const SculptSession *ss, PBVHVertRef vertex, float
float SCULPT_mask_get_at_grids_vert_index(const SubdivCCG &subdiv_ccg,
const CCGKey &key,
int vert_index);
float SCULPT_vertex_mask_get(SculptSession *ss, PBVHVertRef vertex);
void SCULPT_vertex_color_get(const SculptSession *ss, PBVHVertRef vertex, float r_color[4]);
void SCULPT_vertex_color_set(SculptSession *ss, PBVHVertRef vertex, const float color[4]);
@ -1522,7 +1521,7 @@ namespace blender::ed::sculpt_paint::smooth {
void bmesh_four_neighbor_average(float avg[3], float direction[3], BMVert *v);
void neighbor_coords_average(SculptSession *ss, float result[3], PBVHVertRef vertex);
float neighbor_mask_average(SculptSession *ss, PBVHVertRef vertex);
float neighbor_mask_average(SculptSession *ss, SculptMaskWriteInfo write_info, PBVHVertRef vertex);
void neighbor_color_average(SculptSession *ss, float result[4], PBVHVertRef vertex);
/**

View File

@ -134,22 +134,40 @@ void neighbor_coords_average(SculptSession *ss, float result[3], PBVHVertRef ver
}
}
float neighbor_mask_average(SculptSession *ss, PBVHVertRef vertex)
float neighbor_mask_average(SculptSession *ss,
const SculptMaskWriteInfo mask_write,
PBVHVertRef vertex)
{
float avg = 0.0f;
int total = 0;
SculptVertexNeighborIter ni;
SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vertex, ni) {
avg += SCULPT_vertex_mask_get(ss, ni.vertex);
total++;
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES:
SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vertex, ni) {
avg += mask_write.layer[ni.vertex.i];
total++;
}
SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
break;
case PBVH_GRIDS:
SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vertex, ni) {
avg += SCULPT_mask_get_at_grids_vert_index(
*ss->subdiv_ccg, *BKE_pbvh_get_grid_key(ss->pbvh), vertex.i);
total++;
}
SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
break;
case PBVH_BMESH:
SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vertex, ni) {
BMVert *vert = reinterpret_cast<BMVert *>(vertex.i);
avg += BM_ELEM_CD_GET_FLOAT(vert, mask_write.bm_offset);
total++;
}
SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
break;
}
SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
if (total > 0) {
return avg / total;
}
return SCULPT_vertex_mask_get(ss, vertex);
BLI_assert(total > 0);
return avg / total;
}
void neighbor_color_average(SculptSession *ss, float result[4], PBVHVertRef vertex)
@ -289,7 +307,7 @@ static void smooth_mask_node(Object *ob,
vd.vertex,
thread_id,
&automask_data);
float val = neighbor_mask_average(ss, vd.vertex) - vd.mask;
float val = neighbor_mask_average(ss, mask_write, vd.vertex) - vd.mask;
val *= fade * bstrength;
float new_mask = vd.mask + val;
CLAMP(new_mask, 0.0f, 1.0f);