| // 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 |