Fix #116532: Cloth filter performance issue from mask attribute access

The cloth filter accesses the vertex mask for every length constraint.
Previously that used a cached pointer, but that was removed, and then
the access was changed to use the attribute API, which is slower since
it isn't designed to be accessed for every element. The solution is
to just let the PBVH type abstraction "leak" when accessing mask data.
This commit is contained in:
Hans Goudey
2023-12-28 15:15:18 -05:00
parent 70ae6f5d41
commit 27582ddb93
3 changed files with 60 additions and 15 deletions

View File

@@ -290,6 +290,19 @@ void SCULPT_vertex_persistent_normal_get(SculptSession *ss, PBVHVertRef vertex,
SCULPT_vertex_normal_get(ss, vertex, no);
}
float SCULPT_mask_get_at_grids_vert_index(const SubdivCCG &subdiv_ccg,
const CCGKey &key,
const int vert_index)
{
if (key.mask_offset == -1) {
return 0.0f;
}
const int grid_index = vert_index / key.grid_area;
const int index_in_grid = vert_index - grid_index * key.grid_area;
CCGElem *elem = subdiv_ccg.grids[grid_index];
return *CCG_elem_offset_mask(&key, elem, index_in_grid);
}
float SCULPT_vertex_mask_get(SculptSession *ss, PBVHVertRef vertex)
{
using namespace blender;
@@ -309,16 +322,8 @@ float SCULPT_vertex_mask_get(SculptSession *ss, PBVHVertRef vertex)
return cd_mask != -1 ? BM_ELEM_CD_GET_FLOAT(v, cd_mask) : 0.0f;
}
case PBVH_GRIDS: {
const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh);
if (key->mask_offset == -1) {
return 0.0f;
}
const int grid_index = vertex.i / key->grid_area;
const int vertex_index = vertex.i - grid_index * key->grid_area;
CCGElem *elem = ss->subdiv_ccg->grids[grid_index];
return *CCG_elem_mask(key, CCG_elem_offset(key, elem, vertex_index));
return SCULPT_mask_get_at_grids_vert_index(
*ss->subdiv_ccg, *BKE_pbvh_get_grid_key(ss->pbvh), vertex.i);
}
}

View File

@@ -794,6 +794,25 @@ static void do_cloth_brush_solve_simulation_task(Object *ob,
cloth_sim->node_state[node_index] = SCULPT_CLOTH_NODE_INACTIVE;
}
static float get_vert_mask(const SculptSession &ss,
const SimulationData &cloth_sim,
const int vert_index)
{
switch (BKE_pbvh_type(ss.pbvh)) {
case PBVH_FACES:
return cloth_sim.mask_mesh.is_empty() ? 0.0f : cloth_sim.mask_mesh[vert_index];
case PBVH_BMESH:
return cloth_sim.mask_cd_offset_bmesh == -1 ?
0.0f :
BM_ELEM_CD_GET_FLOAT(BM_vert_at_index(BKE_pbvh_get_bmesh(ss.pbvh), vert_index),
cloth_sim.mask_cd_offset_bmesh);
case PBVH_GRIDS:
return SCULPT_mask_get_at_grids_vert_index(*ss.subdiv_ccg, cloth_sim.grid_key, vert_index);
}
BLI_assert_unreachable();
return 0.0f;
}
static void cloth_brush_satisfy_constraints(SculptSession *ss,
Brush *brush,
SimulationData *cloth_sim)
@@ -843,12 +862,12 @@ static void cloth_brush_satisfy_constraints(SculptSession *ss,
automask_data.orig_data.co = cloth_sim->init_pos[v1];
automask_data.orig_data.no = cloth_sim->init_no[v1];
const float mask_v1 = (1.0f - SCULPT_vertex_mask_get(ss, vertex1)) *
const float mask_v1 = (1.0f - get_vert_mask(*ss, *cloth_sim, v1)) *
auto_mask::factor_get(automasking, ss, vertex1, &automask_data);
automask_data.orig_data.co = cloth_sim->init_pos[v2];
automask_data.orig_data.no = cloth_sim->init_no[v2];
const float mask_v2 = (1.0f - SCULPT_vertex_mask_get(ss, vertex2)) *
const float mask_v2 = (1.0f - get_vert_mask(*ss, *cloth_sim, v2)) *
auto_mask::factor_get(automasking, ss, vertex2, &automask_data);
float sim_location[3];
@@ -1006,9 +1025,7 @@ SimulationData *brush_simulation_create(Object *ob,
{
SculptSession *ss = ob->sculpt;
const int totverts = SCULPT_vertex_count_get(ss);
SimulationData *cloth_sim;
cloth_sim = MEM_new<SimulationData>(__func__);
SimulationData *cloth_sim = MEM_new<SimulationData>(__func__);
cloth_sim->length_constraints = MEM_cnew_array<LengthConstraint>(CLOTH_LENGTH_CONSTRAINTS_BLOCK,
__func__);
@@ -1041,6 +1058,22 @@ SimulationData *brush_simulation_create(Object *ob,
cloth_sim_initialize_default_node_state(ss, cloth_sim);
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES: {
const Mesh *mesh = static_cast<const Mesh *>(ob->data);
const bke::AttributeAccessor attributes = mesh->attributes();
cloth_sim->mask_mesh = *attributes.lookup<float>(".sculpt_mask", bke::AttrDomain::Point);
break;
}
case PBVH_BMESH:
cloth_sim->mask_cd_offset_bmesh = CustomData_get_offset_named(
&ss->bm->vdata, CD_PROP_FLOAT, ".sculpt_mask");
break;
case PBVH_GRIDS:
cloth_sim->grid_key = *BKE_pbvh_get_grid_key(ss->pbvh);
break;
}
return cloth_sim;
}

View File

@@ -874,6 +874,9 @@ const float *SCULPT_vertex_co_get(const SculptSession *ss, PBVHVertRef vertex);
/** Get the normal for a given sculpt vertex; do not modify the result */
void SCULPT_vertex_normal_get(const SculptSession *ss, PBVHVertRef vertex, float no[3]);
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]);
@@ -1448,6 +1451,10 @@ struct SimulationData {
/** #PBVHNode pointer as a key, index in #SimulationData.node_state as value. */
GHash *node_state_index;
NodeSimState *node_state;
VArraySpan<float> mask_mesh;
int mask_cd_offset_bmesh;
CCGKey grid_key;
};
/* Main cloth brush function */