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

Commit 838eb3d

Browse files
authored
Improve performance of performance overlay by caching. (#6225)
Cache a SkSurface with previously drawn shapes so that we do not need to draw them again in future frames. On Nexus 5X test device, old render time for just the overlay was 1.3ms-3.0ms and this version improves to 0.9ms-1.3ms running flutter gallery in profile mode.
1 parent 7ac3345 commit 838eb3d

File tree

2 files changed

+91
-23
lines changed

2 files changed

+91
-23
lines changed

flow/instrumentation.cc

Lines changed: 84 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <limits>
99

1010
#include "third_party/skia/include/core/SkPath.h"
11+
#include "third_party/skia/include/core/SkSurface.h"
1112

1213
namespace flow {
1314

@@ -17,6 +18,8 @@ static const size_t kMaxFrameMarkers = 8;
1718
Stopwatch::Stopwatch() : start_(fml::TimePoint::Now()), current_sample_(0) {
1819
const fml::TimeDelta delta = fml::TimeDelta::Zero();
1920
laps_.resize(kMaxSamples, delta);
21+
cache_dirty_ = true;
22+
prev_drawn_sample_index_ = 0;
2023
}
2124

2225
Stopwatch::~Stopwatch() = default;
@@ -60,32 +63,41 @@ fml::TimeDelta Stopwatch::MaxDelta() const {
6063
return max_delta;
6164
}
6265

63-
void Stopwatch::Visualize(SkCanvas& canvas, const SkRect& rect) const {
64-
SkPaint paint;
66+
// Initialize the SkSurface for drawing into. Draws the base background and any
67+
// timing data from before the initial Visualize() call.
68+
void Stopwatch::InitVisualizeSurface(const SkRect& rect) const {
69+
if (!cache_dirty_) {
70+
return;
71+
}
72+
cache_dirty_ = false;
6573

66-
// Paint the background.
67-
paint.setColor(0x99FFFFFF);
68-
canvas.drawRect(rect, paint);
74+
// TODO(garyq): Use a GPU surface instead of a CPU surface.
75+
visualize_cache_surface_ =
76+
SkSurface::MakeRasterN32Premul(rect.width(), rect.height());
77+
78+
SkCanvas* cache_canvas = visualize_cache_surface_->getCanvas();
6979

7080
// Establish the graph position.
71-
const SkScalar x = rect.x();
72-
const SkScalar y = rect.y();
81+
const SkScalar x = 0;
82+
const SkScalar y = 0;
7383
const SkScalar width = rect.width();
7484
const SkScalar height = rect.height();
75-
const SkScalar bottom = y + height;
76-
const SkScalar right = x + width;
85+
86+
SkPaint paint;
87+
paint.setColor(0x99FFFFFF);
88+
cache_canvas->drawRect(SkRect::MakeXYWH(x, y, width, height), paint);
7789

7890
// Scale the graph to show frame times up to those that are 3 times the frame
7991
// time.
8092
const double max_interval = kOneFrameMS * 3.0;
8193
const double max_unit_interval = UnitFrameInterval(max_interval);
8294

83-
// Prepare a path for the data.
84-
// we start at the height of the last point, so it looks like we wrap around
95+
// Draw the old data to initially populate the graph.
96+
// Prepare a path for the data. We start at the height of the last point, so
97+
// it looks like we wrap around
8598
SkPath path;
8699
path.setIsVolatile(true);
87-
const double sample_unit_width = (1.0 / kMaxSamples);
88-
path.moveTo(x, bottom);
100+
path.moveTo(x, height);
89101
path.lineTo(x, y + height * (1.0 - UnitHeight(laps_[0].ToMillisecondsF(),
90102
max_unit_interval)));
91103
double unit_x;
@@ -100,17 +112,61 @@ void Stopwatch::Visualize(SkCanvas& canvas, const SkRect& rect) const {
100112
path.lineTo(x + width * unit_next_x, sample_y);
101113
}
102114
path.lineTo(
103-
right,
115+
width,
104116
y + height * (1.0 - UnitHeight(laps_[kMaxSamples - 1].ToMillisecondsF(),
105117
max_unit_interval)));
106-
path.lineTo(right, bottom);
118+
path.lineTo(width, height);
107119
path.close();
108120

109121
// Draw the graph.
110122
paint.setColor(0xAA0000FF);
111-
canvas.drawPath(path, paint);
123+
cache_canvas->drawPath(path, paint);
124+
}
125+
126+
void Stopwatch::Visualize(SkCanvas& canvas, const SkRect& rect) const {
127+
// Initialize visualize cache if it has not yet been initialized.
128+
InitVisualizeSurface(rect);
112129

113-
// Draw horizontal markers.
130+
SkCanvas* cache_canvas = visualize_cache_surface_->getCanvas();
131+
SkPaint paint;
132+
133+
// Establish the graph position.
134+
const SkScalar x = 0;
135+
const SkScalar y = 0;
136+
const SkScalar width = rect.width();
137+
const SkScalar height = rect.height();
138+
139+
// Scale the graph to show frame times up to those that are 3 times the frame
140+
// time.
141+
const double max_interval = kOneFrameMS * 3.0;
142+
const double max_unit_interval = UnitFrameInterval(max_interval);
143+
144+
const double sample_unit_width = (1.0 / kMaxSamples);
145+
146+
// Draw vertical replacement bar to erase old/stale pixels.
147+
paint.setColor(0x99FFFFFF);
148+
paint.setStyle(SkPaint::Style::kFill_Style);
149+
paint.setBlendMode(SkBlendMode::kSrc);
150+
double sample_x =
151+
x + width * (static_cast<double>(prev_drawn_sample_index_) / kMaxSamples);
152+
const auto eraser_rect = SkRect::MakeLTRB(
153+
sample_x, y, sample_x + width * sample_unit_width, height);
154+
cache_canvas->drawRect(eraser_rect, paint);
155+
156+
// Draws blue timing bar for new data.
157+
paint.setColor(0xAA0000FF);
158+
paint.setBlendMode(SkBlendMode::kSrcOver);
159+
const auto bar_rect = SkRect::MakeLTRB(
160+
sample_x,
161+
y + height * (1.0 -
162+
UnitHeight(laps_[current_sample_ == 0 ? kMaxSamples - 1
163+
: current_sample_ - 1]
164+
.ToMillisecondsF(),
165+
max_unit_interval)),
166+
sample_x + width * sample_unit_width, height);
167+
cache_canvas->drawRect(bar_rect, paint);
168+
169+
// Draw horizontal frame markers.
114170
paint.setStrokeWidth(0); // hairline
115171
paint.setStyle(SkPaint::Style::kStroke_Style);
116172
paint.setColor(0xCC000000);
@@ -129,27 +185,32 @@ void Stopwatch::Visualize(SkCanvas& canvas, const SkRect& rect) const {
129185
const double frame_height =
130186
height * (1.0 - (UnitFrameInterval((frame_index + 1) * kOneFrameMS) /
131187
max_unit_interval));
132-
canvas.drawLine(x, y + frame_height, right, y + frame_height, paint);
188+
cache_canvas->drawLine(x, y + frame_height, width, y + frame_height,
189+
paint);
133190
}
134191
}
135192

136193
// Paint the vertical marker for the current frame.
137194
// We paint it over the current frame, not after it, because when we
138195
// paint this we don't yet have all the times for the current frame.
139196
paint.setStyle(SkPaint::Style::kFill_Style);
197+
paint.setBlendMode(SkBlendMode::kSrcOver);
140198
if (UnitFrameInterval(LastLap().ToMillisecondsF()) > 1.0) {
141199
// budget exceeded
142200
paint.setColor(SK_ColorRED);
143201
} else {
144202
// within budget
145203
paint.setColor(SK_ColorGREEN);
146204
}
147-
double sample_x =
148-
x + width * (static_cast<double>(current_sample_) / kMaxSamples);
149-
205+
sample_x = x + width * (static_cast<double>(current_sample_) / kMaxSamples);
150206
const auto marker_rect = SkRect::MakeLTRB(
151-
sample_x, y, sample_x + width * sample_unit_width, bottom);
152-
canvas.drawRect(marker_rect, paint);
207+
sample_x, y, sample_x + width * sample_unit_width, height);
208+
cache_canvas->drawRect(marker_rect, paint);
209+
prev_drawn_sample_index_ = current_sample_;
210+
211+
// Draw the cached surface onto the output canvas.
212+
paint.reset();
213+
visualize_cache_surface_->draw(&canvas, rect.x(), rect.y(), &paint);
153214
}
154215

155216
CounterValues::CounterValues() : current_sample_(kMaxSamples - 1) {

flow/instrumentation.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ class Stopwatch {
2828

2929
fml::TimeDelta MaxDelta() const;
3030

31+
void InitVisualizeSurface(const SkRect& rect) const;
32+
3133
void Visualize(SkCanvas& canvas, const SkRect& rect) const;
3234

3335
void Start();
@@ -40,6 +42,11 @@ class Stopwatch {
4042
fml::TimePoint start_;
4143
std::vector<fml::TimeDelta> laps_;
4244
size_t current_sample_;
45+
// Mutable data cache for performance optimization of the graphs. Prevents
46+
// expensive redrawing of old data.
47+
mutable bool cache_dirty_;
48+
mutable sk_sp<SkSurface> visualize_cache_surface_;
49+
mutable size_t prev_drawn_sample_index_;
4350

4451
FML_DISALLOW_COPY_AND_ASSIGN(Stopwatch);
4552
};

0 commit comments

Comments
 (0)