Sculpt: Only re-upload face color attribute data

Similar to the previous commit, previously all GPU buffers
were recreated when only a color attribute changed. Now only
that attribute is re-uploaded, using the same mechanism.

Part of #118145.
This commit is contained in:
Hans Goudey
2024-09-13 16:55:53 -04:00
parent 60ab232afb
commit d24e8029d2
9 changed files with 63 additions and 37 deletions

View File

@@ -25,6 +25,7 @@
#include "BLI_offset_indices.hh"
#include "BLI_set.hh"
#include "BLI_span.hh"
#include "BLI_string_ref.hh"
#include "BLI_utildefines.h"
#include "BLI_vector.hh"
@@ -178,6 +179,7 @@ class DrawCache {
virtual ~DrawCache() = default;
virtual void tag_positions_changed(const IndexMask &node_mask) = 0;
virtual void tag_face_sets_changed(const IndexMask &node_mask) = 0;
virtual void tag_attribute_changed(const IndexMask &node_mask, StringRef attribute_name) = 0;
};
/**
@@ -237,6 +239,11 @@ class Tree {
/** Tag nodes where face sets have changed, causing refresh of derived data. */
void tag_face_sets_changed(const IndexMask &node_mask);
/**
* Tag nodes where generic attribute data has changed (not positions, masks, or face sets).
*/
void tag_attribute_changed(const IndexMask &node_mask, StringRef attribute_name);
};
} // namespace blender::bke::pbvh
@@ -400,7 +407,6 @@ bool bmesh_update_topology(BMesh &bm,
void BKE_pbvh_node_mark_update(blender::bke::pbvh::Node &node);
void BKE_pbvh_node_mark_update_mask(blender::bke::pbvh::Node &node);
void BKE_pbvh_node_mark_update_color(blender::bke::pbvh::Node &node);
void BKE_pbvh_node_mark_update_visibility(blender::bke::pbvh::Node &node);
void BKE_pbvh_node_mark_rebuild_draw(blender::bke::pbvh::Node &node);
void BKE_pbvh_node_mark_redraw(blender::bke::pbvh::Node &node);

View File

@@ -567,6 +567,13 @@ void Tree::tag_face_sets_changed(const IndexMask &node_mask)
}
}
void Tree::tag_attribute_changed(const IndexMask &node_mask, const StringRef attribute_name)
{
if (this->draw_data) {
this->draw_data->tag_attribute_changed(node_mask, attribute_name);
}
}
static bool tree_is_empty(const Tree &pbvh)
{
return std::visit([](const auto &nodes) { return nodes.is_empty(); }, pbvh.nodes_);
@@ -1542,11 +1549,6 @@ void BKE_pbvh_node_mark_update_mask(blender::bke::pbvh::Node &node)
node.flag_ |= PBVH_UpdateMask | PBVH_UpdateDrawBuffers | PBVH_UpdateRedraw;
}
void BKE_pbvh_node_mark_update_color(blender::bke::pbvh::Node &node)
{
node.flag_ |= PBVH_UpdateColor | PBVH_UpdateDrawBuffers | PBVH_UpdateRedraw;
}
void BKE_pbvh_mark_rebuild_pixels(blender::bke::pbvh::Tree &pbvh)
{
std::visit(

View File

@@ -141,6 +141,7 @@ class DrawCacheImpl : public DrawCache {
void tag_all_attributes_dirty(const IndexMask &node_mask) override;
void tag_positions_changed(const IndexMask &node_mask) override;
void tag_face_sets_changed(const IndexMask &node_mask) override;
void tag_attribute_changed(const IndexMask &node_mask, StringRef attribute_name) override;
Span<gpu::Batch *> ensure_tris_batches(const Object &object,
const ViewportRequest &request,
@@ -211,6 +212,17 @@ void DrawCacheImpl::tag_face_sets_changed(const IndexMask &node_mask)
}
}
void DrawCacheImpl::tag_attribute_changed(const IndexMask &node_mask, StringRef attribute_name)
{
for (const auto &[data_request, data] : attribute_vbos_.items()) {
if (const GenericRequest *request = std::get_if<GenericRequest>(&data_request)) {
if (request->name == attribute_name) {
data.tag_dirty(node_mask);
}
}
}
}
DrawCache &ensure_draw_data(std::unique_ptr<bke::pbvh::DrawCache> &ptr)
{
if (!ptr) {

View File

@@ -2316,10 +2316,11 @@ static int vertex_color_set_exec(bContext *C, wmOperator *op)
undo::push_nodes(depsgraph, obact, node_mask, undo::Type::Color);
Mesh &mesh = *static_cast<Mesh *>(obact.data);
fill_active_color(obact, paintcol, true, affect_alpha);
MutableSpan<bke::pbvh::MeshNode> nodes = pbvh.nodes<bke::pbvh::MeshNode>();
node_mask.foreach_index([&](const int i) { BKE_pbvh_node_mark_update_color(nodes[i]); });
pbvh.tag_attribute_changed(node_mask, mesh.active_color_attribute);
undo::push_end(obact);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, &obact);

View File

@@ -322,10 +322,10 @@ static void transform_active_color(bContext *C,
const IndexMask node_mask = bke::pbvh::all_leaf_nodes(pbvh, memory);
undo::push_nodes(depsgraph, obact, node_mask, undo::Type::Color);
transform_active_color_data(*BKE_mesh_from_object(&obact), transform_fn);
Mesh &mesh = *static_cast<Mesh *>(obact.data);
transform_active_color_data(mesh, transform_fn);
MutableSpan<bke::pbvh::MeshNode> nodes = pbvh.nodes<bke::pbvh::MeshNode>();
node_mask.foreach_index([&](const int i) { BKE_pbvh_node_mark_update_color(nodes[i]); });
pbvh.tag_attribute_changed(node_mask, mesh.active_color_attribute);
undo::push_end(obact);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, &obact);

View File

@@ -1447,8 +1447,8 @@ static void restore_color_data(Object &ob, Cache &expand_cache)
expand_cache.original_colors[vert],
color_attribute.span);
}
BKE_pbvh_node_mark_redraw(nodes[i]);
});
pbvh.tag_attribute_changed(node_mask, mesh.active_color_attribute);
color_attribute.finish();
}
@@ -1699,7 +1699,7 @@ static void face_sets_update(Object &object, Cache &expand_cache)
/**
* Callback to update vertex colors per bke::pbvh::Tree node.
*/
static void colors_update_task(const Depsgraph &depsgraph,
static bool colors_update_task(const Depsgraph &depsgraph,
Object &object,
const Span<float3> vert_positions,
const OffsetIndices<int> faces,
@@ -1762,9 +1762,7 @@ static void colors_update_task(const Depsgraph &depsgraph,
any_changed = true;
}
if (any_changed) {
BKE_pbvh_node_mark_update_color(*node);
}
return any_changed;
}
/* Store the original mesh data state in the expand cache. */
@@ -1897,19 +1895,26 @@ static void update_for_vert(bContext *C, Object &ob, const std::optional<int> ve
const VArraySpan mask = *attributes.lookup<float>(".sculpt_mask", bke::AttrDomain::Point);
bke::GSpanAttributeWriter color_attribute = color::active_color_attribute_for_write(mesh);
Array<bool> node_changed(node_mask.min_array_size(), false);
MutableSpan<bke::pbvh::MeshNode> nodes = pbvh.nodes<bke::pbvh::MeshNode>();
node_mask.foreach_index(GrainSize(1), [&](const int i) {
colors_update_task(depsgraph,
ob,
vert_positions,
faces,
corner_verts,
vert_to_face_map,
hide_vert,
mask,
&nodes[i],
color_attribute);
node_changed[i] = colors_update_task(depsgraph,
ob,
vert_positions,
faces,
corner_verts,
vert_to_face_map,
hide_vert,
mask,
&nodes[i],
color_attribute);
});
IndexMaskMemory memory;
pbvh.tag_attribute_changed(IndexMask::from_bools(node_changed, memory),
mesh.active_color_attribute);
color_attribute.finish();
flush_update_step(C, UpdateType::Color);
break;

View File

@@ -403,9 +403,9 @@ static void sculpt_color_filter_apply(bContext *C, wmOperator *op, Object &ob)
nodes[i],
tls,
color_attribute);
BKE_pbvh_node_mark_update_color(nodes[i]);
});
});
pbvh.tag_attribute_changed(node_mask, mesh.active_color_attribute);
color_attribute.finish();
flush_update_step(C, UpdateType::Color);
}

View File

@@ -592,9 +592,9 @@ void do_paint_brush(const Scene &scene,
nodes[i],
tls,
color_attribute);
BKE_pbvh_node_mark_update_color(nodes[i]);
});
});
pbvh.tag_attribute_changed(node_mask, mesh.active_color_attribute);
color_attribute.finish();
return;
}
@@ -670,9 +670,9 @@ void do_paint_brush(const Scene &scene,
tls,
ss.cache->paint_brush.mix_colors,
color_attribute);
BKE_pbvh_node_mark_update_color(nodes[i]);
});
});
pbvh.tag_attribute_changed(node_mask, mesh.active_color_attribute);
color_attribute.finish();
}
@@ -894,7 +894,6 @@ void do_smear_brush(const Depsgraph &depsgraph,
nodes[i],
tls,
color_attribute);
BKE_pbvh_node_mark_update_color(nodes[i]);
});
});
}
@@ -926,10 +925,10 @@ void do_smear_brush(const Depsgraph &depsgraph,
nodes[i],
tls,
color_attribute);
BKE_pbvh_node_mark_update_color(nodes[i]);
});
});
}
pbvh.tag_attribute_changed(node_mask, mesh.active_color_attribute);
color_attribute.finish();
}

View File

@@ -1202,15 +1202,16 @@ static void restore_list(bContext *C, Depsgraph *depsgraph, StepData &step_data)
return;
}
MutableSpan<bke::pbvh::MeshNode> nodes = pbvh.nodes<bke::pbvh::MeshNode>();
const Span<bke::pbvh::MeshNode> nodes = pbvh.nodes<bke::pbvh::MeshNode>();
const Mesh &mesh = *static_cast<const Mesh *>(object.data);
Array<bool> modified_verts(mesh.verts_num, false);
restore_color(object, step_data, modified_verts);
node_mask.foreach_index([&](const int i) {
if (indices_contain_true(modified_verts, nodes[i].all_verts())) {
BKE_pbvh_node_mark_update_color(nodes[i]);
}
});
const IndexMask changed_nodes = IndexMask::from_predicate(
node_mask, GrainSize(1), memory, [&](const int i) {
return indices_contain_true(modified_verts, nodes[i].all_verts());
});
pbvh.tag_attribute_changed(changed_nodes, mesh.active_color_attribute);
break;
}
case Type::Geometry: {