Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 02d6fbb

Browse files
author
Jonah Williams
authored
[Impeller] Emplace directly into host buffer (avoid VBB) for text data (#42484)
From local testing, this shaves off about 0.3-4 ms of pure allocation overhead from flutter/flutter#127760 ### Before ![image](https://github.com/flutter/engine/assets/8975114/55701559-fba8-4f11-b606-f819d197626e) ### After ![image](https://github.com/flutter/engine/assets/8975114/b6843c13-d6c7-4364-86b1-c78e216307b3)
1 parent 59afddd commit 02d6fbb

3 files changed

Lines changed: 80 additions & 50 deletions

File tree

impeller/core/host_buffer.cc

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,22 @@ BufferView HostBuffer::Emplace(const void* buffer, size_t length) {
5656
return BufferView{shared_from_this(), GetBuffer(), Range{old_length, length}};
5757
}
5858

59+
BufferView HostBuffer::Emplace(size_t length,
60+
size_t align,
61+
const EmplaceProc& cb) {
62+
if (!cb) {
63+
return {};
64+
}
65+
auto old_length = GetLength();
66+
if (!Truncate(old_length + length)) {
67+
return {};
68+
}
69+
generation_++;
70+
cb(GetBuffer() + old_length);
71+
72+
return BufferView{shared_from_this(), GetBuffer(), Range{old_length, length}};
73+
}
74+
5975
std::shared_ptr<const DeviceBuffer> HostBuffer::GetDeviceBuffer(
6076
Allocator& allocator) const {
6177
if (generation_ == device_buffer_generation_) {

impeller/core/host_buffer.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,22 @@ class HostBuffer final : public std::enable_shared_from_this<HostBuffer>,
9595
size_t length,
9696
size_t align);
9797

98+
using EmplaceProc = std::function<void(uint8_t* buffer)>;
99+
100+
//----------------------------------------------------------------------------
101+
/// @brief Emplaces undefined data onto the managed buffer and gives the
102+
/// caller a chance to update it using the specified callback. The
103+
/// buffer is guaranteed to have enough space for length bytes. It
104+
/// is the responsibility of the caller to not exceed the bounds
105+
/// of the buffer returned in the EmplaceProc.
106+
///
107+
/// @param[in] cb A callback that will be passed a ptr to the
108+
/// underlying host buffer.
109+
///
110+
/// @return The buffer view.
111+
///
112+
BufferView Emplace(size_t length, size_t align, const EmplaceProc& cb);
113+
98114
private:
99115
mutable std::shared_ptr<DeviceBuffer> device_buffer_;
100116
mutable size_t device_buffer_generation_ = 0u;

impeller/entity/contents/text_contents.cc

Lines changed: 48 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -135,60 +135,58 @@ static bool CommonRender(const ContentContext& renderer,
135135
// interpolated vertex information is also used in the fragment shader to
136136
// sample from the glyph atlas.
137137

138-
constexpr std::array<Point, 4> unit_points = {Point{0, 0}, Point{1, 0},
138+
constexpr std::array<Point, 6> unit_points = {Point{0, 0}, Point{1, 0},
139+
Point{0, 1}, Point{1, 0},
139140
Point{0, 1}, Point{1, 1}};
140-
constexpr std::array<uint32_t, 6> indices = {0, 1, 2, 1, 2, 3};
141-
142-
VertexBufferBuilder<typename VS::PerVertexData> vertex_builder;
143-
144-
size_t count = 0;
145-
for (const auto& run : frame.GetRuns()) {
146-
count += run.GetGlyphPositions().size();
147-
}
148-
149-
vertex_builder.Reserve(count * 4);
150-
vertex_builder.ReserveIndices(count * 6);
151-
152-
uint32_t index_offset = 0u;
153-
for (auto i = 0u; i < count; i++) {
154-
for (const auto& index : indices) {
155-
vertex_builder.AppendIndex(index + index_offset);
156-
}
157-
index_offset += 4;
158-
}
159141

142+
auto& host_buffer = pass.GetTransientsBuffer();
143+
size_t vertex_count = 0;
160144
for (const auto& run : frame.GetRuns()) {
161-
const Font& font = run.GetFont();
162-
163-
for (const auto& glyph_position : run.GetGlyphPositions()) {
164-
FontGlyphPair font_glyph_pair{font, glyph_position.glyph};
165-
auto atlas_glyph_bounds = atlas->FindFontGlyphBounds(font_glyph_pair);
166-
if (!atlas_glyph_bounds.has_value()) {
167-
VALIDATION_LOG << "Could not find glyph position in the atlas.";
168-
return false;
169-
}
170-
Vector4 atlas_glyph_bounds_vec = Vector4(
171-
atlas_glyph_bounds->origin.x, atlas_glyph_bounds->origin.y,
172-
atlas_glyph_bounds->size.width, atlas_glyph_bounds->size.height);
173-
Vector4 glyph_bounds_vec =
174-
Vector4(glyph_position.glyph.bounds.origin.x,
175-
glyph_position.glyph.bounds.origin.y,
176-
glyph_position.glyph.bounds.size.width,
177-
glyph_position.glyph.bounds.size.height);
178-
179-
for (const auto& point : unit_points) {
180-
vertex_builder.AppendVertex(VS::PerVertexData{
181-
.atlas_glyph_bounds = atlas_glyph_bounds_vec,
182-
.glyph_bounds = glyph_bounds_vec,
183-
.unit_position = point,
184-
.glyph_position = glyph_position.position,
185-
});
186-
}
187-
}
145+
vertex_count += run.GetGlyphPositions().size();
188146
}
189-
auto vertex_buffer =
190-
vertex_builder.CreateVertexBuffer(pass.GetTransientsBuffer());
191-
cmd.BindVertices(vertex_buffer);
147+
vertex_count *= 6;
148+
149+
auto buffer_view = host_buffer.Emplace(
150+
vertex_count * sizeof(VS::PerVertexData), alignof(VS::PerVertexData),
151+
[&](uint8_t* contents) {
152+
VS::PerVertexData vtx;
153+
size_t vertex_offset = 0;
154+
for (const auto& run : frame.GetRuns()) {
155+
const Font& font = run.GetFont();
156+
for (const auto& glyph_position : run.GetGlyphPositions()) {
157+
FontGlyphPair font_glyph_pair{font, glyph_position.glyph};
158+
auto maybe_atlas_glyph_bounds =
159+
atlas->FindFontGlyphBounds(font_glyph_pair);
160+
if (!maybe_atlas_glyph_bounds.has_value()) {
161+
VALIDATION_LOG << "Could not find glyph position in the atlas.";
162+
continue;
163+
}
164+
auto atlas_glyph_bounds = maybe_atlas_glyph_bounds.value();
165+
vtx.atlas_glyph_bounds = Vector4(
166+
atlas_glyph_bounds.origin.x, atlas_glyph_bounds.origin.y,
167+
atlas_glyph_bounds.size.width, atlas_glyph_bounds.size.height);
168+
vtx.glyph_bounds = Vector4(glyph_position.glyph.bounds.origin.x,
169+
glyph_position.glyph.bounds.origin.y,
170+
glyph_position.glyph.bounds.size.width,
171+
glyph_position.glyph.bounds.size.height);
172+
vtx.glyph_position = glyph_position.position;
173+
174+
for (const auto& point : unit_points) {
175+
vtx.unit_position = point;
176+
::memcpy(contents + vertex_offset, &vtx,
177+
sizeof(VS::PerVertexData));
178+
vertex_offset += sizeof(VS::PerVertexData);
179+
}
180+
}
181+
}
182+
});
183+
184+
cmd.BindVertices({
185+
.vertex_buffer = buffer_view,
186+
.index_buffer = {},
187+
.vertex_count = vertex_count,
188+
.index_type = IndexType::kNone,
189+
});
192190

193191
return pass.AddCommand(cmd);
194192
}

0 commit comments

Comments
 (0)