Flutter Engine
The Flutter Engine
stopwatch_sk.cc
Go to the documentation of this file.
1// Copyright 2013 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "flutter/flow/stopwatch_sk.h"
10#include "include/core/SkSize.h"
12
13namespace flutter {
14
15static const size_t kMaxSamples = 120;
16static const size_t kMaxFrameMarkers = 8;
17
18void SkStopwatchVisualizer::InitVisualizeSurface(SkISize size) const {
19 // Mark as dirty if the size has changed.
20 if (visualize_cache_surface_) {
21 if (size.width() != visualize_cache_surface_->width() ||
22 size.height() != visualize_cache_surface_->height()) {
23 cache_dirty_ = true;
24 };
25 }
26
27 if (!cache_dirty_) {
28 return;
29 }
30 cache_dirty_ = false;
31
32 // TODO(garyq): Use a GPU surface instead of a CPU surface.
33 visualize_cache_surface_ =
35
36 SkCanvas* cache_canvas = visualize_cache_surface_->getCanvas();
37
38 // Establish the graph position.
39 const SkScalar x = 0;
40 const SkScalar y = 0;
41 const SkScalar width = size.width();
42 const SkScalar height = size.height();
43
45 paint.setColor(0x99FFFFFF);
46 cache_canvas->drawRect(SkRect::MakeXYWH(x, y, width, height), paint);
47
48 // Scale the graph to show frame times up to those that are 3 times the frame
49 // time.
50 const double one_frame_ms = GetFrameBudget().count();
51 const double max_interval = one_frame_ms * 3.0;
52 const double max_unit_interval = UnitFrameInterval(max_interval);
53
54 // Draw the old data to initially populate the graph.
55 // Prepare a path for the data. We start at the height of the last point, so
56 // it looks like we wrap around
58 path.setIsVolatile(true);
59 path.moveTo(x, height);
60 path.lineTo(
62 max_unit_interval)));
63 double unit_x;
64 double unit_next_x = 0.0;
65 for (size_t i = 0; i < kMaxSamples; i += 1) {
66 unit_x = unit_next_x;
67 unit_next_x = (static_cast<double>(i + 1) / kMaxSamples);
68 const double sample_y =
70 max_unit_interval));
71 path.lineTo(x + width * unit_x, sample_y);
72 path.lineTo(x + width * unit_next_x, sample_y);
73 }
74 path.lineTo(
75 width,
76 y + height *
77 (1.0 -
79 max_unit_interval)));
80 path.lineTo(width, height);
81 path.close();
82
83 // Draw the graph.
84 paint.setColor(0xAA0000FF);
85 cache_canvas->drawPath(path, paint);
86}
87
89 const SkRect& rect) const {
90 // Initialize visualize cache if it has not yet been initialized.
91 InitVisualizeSurface(SkISize::Make(rect.width(), rect.height()));
92
93 SkCanvas* cache_canvas = visualize_cache_surface_->getCanvas();
95
96 // Establish the graph position.
97 const SkScalar x = 0;
98 const SkScalar y = 0;
99 const SkScalar width = visualize_cache_surface_->width();
100 const SkScalar height = visualize_cache_surface_->height();
101
102 // Scale the graph to show frame times up to those that are 3 times the frame
103 // time.
104 const double one_frame_ms = GetFrameBudget().count();
105 const double max_interval = one_frame_ms * 3.0;
106 const double max_unit_interval = UnitFrameInterval(max_interval);
107
108 const double sample_unit_width = (1.0 / kMaxSamples);
109
110 // Draw vertical replacement bar to erase old/stale pixels.
111 paint.setColor(0x99FFFFFF);
112 paint.setStyle(SkPaint::Style::kFill_Style);
113 paint.setBlendMode(SkBlendMode::kSrc);
114 double sample_x =
115 x + width * (static_cast<double>(prev_drawn_sample_index_) / kMaxSamples);
116 const auto eraser_rect = SkRect::MakeLTRB(
117 sample_x, y, sample_x + width * sample_unit_width, height);
118 cache_canvas->drawRect(eraser_rect, paint);
119
120 // Draws blue timing bar for new data.
121 paint.setColor(0xAA0000FF);
122 paint.setBlendMode(SkBlendMode::kSrcOver);
123 const auto bar_rect = SkRect::MakeLTRB(
124 sample_x,
125 y + height *
126 (1.0 -
128 .GetLap(stopwatch_.GetCurrentSample() == 0
129 ? kMaxSamples - 1
131 .ToMillisecondsF(),
132 max_unit_interval)),
133 sample_x + width * sample_unit_width, height);
134 cache_canvas->drawRect(bar_rect, paint);
135
136 // Draw horizontal frame markers.
137 paint.setStrokeWidth(0); // hairline
138 paint.setStyle(SkPaint::Style::kStroke_Style);
139 paint.setColor(0xCC000000);
140
141 if (max_interval > one_frame_ms) {
142 // Paint the horizontal markers
143 size_t frame_marker_count =
144 static_cast<size_t>(max_interval / one_frame_ms);
145
146 // Limit the number of markers displayed. After a certain point, the graph
147 // becomes crowded
148 if (frame_marker_count > kMaxFrameMarkers) {
149 frame_marker_count = 1;
150 }
151
152 for (size_t frame_index = 0; frame_index < frame_marker_count;
153 frame_index++) {
154 const double frame_height =
155 height * (1.0 - (UnitFrameInterval((frame_index + 1) * one_frame_ms) /
156 max_unit_interval));
157 cache_canvas->drawLine(x, y + frame_height, width, y + frame_height,
158 paint);
159 }
160 }
161
162 // Paint the vertical marker for the current frame.
163 // We paint it over the current frame, not after it, because when we
164 // paint this we don't yet have all the times for the current frame.
165 paint.setStyle(SkPaint::Style::kFill_Style);
166 paint.setBlendMode(SkBlendMode::kSrcOver);
168 // budget exceeded
169 paint.setColor(SK_ColorRED);
170 } else {
171 // within budget
172 paint.setColor(SK_ColorGREEN);
173 }
174 sample_x = x + width * (static_cast<double>(stopwatch_.GetCurrentSample()) /
176 const auto marker_rect = SkRect::MakeLTRB(
177 sample_x, y, sample_x + width * sample_unit_width, height);
178 cache_canvas->drawRect(marker_rect, paint);
179 prev_drawn_sample_index_ = stopwatch_.GetCurrentSample();
180
181 // Draw the cached surface onto the output canvas.
182 auto image = DlImage::Make(visualize_cache_surface_->makeImageSnapshot());
183 canvas->DrawImage(image, {rect.x(), rect.y()},
185}
186
187} // namespace flutter
@ kSrcOver
r = s + (1-sa)*d
constexpr SkColor SK_ColorRED
Definition: SkColor.h:126
constexpr SkColor SK_ColorGREEN
Definition: SkColor.h:131
void drawRect(const SkRect &rect, const SkPaint &paint)
Definition: SkCanvas.cpp:1673
void drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint &paint)
Definition: SkCanvas.cpp:2700
void drawPath(const SkPath &path, const SkPaint &paint)
Definition: SkCanvas.cpp:1747
Definition: SkPath.h:59
SkCanvas * getCanvas()
Definition: SkSurface.cpp:82
int width() const
Definition: SkSurface.h:178
sk_sp< SkImage > makeImageSnapshot()
Definition: SkSurface.cpp:90
int height() const
Definition: SkSurface.h:184
Developer-facing API for rendering anything within the engine.
Definition: dl_canvas.h:38
virtual void DrawImage(const sk_sp< DlImage > &image, const SkPoint point, DlImageSampling sampling, const DlPaint *paint=nullptr)=0
static sk_sp< DlImage > Make(const SkImage *image)
Definition: dl_image.cc:11
void Visualize(DlCanvas *canvas, const SkRect &rect) const override
Renders the stopwatch as a graph.
Definition: stopwatch_sk.cc:88
double UnitHeight(double time_ms, double max_height) const
Converts a raster time to a unit height.
Definition: stopwatch.cc:61
const Stopwatch & stopwatch_
Definition: stopwatch.h:122
fml::Milliseconds GetFrameBudget() const
Definition: stopwatch.h:120
double UnitFrameInterval(double time_ms) const
Converts a raster time to a unit interval.
Definition: stopwatch.cc:57
const fml::TimeDelta & GetLap(size_t index) const
Definition: stopwatch.cc:45
const fml::TimeDelta & LastLap() const
Definition: stopwatch.cc:41
size_t GetCurrentSample() const
Definition: stopwatch.cc:53
constexpr double ToMillisecondsF() const
Definition: time_delta.h:68
const Paint & paint
Definition: color_source.cc:38
float SkScalar
Definition: extension.cpp:12
double y
double x
sk_sp< const SkImage > image
Definition: SkRecords.h:269
sk_sp< SkBlender > blender SkRect rect
Definition: SkRecords.h:350
SK_API sk_sp< SkSurface > Raster(const SkImageInfo &imageInfo, size_t rowBytes, const SkSurfaceProps *surfaceProps)
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir path
Definition: switches.h:57
static const size_t kMaxSamples
Definition: stopwatch.cc:9
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
static const size_t kMaxFrameMarkers
Definition: stopwatch_dl.cc:18
int32_t height
int32_t width
Definition: SkSize.h:16
static constexpr SkISize Make(int32_t w, int32_t h)
Definition: SkSize.h:20
static SkImageInfo MakeN32Premul(int width, int height)
static constexpr SkRect MakeXYWH(float x, float y, float w, float h)
Definition: SkRect.h:659
static constexpr SkRect MakeLTRB(float l, float t, float r, float b)
Definition: SkRect.h:646