mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
[Impeller] Emplace directly into host buffer (avoid VBB) for text data (flutter/engine#42484)
From local testing, this shaves off about 0.3-4 ms of pure allocation overhead from https://github.com/flutter/flutter/issues/127760 ### Before  ### After 
This commit is contained in:
parent
d72aace3ef
commit
b06489fa4b
@ -56,6 +56,22 @@ BufferView HostBuffer::Emplace(const void* buffer, size_t length) {
|
||||
return BufferView{shared_from_this(), GetBuffer(), Range{old_length, length}};
|
||||
}
|
||||
|
||||
BufferView HostBuffer::Emplace(size_t length,
|
||||
size_t align,
|
||||
const EmplaceProc& cb) {
|
||||
if (!cb) {
|
||||
return {};
|
||||
}
|
||||
auto old_length = GetLength();
|
||||
if (!Truncate(old_length + length)) {
|
||||
return {};
|
||||
}
|
||||
generation_++;
|
||||
cb(GetBuffer() + old_length);
|
||||
|
||||
return BufferView{shared_from_this(), GetBuffer(), Range{old_length, length}};
|
||||
}
|
||||
|
||||
std::shared_ptr<const DeviceBuffer> HostBuffer::GetDeviceBuffer(
|
||||
Allocator& allocator) const {
|
||||
if (generation_ == device_buffer_generation_) {
|
||||
|
||||
@ -95,6 +95,22 @@ class HostBuffer final : public std::enable_shared_from_this<HostBuffer>,
|
||||
size_t length,
|
||||
size_t align);
|
||||
|
||||
using EmplaceProc = std::function<void(uint8_t* buffer)>;
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
/// @brief Emplaces undefined data onto the managed buffer and gives the
|
||||
/// caller a chance to update it using the specified callback. The
|
||||
/// buffer is guaranteed to have enough space for length bytes. It
|
||||
/// is the responsibility of the caller to not exceed the bounds
|
||||
/// of the buffer returned in the EmplaceProc.
|
||||
///
|
||||
/// @param[in] cb A callback that will be passed a ptr to the
|
||||
/// underlying host buffer.
|
||||
///
|
||||
/// @return The buffer view.
|
||||
///
|
||||
BufferView Emplace(size_t length, size_t align, const EmplaceProc& cb);
|
||||
|
||||
private:
|
||||
mutable std::shared_ptr<DeviceBuffer> device_buffer_;
|
||||
mutable size_t device_buffer_generation_ = 0u;
|
||||
|
||||
@ -135,60 +135,58 @@ static bool CommonRender(const ContentContext& renderer,
|
||||
// interpolated vertex information is also used in the fragment shader to
|
||||
// sample from the glyph atlas.
|
||||
|
||||
constexpr std::array<Point, 4> unit_points = {Point{0, 0}, Point{1, 0},
|
||||
constexpr std::array<Point, 6> unit_points = {Point{0, 0}, Point{1, 0},
|
||||
Point{0, 1}, Point{1, 0},
|
||||
Point{0, 1}, Point{1, 1}};
|
||||
constexpr std::array<uint32_t, 6> indices = {0, 1, 2, 1, 2, 3};
|
||||
|
||||
VertexBufferBuilder<typename VS::PerVertexData> vertex_builder;
|
||||
|
||||
size_t count = 0;
|
||||
auto& host_buffer = pass.GetTransientsBuffer();
|
||||
size_t vertex_count = 0;
|
||||
for (const auto& run : frame.GetRuns()) {
|
||||
count += run.GetGlyphPositions().size();
|
||||
vertex_count += run.GetGlyphPositions().size();
|
||||
}
|
||||
vertex_count *= 6;
|
||||
|
||||
vertex_builder.Reserve(count * 4);
|
||||
vertex_builder.ReserveIndices(count * 6);
|
||||
auto buffer_view = host_buffer.Emplace(
|
||||
vertex_count * sizeof(VS::PerVertexData), alignof(VS::PerVertexData),
|
||||
[&](uint8_t* contents) {
|
||||
VS::PerVertexData vtx;
|
||||
size_t vertex_offset = 0;
|
||||
for (const auto& run : frame.GetRuns()) {
|
||||
const Font& font = run.GetFont();
|
||||
for (const auto& glyph_position : run.GetGlyphPositions()) {
|
||||
FontGlyphPair font_glyph_pair{font, glyph_position.glyph};
|
||||
auto maybe_atlas_glyph_bounds =
|
||||
atlas->FindFontGlyphBounds(font_glyph_pair);
|
||||
if (!maybe_atlas_glyph_bounds.has_value()) {
|
||||
VALIDATION_LOG << "Could not find glyph position in the atlas.";
|
||||
continue;
|
||||
}
|
||||
auto atlas_glyph_bounds = maybe_atlas_glyph_bounds.value();
|
||||
vtx.atlas_glyph_bounds = Vector4(
|
||||
atlas_glyph_bounds.origin.x, atlas_glyph_bounds.origin.y,
|
||||
atlas_glyph_bounds.size.width, atlas_glyph_bounds.size.height);
|
||||
vtx.glyph_bounds = Vector4(glyph_position.glyph.bounds.origin.x,
|
||||
glyph_position.glyph.bounds.origin.y,
|
||||
glyph_position.glyph.bounds.size.width,
|
||||
glyph_position.glyph.bounds.size.height);
|
||||
vtx.glyph_position = glyph_position.position;
|
||||
|
||||
uint32_t index_offset = 0u;
|
||||
for (auto i = 0u; i < count; i++) {
|
||||
for (const auto& index : indices) {
|
||||
vertex_builder.AppendIndex(index + index_offset);
|
||||
}
|
||||
index_offset += 4;
|
||||
}
|
||||
for (const auto& point : unit_points) {
|
||||
vtx.unit_position = point;
|
||||
::memcpy(contents + vertex_offset, &vtx,
|
||||
sizeof(VS::PerVertexData));
|
||||
vertex_offset += sizeof(VS::PerVertexData);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
for (const auto& run : frame.GetRuns()) {
|
||||
const Font& font = run.GetFont();
|
||||
|
||||
for (const auto& glyph_position : run.GetGlyphPositions()) {
|
||||
FontGlyphPair font_glyph_pair{font, glyph_position.glyph};
|
||||
auto atlas_glyph_bounds = atlas->FindFontGlyphBounds(font_glyph_pair);
|
||||
if (!atlas_glyph_bounds.has_value()) {
|
||||
VALIDATION_LOG << "Could not find glyph position in the atlas.";
|
||||
return false;
|
||||
}
|
||||
Vector4 atlas_glyph_bounds_vec = Vector4(
|
||||
atlas_glyph_bounds->origin.x, atlas_glyph_bounds->origin.y,
|
||||
atlas_glyph_bounds->size.width, atlas_glyph_bounds->size.height);
|
||||
Vector4 glyph_bounds_vec =
|
||||
Vector4(glyph_position.glyph.bounds.origin.x,
|
||||
glyph_position.glyph.bounds.origin.y,
|
||||
glyph_position.glyph.bounds.size.width,
|
||||
glyph_position.glyph.bounds.size.height);
|
||||
|
||||
for (const auto& point : unit_points) {
|
||||
vertex_builder.AppendVertex(VS::PerVertexData{
|
||||
.atlas_glyph_bounds = atlas_glyph_bounds_vec,
|
||||
.glyph_bounds = glyph_bounds_vec,
|
||||
.unit_position = point,
|
||||
.glyph_position = glyph_position.position,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
auto vertex_buffer =
|
||||
vertex_builder.CreateVertexBuffer(pass.GetTransientsBuffer());
|
||||
cmd.BindVertices(vertex_buffer);
|
||||
cmd.BindVertices({
|
||||
.vertex_buffer = buffer_view,
|
||||
.index_buffer = {},
|
||||
.vertex_count = vertex_count,
|
||||
.index_type = IndexType::kNone,
|
||||
});
|
||||
|
||||
return pass.AddCommand(cmd);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user