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

Commit 86c5ea4

Browse files
chinmaygardednfield
authored andcommitted
Draw all glyphs in a text run using a single draw call. (#97)
1 parent 47e9b08 commit 86c5ea4

File tree

3 files changed

+73
-32
lines changed

3 files changed

+73
-32
lines changed

impeller/entity/contents/text_contents.cc

+35-15
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ bool TextContents::Render(const ContentContext& renderer,
6767

6868
// Information shared by all glyph draw calls.
6969
Command cmd;
70-
cmd.label = "Glyph";
70+
cmd.label = "TextRun";
7171
cmd.primitive_type = PrimitiveType::kTriangle;
7272
cmd.pipeline =
7373
renderer.GetGlyphAtlasPipeline(OptionsFromPassAndEntity(pass, entity));
@@ -121,8 +121,20 @@ bool TextContents::Render(const ContentContext& renderer,
121121
cmd.BindVertices(std::move(vertex_buffer));
122122
}
123123

124+
size_t instance_count = 0u;
125+
std::vector<Matrix> glyph_positions;
126+
std::vector<Point> glyph_sizes;
127+
std::vector<Point> atlas_positions;
128+
std::vector<Point> atlas_glyph_sizes;
129+
124130
// Iterate through all the runs in the blob.
125131
for (const auto& run : frame_.GetRuns()) {
132+
instance_count = 0u;
133+
glyph_positions.clear();
134+
glyph_sizes.clear();
135+
atlas_positions.clear();
136+
atlas_glyph_sizes.clear();
137+
126138
auto font = run.GetFont();
127139
auto glyph_size = ISize::Ceil(font.GetMetrics().GetBoundingBox().size);
128140
// Draw each glyph individually. This should probably be batched.
@@ -133,21 +145,29 @@ bool TextContents::Render(const ContentContext& renderer,
133145
VALIDATION_LOG << "Could not find glyph position in the atlas.";
134146
return false;
135147
}
148+
instance_count++;
149+
glyph_positions.emplace_back(glyph_position.position.Translate(
150+
{font.GetMetrics().min_extent.x, font.GetMetrics().ascent, 0.0}));
151+
glyph_sizes.emplace_back(Point{static_cast<Scalar>(glyph_size.width),
152+
static_cast<Scalar>(glyph_size.height)});
153+
atlas_positions.emplace_back(atlas_glyph_pos->origin);
154+
atlas_glyph_sizes.emplace_back(
155+
Point{atlas_glyph_pos->size.width, atlas_glyph_pos->size.height});
156+
}
136157

137-
VS::GlyphInfo glyph_info;
138-
glyph_info.position = glyph_position.position.Translate(
139-
{font.GetMetrics().min_extent.x, font.GetMetrics().ascent, 0.0});
140-
glyph_info.glyph_size = {static_cast<Scalar>(glyph_size.width),
141-
static_cast<Scalar>(glyph_size.height)};
142-
glyph_info.atlas_position = atlas_glyph_pos->origin;
143-
glyph_info.atlas_glyph_size = {atlas_glyph_pos->size.width,
144-
atlas_glyph_pos->size.height};
145-
VS::BindGlyphInfo(cmd,
146-
pass.GetTransientsBuffer().EmplaceUniform(glyph_info));
147-
148-
if (!pass.AddCommand(cmd)) {
149-
return false;
150-
}
158+
cmd.instance_count = instance_count;
159+
VS::BindGlyphPositions(
160+
cmd, pass.GetTransientsBuffer().EmplaceStorageBuffer(glyph_positions));
161+
VS::BindGlyphSizes(
162+
cmd, pass.GetTransientsBuffer().EmplaceStorageBuffer(glyph_sizes));
163+
VS::BindAtlasPositions(
164+
cmd, pass.GetTransientsBuffer().EmplaceStorageBuffer(atlas_positions));
165+
VS::BindAtlasGlyphSizes(
166+
cmd,
167+
pass.GetTransientsBuffer().EmplaceStorageBuffer(atlas_glyph_sizes));
168+
169+
if (!pass.AddCommand(cmd)) {
170+
return false;
151171
}
152172
}
153173

impeller/entity/shaders/glyph_atlas.vert

+29-17
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,21 @@ uniform FrameInfo {
88
vec4 text_color;
99
} frame_info;
1010

11-
uniform GlyphInfo {
12-
mat4 position;
13-
vec2 glyph_size;
14-
vec2 atlas_position;
15-
vec2 atlas_glyph_size;
16-
} glyph_info;
11+
readonly buffer GlyphPositions {
12+
mat4 position[];
13+
} glyph_positions;
14+
15+
readonly buffer GlyphSizes {
16+
vec2 size[];
17+
} glyph_sizes;
18+
19+
readonly buffer AtlasPositions {
20+
vec2 position[];
21+
} atlas_positions;
22+
23+
readonly buffer AtlasGlyphSizes {
24+
vec2 size[];
25+
} atlas_glyph_sizes;
1726

1827
in vec2 unit_vertex;
1928

@@ -24,20 +33,23 @@ out vec2 v_atlas_size;
2433
out vec4 v_text_color;
2534

2635
void main() {
27-
mat4 scale = mat4(
28-
glyph_info.glyph_size.x, 0.0, 0.0, 0.0,
29-
0.0, glyph_info.glyph_size.y, 0.0, 0.0,
30-
0.0, 0.0, 1.0 , 0.0,
31-
0.0, 0.0, 0.0 , 1.0
32-
);
36+
// The position to place the glyph.
37+
mat4 glyph_position = glyph_positions.position[gl_InstanceIndex];
38+
// The size of the glyph.
39+
vec2 glyph_size = glyph_sizes.size[gl_InstanceIndex];
40+
// The location of the glyph in the atlas.
41+
vec2 glyph_atlas_position = atlas_positions.position[gl_InstanceIndex];
42+
// The size of the glyph within the atlas.
43+
vec2 glyph_atlas_size = atlas_glyph_sizes.size[gl_InstanceIndex];
44+
3345
gl_Position = frame_info.mvp
34-
* glyph_info.position
35-
* scale
36-
* vec4(unit_vertex, 0.0, 1.0);
46+
* glyph_position
47+
* vec4(unit_vertex.x * glyph_size.x,
48+
unit_vertex.y * glyph_size.y, 0.0, 1.0);
3749

3850
v_unit_vertex = unit_vertex;
39-
v_atlas_position = glyph_info.atlas_position;
40-
v_atlas_glyph_size = glyph_info.atlas_glyph_size;
51+
v_atlas_position = glyph_atlas_position;
52+
v_atlas_glyph_size = glyph_atlas_size;
4153
v_atlas_size = frame_info.atlas_size;
4254
v_text_color = frame_info.text_color;
4355
}

impeller/renderer/backend/metal/render_pass_mtl.mm

+9
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,9 @@ static bool Bind(PassBindingsCache& pass,
399399
if (command.index_count == 0u) {
400400
continue;
401401
}
402+
if (command.instance_count == 0u) {
403+
continue;
404+
}
402405

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

516+
if (command.instance_count == 0u) {
517+
// Essentially a no-op. Don't record the command but this is not necessary
518+
// an error either.
519+
return true;
520+
}
521+
513522
commands_.emplace_back(std::move(command));
514523
return true;
515524
}

0 commit comments

Comments
 (0)