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

Add a DlStopwatchVisualizer and conditionally use it for Impeller #45259

Merged
merged 17 commits into from
Aug 30, 2023
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions ci/licenses_golden/excluded_files
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
../../../flutter/flow/mutators_stack_unittests.cc
../../../flutter/flow/raster_cache_unittests.cc
../../../flutter/flow/skia_gpu_object_unittests.cc
../../../flutter/flow/stopwatch_dl_unittests.cc
../../../flutter/flow/stopwatch_unittests.cc
../../../flutter/flow/surface_frame_unittests.cc
../../../flutter/flow/testing
Expand Down
4 changes: 4 additions & 0 deletions ci/licenses_golden/licenses_flutter
Original file line number Diff line number Diff line change
Expand Up @@ -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_dl.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/flow/stopwatch_dl.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
Expand Down Expand Up @@ -3594,6 +3596,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_dl.cc
FILE: ../../../flutter/flow/stopwatch_dl.h
FILE: ../../../flutter/flow/stopwatch_sk.cc
FILE: ../../../flutter/flow/stopwatch_sk.h
FILE: ../../../flutter/flow/surface.cc
Expand Down
3 changes: 3 additions & 0 deletions flow/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ source_set("flow") {
"skia_gpu_object.h",
"stopwatch.cc",
"stopwatch.h",
"stopwatch_dl.cc",
"stopwatch_dl.h",
"stopwatch_sk.cc",
"stopwatch_sk.h",
"surface.cc",
Expand Down Expand Up @@ -168,6 +170,7 @@ if (enable_unittests) {
"mutators_stack_unittests.cc",
"raster_cache_unittests.cc",
"skia_gpu_object_unittests.cc",
"stopwatch_dl_unittests.cc",
"stopwatch_unittests.cc",
"surface_frame_unittests.cc",
"testing/mock_layer_unittests.cc",
Expand Down
25 changes: 17 additions & 8 deletions flow/layers/performance_overlay_layer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,11 @@

#include <iomanip>
#include <iostream>
#include <memory>
#include <string>

#include "flow/stopwatch.h"
#include "flow/stopwatch_dl.h"
#include "flow/stopwatch_sk.h"
#include "third_party/skia/include/core/SkFont.h"
#include "third_party/skia/include/core/SkTextBlob.h"
Expand All @@ -16,6 +19,7 @@ namespace flutter {
namespace {

void VisualizeStopWatch(DlCanvas* canvas,
const bool impeller_enabled,
const Stopwatch& stopwatch,
SkScalar x,
SkScalar y,
Expand All @@ -30,11 +34,15 @@ void VisualizeStopWatch(DlCanvas* canvas,

if (show_graph) {
SkRect visualization_rect = SkRect::MakeXYWH(x, y, width, height);
std::unique_ptr<StopwatchVisualizer> visualizer;

// 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 (impeller_enabled) {
visualizer = std::make_unique<DlStopwatchVisualizer>(stopwatch);
} else {
visualizer = std::make_unique<SkStopwatchVisualizer>(stopwatch);
}

visualizer->Visualize(canvas, visualization_rect);
}

if (show_labels) {
Expand Down Expand Up @@ -105,12 +113,13 @@ void PerformanceOverlayLayer::Paint(PaintContext& context) const {
auto mutator = context.state_stack.save();

VisualizeStopWatch(
context.canvas, context.raster_time, x, y, width, height - padding,
options_ & kVisualizeRasterizerStatistics,
context.canvas, context.impeller_enabled, context.raster_time, x, y,
width, height - padding, options_ & kVisualizeRasterizerStatistics,
options_ & kDisplayRasterizerStatistics, "Raster", font_path_);

VisualizeStopWatch(context.canvas, context.ui_time, x, y + height, width,
height - padding, options_ & kVisualizeEngineStatistics,
VisualizeStopWatch(context.canvas, context.impeller_enabled, context.ui_time,
x, y + height, width, height - padding,
options_ & kVisualizeEngineStatistics,
options_ & kDisplayEngineStatistics, "UI", font_path_);
}

Expand Down
4 changes: 4 additions & 0 deletions flow/stopwatch.cc
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ const fml::TimeDelta& Stopwatch::GetLap(size_t index) const {
return laps_[index];
}

size_t Stopwatch::GetLapsCount() const {
return laps_.size();
}

size_t Stopwatch::GetCurrentSample() const {
return current_sample_;
}
Expand Down
3 changes: 3 additions & 0 deletions flow/stopwatch.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ class Stopwatch {

const fml::TimeDelta& GetLap(size_t index) const;

/// Return a reference to all the laps.
size_t GetLapsCount() const;

size_t GetCurrentSample() const;

const fml::TimeDelta& LastLap() const;
Expand Down
149 changes: 149 additions & 0 deletions flow/stopwatch_dl.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
// 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_dl.h"
#include <memory>
#include <vector>
#include "display_list/dl_blend_mode.h"
#include "display_list/dl_canvas.h"
#include "display_list/dl_color.h"
#include "display_list/dl_paint.h"
#include "display_list/dl_vertices.h"
#include "include/core/SkRect.h"

namespace flutter {

static const size_t kMaxSamples = 120;
static const size_t kMaxFrameMarkers = 8;

void DlStopwatchVisualizer::Visualize(DlCanvas* canvas,
const SkRect& rect) const {
auto painter = DlVertexPainter();
DlPaint paint;

// Establish the graph position.
auto const x = rect.x();
auto const y = rect.y();
auto const width = rect.width();
auto const height = rect.height();
auto const bottom = rect.bottom();

// Scale the graph to show time frames up to those that are 3x the frame time.
auto const one_frame_ms = stopwatch_.GetFrameBudget().count();
auto const max_interval = one_frame_ms * 3.0;
auto const max_unit_interval = UnitFrameInterval(max_interval);
auto const sample_unit_width = (1.0 / kMaxSamples);

// Provide a semi-transparent background for the graph.
painter.DrawRect(rect, 0x99FFFFFF);

// Prepare a path for the data; we start at the height of the last point so
// it looks like we wrap around.
{
for (auto i = size_t(0); i < stopwatch_.GetLapsCount(); i++) {
auto const sample_unit_height =
(1.0 - UnitHeight(stopwatch_.GetLap(i).ToMillisecondsF(),
max_unit_interval));

auto const bar_width = width * sample_unit_width;
auto const bar_height = height * sample_unit_height;
auto const bar_left = x + width * sample_unit_width * i;

painter.DrawRect(SkRect::MakeLTRB(/*left=*/bar_left,
/*top=*/y + bar_height,
/*right=*/bar_left + bar_width,
/*bottom=*/bottom),
0xAA0000FF);
}
}

// Draw horizontal frame markers.
{
if (max_interval > one_frame_ms) {
// Paint the horizontal markers.
auto count = static_cast<size_t>(max_interval / one_frame_ms);

// Limit the number of markers to a reasonable amount.
if (count > kMaxFrameMarkers) {
count = 1;
}

for (auto i = size_t(0); i < count; i++) {
auto const frame_height =
height * (1.0 - (UnitFrameInterval(i + 1) * one_frame_ms) /
max_unit_interval);

// Draw a skinny rectangle (i.e. a line).
painter.DrawRect(SkRect::MakeLTRB(/*left=*/x,
/*top=*/y + frame_height,
/*right=*/width,
/*bottom=*/y + frame_height + 1),
0xCC000000);
}
}
}

// Paint the vertical marker for the current frame.
{
DlColor color = DlColor::kGreen();
if (UnitFrameInterval(stopwatch_.LastLap().ToMillisecondsF()) > 1.0) {
// budget exceeded.
color = DlColor::kRed();
}
auto const l =
x + width * (static_cast<double>(stopwatch_.GetCurrentSample()) /
kMaxSamples);
auto const t = y;
auto const r = l + width * sample_unit_width;
auto const b = rect.bottom();
painter.DrawRect(SkRect::MakeLTRB(l, t, r, b), color);
}

// Actually draw.
// Note we use kSrcOut, because some of the colors above have opacity < 1.0.
canvas->DrawVertices(painter.IntoVertices(), DlBlendMode::kSrcOut, paint);
}

void DlVertexPainter::DrawRect(const SkRect& rect, const DlColor& color) {
// Draw 6 vertices representing 2 triangles.
auto const left = rect.x();
auto const top = rect.y();
auto const right = rect.right();
auto const bottom = rect.bottom();

auto const vertices = std::array<SkPoint, 6>{
SkPoint::Make(left, top), // tl tr
SkPoint::Make(right, top), // br
SkPoint::Make(right, bottom), //
SkPoint::Make(right, bottom), // tl
SkPoint::Make(left, bottom), // bl br
SkPoint::Make(left, top) //
};

auto const colors = std::array<DlColor, 6>{
color, // tl tr
color, // br
color, //
color, // tl
color, // bl br
color //
};

vertices_.insert(vertices_.end(), vertices.begin(), vertices.end());
colors_.insert(colors_.end(), colors.begin(), colors.end());
}

std::shared_ptr<DlVertices> DlVertexPainter::IntoVertices() {
auto const result = DlVertices::Make(
/*mode=*/DlVertexMode::kTriangles,
/*vertex_count=*/vertices_.size(),
/*vertices=*/vertices_.data(),
/*texture_coordinates=*/nullptr,
/*colors=*/colors_.data());
vertices_.clear();
colors_.clear();
return result;
}

} // namespace flutter
56 changes: 56 additions & 0 deletions flow/stopwatch_dl.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// 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_DL_H_
#define FLUTTER_FLOW_STOPWATCH_DL_H_

#include "flow/stopwatch.h"

namespace flutter {

//------------------------------------------------------------------------------
/// A stopwatch visualizer that uses DisplayList (|DlCanvas|) to draw.
///
/// @note This is the newer non-backend specific version, that works in both
/// Skia and Impeller. The older Skia-specific version is
/// |SkStopwatchVisualizer|, which still should be used for Skia-specific
/// optimizations.
class DlStopwatchVisualizer : public StopwatchVisualizer {
public:
explicit DlStopwatchVisualizer(const Stopwatch& stopwatch)
: StopwatchVisualizer(stopwatch) {}

void Visualize(DlCanvas* canvas, const SkRect& rect) const override;
};

/// @brief Provides canvas-like painting methods that actually build vertices.
///
/// The goal is minimally invasive rendering for the performance monitor.
///
/// The methods in this class are intended to be used by |DlStopwatchVisualizer|
/// only. The rationale is the creating lines, rectangles, and paths (while OK
/// for general apps) would cause non-trivial work for the performance monitor
/// due to tessellation per-frame.
///
/// @note A goal of this class was to make updating the performance monitor
/// (and keeping it in sync with the |SkStopwatchVisualizer|) as easy as
/// possible (i.e. not having to do triangle-math).
class DlVertexPainter final {
public:
/// Draws a rectangle with the given color to a buffer.
void DrawRect(const SkRect& rect, const DlColor& color);

/// Converts the buffered vertices into a |DlVertices| object.
///
/// @note This method clears the buffer.
std::shared_ptr<DlVertices> IntoVertices();

private:
std::vector<SkPoint> vertices_;
std::vector<DlColor> colors_;
};

} // namespace flutter

#endif // FLUTTER_FLOW_STOPWATCH_DL_H_
Loading