blob: 9f7fa3f37aef8d38b4ede198d5ba658db5329951 [file] [log] [blame]
// 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 = 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, DlColor(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(/*l=*/bar_left,
/*t=*/y + bar_height,
/*r=*/bar_left + bar_width,
/*b=*/bottom),
DlColor(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(/*l=*/x,
/*t=*/y + frame_height,
/*r=*/width,
/*b=*/y + frame_height + 1),
DlColor(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.
// Use kSrcOver blend mode so that elements under the performance overlay are
// partially visible.
paint.setBlendMode(DlBlendMode::kSrcOver);
// The second blend mode does nothing since the paint has no additional color
// sources like a tiled image or gradient.
canvas->DrawVertices(painter.IntoVertices(), DlBlendMode::kSrcOver, 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