88#include < limits>
99
1010#include " third_party/skia/include/core/SkPath.h"
11+ #include " third_party/skia/include/core/SkSurface.h"
1112
1213namespace flow {
1314
@@ -17,6 +18,8 @@ static const size_t kMaxFrameMarkers = 8;
1718Stopwatch::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
2225Stopwatch::~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
155216CounterValues::CounterValues () : current_sample_(kMaxSamples - 1 ) {
0 commit comments