Skip to content

Commit

Permalink
Draw all glyphs in a text run using a single draw call. (flutter#97)
Browse files Browse the repository at this point in the history
  • Loading branch information
chinmaygarde authored and dnfield committed Apr 27, 2022
1 parent 47e9b08 commit 86c5ea4
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 32 deletions.
50 changes: 35 additions & 15 deletions impeller/entity/contents/text_contents.cc
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ bool TextContents::Render(const ContentContext& renderer,

// Information shared by all glyph draw calls.
Command cmd;
cmd.label = "Glyph";
cmd.label = "TextRun";
cmd.primitive_type = PrimitiveType::kTriangle;
cmd.pipeline =
renderer.GetGlyphAtlasPipeline(OptionsFromPassAndEntity(pass, entity));
Expand Down Expand Up @@ -121,8 +121,20 @@ bool TextContents::Render(const ContentContext& renderer,
cmd.BindVertices(std::move(vertex_buffer));
}

size_t instance_count = 0u;
std::vector<Matrix> glyph_positions;
std::vector<Point> glyph_sizes;
std::vector<Point> atlas_positions;
std::vector<Point> atlas_glyph_sizes;

// Iterate through all the runs in the blob.
for (const auto& run : frame_.GetRuns()) {
instance_count = 0u;
glyph_positions.clear();
glyph_sizes.clear();
atlas_positions.clear();
atlas_glyph_sizes.clear();

auto font = run.GetFont();
auto glyph_size = ISize::Ceil(font.GetMetrics().GetBoundingBox().size);
// Draw each glyph individually. This should probably be batched.
Expand All @@ -133,21 +145,29 @@ bool TextContents::Render(const ContentContext& renderer,
VALIDATION_LOG << "Could not find glyph position in the atlas.";
return false;
}
instance_count++;
glyph_positions.emplace_back(glyph_position.position.Translate(
{font.GetMetrics().min_extent.x, font.GetMetrics().ascent, 0.0}));
glyph_sizes.emplace_back(Point{static_cast<Scalar>(glyph_size.width),
static_cast<Scalar>(glyph_size.height)});
atlas_positions.emplace_back(atlas_glyph_pos->origin);
atlas_glyph_sizes.emplace_back(
Point{atlas_glyph_pos->size.width, atlas_glyph_pos->size.height});
}

VS::GlyphInfo glyph_info;
glyph_info.position = glyph_position.position.Translate(
{font.GetMetrics().min_extent.x, font.GetMetrics().ascent, 0.0});
glyph_info.glyph_size = {static_cast<Scalar>(glyph_size.width),
static_cast<Scalar>(glyph_size.height)};
glyph_info.atlas_position = atlas_glyph_pos->origin;
glyph_info.atlas_glyph_size = {atlas_glyph_pos->size.width,
atlas_glyph_pos->size.height};
VS::BindGlyphInfo(cmd,
pass.GetTransientsBuffer().EmplaceUniform(glyph_info));

if (!pass.AddCommand(cmd)) {
return false;
}
cmd.instance_count = instance_count;
VS::BindGlyphPositions(
cmd, pass.GetTransientsBuffer().EmplaceStorageBuffer(glyph_positions));
VS::BindGlyphSizes(
cmd, pass.GetTransientsBuffer().EmplaceStorageBuffer(glyph_sizes));
VS::BindAtlasPositions(
cmd, pass.GetTransientsBuffer().EmplaceStorageBuffer(atlas_positions));
VS::BindAtlasGlyphSizes(
cmd,
pass.GetTransientsBuffer().EmplaceStorageBuffer(atlas_glyph_sizes));

if (!pass.AddCommand(cmd)) {
return false;
}
}

Expand Down
46 changes: 29 additions & 17 deletions impeller/entity/shaders/glyph_atlas.vert
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,21 @@ uniform FrameInfo {
vec4 text_color;
} frame_info;

uniform GlyphInfo {
mat4 position;
vec2 glyph_size;
vec2 atlas_position;
vec2 atlas_glyph_size;
} glyph_info;
readonly buffer GlyphPositions {
mat4 position[];
} glyph_positions;

readonly buffer GlyphSizes {
vec2 size[];
} glyph_sizes;

readonly buffer AtlasPositions {
vec2 position[];
} atlas_positions;

readonly buffer AtlasGlyphSizes {
vec2 size[];
} atlas_glyph_sizes;

in vec2 unit_vertex;

Expand All @@ -24,20 +33,23 @@ out vec2 v_atlas_size;
out vec4 v_text_color;

void main() {
mat4 scale = mat4(
glyph_info.glyph_size.x, 0.0, 0.0, 0.0,
0.0, glyph_info.glyph_size.y, 0.0, 0.0,
0.0, 0.0, 1.0 , 0.0,
0.0, 0.0, 0.0 , 1.0
);
// The position to place the glyph.
mat4 glyph_position = glyph_positions.position[gl_InstanceIndex];
// The size of the glyph.
vec2 glyph_size = glyph_sizes.size[gl_InstanceIndex];
// The location of the glyph in the atlas.
vec2 glyph_atlas_position = atlas_positions.position[gl_InstanceIndex];
// The size of the glyph within the atlas.
vec2 glyph_atlas_size = atlas_glyph_sizes.size[gl_InstanceIndex];

gl_Position = frame_info.mvp
* glyph_info.position
* scale
* vec4(unit_vertex, 0.0, 1.0);
* glyph_position
* vec4(unit_vertex.x * glyph_size.x,
unit_vertex.y * glyph_size.y, 0.0, 1.0);

v_unit_vertex = unit_vertex;
v_atlas_position = glyph_info.atlas_position;
v_atlas_glyph_size = glyph_info.atlas_glyph_size;
v_atlas_position = glyph_atlas_position;
v_atlas_glyph_size = glyph_atlas_size;
v_atlas_size = frame_info.atlas_size;
v_text_color = frame_info.text_color;
}
9 changes: 9 additions & 0 deletions impeller/renderer/backend/metal/render_pass_mtl.mm
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,9 @@ static bool Bind(PassBindingsCache& pass,
if (command.index_count == 0u) {
continue;
}
if (command.instance_count == 0u) {
continue;
}

fml::ScopedCleanupClosure auto_pop_debug_marker(pop_debug_marker);
if (!command.label.empty()) {
Expand Down Expand Up @@ -510,6 +513,12 @@ static bool Bind(PassBindingsCache& pass,
return true;
}

if (command.instance_count == 0u) {
// Essentially a no-op. Don't record the command but this is not necessary
// an error either.
return true;
}

commands_.emplace_back(std::move(command));
return true;
}
Expand Down

0 comments on commit 86c5ea4

Please sign in to comment.