Avoid instancing/SSBOs for text to support GLES (flutter/engine#160)

This commit is contained in:
Dan Field 2022-04-25 14:12:44 -07:00 committed by Dan Field
parent 21088d20a8
commit bc34d52063
6 changed files with 52 additions and 98 deletions

View File

@ -106,65 +106,41 @@ bool TextContents::Render(const ContentContext& renderer,
// and the vertex shader uses this to size the glyph correctly. The
// interpolated vertex information is also used in the fragment shader to
// sample from the glyph atlas.
{
VertexBufferBuilder<VS::PerVertexData> vertex_builder;
if (!Tessellator{}.Tessellate(
FillType::kPositive,
PathBuilder{}
.AddRect(Rect::MakeXYWH(0.0, 0.0, 1.0, 1.0))
.TakePath()
.CreatePolyline(),
[&vertex_builder](Point point) {
VS::PerVertexData vtx;
vtx.unit_vertex = point;
vertex_builder.AppendVertex(std::move(vtx));
})) {
return false;
}
auto dummy = vertex_builder.CreateVertexBuffer(pass.GetTransientsBuffer());
auto vertex_buffer = dummy;
if (!vertex_buffer) {
return false;
}
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;
const std::vector<Point> unit_vertex_points = {
{0, 0}, {1, 0}, {0, 1}, {1, 0}, {0, 1}, {1, 1},
};
VertexBufferBuilder<VS::PerVertexData> vertex_builder;
for (const auto& run : frame_.GetRuns()) {
auto font = run.GetFont();
auto glyph_size = ISize::Ceil(font.GetMetrics().GetBoundingBox().size);
for (const auto& glyph_position : run.GetGlyphPositions()) {
FontGlyphPair font_glyph_pair{font, glyph_position.glyph};
auto atlas_glyph_pos = atlas->FindFontGlyphPosition(font_glyph_pair);
if (!atlas_glyph_pos.has_value()) {
VALIDATION_LOG << "Could not find glyph position in the atlas.";
return false;
for (const auto& point : unit_vertex_points) {
VS::PerVertexData vtx;
vtx.unit_vertex = point;
FontGlyphPair font_glyph_pair{font, glyph_position.glyph};
auto atlas_glyph_pos = atlas->FindFontGlyphPosition(font_glyph_pair);
if (!atlas_glyph_pos.has_value()) {
VALIDATION_LOG << "Could not find glyph position in the atlas.";
return false;
}
vtx.glyph_position =
glyph_position.position +
Point{font.GetMetrics().min_extent.x, font.GetMetrics().ascent};
vtx.glyph_size = Point{static_cast<Scalar>(glyph_size.width),
static_cast<Scalar>(glyph_size.height)};
vtx.atlas_position = atlas_glyph_pos->origin;
vtx.atlas_glyph_size =
Point{atlas_glyph_pos->size.width, atlas_glyph_pos->size.height};
vertex_builder.AppendVertex(std::move(vtx));
}
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});
}
}
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));
auto vertex_buffer =
vertex_builder.CreateVertexBuffer(pass.GetTransientsBuffer());
cmd.BindVertices(std::move(vertex_buffer));
if (!pass.AddCommand(cmd)) {
return false;

View File

@ -2,37 +2,17 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifdef IMPELLER_TARGET_OPENGLES
void main() {
// Unimplemented because the implementation uses instancing and SSBOs.
}
#else // IMPELLER_TARGET_OPENGLES
uniform FrameInfo {
mat4 mvp;
vec2 atlas_size;
vec4 text_color;
} frame_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;
in vec2 glyph_position;
in vec2 glyph_size;
in vec2 atlas_position;
in vec2 atlas_glyph_size;
out vec2 v_unit_vertex;
out vec2 v_atlas_position;
@ -41,26 +21,25 @@ out vec2 v_atlas_size;
out vec4 v_text_color;
void main() {
// 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_position
vec4 translate = frame_info.mvp[0] * glyph_position.x
+ frame_info.mvp[1] * glyph_position.y
+ frame_info.mvp[3];
mat4 translated_mvp = mat4(
frame_info.mvp[0],
frame_info.mvp[1],
frame_info.mvp[2],
vec4(
translate.xyz,
frame_info.mvp[3].w
)
);
gl_Position = translated_mvp
* 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_atlas_position;
v_atlas_glyph_size = glyph_atlas_size;
v_atlas_position = atlas_position;
v_atlas_glyph_size = atlas_glyph_size;
v_atlas_size = frame_info.atlas_size;
v_text_color = frame_info.text_color;
}
#endif // IMPELLER_TARGET_OPENGLES

View File

@ -52,8 +52,7 @@ TextFrame TextFrameFromTextBlob(sk_sp<SkTextBlob> blob, Scalar scale) {
// kFull_Positioning has two scalars per glyph.
const SkPoint* glyph_points = run.points();
const auto* point = glyph_points + i;
text_run.AddGlyph(glyphs[i],
Matrix::MakeTranslation({point->x(), point->y()}));
text_run.AddGlyph(glyphs[i], Point{point->x(), point->y()});
}
break;
case SkTextBlobRunIterator::kRSXform_Positioning:

View File

@ -16,8 +16,8 @@ std::optional<Rect> TextFrame::GetBounds() const {
for (const auto& run : runs_) {
const auto glyph_bounds = run.GetFont().GetMetrics().GetBoundingBox();
for (const auto& glyph_position : run.GetGlyphPositions()) {
Vector2 position = glyph_position.position * Vector2();
Rect glyph_rect = Rect(position + glyph_bounds.origin, glyph_bounds.size);
Rect glyph_rect = Rect(glyph_position.position + glyph_bounds.origin,
glyph_bounds.size);
result = result.has_value() ? result->Union(glyph_rect) : glyph_rect;
}
}

View File

@ -15,7 +15,7 @@ TextRun::TextRun(Font font) : font_(std::move(font)) {
TextRun::~TextRun() = default;
bool TextRun::AddGlyph(Glyph glyph, Matrix position) {
bool TextRun::AddGlyph(Glyph glyph, Point position) {
glyphs_.emplace_back(GlyphPosition{glyph, position});
return true;
}

View File

@ -20,9 +20,9 @@ class TextRun {
public:
struct GlyphPosition {
Glyph glyph;
Matrix position;
Point position;
GlyphPosition(Glyph p_glyph, Matrix p_position)
GlyphPosition(Glyph p_glyph, Point p_position)
: glyph(p_glyph), position(p_position) {}
};
@ -45,7 +45,7 @@ class TextRun {
///
/// @return If the glyph could be added to the run.
///
bool AddGlyph(Glyph glyph, Matrix position);
bool AddGlyph(Glyph glyph, Point position);
//----------------------------------------------------------------------------
/// @brief Get the number of glyphs in the run.