diff --git a/source/blender/editors/sculpt_paint/sculpt.cc b/source/blender/editors/sculpt_paint/sculpt.cc index 2329b3d673c..2f6c8e1e2d2 100644 --- a/source/blender/editors/sculpt_paint/sculpt.cc +++ b/source/blender/editors/sculpt_paint/sculpt.cc @@ -3544,38 +3544,46 @@ static void sculpt_topology_update(const Scene & /*scene*/, mul_m4_v3(ob.object_to_world().ptr(), location); } -static void push_undo_nodes(Object &ob, const Brush &brush, PBVHNode *node) +static void push_undo_nodes(Object &ob, const Brush &brush, const Span nodes) { SculptSession &ss = *ob.sculpt; bool need_coords = ss.cache->supports_gravity; if (brush.sculpt_tool == SCULPT_TOOL_DRAW_FACE_SETS) { - BKE_pbvh_node_mark_update_face_sets(node); + for (PBVHNode *node : nodes) { + BKE_pbvh_node_mark_update_face_sets(node); + } /* Draw face sets in smooth mode moves the vertices. */ if (ss.cache->alt_smooth) { need_coords = true; } else { - undo::push_node(ob, node, undo::Type::FaceSet); + undo::push_nodes(ob, nodes, undo::Type::FaceSet); } } else if (brush.sculpt_tool == SCULPT_TOOL_MASK) { - undo::push_node(ob, node, undo::Type::Mask); - BKE_pbvh_node_mark_update_mask(node); + undo::push_nodes(ob, nodes, undo::Type::Mask); + for (PBVHNode *node : nodes) { + BKE_pbvh_node_mark_update_mask(node); + } } else if (SCULPT_tool_is_paint(brush.sculpt_tool)) { - undo::push_node(ob, node, undo::Type::Color); - BKE_pbvh_node_mark_update_color(node); + undo::push_nodes(ob, nodes, undo::Type::Color); + for (PBVHNode *node : nodes) { + BKE_pbvh_node_mark_update_color(node); + } } else { need_coords = true; } if (need_coords) { - undo::push_node(ob, node, undo::Type::Position); - BKE_pbvh_node_mark_positions_update(node); + undo::push_nodes(ob, nodes, undo::Type::Position); + for (PBVHNode *node : nodes) { + BKE_pbvh_node_mark_positions_update(node); + } } } @@ -3685,11 +3693,7 @@ static void do_brush_action(const Scene &scene, float location[3]; if (!use_pixels) { - threading::parallel_for(nodes.index_range(), 1, [&](const IndexRange range) { - for (const int i : range) { - push_undo_nodes(ob, brush, nodes[i]); - } - }); + push_undo_nodes(ob, brush, nodes); } if (sculpt_brush_needs_normal(ss, sd, brush)) { diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.hh b/source/blender/editors/sculpt_paint/sculpt_intern.hh index eae526c16b9..72075b7411e 100644 --- a/source/blender/editors/sculpt_paint/sculpt_intern.hh +++ b/source/blender/editors/sculpt_paint/sculpt_intern.hh @@ -1653,6 +1653,7 @@ namespace blender::ed::sculpt_paint::undo { * This is only possible when building an undo step, in between #push_begin and #push_end. */ void push_node(const Object &object, const PBVHNode *node, undo::Type type); +void push_nodes(Object &object, Span nodes, undo::Type type); /** * Retrieve the undo data of a given type for the active undo step. For example, this is used to diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.cc b/source/blender/editors/sculpt_paint/sculpt_undo.cc index 661f53f729c..f93ae7f5750 100644 --- a/source/blender/editors/sculpt_paint/sculpt_undo.cc +++ b/source/blender/editors/sculpt_paint/sculpt_undo.cc @@ -1587,6 +1587,36 @@ void push_node(const Object &object, const PBVHNode *node, Type type) fill_node_data(object, node, type, *unode); } +void push_nodes(Object &object, const Span nodes, const Type type) +{ + SculptSession &ss = *object.sculpt; + if (ss.bm || ELEM(type, Type::DyntopoBegin, Type::DyntopoEnd)) { + for (const PBVHNode *node : nodes) { + bmesh_push(object, node, type); + } + return; + } + + StepData *step_data = get_step_data(); + + Vector, 32> nodes_to_fill; + for (const PBVHNode *node : nodes) { + bool newly_added; + Node *unode = ensure_node(*step_data, *node, type, newly_added); + if (newly_added) { + nodes_to_fill.append({node, unode}); + } + } + + ss.needs_flush_to_id = 1; + + threading::parallel_for(nodes_to_fill.index_range(), 1, [&](const IndexRange range) { + for (const auto &[node, unode] : nodes_to_fill.as_span().slice(range)) { + fill_node_data(object, node, type, *unode); + } + }); +} + static void save_active_attribute(Object &object, SculptAttrRef *attr) { Mesh *mesh = BKE_object_get_original_mesh(&object);