// 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 #include #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(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(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::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{ 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 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