From 2102048a58a650ef66c4fe95b72fb7104d9459ff Mon Sep 17 00:00:00 2001 From: alokads06 Date: Sun, 28 Jun 2026 18:09:54 +0530 Subject: [PATCH 1/2] perf(mutable_mesh): optimize partition lookup and copy perf(mutable_mesh): replace linear partition scan with O(log N) upper_bound perf(mutable_mesh): use memcpy for bulk vertex copies in CopyVertexIntoPartition feat(geometry): expose MutRawVertexData for fast zero-overhead memory transfers --- ink/geometry/mutable_mesh.h | 3 ++ ink/strokes/internal/mutable_multi_mesh.cc | 38 ++++++++++++---------- 2 files changed, 23 insertions(+), 18 deletions(-) diff --git a/ink/geometry/mutable_mesh.h b/ink/geometry/mutable_mesh.h index 338e1486..c45ac8e2 100644 --- a/ink/geometry/mutable_mesh.h +++ b/ink/geometry/mutable_mesh.h @@ -301,6 +301,9 @@ class MutableMesh { // Returns the raw data of the mesh's vertices. absl::Span RawVertexData() const { return vertex_data_; } + // Returns the mutable raw data of the mesh's vertices. + absl::Span MutRawVertexData() { return absl::MakeSpan(vertex_data_); } + // Returns the number of bytes used to represent a vertex in this mesh. This // is equivalent to: // mesh.Format().UnpackedVertexStride(); diff --git a/ink/strokes/internal/mutable_multi_mesh.cc b/ink/strokes/internal/mutable_multi_mesh.cc index e0091139..95dfa074 100644 --- a/ink/strokes/internal/mutable_multi_mesh.cc +++ b/ink/strokes/internal/mutable_multi_mesh.cc @@ -1,8 +1,11 @@ #include "ink/strokes/internal/mutable_multi_mesh.h" +#include #include #include #include +#include +#include #include #include @@ -247,17 +250,18 @@ void MutableMultiMesh::AddNewPartition() { TriangleIndexPair MutableMultiMesh::GetPartitionTriangle( uint32_t triangle_index) const { - // TODO: b/295166196 - Consider using a binary search here. - for (int partition_index = partitions_.size() - 1; partition_index >= 0; - --partition_index) { - uint32_t previous_triangle_count = - partitions_[partition_index].previous_triangle_count; - if (triangle_index >= previous_triangle_count) { - return TriangleIndexPair{ - static_cast(partition_index), - static_cast(triangle_index - previous_triangle_count), - }; - } + auto it = std::upper_bound( + partitions_.begin(), partitions_.end(), triangle_index, + [](uint32_t val, const Partition& p) { + return val < p.previous_triangle_count; + }); + if (it != partitions_.begin()) { + --it; + uint32_t partition_index = std::distance(partitions_.begin(), it); + return TriangleIndexPair{ + static_cast(partition_index), + static_cast(triangle_index - it->previous_triangle_count), + }; } ABSL_CHECK(false) << "triangle_index out of bounds"; } @@ -291,13 +295,11 @@ uint16_t MutableMultiMesh::CopyVertexIntoPartition(uint32_t vertex_index, VertexIndexPair{partition_index, mesh_vertex_index}); partitions_[partition_index].vertex_indices.push_back(vertex_index); mesh.AppendVertex(other_mesh.VertexPosition(other_mesh_vertex_index)); - // TODO: b/306149329 - Investigate memcpy-ing the vertex data instead of - // repeatedly calling `SetFloatVertexAttribute()`. - for (size_t i = 0; i < format_.Attributes().size(); ++i) { - mesh.SetFloatVertexAttribute( - mesh_vertex_index, i, - other_mesh.FloatVertexAttribute(other_mesh_vertex_index, i)); - } + std::memcpy( + mesh.MutRawVertexData().data() + mesh_vertex_index * mesh.VertexStride(), + other_mesh.RawVertexData().data() + + other_mesh_vertex_index * other_mesh.VertexStride(), + mesh.VertexStride()); return mesh_vertex_index; } From f1211c7570dfa36d481903e587ac8934cee4e084 Mon Sep 17 00:00:00 2001 From: alokads06 Date: Tue, 30 Jun 2026 20:36:29 +0530 Subject: [PATCH 2/2] refactor: rename MutRawVertexData to MutableRawVertexData per review feedback --- ink/geometry/mutable_mesh.h | 2 +- ink/strokes/internal/mutable_multi_mesh.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ink/geometry/mutable_mesh.h b/ink/geometry/mutable_mesh.h index c45ac8e2..63f23a1b 100644 --- a/ink/geometry/mutable_mesh.h +++ b/ink/geometry/mutable_mesh.h @@ -302,7 +302,7 @@ class MutableMesh { absl::Span RawVertexData() const { return vertex_data_; } // Returns the mutable raw data of the mesh's vertices. - absl::Span MutRawVertexData() { return absl::MakeSpan(vertex_data_); } + absl::Span MutableRawVertexData() { return absl::MakeSpan(vertex_data_); } // Returns the number of bytes used to represent a vertex in this mesh. This // is equivalent to: diff --git a/ink/strokes/internal/mutable_multi_mesh.cc b/ink/strokes/internal/mutable_multi_mesh.cc index 95dfa074..e5963011 100644 --- a/ink/strokes/internal/mutable_multi_mesh.cc +++ b/ink/strokes/internal/mutable_multi_mesh.cc @@ -296,7 +296,7 @@ uint16_t MutableMultiMesh::CopyVertexIntoPartition(uint32_t vertex_index, partitions_[partition_index].vertex_indices.push_back(vertex_index); mesh.AppendVertex(other_mesh.VertexPosition(other_mesh_vertex_index)); std::memcpy( - mesh.MutRawVertexData().data() + mesh_vertex_index * mesh.VertexStride(), + mesh.MutableRawVertexData().data() + mesh_vertex_index * mesh.VertexStride(), other_mesh.RawVertexData().data() + other_mesh_vertex_index * other_mesh.VertexStride(), mesh.VertexStride());