mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Refactor Stopwatch into StopwatchVisualizer and SkStopwatchVisualizer (flutter/engine#45200)
Partial work towards https://github.com/flutter/flutter/issues/126009. Still working as before: <img width="1210" alt="Screenshot 2023-08-28 at 6 32 45 PM" src="https://github.com/flutter/engine/assets/168174/38728015-d0d4-4933-bd31-d2326c76aeee"> (There are some `PerformanceOverlayLayerDefault.*` tests that don't run locally, so I guess I'll let CI run those)
This commit is contained in:
parent
9ea8a110c7
commit
b3bb59e4b5
@ -846,6 +846,8 @@ ORIGIN: ../../../flutter/flow/raster_cache_util.h + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/flow/skia_gpu_object.h + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/flow/stopwatch.cc + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/flow/stopwatch.h + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/flow/stopwatch_sk.cc + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/flow/stopwatch_sk.h + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/flow/surface.cc + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/flow/surface.h + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/flow/surface_frame.cc + ../../../flutter/LICENSE
|
||||
@ -3592,6 +3594,8 @@ FILE: ../../../flutter/flow/raster_cache_util.h
|
||||
FILE: ../../../flutter/flow/skia_gpu_object.h
|
||||
FILE: ../../../flutter/flow/stopwatch.cc
|
||||
FILE: ../../../flutter/flow/stopwatch.h
|
||||
FILE: ../../../flutter/flow/stopwatch_sk.cc
|
||||
FILE: ../../../flutter/flow/stopwatch_sk.h
|
||||
FILE: ../../../flutter/flow/surface.cc
|
||||
FILE: ../../../flutter/flow/surface.h
|
||||
FILE: ../../../flutter/flow/surface_frame.cc
|
||||
|
||||
@ -77,6 +77,8 @@ source_set("flow") {
|
||||
"skia_gpu_object.h",
|
||||
"stopwatch.cc",
|
||||
"stopwatch.h",
|
||||
"stopwatch_sk.cc",
|
||||
"stopwatch_sk.h",
|
||||
"surface.cc",
|
||||
"surface.h",
|
||||
"surface_frame.cc",
|
||||
|
||||
@ -8,6 +8,7 @@
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include "flow/stopwatch_sk.h"
|
||||
#include "third_party/skia/include/core/SkFont.h"
|
||||
#include "third_party/skia/include/core/SkTextBlob.h"
|
||||
|
||||
@ -29,7 +30,11 @@ void VisualizeStopWatch(DlCanvas* canvas,
|
||||
|
||||
if (show_graph) {
|
||||
SkRect visualization_rect = SkRect::MakeXYWH(x, y, width, height);
|
||||
stopwatch.Visualize(canvas, visualization_rect);
|
||||
|
||||
// TODO(matanlurey): Select a visualizer based on the current backend.
|
||||
// https://github.com/flutter/flutter/issues/126009
|
||||
SkStopwatchVisualizer visualizer = SkStopwatchVisualizer(stopwatch);
|
||||
visualizer.Visualize(canvas, visualization_rect);
|
||||
}
|
||||
|
||||
if (show_labels) {
|
||||
|
||||
@ -4,14 +4,9 @@
|
||||
|
||||
#include "flutter/flow/stopwatch.h"
|
||||
|
||||
#include "include/core/SkCanvas.h"
|
||||
#include "third_party/skia/include/core/SkPath.h"
|
||||
#include "third_party/skia/include/core/SkSurface.h"
|
||||
|
||||
namespace flutter {
|
||||
|
||||
static const size_t kMaxSamples = 120;
|
||||
static const size_t kMaxFrameMarkers = 8;
|
||||
|
||||
Stopwatch::Stopwatch(const RefreshRateUpdater& updater)
|
||||
: refresh_rate_updater_(updater),
|
||||
@ -19,8 +14,6 @@ Stopwatch::Stopwatch(const RefreshRateUpdater& updater)
|
||||
current_sample_(0) {
|
||||
const fml::TimeDelta delta = fml::TimeDelta::Zero();
|
||||
laps_.resize(kMaxSamples, delta);
|
||||
cache_dirty_ = true;
|
||||
prev_drawn_sample_index_ = 0;
|
||||
}
|
||||
|
||||
Stopwatch::~Stopwatch() = default;
|
||||
@ -51,12 +44,20 @@ const fml::TimeDelta& Stopwatch::LastLap() const {
|
||||
return laps_[(current_sample_ - 1) % kMaxSamples];
|
||||
}
|
||||
|
||||
double Stopwatch::UnitFrameInterval(double raster_time_ms) const {
|
||||
return raster_time_ms / GetFrameBudget().count();
|
||||
const fml::TimeDelta& Stopwatch::GetLap(size_t index) const {
|
||||
return laps_[index];
|
||||
}
|
||||
|
||||
double Stopwatch::UnitHeight(double raster_time_ms,
|
||||
double max_unit_interval) const {
|
||||
size_t Stopwatch::GetCurrentSample() const {
|
||||
return current_sample_;
|
||||
}
|
||||
|
||||
double StopwatchVisualizer::UnitFrameInterval(double raster_time_ms) const {
|
||||
return raster_time_ms / stopwatch_.GetFrameBudget().count();
|
||||
}
|
||||
|
||||
double StopwatchVisualizer::UnitHeight(double raster_time_ms,
|
||||
double max_unit_interval) const {
|
||||
double unit_height = UnitFrameInterval(raster_time_ms) / max_unit_interval;
|
||||
if (unit_height > 1.0) {
|
||||
unit_height = 1.0;
|
||||
@ -82,169 +83,6 @@ fml::TimeDelta Stopwatch::AverageDelta() const {
|
||||
return sum / kMaxSamples;
|
||||
}
|
||||
|
||||
// Initialize the SkSurface for drawing into. Draws the base background and any
|
||||
// timing data from before the initial Visualize() call.
|
||||
void Stopwatch::InitVisualizeSurface(SkISize size) const {
|
||||
// Mark as dirty if the size has changed.
|
||||
if (visualize_cache_surface_) {
|
||||
if (size.width() != visualize_cache_surface_->width() ||
|
||||
size.height() != visualize_cache_surface_->height()) {
|
||||
cache_dirty_ = true;
|
||||
};
|
||||
}
|
||||
|
||||
if (!cache_dirty_) {
|
||||
return;
|
||||
}
|
||||
cache_dirty_ = false;
|
||||
|
||||
// TODO(garyq): Use a GPU surface instead of a CPU surface.
|
||||
visualize_cache_surface_ =
|
||||
SkSurfaces::Raster(SkImageInfo::MakeN32Premul(size));
|
||||
|
||||
SkCanvas* cache_canvas = visualize_cache_surface_->getCanvas();
|
||||
|
||||
// Establish the graph position.
|
||||
const SkScalar x = 0;
|
||||
const SkScalar y = 0;
|
||||
const SkScalar width = size.width();
|
||||
const SkScalar height = size.height();
|
||||
|
||||
SkPaint paint;
|
||||
paint.setColor(0x99FFFFFF);
|
||||
cache_canvas->drawRect(SkRect::MakeXYWH(x, y, width, height), paint);
|
||||
|
||||
// Scale the graph to show frame times up to those that are 3 times the frame
|
||||
// time.
|
||||
const double one_frame_ms = GetFrameBudget().count();
|
||||
const double max_interval = one_frame_ms * 3.0;
|
||||
const double max_unit_interval = UnitFrameInterval(max_interval);
|
||||
|
||||
// Draw the old data to initially populate the graph.
|
||||
// Prepare a path for the data. We start at the height of the last point, so
|
||||
// it looks like we wrap around
|
||||
SkPath path;
|
||||
path.setIsVolatile(true);
|
||||
path.moveTo(x, height);
|
||||
path.lineTo(x, y + height * (1.0 - UnitHeight(laps_[0].ToMillisecondsF(),
|
||||
max_unit_interval)));
|
||||
double unit_x;
|
||||
double unit_next_x = 0.0;
|
||||
for (size_t i = 0; i < kMaxSamples; i += 1) {
|
||||
unit_x = unit_next_x;
|
||||
unit_next_x = (static_cast<double>(i + 1) / kMaxSamples);
|
||||
const double sample_y =
|
||||
y + height * (1.0 - UnitHeight(laps_[i].ToMillisecondsF(),
|
||||
max_unit_interval));
|
||||
path.lineTo(x + width * unit_x, sample_y);
|
||||
path.lineTo(x + width * unit_next_x, sample_y);
|
||||
}
|
||||
path.lineTo(
|
||||
width,
|
||||
y + height * (1.0 - UnitHeight(laps_[kMaxSamples - 1].ToMillisecondsF(),
|
||||
max_unit_interval)));
|
||||
path.lineTo(width, height);
|
||||
path.close();
|
||||
|
||||
// Draw the graph.
|
||||
paint.setColor(0xAA0000FF);
|
||||
cache_canvas->drawPath(path, paint);
|
||||
}
|
||||
|
||||
void Stopwatch::Visualize(DlCanvas* canvas, const SkRect& rect) const {
|
||||
// Initialize visualize cache if it has not yet been initialized.
|
||||
InitVisualizeSurface(SkISize::Make(rect.width(), rect.height()));
|
||||
|
||||
SkCanvas* cache_canvas = visualize_cache_surface_->getCanvas();
|
||||
SkPaint paint;
|
||||
|
||||
// Establish the graph position.
|
||||
const SkScalar x = 0;
|
||||
const SkScalar y = 0;
|
||||
const SkScalar width = visualize_cache_surface_->width();
|
||||
const SkScalar height = visualize_cache_surface_->height();
|
||||
|
||||
// Scale the graph to show frame times up to those that are 3 times the frame
|
||||
// time.
|
||||
const double one_frame_ms = GetFrameBudget().count();
|
||||
const double max_interval = one_frame_ms * 3.0;
|
||||
const double max_unit_interval = UnitFrameInterval(max_interval);
|
||||
|
||||
const double sample_unit_width = (1.0 / kMaxSamples);
|
||||
|
||||
// Draw vertical replacement bar to erase old/stale pixels.
|
||||
paint.setColor(0x99FFFFFF);
|
||||
paint.setStyle(SkPaint::Style::kFill_Style);
|
||||
paint.setBlendMode(SkBlendMode::kSrc);
|
||||
double sample_x =
|
||||
x + width * (static_cast<double>(prev_drawn_sample_index_) / kMaxSamples);
|
||||
const auto eraser_rect = SkRect::MakeLTRB(
|
||||
sample_x, y, sample_x + width * sample_unit_width, height);
|
||||
cache_canvas->drawRect(eraser_rect, paint);
|
||||
|
||||
// Draws blue timing bar for new data.
|
||||
paint.setColor(0xAA0000FF);
|
||||
paint.setBlendMode(SkBlendMode::kSrcOver);
|
||||
const auto bar_rect = SkRect::MakeLTRB(
|
||||
sample_x,
|
||||
y + height * (1.0 -
|
||||
UnitHeight(laps_[current_sample_ == 0 ? kMaxSamples - 1
|
||||
: current_sample_ - 1]
|
||||
.ToMillisecondsF(),
|
||||
max_unit_interval)),
|
||||
sample_x + width * sample_unit_width, height);
|
||||
cache_canvas->drawRect(bar_rect, paint);
|
||||
|
||||
// Draw horizontal frame markers.
|
||||
paint.setStrokeWidth(0); // hairline
|
||||
paint.setStyle(SkPaint::Style::kStroke_Style);
|
||||
paint.setColor(0xCC000000);
|
||||
|
||||
if (max_interval > one_frame_ms) {
|
||||
// Paint the horizontal markers
|
||||
size_t frame_marker_count =
|
||||
static_cast<size_t>(max_interval / one_frame_ms);
|
||||
|
||||
// Limit the number of markers displayed. After a certain point, the graph
|
||||
// becomes crowded
|
||||
if (frame_marker_count > kMaxFrameMarkers) {
|
||||
frame_marker_count = 1;
|
||||
}
|
||||
|
||||
for (size_t frame_index = 0; frame_index < frame_marker_count;
|
||||
frame_index++) {
|
||||
const double frame_height =
|
||||
height * (1.0 - (UnitFrameInterval((frame_index + 1) * one_frame_ms) /
|
||||
max_unit_interval));
|
||||
cache_canvas->drawLine(x, y + frame_height, width, y + frame_height,
|
||||
paint);
|
||||
}
|
||||
}
|
||||
|
||||
// Paint the vertical marker for the current frame.
|
||||
// We paint it over the current frame, not after it, because when we
|
||||
// paint this we don't yet have all the times for the current frame.
|
||||
paint.setStyle(SkPaint::Style::kFill_Style);
|
||||
paint.setBlendMode(SkBlendMode::kSrcOver);
|
||||
if (UnitFrameInterval(LastLap().ToMillisecondsF()) > 1.0) {
|
||||
// budget exceeded
|
||||
paint.setColor(SK_ColorRED);
|
||||
} else {
|
||||
// within budget
|
||||
paint.setColor(SK_ColorGREEN);
|
||||
}
|
||||
sample_x = x + width * (static_cast<double>(current_sample_) / kMaxSamples);
|
||||
const auto marker_rect = SkRect::MakeLTRB(
|
||||
sample_x, y, sample_x + width * sample_unit_width, height);
|
||||
cache_canvas->drawRect(marker_rect, paint);
|
||||
prev_drawn_sample_index_ = current_sample_;
|
||||
|
||||
// Draw the cached surface onto the output canvas.
|
||||
auto image = DlImage::Make(visualize_cache_surface_->makeImageSnapshot());
|
||||
canvas->DrawImage(image, {rect.x(), rect.y()},
|
||||
DlImageSampling::kNearestNeighbor);
|
||||
}
|
||||
|
||||
fml::Milliseconds Stopwatch::GetFrameBudget() const {
|
||||
return refresh_rate_updater_.GetFrameBudget();
|
||||
}
|
||||
|
||||
@ -12,8 +12,6 @@
|
||||
#include "flutter/fml/time/time_delta.h"
|
||||
#include "flutter/fml/time/time_point.h"
|
||||
|
||||
#include "third_party/skia/include/core/SkSurface.h"
|
||||
|
||||
namespace flutter {
|
||||
|
||||
class Stopwatch {
|
||||
@ -32,16 +30,16 @@ class Stopwatch {
|
||||
|
||||
~Stopwatch();
|
||||
|
||||
const fml::TimeDelta& GetLap(size_t index) const;
|
||||
|
||||
size_t GetCurrentSample() const;
|
||||
|
||||
const fml::TimeDelta& LastLap() const;
|
||||
|
||||
fml::TimeDelta MaxDelta() const;
|
||||
|
||||
fml::TimeDelta AverageDelta() const;
|
||||
|
||||
void InitVisualizeSurface(SkISize size) const;
|
||||
|
||||
void Visualize(DlCanvas* canvas, const SkRect& rect) const;
|
||||
|
||||
void Start();
|
||||
|
||||
void Stop();
|
||||
@ -52,20 +50,11 @@ class Stopwatch {
|
||||
fml::Milliseconds GetFrameBudget() const;
|
||||
|
||||
private:
|
||||
inline double UnitFrameInterval(double time_ms) const;
|
||||
inline double UnitHeight(double time_ms, double max_height) const;
|
||||
|
||||
const RefreshRateUpdater& refresh_rate_updater_;
|
||||
fml::TimePoint start_;
|
||||
std::vector<fml::TimeDelta> laps_;
|
||||
size_t current_sample_;
|
||||
|
||||
// Mutable data cache for performance optimization of the graphs. Prevents
|
||||
// expensive redrawing of old data.
|
||||
mutable bool cache_dirty_;
|
||||
mutable sk_sp<SkSurface> visualize_cache_surface_;
|
||||
mutable size_t prev_drawn_sample_index_;
|
||||
|
||||
FML_DISALLOW_COPY_AND_ASSIGN(Stopwatch);
|
||||
};
|
||||
|
||||
@ -91,6 +80,38 @@ class FixedRefreshRateStopwatch : public Stopwatch {
|
||||
FixedRefreshRateUpdater fixed_delegate_;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// @brief Abstract class for visualizing (i.e. drawing) a stopwatch.
|
||||
///
|
||||
/// @note This was originally folded into the |Stopwatch| class, but
|
||||
/// was separated out to make it easier to change the underlying
|
||||
/// implementation (which relied directly on Skia, not showing on
|
||||
/// Impeller: https://github.com/flutter/flutter/issues/126009).
|
||||
class StopwatchVisualizer {
|
||||
public:
|
||||
explicit StopwatchVisualizer(const Stopwatch& stopwatch)
|
||||
: stopwatch_(stopwatch) {}
|
||||
|
||||
virtual ~StopwatchVisualizer() = default;
|
||||
|
||||
/// @brief Renders the stopwatch as a graph.
|
||||
///
|
||||
/// @param canvas The canvas to draw on.
|
||||
/// @param[in] rect The rectangle to draw in.
|
||||
virtual void Visualize(DlCanvas* canvas, const SkRect& rect) const = 0;
|
||||
|
||||
FML_DISALLOW_COPY_AND_ASSIGN(StopwatchVisualizer);
|
||||
|
||||
protected:
|
||||
/// @brief Converts a raster time to a unit interval.
|
||||
double UnitFrameInterval(double time_ms) const;
|
||||
|
||||
/// @brief Converts a raster time to a unit height.
|
||||
double UnitHeight(double time_ms, double max_height) const;
|
||||
|
||||
const Stopwatch& stopwatch_;
|
||||
};
|
||||
|
||||
} // namespace flutter
|
||||
|
||||
#endif // FLUTTER_FLOW_INSTRUMENTATION_H_
|
||||
|
||||
187
engine/src/flutter/flow/stopwatch_sk.cc
Normal file
187
engine/src/flutter/flow/stopwatch_sk.cc
Normal file
@ -0,0 +1,187 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "flutter/flow/stopwatch_sk.h"
|
||||
#include "include/core/SkCanvas.h"
|
||||
#include "include/core/SkImageInfo.h"
|
||||
#include "include/core/SkPaint.h"
|
||||
#include "include/core/SkPath.h"
|
||||
#include "include/core/SkSize.h"
|
||||
#include "include/core/SkSurface.h"
|
||||
|
||||
namespace flutter {
|
||||
|
||||
static const size_t kMaxSamples = 120;
|
||||
static const size_t kMaxFrameMarkers = 8;
|
||||
|
||||
void SkStopwatchVisualizer::InitVisualizeSurface(SkISize size) const {
|
||||
// Mark as dirty if the size has changed.
|
||||
if (visualize_cache_surface_) {
|
||||
if (size.width() != visualize_cache_surface_->width() ||
|
||||
size.height() != visualize_cache_surface_->height()) {
|
||||
cache_dirty_ = true;
|
||||
};
|
||||
}
|
||||
|
||||
if (!cache_dirty_) {
|
||||
return;
|
||||
}
|
||||
cache_dirty_ = false;
|
||||
|
||||
// TODO(garyq): Use a GPU surface instead of a CPU surface.
|
||||
visualize_cache_surface_ =
|
||||
SkSurfaces::Raster(SkImageInfo::MakeN32Premul(size));
|
||||
|
||||
SkCanvas* cache_canvas = visualize_cache_surface_->getCanvas();
|
||||
|
||||
// Establish the graph position.
|
||||
const SkScalar x = 0;
|
||||
const SkScalar y = 0;
|
||||
const SkScalar width = size.width();
|
||||
const SkScalar height = size.height();
|
||||
|
||||
SkPaint paint;
|
||||
paint.setColor(0x99FFFFFF);
|
||||
cache_canvas->drawRect(SkRect::MakeXYWH(x, y, width, height), paint);
|
||||
|
||||
// Scale the graph to show frame times up to those that are 3 times the frame
|
||||
// time.
|
||||
const double one_frame_ms = stopwatch_.GetFrameBudget().count();
|
||||
const double max_interval = one_frame_ms * 3.0;
|
||||
const double max_unit_interval = UnitFrameInterval(max_interval);
|
||||
|
||||
// Draw the old data to initially populate the graph.
|
||||
// Prepare a path for the data. We start at the height of the last point, so
|
||||
// it looks like we wrap around
|
||||
SkPath path;
|
||||
path.setIsVolatile(true);
|
||||
path.moveTo(x, height);
|
||||
path.lineTo(
|
||||
x, y + height * (1.0 - UnitHeight(stopwatch_.GetLap(0).ToMillisecondsF(),
|
||||
max_unit_interval)));
|
||||
double unit_x;
|
||||
double unit_next_x = 0.0;
|
||||
for (size_t i = 0; i < kMaxSamples; i += 1) {
|
||||
unit_x = unit_next_x;
|
||||
unit_next_x = (static_cast<double>(i + 1) / kMaxSamples);
|
||||
const double sample_y =
|
||||
y + height * (1.0 - UnitHeight(stopwatch_.GetLap(i).ToMillisecondsF(),
|
||||
max_unit_interval));
|
||||
path.lineTo(x + width * unit_x, sample_y);
|
||||
path.lineTo(x + width * unit_next_x, sample_y);
|
||||
}
|
||||
path.lineTo(
|
||||
width,
|
||||
y + height *
|
||||
(1.0 -
|
||||
UnitHeight(stopwatch_.GetLap(kMaxSamples - 1).ToMillisecondsF(),
|
||||
max_unit_interval)));
|
||||
path.lineTo(width, height);
|
||||
path.close();
|
||||
|
||||
// Draw the graph.
|
||||
paint.setColor(0xAA0000FF);
|
||||
cache_canvas->drawPath(path, paint);
|
||||
}
|
||||
|
||||
void SkStopwatchVisualizer::Visualize(DlCanvas* canvas,
|
||||
const SkRect& rect) const {
|
||||
// Initialize visualize cache if it has not yet been initialized.
|
||||
InitVisualizeSurface(SkISize::Make(rect.width(), rect.height()));
|
||||
|
||||
SkCanvas* cache_canvas = visualize_cache_surface_->getCanvas();
|
||||
SkPaint paint;
|
||||
|
||||
// Establish the graph position.
|
||||
const SkScalar x = 0;
|
||||
const SkScalar y = 0;
|
||||
const SkScalar width = visualize_cache_surface_->width();
|
||||
const SkScalar height = visualize_cache_surface_->height();
|
||||
|
||||
// Scale the graph to show frame times up to those that are 3 times the frame
|
||||
// time.
|
||||
const double one_frame_ms = stopwatch_.GetFrameBudget().count();
|
||||
const double max_interval = one_frame_ms * 3.0;
|
||||
const double max_unit_interval = UnitFrameInterval(max_interval);
|
||||
|
||||
const double sample_unit_width = (1.0 / kMaxSamples);
|
||||
|
||||
// Draw vertical replacement bar to erase old/stale pixels.
|
||||
paint.setColor(0x99FFFFFF);
|
||||
paint.setStyle(SkPaint::Style::kFill_Style);
|
||||
paint.setBlendMode(SkBlendMode::kSrc);
|
||||
double sample_x =
|
||||
x + width * (static_cast<double>(prev_drawn_sample_index_) / kMaxSamples);
|
||||
const auto eraser_rect = SkRect::MakeLTRB(
|
||||
sample_x, y, sample_x + width * sample_unit_width, height);
|
||||
cache_canvas->drawRect(eraser_rect, paint);
|
||||
|
||||
// Draws blue timing bar for new data.
|
||||
paint.setColor(0xAA0000FF);
|
||||
paint.setBlendMode(SkBlendMode::kSrcOver);
|
||||
const auto bar_rect = SkRect::MakeLTRB(
|
||||
sample_x,
|
||||
y + height *
|
||||
(1.0 -
|
||||
UnitHeight(stopwatch_
|
||||
.GetLap(stopwatch_.GetCurrentSample() == 0
|
||||
? kMaxSamples - 1
|
||||
: stopwatch_.GetCurrentSample() - 1)
|
||||
.ToMillisecondsF(),
|
||||
max_unit_interval)),
|
||||
sample_x + width * sample_unit_width, height);
|
||||
cache_canvas->drawRect(bar_rect, paint);
|
||||
|
||||
// Draw horizontal frame markers.
|
||||
paint.setStrokeWidth(0); // hairline
|
||||
paint.setStyle(SkPaint::Style::kStroke_Style);
|
||||
paint.setColor(0xCC000000);
|
||||
|
||||
if (max_interval > one_frame_ms) {
|
||||
// Paint the horizontal markers
|
||||
size_t frame_marker_count =
|
||||
static_cast<size_t>(max_interval / one_frame_ms);
|
||||
|
||||
// Limit the number of markers displayed. After a certain point, the graph
|
||||
// becomes crowded
|
||||
if (frame_marker_count > kMaxFrameMarkers) {
|
||||
frame_marker_count = 1;
|
||||
}
|
||||
|
||||
for (size_t frame_index = 0; frame_index < frame_marker_count;
|
||||
frame_index++) {
|
||||
const double frame_height =
|
||||
height * (1.0 - (UnitFrameInterval((frame_index + 1) * one_frame_ms) /
|
||||
max_unit_interval));
|
||||
cache_canvas->drawLine(x, y + frame_height, width, y + frame_height,
|
||||
paint);
|
||||
}
|
||||
}
|
||||
|
||||
// Paint the vertical marker for the current frame.
|
||||
// We paint it over the current frame, not after it, because when we
|
||||
// paint this we don't yet have all the times for the current frame.
|
||||
paint.setStyle(SkPaint::Style::kFill_Style);
|
||||
paint.setBlendMode(SkBlendMode::kSrcOver);
|
||||
if (UnitFrameInterval(stopwatch_.LastLap().ToMillisecondsF()) > 1.0) {
|
||||
// budget exceeded
|
||||
paint.setColor(SK_ColorRED);
|
||||
} else {
|
||||
// within budget
|
||||
paint.setColor(SK_ColorGREEN);
|
||||
}
|
||||
sample_x = x + width * (static_cast<double>(stopwatch_.GetCurrentSample()) /
|
||||
kMaxSamples);
|
||||
const auto marker_rect = SkRect::MakeLTRB(
|
||||
sample_x, y, sample_x + width * sample_unit_width, height);
|
||||
cache_canvas->drawRect(marker_rect, paint);
|
||||
prev_drawn_sample_index_ = stopwatch_.GetCurrentSample();
|
||||
|
||||
// Draw the cached surface onto the output canvas.
|
||||
auto image = DlImage::Make(visualize_cache_surface_->makeImageSnapshot());
|
||||
canvas->DrawImage(image, {rect.x(), rect.y()},
|
||||
DlImageSampling::kNearestNeighbor);
|
||||
}
|
||||
|
||||
} // namespace flutter
|
||||
40
engine/src/flutter/flow/stopwatch_sk.h
Normal file
40
engine/src/flutter/flow/stopwatch_sk.h
Normal file
@ -0,0 +1,40 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef FLUTTER_FLOW_STOPWATCH_SK_H_
|
||||
#define FLUTTER_FLOW_STOPWATCH_SK_H_
|
||||
|
||||
#include "flow/stopwatch.h"
|
||||
#include "include/core/SkSurface.h"
|
||||
|
||||
namespace flutter {
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// A stopwatch visualizer that uses Skia (|SkCanvas|) to draw the stopwatch.
|
||||
///
|
||||
/// @see DlStopwatchVisualizer for the newer non-backend specific version.
|
||||
class SkStopwatchVisualizer : public StopwatchVisualizer {
|
||||
public:
|
||||
explicit SkStopwatchVisualizer(const Stopwatch& stopwatch)
|
||||
: StopwatchVisualizer(stopwatch) {}
|
||||
|
||||
void Visualize(DlCanvas* canvas, const SkRect& rect) const override;
|
||||
|
||||
private:
|
||||
/// Initializes the |SkSurface| used for drawing the stopwatch.
|
||||
///
|
||||
/// Draws the base background and any timing data from before the initial
|
||||
/// call to |Visualize|.
|
||||
void InitVisualizeSurface(SkISize size) const;
|
||||
|
||||
// Mutable data cache for performance optimization of the graphs.
|
||||
// Prevents expensive redrawing of old data.
|
||||
mutable bool cache_dirty_ = true;
|
||||
mutable sk_sp<SkSurface> visualize_cache_surface_;
|
||||
mutable size_t prev_drawn_sample_index_ = 0;
|
||||
};
|
||||
|
||||
} // namespace flutter
|
||||
|
||||
#endif // FLUTTER_FLOW_STOPWATCH_SK_H_
|
||||
@ -42,5 +42,20 @@ TEST(Instrumentation, GetFrameBudgetFromUpdaterTest) {
|
||||
EXPECT_EQ(frame_budget_90fps, actual_frame_budget);
|
||||
}
|
||||
|
||||
TEST(Instrumentation, GetLapByIndexTest) {
|
||||
fml::Milliseconds frame_budget_90fps = fml::RefreshRateToFrameBudget(90);
|
||||
FixedRefreshRateStopwatch stopwatch(frame_budget_90fps);
|
||||
stopwatch.SetLapTime(fml::TimeDelta::FromMilliseconds(10));
|
||||
EXPECT_EQ(stopwatch.GetLap(1), fml::TimeDelta::FromMilliseconds(10));
|
||||
}
|
||||
|
||||
TEST(Instrumentation, GetCurrentSampleTest) {
|
||||
fml::Milliseconds frame_budget_90fps = fml::RefreshRateToFrameBudget(90);
|
||||
FixedRefreshRateStopwatch stopwatch(frame_budget_90fps);
|
||||
stopwatch.Start();
|
||||
stopwatch.Stop();
|
||||
EXPECT_EQ(stopwatch.GetCurrentSample(), size_t(1));
|
||||
}
|
||||
|
||||
} // namespace testing
|
||||
} // namespace flutter
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
Loading…
x
Reference in New Issue
Block a user