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

Commit 94cd992

Browse files
jonahwilliamsharryterkelsen
authored andcommitted
[Impeller] Reland: construct text frames on UI thread. (#46115)
Due to flutter/flutter#127500 , we can get in a state where enable-impeller is true but we're using Skia. We need to either fall back completely to Skia, make this configuration fatal, or remote the check ---------------- Conversion of SkTextBlobs to impeller::TextFrame objects is one of the most expensive operations in display list dispatching. While the rest of the engine and framework makes a reasonable attempt to cache the SkTextBlobs generated during paragraph construction, the design of the dl dispatcher means that these the Impeller backend will always reconstruct all text frames on each frame - even if the display list/picture that contained those text frames was unchanged. Removing this overhead is one of the goals of #45386 , however this patch is also fairly risky and will be difficult to land. As a more incremental solution, we can instead construct the impeller::TextFrame objects when performing paragraph painting and record them in the display list. This both moves the text frame construction to the UI thread and allows the framework/engine to cache unchanged text frames. This also does not conflict with the dl_aiks_canvas patch directly, and is fine to land before or after it does. (though I'd argue we should land this first). To compare the current performance levels, I ran the complex_layout_scroll perf test, since this is fairly text filled. On a Pixel 6 pro. Across several runs this is a fairly consistent ~1ms raster time improvement. Fixes flutter/flutter#133204
1 parent 6a5c3ef commit 94cd992

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+407
-121
lines changed

display_list/BUILD.gn

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ source_set("display_list") {
8787
public_deps = [
8888
"//flutter/fml",
8989
"//flutter/impeller/runtime_stage",
90+
"//flutter/impeller/typographer",
9091
"//third_party/skia",
9192
]
9293

display_list/benchmarking/dl_complexity_gl.cc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -637,6 +637,11 @@ void DisplayListGLComplexityCalculator::GLHelper::drawTextBlob(
637637
draw_text_blob_count_++;
638638
}
639639

640+
void DisplayListGLComplexityCalculator::GLHelper::drawTextFrame(
641+
const std::shared_ptr<impeller::TextFrame>& text_frame,
642+
SkScalar x,
643+
SkScalar y) {}
644+
640645
void DisplayListGLComplexityCalculator::GLHelper::drawShadow(
641646
const SkPath& path,
642647
const DlColor color,

display_list/benchmarking/dl_complexity_gl.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,9 @@ class DisplayListGLComplexityCalculator
7070
void drawTextBlob(const sk_sp<SkTextBlob> blob,
7171
SkScalar x,
7272
SkScalar y) override;
73+
void drawTextFrame(const std::shared_ptr<impeller::TextFrame>& text_frame,
74+
SkScalar x,
75+
SkScalar y) override;
7376
void drawShadow(const SkPath& path,
7477
const DlColor color,
7578
const SkScalar elevation,

display_list/benchmarking/dl_complexity_metal.cc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -581,6 +581,11 @@ void DisplayListMetalComplexityCalculator::MetalHelper::drawTextBlob(
581581
draw_text_blob_count_++;
582582
}
583583

584+
void DisplayListMetalComplexityCalculator::MetalHelper::drawTextFrame(
585+
const std::shared_ptr<impeller::TextFrame>& text_frame,
586+
SkScalar x,
587+
SkScalar y) {}
588+
584589
void DisplayListMetalComplexityCalculator::MetalHelper::drawShadow(
585590
const SkPath& path,
586591
const DlColor color,

display_list/benchmarking/dl_complexity_metal.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,9 @@ class DisplayListMetalComplexityCalculator
6868
void drawTextBlob(const sk_sp<SkTextBlob> blob,
6969
SkScalar x,
7070
SkScalar y) override;
71+
void drawTextFrame(const std::shared_ptr<impeller::TextFrame>& text_frame,
72+
SkScalar x,
73+
SkScalar y) override;
7174
void drawShadow(const SkPath& path,
7275
const DlColor color,
7376
const SkScalar elevation,

display_list/display_list.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ namespace flutter {
136136
\
137137
V(DrawDisplayList) \
138138
V(DrawTextBlob) \
139+
V(DrawTextFrame) \
139140
\
140141
V(DrawShadow) \
141142
V(DrawShadowTransparentOccluder)

display_list/dl_builder.cc

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1302,6 +1302,48 @@ void DisplayListBuilder::DrawTextBlob(const sk_sp<SkTextBlob>& blob,
13021302
SetAttributesFromPaint(paint, DisplayListOpFlags::kDrawTextBlobFlags);
13031303
drawTextBlob(blob, x, y);
13041304
}
1305+
1306+
void DisplayListBuilder::drawTextFrame(
1307+
const std::shared_ptr<impeller::TextFrame>& text_frame,
1308+
SkScalar x,
1309+
SkScalar y) {
1310+
DisplayListAttributeFlags flags = kDrawTextBlobFlags;
1311+
OpResult result = PaintResult(current_, flags);
1312+
if (result == OpResult::kNoEffect) {
1313+
return;
1314+
}
1315+
impeller::Rect bounds = text_frame->GetBounds();
1316+
SkRect sk_bounds = SkRect::MakeLTRB(bounds.GetLeft(), bounds.GetTop(),
1317+
bounds.GetRight(), bounds.GetBottom());
1318+
bool unclipped = AccumulateOpBounds(sk_bounds.makeOffset(x, y), flags);
1319+
// TODO(https://github.com/flutter/flutter/issues/82202): Remove once the
1320+
// unit tests can use Fuchsia's font manager instead of the empty default.
1321+
// Until then we might encounter empty bounds for otherwise valid text and
1322+
// thus we ignore the results from AccumulateOpBounds.
1323+
#if defined(OS_FUCHSIA)
1324+
unclipped = true;
1325+
#endif // OS_FUCHSIA
1326+
if (unclipped) {
1327+
Push<DrawTextFrameOp>(0, 1, text_frame, x, y);
1328+
// There is no way to query if the glyphs of a text blob overlap and
1329+
// there are no current guarantees from either Skia or Impeller that
1330+
// they will protect overlapping glyphs from the effects of overdraw
1331+
// so we must make the conservative assessment that this DL layer is
1332+
// not compatible with group opacity inheritance.
1333+
UpdateLayerOpacityCompatibility(false);
1334+
UpdateLayerResult(result);
1335+
}
1336+
}
1337+
1338+
void DisplayListBuilder::DrawTextFrame(
1339+
const std::shared_ptr<impeller::TextFrame>& text_frame,
1340+
SkScalar x,
1341+
SkScalar y,
1342+
const DlPaint& paint) {
1343+
SetAttributesFromPaint(paint, DisplayListOpFlags::kDrawTextBlobFlags);
1344+
drawTextFrame(text_frame, x, y);
1345+
}
1346+
13051347
void DisplayListBuilder::DrawShadow(const SkPath& path,
13061348
const DlColor color,
13071349
const SkScalar elevation,

display_list/dl_builder.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,16 @@ class DisplayListBuilder final : public virtual DlCanvas,
224224
SkScalar x,
225225
SkScalar y,
226226
const DlPaint& paint) override;
227+
228+
void drawTextFrame(const std::shared_ptr<impeller::TextFrame>& text_frame,
229+
SkScalar x,
230+
SkScalar y) override;
231+
232+
void DrawTextFrame(const std::shared_ptr<impeller::TextFrame>& text_frame,
233+
SkScalar x,
234+
SkScalar y,
235+
const DlPaint& paint) override;
236+
227237
// |DlCanvas|
228238
void DrawShadow(const SkPath& path,
229239
const DlColor color,

display_list/dl_canvas.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
#include "third_party/skia/include/core/SkRect.h"
1919
#include "third_party/skia/include/core/SkTextBlob.h"
2020

21+
#include "impeller/typographer/text_frame.h"
22+
2123
namespace flutter {
2224

2325
//------------------------------------------------------------------------------
@@ -201,6 +203,13 @@ class DlCanvas {
201203
const DlPaint* paint = nullptr) = 0;
202204
virtual void DrawDisplayList(const sk_sp<DisplayList> display_list,
203205
SkScalar opacity = SK_Scalar1) = 0;
206+
207+
virtual void DrawTextFrame(
208+
const std::shared_ptr<impeller::TextFrame>& text_frame,
209+
SkScalar x,
210+
SkScalar y,
211+
const DlPaint& paint) = 0;
212+
204213
virtual void DrawTextBlob(const sk_sp<SkTextBlob>& blob,
205214
SkScalar x,
206215
SkScalar y,

display_list/dl_op_receiver.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,10 @@ class DlOpReceiver {
257257
virtual void drawTextBlob(const sk_sp<SkTextBlob> blob,
258258
SkScalar x,
259259
SkScalar y) = 0;
260+
virtual void drawTextFrame(
261+
const std::shared_ptr<impeller::TextFrame>& text_frame,
262+
SkScalar x,
263+
SkScalar y) = 0;
260264
virtual void drawShadow(const SkPath& path,
261265
const DlColor color,
262266
const SkScalar elevation,

display_list/dl_op_records.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "flutter/display_list/effects/dl_color_source.h"
1313
#include "flutter/fml/macros.h"
1414

15+
#include "impeller/typographer/text_frame.h"
1516
#include "third_party/skia/include/core/SkRSXform.h"
1617

1718
namespace flutter {
@@ -1085,6 +1086,25 @@ struct DrawTextBlobOp final : DrawOpBase {
10851086
}
10861087
};
10871088

1089+
struct DrawTextFrameOp final : DrawOpBase {
1090+
static const auto kType = DisplayListOpType::kDrawTextFrame;
1091+
1092+
DrawTextFrameOp(const std::shared_ptr<impeller::TextFrame>& text_frame,
1093+
SkScalar x,
1094+
SkScalar y)
1095+
: x(x), y(y), text_frame(text_frame) {}
1096+
1097+
const SkScalar x;
1098+
const SkScalar y;
1099+
const std::shared_ptr<impeller::TextFrame> text_frame;
1100+
1101+
void dispatch(DispatchContext& ctx) const {
1102+
if (op_needed(ctx)) {
1103+
ctx.receiver.drawTextFrame(text_frame, x, y);
1104+
}
1105+
}
1106+
};
1107+
10881108
// 4 byte header + 28 byte payload packs evenly into 32 bytes
10891109
#define DEFINE_DRAW_SHADOW_OP(name, transparent_occluder) \
10901110
struct Draw##name##Op final : DrawOpBase { \

display_list/skia/dl_sk_canvas.cc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,14 @@ void DlSkCanvasAdapter::DrawTextBlob(const sk_sp<SkTextBlob>& blob,
325325
delegate_->drawTextBlob(blob, x, y, ToSk(paint));
326326
}
327327

328+
void DlSkCanvasAdapter::DrawTextFrame(
329+
const std::shared_ptr<impeller::TextFrame>& text_frame,
330+
SkScalar x,
331+
SkScalar y,
332+
const DlPaint& paint) {
333+
FML_CHECK(false);
334+
}
335+
328336
void DlSkCanvasAdapter::DrawShadow(const SkPath& path,
329337
const DlColor color,
330338
const SkScalar elevation,

display_list/skia/dl_sk_canvas.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
#include "flutter/display_list/dl_canvas.h"
99
#include "flutter/display_list/skia/dl_sk_types.h"
10+
#include "impeller/typographer/text_frame.h"
1011

1112
namespace flutter {
1213

@@ -144,6 +145,10 @@ class DlSkCanvasAdapter final : public virtual DlCanvas {
144145
SkScalar x,
145146
SkScalar y,
146147
const DlPaint& paint) override;
148+
void DrawTextFrame(const std::shared_ptr<impeller::TextFrame>& text_frame,
149+
SkScalar x,
150+
SkScalar y,
151+
const DlPaint& paint) override;
147152
void DrawShadow(const SkPath& path,
148153
const DlColor color,
149154
const SkScalar elevation,

display_list/skia/dl_sk_dispatcher.cc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,13 @@ void DlSkCanvasDispatcher::drawTextBlob(const sk_sp<SkTextBlob> blob,
270270
canvas_->drawTextBlob(blob, x, y, paint());
271271
}
272272

273+
void DlSkCanvasDispatcher::drawTextFrame(
274+
const std::shared_ptr<impeller::TextFrame>& text_frame,
275+
SkScalar x,
276+
SkScalar y) {
277+
FML_CHECK(false);
278+
}
279+
273280
void DlSkCanvasDispatcher::DrawShadow(SkCanvas* canvas,
274281
const SkPath& path,
275282
DlColor color,

display_list/skia/dl_sk_dispatcher.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,9 @@ class DlSkCanvasDispatcher : public virtual DlOpReceiver,
9898
void drawTextBlob(const sk_sp<SkTextBlob> blob,
9999
SkScalar x,
100100
SkScalar y) override;
101+
void drawTextFrame(const std::shared_ptr<impeller::TextFrame>& text_frame,
102+
SkScalar x,
103+
SkScalar y) override;
101104
void drawShadow(const SkPath& path,
102105
const DlColor color,
103106
const SkScalar elevation,

display_list/utils/dl_receiver_utils.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,9 @@ class IgnoreDrawDispatchHelper : public virtual DlOpReceiver {
129129
void drawTextBlob(const sk_sp<SkTextBlob> blob,
130130
SkScalar x,
131131
SkScalar y) override {}
132+
void drawTextFrame(const std::shared_ptr<impeller::TextFrame>& text_frame,
133+
SkScalar x,
134+
SkScalar y) override {}
132135
void drawShadow(const SkPath& path,
133136
const DlColor color,
134137
const SkScalar elevation,

flow/BUILD.gn

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,10 @@ source_set("flow") {
9999
deps = [ "//third_party/skia" ]
100100

101101
if (impeller_supports_rendering) {
102-
deps += [ "//flutter/impeller" ]
102+
deps += [
103+
"//flutter/impeller",
104+
"//flutter/impeller/typographer/backends/skia:typographer_skia_backend",
105+
]
103106
}
104107
}
105108

flow/layers/performance_overlay_layer.cc

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414
#include "flow/stopwatch_sk.h"
1515
#include "third_party/skia/include/core/SkFont.h"
1616
#include "third_party/skia/include/core/SkTextBlob.h"
17+
#ifdef IMPELLER_SUPPORTS_RENDERING
18+
#include "impeller/typographer/backends/skia/text_frame_skia.h" // nogncheck
19+
#endif // IMPELLER_SUPPORTS_RENDERING
1720

1821
namespace flutter {
1922
namespace {
@@ -50,7 +53,14 @@ void VisualizeStopWatch(DlCanvas* canvas,
5053
stopwatch, label_prefix, font_path);
5154
// Historically SK_ColorGRAY (== 0xFF888888) was used here
5255
DlPaint paint(DlColor(0xFF888888));
56+
#ifdef IMPELLER_SUPPORTS_RENDERING
57+
if (impeller_enabled) {
58+
canvas->DrawTextFrame(impeller::MakeTextFrameFromTextBlobSkia(text),
59+
x + label_x, y + height + label_y, paint);
60+
}
61+
#endif // IMPELLER_SUPPORTS_RENDERING
5362
canvas->DrawTextBlob(text, x + label_x, y + height + label_y, paint);
63+
return;
5464
}
5565
}
5666

impeller/aiks/aiks_unittests.cc

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
#include <array>
66
#include <cmath>
77
#include <cstdlib>
8-
#include <iostream>
98
#include <memory>
109
#include <tuple>
1110
#include <utility>
@@ -1335,11 +1334,7 @@ bool RenderTextInCanvasSkia(const std::shared_ptr<Context>& context,
13351334
}
13361335

13371336
// Create the Impeller text frame and draw it at the designated baseline.
1338-
auto maybe_frame = MakeTextFrameFromTextBlobSkia(blob);
1339-
if (!maybe_frame.has_value()) {
1340-
return false;
1341-
}
1342-
auto frame = maybe_frame.value();
1337+
auto frame = MakeTextFrameFromTextBlobSkia(blob);
13431338

13441339
Paint text_paint;
13451340
text_paint.color = Color::Yellow().WithAlpha(options.alpha);
@@ -1528,7 +1523,7 @@ TEST_P(AiksTest, CanRenderTextOutsideBoundaries) {
15281523
{
15291524
auto blob = SkTextBlob::MakeFromString(t.text, sk_font);
15301525
ASSERT_NE(blob, nullptr);
1531-
auto frame = MakeTextFrameFromTextBlobSkia(blob).value();
1526+
auto frame = MakeTextFrameFromTextBlobSkia(blob);
15321527
canvas.DrawTextFrame(frame, Point(), text_paint);
15331528
}
15341529
canvas.Restore();
@@ -3202,12 +3197,7 @@ TEST_P(AiksTest, TextForegroundShaderWithTransform) {
32023197

32033198
auto blob = SkTextBlob::MakeFromString("Hello", sk_font);
32043199
ASSERT_NE(blob, nullptr);
3205-
auto maybe_frame = MakeTextFrameFromTextBlobSkia(blob);
3206-
ASSERT_TRUE(maybe_frame.has_value());
3207-
if (!maybe_frame.has_value()) {
3208-
return;
3209-
}
3210-
auto frame = maybe_frame.value();
3200+
auto frame = MakeTextFrameFromTextBlobSkia(blob);
32113201
canvas.DrawTextFrame(frame, Point(), text_paint);
32123202

32133203
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));

impeller/aiks/canvas.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -546,15 +546,15 @@ void Canvas::SaveLayer(const Paint& paint,
546546
}
547547
}
548548

549-
void Canvas::DrawTextFrame(const TextFrame& text_frame,
549+
void Canvas::DrawTextFrame(const std::shared_ptr<TextFrame>& text_frame,
550550
Point position,
551551
const Paint& paint) {
552552
Entity entity;
553553
entity.SetStencilDepth(GetStencilDepth());
554554
entity.SetBlendMode(paint.blend_mode);
555555

556556
auto text_contents = std::make_shared<TextContents>();
557-
text_contents->SetTextFrame(TextFrame(text_frame));
557+
text_contents->SetTextFrame(text_frame);
558558
text_contents->SetColor(paint.color);
559559

560560
entity.SetTransformation(GetCurrentTransformation() *

impeller/aiks/canvas.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ class Canvas {
140140

141141
void DrawPicture(const Picture& picture);
142142

143-
void DrawTextFrame(const TextFrame& text_frame,
143+
void DrawTextFrame(const std::shared_ptr<TextFrame>& text_frame,
144144
Point position,
145145
const Paint& paint);
146146

0 commit comments

Comments
 (0)