[engine] changes to DlVertices::Builder and Stopwatch visualizer. (flutter/engine#57031)

Collection of changes to DlVertices::Builder and the stopwatch visualizer.

At a high level:

* improve performance of the stopwatch visualizer by pre-allocating storage (and sharing it across both visualizers), lookup up font once, and cache the debug frame rate used. Updates to use Dl types instead of SkTypes.

* Change DlVerticesBuilder to allow storing the bounds and use that in the visualizer, since we already know them. Make FML_CHECKS into dchecks, as the dart:ui vertices will already bounds check correctly - so these should only be necessary for debugging engine changes.
diff --git a/engine/src/flutter/display_list/dl_vertices.cc b/engine/src/flutter/display_list/dl_vertices.cc
index f0cf5ae..5d32577 100644
--- a/engine/src/flutter/display_list/dl_vertices.cc
+++ b/engine/src/flutter/display_list/dl_vertices.cc
@@ -43,7 +43,8 @@
     const SkPoint texture_coordinates[],
     const DlColor colors[],
     int index_count,
-    const uint16_t indices[]) {
+    const uint16_t indices[],
+    const DlRect* bounds) {
   if (!vertices || vertex_count <= 0) {
     vertex_count = 0;
     texture_coordinates = nullptr;
@@ -75,6 +76,9 @@
   if (indices) {
     builder.store_indices(indices);
   }
+  if (bounds != nullptr) {
+    builder.store_bounds(*bounds);
+  }
 
   return builder.build();
 }
@@ -223,8 +227,8 @@
 }
 
 void DlVertices::Builder::store_vertices(const SkPoint vertices[]) {
-  FML_CHECK(is_valid());
-  FML_CHECK(needs_vertices_);
+  FML_DCHECK(is_valid());
+  FML_DCHECK(needs_vertices_);
   char* pod = reinterpret_cast<char*>(vertices_.get());
   size_t bytes = vertices_->vertex_count_ * sizeof(vertices[0]);
   memcpy(pod + vertices_->vertices_offset_, vertices, bytes);
@@ -232,8 +236,8 @@
 }
 
 void DlVertices::Builder::store_vertices(const float vertices[]) {
-  FML_CHECK(is_valid());
-  FML_CHECK(needs_vertices_);
+  FML_DCHECK(is_valid());
+  FML_DCHECK(needs_vertices_);
   char* pod = reinterpret_cast<char*>(vertices_.get());
   store_points(pod, vertices_->vertices_offset_, vertices,
                vertices_->vertex_count_);
@@ -241,8 +245,8 @@
 }
 
 void DlVertices::Builder::store_texture_coordinates(const SkPoint coords[]) {
-  FML_CHECK(is_valid());
-  FML_CHECK(needs_texture_coords_);
+  FML_DCHECK(is_valid());
+  FML_DCHECK(needs_texture_coords_);
   char* pod = reinterpret_cast<char*>(vertices_.get());
   size_t bytes = vertices_->vertex_count_ * sizeof(coords[0]);
   memcpy(pod + vertices_->texture_coordinates_offset_, coords, bytes);
@@ -250,8 +254,8 @@
 }
 
 void DlVertices::Builder::store_texture_coordinates(const float coords[]) {
-  FML_CHECK(is_valid());
-  FML_CHECK(needs_texture_coords_);
+  FML_DCHECK(is_valid());
+  FML_DCHECK(needs_texture_coords_);
   char* pod = reinterpret_cast<char*>(vertices_.get());
   store_points(pod, vertices_->texture_coordinates_offset_, coords,
                vertices_->vertex_count_);
@@ -259,8 +263,8 @@
 }
 
 void DlVertices::Builder::store_colors(const DlColor colors[]) {
-  FML_CHECK(is_valid());
-  FML_CHECK(needs_colors_);
+  FML_DCHECK(is_valid());
+  FML_DCHECK(needs_colors_);
   char* pod = reinterpret_cast<char*>(vertices_.get());
   size_t bytes = vertices_->vertex_count_ * sizeof(colors[0]);
   memcpy(pod + vertices_->colors_offset_, colors, bytes);
@@ -268,8 +272,8 @@
 }
 
 void DlVertices::Builder::store_colors(const uint32_t colors[]) {
-  FML_CHECK(is_valid());
-  FML_CHECK(needs_colors_);
+  FML_DCHECK(is_valid());
+  FML_DCHECK(needs_colors_);
   char* pod = reinterpret_cast<char*>(vertices_.get());
   DlColor* dlcolors_ptr =
       reinterpret_cast<DlColor*>(pod + vertices_->colors_offset_);
@@ -280,29 +284,37 @@
 }
 
 void DlVertices::Builder::store_indices(const uint16_t indices[]) {
-  FML_CHECK(is_valid());
-  FML_CHECK(needs_indices_);
+  FML_DCHECK(is_valid());
+  FML_DCHECK(needs_indices_);
   char* pod = reinterpret_cast<char*>(vertices_.get());
   size_t bytes = vertices_->index_count_ * sizeof(indices[0]);
   memcpy(pod + vertices_->indices_offset_, indices, bytes);
   needs_indices_ = false;
 }
 
+void DlVertices::Builder::store_bounds(DlRect bounds) {
+  vertices_->bounds_ = SkRect::MakeLTRB(bounds.GetLeft(), bounds.GetTop(),
+                                        bounds.GetRight(), bounds.GetBottom());
+  needs_bounds_ = false;
+}
+
 std::shared_ptr<DlVertices> DlVertices::Builder::build() {
-  FML_CHECK(is_valid());
+  FML_DCHECK(is_valid());
   if (vertices_->vertex_count() <= 0) {
     // We set this to true in the constructor to make sure that they
     // call store_vertices() only once, but if there are no vertices
     // then we will not object to them never having stored any vertices
     needs_vertices_ = false;
   }
-  FML_CHECK(!needs_vertices_);
-  FML_CHECK(!needs_texture_coords_);
-  FML_CHECK(!needs_colors_);
-  FML_CHECK(!needs_indices_);
+  FML_DCHECK(!needs_vertices_);
+  FML_DCHECK(!needs_texture_coords_);
+  FML_DCHECK(!needs_colors_);
+  FML_DCHECK(!needs_indices_);
 
-  vertices_->bounds_ =
-      compute_bounds(vertices_->vertices(), vertices_->vertex_count_);
+  if (needs_bounds_) {
+    vertices_->bounds_ =
+        compute_bounds(vertices_->vertices(), vertices_->vertex_count_);
+  }
 
   return std::move(vertices_);
 }
diff --git a/engine/src/flutter/display_list/dl_vertices.h b/engine/src/flutter/display_list/dl_vertices.h
index ddbaa3f..8a3bed3 100644
--- a/engine/src/flutter/display_list/dl_vertices.h
+++ b/engine/src/flutter/display_list/dl_vertices.h
@@ -155,6 +155,9 @@
     /// promised by (index_count > 0).
     void store_indices(const uint16_t indices[]);
 
+    /// @brief Overwrite the internal bounds with a precomputed bounding rect.
+    void store_bounds(DlRect bounds);
+
     /// @brief Finalizes and the constructed DlVertices object.
     ///
     /// fails if any of the optional data promised in the constructor is
@@ -167,6 +170,7 @@
     bool needs_texture_coords_;
     bool needs_colors_;
     bool needs_indices_;
+    bool needs_bounds_ = true;
   };
 
   //--------------------------------------------------------------------------
@@ -183,7 +187,8 @@
                                           const SkPoint texture_coordinates[],
                                           const DlColor colors[],
                                           int index_count = 0,
-                                          const uint16_t indices[] = nullptr);
+                                          const uint16_t indices[] = nullptr,
+                                          const DlRect* bounds = nullptr);
 
   /// Returns the size of the object including all of the inlined data.
   size_t size() const;
diff --git a/engine/src/flutter/flow/layers/performance_overlay_layer.cc b/engine/src/flutter/flow/layers/performance_overlay_layer.cc
index 63e41dd..7761faf 100644
--- a/engine/src/flutter/flow/layers/performance_overlay_layer.cc
+++ b/engine/src/flutter/flow/layers/performance_overlay_layer.cc
@@ -34,26 +34,25 @@
                         bool show_graph,
                         bool show_labels,
                         const std::string& label_prefix,
-                        const std::string& font_path) {
+                        std::vector<DlPoint>& point_storage,
+                        std::vector<DlColor>& color_storage,
+                        const SkFont& font) {
   const int label_x = 8;    // distance from x
   const int label_y = -10;  // distance from y+height
 
   if (show_graph) {
-    SkRect visualization_rect = SkRect::MakeXYWH(x, y, width, height);
-    std::unique_ptr<StopwatchVisualizer> visualizer;
-
+    DlRect visualization_rect = DlRect::MakeXYWH(x, y, width, height);
     if (impeller_enabled) {
-      visualizer = std::make_unique<DlStopwatchVisualizer>(stopwatch);
+      DlStopwatchVisualizer(stopwatch, point_storage, color_storage)
+          .Visualize(canvas, visualization_rect);
     } else {
-      visualizer = std::make_unique<SkStopwatchVisualizer>(stopwatch);
+      SkStopwatchVisualizer(stopwatch).Visualize(canvas, visualization_rect);
     }
-
-    visualizer->Visualize(canvas, visualization_rect);
   }
 
   if (show_labels) {
-    auto text = PerformanceOverlayLayer::MakeStatisticsText(
-        stopwatch, label_prefix, font_path);
+    auto text = PerformanceOverlayLayer::MakeStatisticsText(stopwatch, font,
+                                                            label_prefix);
     // Historically SK_ColorGRAY (== 0xFF888888) was used here
     DlPaint paint(DlColor(0xFF888888));
 #ifdef IMPELLER_SUPPORTS_RENDERING
@@ -69,24 +68,28 @@
 
 }  // namespace
 
-sk_sp<SkTextBlob> PerformanceOverlayLayer::MakeStatisticsText(
-    const Stopwatch& stopwatch,
-    const std::string& label_prefix,
-    const std::string& font_path) {
-  SkFont font;
+// static
+SkFont PerformanceOverlayLayer::MakeStatisticsFont(std::string_view font_path) {
   sk_sp<SkFontMgr> font_mgr = txt::GetDefaultFontManager();
   if (font_path == "") {
     if (sk_sp<SkTypeface> face = font_mgr->matchFamilyStyle(nullptr, {})) {
-      font = SkFont(face, 15);
+      return SkFont(face, 15);
     } else {
       // In Skia's Android fontmgr, matchFamilyStyle can return null instead
       // of falling back to a default typeface. If that's the case, we can use
       // legacyMakeTypeface, which *does* use that default typeface.
-      font = SkFont(font_mgr->legacyMakeTypeface(nullptr, {}), 15);
+      return SkFont(font_mgr->legacyMakeTypeface(nullptr, {}), 15);
     }
   } else {
-    font = SkFont(font_mgr->makeFromFile(font_path.c_str()), 15);
+    return SkFont(font_mgr->makeFromFile(font_path.data()), 15);
   }
+}
+
+// static
+sk_sp<SkTextBlob> PerformanceOverlayLayer::MakeStatisticsText(
+    const Stopwatch& stopwatch,
+    const SkFont& font,
+    std::string_view label_prefix) {
   // Make sure there's not an empty typeface returned, or we won't see any text.
   FML_DCHECK(font.getTypeface()->countGlyphs() > 0);
 
@@ -134,16 +137,22 @@
   SkScalar width = paint_bounds().width() - (padding * 2);
   SkScalar height = paint_bounds().height() / 2;
   auto mutator = context.state_stack.save();
+  // Cached storage for vertex output.
+  std::vector<DlPoint> vertices_storage;
+  std::vector<DlColor> color_storage;
+  SkFont font = MakeStatisticsFont(font_path_);
 
-  VisualizeStopWatch(
-      context.canvas, context.impeller_enabled, context.raster_time, x, y,
-      width, height - padding, options_ & kVisualizeRasterizerStatistics,
-      options_ & kDisplayRasterizerStatistics, "Raster", font_path_);
+  VisualizeStopWatch(context.canvas, context.impeller_enabled,
+                     context.raster_time, x, y, width, height - padding,
+                     options_ & kVisualizeRasterizerStatistics,
+                     options_ & kDisplayRasterizerStatistics, "Raster",
+                     vertices_storage, color_storage, font);
 
   VisualizeStopWatch(context.canvas, context.impeller_enabled, context.ui_time,
                      x, y + height, width, height - padding,
                      options_ & kVisualizeEngineStatistics,
-                     options_ & kDisplayEngineStatistics, "UI", font_path_);
+                     options_ & kDisplayEngineStatistics, "UI",
+                     vertices_storage, color_storage, font);
 }
 
 }  // namespace flutter
diff --git a/engine/src/flutter/flow/layers/performance_overlay_layer.h b/engine/src/flutter/flow/layers/performance_overlay_layer.h
index 5fd1c71..fa99a99 100644
--- a/engine/src/flutter/flow/layers/performance_overlay_layer.h
+++ b/engine/src/flutter/flow/layers/performance_overlay_layer.h
@@ -22,9 +22,11 @@
 
 class PerformanceOverlayLayer : public Layer {
  public:
+  static SkFont MakeStatisticsFont(std::string_view font_path);
+
   static sk_sp<SkTextBlob> MakeStatisticsText(const Stopwatch& stopwatch,
-                                              const std::string& label_prefix,
-                                              const std::string& font_path);
+                                              const SkFont& font,
+                                              std::string_view label_prefix);
 
   bool IsReplacing(DiffContext* context, const Layer* layer) const override {
     return layer->as_performance_overlay_layer() != nullptr;
diff --git a/engine/src/flutter/flow/layers/performance_overlay_layer_unittests.cc b/engine/src/flutter/flow/layers/performance_overlay_layer_unittests.cc
index fa59d17..dafe53c 100644
--- a/engine/src/flutter/flow/layers/performance_overlay_layer_unittests.cc
+++ b/engine/src/flutter/flow/layers/performance_overlay_layer_unittests.cc
@@ -199,6 +199,7 @@
   const SkRect layer_bounds = SkRect::MakeLTRB(0.0f, 0.0f, 64.0f, 64.0f);
   const uint64_t overlay_opts = kDisplayRasterizerStatistics;
   auto layer = std::make_shared<PerformanceOverlayLayer>(overlay_opts);
+  auto font = PerformanceOverlayLayer::MakeStatisticsFont("");
 
   // TODO(): Note calling code has to call set_paint_bounds right now.  Make
   // this a constructor parameter and move the set_paint_bounds into Preroll
@@ -210,7 +211,7 @@
 
   layer->Paint(display_list_paint_context());
   auto overlay_text = PerformanceOverlayLayer::MakeStatisticsText(
-      display_list_paint_context().raster_time, "Raster", "");
+      display_list_paint_context().raster_time, font, "Raster");
   auto overlay_text_data = overlay_text->serialize(SkSerialProcs{});
   // Historically SK_ColorGRAY (== 0xFF888888) was used here
   DlPaint text_paint(DlColor(0xFF888888));
diff --git a/engine/src/flutter/flow/stopwatch.h b/engine/src/flutter/flow/stopwatch.h
index 50d731a..71869aa 100644
--- a/engine/src/flutter/flow/stopwatch.h
+++ b/engine/src/flutter/flow/stopwatch.h
@@ -106,7 +106,7 @@
   ///
   /// @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;
+  virtual void Visualize(DlCanvas* canvas, const DlRect& rect) const = 0;
 
   FML_DISALLOW_COPY_AND_ASSIGN(StopwatchVisualizer);
 
diff --git a/engine/src/flutter/flow/stopwatch_dl.cc b/engine/src/flutter/flow/stopwatch_dl.cc
index 9f7fa3f..3e1a054 100644
--- a/engine/src/flutter/flow/stopwatch_dl.cc
+++ b/engine/src/flutter/flow/stopwatch_dl.cc
@@ -3,14 +3,15 @@
 // 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 {
 
@@ -18,16 +19,16 @@
 static const size_t kMaxFrameMarkers = 8;
 
 void DlStopwatchVisualizer::Visualize(DlCanvas* canvas,
-                                      const SkRect& rect) const {
-  auto painter = DlVertexPainter();
+                                      const DlRect& rect) const {
+  auto painter = DlVertexPainter(vertices_storage_, color_storage_);
   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();
+  auto const x = rect.GetX();
+  auto const y = rect.GetY();
+  auto const width = rect.GetWidth();
+  auto const height = rect.GetHeight();
+  auto const bottom = rect.GetBottom();
 
   // Scale the graph to show time frames up to those that are 3x the frame time.
   auto const one_frame_ms = GetFrameBudget().count();
@@ -35,13 +36,21 @@
   auto const max_unit_interval = UnitFrameInterval(max_interval);
   auto const sample_unit_width = (1.0 / kMaxSamples);
 
+  // resize backing storage to match expected lap count.
+  size_t required_storage =
+      (stopwatch_.GetLapsCount() + 2 + kMaxFrameMarkers) * 6;
+  if (vertices_storage_.size() < required_storage) {
+    vertices_storage_.resize(required_storage);
+    color_storage_.resize(required_storage);
+  }
+
   // 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++) {
+    for (auto i = 0u; i < stopwatch_.GetLapsCount(); i++) {
       auto const sample_unit_height =
           (1.0 - UnitHeight(stopwatch_.GetLap(i).ToMillisecondsF(),
                             max_unit_interval));
@@ -50,10 +59,10 @@
       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),
+      painter.DrawRect(DlRect::MakeLTRB(/*left=*/bar_left,
+                                        /*top=*/y + bar_height,
+                                        /*right=*/bar_left + bar_width,
+                                        /*bottom=*/bottom),
                        DlColor(0xAA0000FF));
     }
   }
@@ -69,16 +78,16 @@
         count = 1;
       }
 
-      for (auto i = size_t(0); i < count; i++) {
+      for (auto i = 0u; 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),
+        painter.DrawRect(DlRect::MakeLTRB(/*left=*/x,
+                                          /*top=*/y + frame_height,
+                                          /*right=*/width,
+                                          /*bottom=*/y + frame_height + 1),
                          DlColor(0xCC000000));
       }
     }
@@ -96,8 +105,8 @@
                      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);
+    auto const b = rect.GetBottom();
+    painter.DrawRect(DlRect::MakeLTRB(l, t, r, b), color);
   }
 
   // Actually draw.
@@ -106,48 +115,46 @@
   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);
+  canvas->DrawVertices(painter.IntoVertices(rect), DlBlendMode::kSrcOver,
+                       paint);
 }
 
-void DlVertexPainter::DrawRect(const SkRect& rect, const DlColor& color) {
+DlVertexPainter::DlVertexPainter(std::vector<DlPoint>& vertices_storage,
+                                 std::vector<DlColor>& color_storage)
+    : vertices_(vertices_storage), colors_(color_storage) {}
+
+void DlVertexPainter::DrawRect(const DlRect& rect, const DlColor& color) {
+  auto const left = rect.GetLeft();
+  auto const top = rect.GetTop();
+  auto const right = rect.GetRight();
+  auto const bottom = rect.GetBottom();
+
+  FML_DCHECK(6 + colors_offset_ <= vertices_.size());
+  FML_DCHECK(6 + colors_offset_ <= colors_.size());
+
   // 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());
+  vertices_[vertices_offset_++] = DlPoint(left, top);      // tl tr
+  vertices_[vertices_offset_++] = DlPoint(right, top);     //    br
+  vertices_[vertices_offset_++] = DlPoint(right, bottom);  //
+  vertices_[vertices_offset_++] = DlPoint(right, bottom);  // tl
+  vertices_[vertices_offset_++] = DlPoint(left, bottom);   // bl br
+  vertices_[vertices_offset_++] = DlPoint(left, top);      //
+  for (auto i = 0u; i < 6u; i++) {
+    colors_[colors_offset_++] = color;
+  }
 }
 
-std::shared_ptr<DlVertices> DlVertexPainter::IntoVertices() {
-  auto const result = DlVertices::Make(
+std::shared_ptr<DlVertices> DlVertexPainter::IntoVertices(
+    const DlRect& bounds_rect) {
+  return DlVertices::Make(
       /*mode=*/DlVertexMode::kTriangles,
       /*vertex_count=*/vertices_.size(),
-      /*vertices=*/vertices_.data(),
+      /*vertices=*/reinterpret_cast<SkPoint*>(vertices_.data()),
       /*texture_coordinates=*/nullptr,
-      /*colors=*/colors_.data());
-  vertices_.clear();
-  colors_.clear();
-  return result;
+      /*colors=*/colors_.data(),
+      /*index_count=*/0,
+      /*indices=*/nullptr,
+      /*bounds=*/&bounds_rect);
 }
 
 }  // namespace flutter
diff --git a/engine/src/flutter/flow/stopwatch_dl.h b/engine/src/flutter/flow/stopwatch_dl.h
index d15dc40..be3aba7 100644
--- a/engine/src/flutter/flow/stopwatch_dl.h
+++ b/engine/src/flutter/flow/stopwatch_dl.h
@@ -18,10 +18,18 @@
 ///       optimizations.
 class DlStopwatchVisualizer : public StopwatchVisualizer {
  public:
-  explicit DlStopwatchVisualizer(const Stopwatch& stopwatch)
-      : StopwatchVisualizer(stopwatch) {}
+  explicit DlStopwatchVisualizer(const Stopwatch& stopwatch,
+                                 std::vector<DlPoint>& vertices_storage,
+                                 std::vector<DlColor>& color_storage)
+      : StopwatchVisualizer(stopwatch),
+        vertices_storage_(vertices_storage),
+        color_storage_(color_storage) {}
 
-  void Visualize(DlCanvas* canvas, const SkRect& rect) const override;
+  void Visualize(DlCanvas* canvas, const DlRect& rect) const override;
+
+ private:
+  std::vector<DlPoint>& vertices_storage_;
+  std::vector<DlColor>& color_storage_;
 };
 
 /// @brief Provides canvas-like painting methods that actually build vertices.
@@ -38,17 +46,22 @@
 /// possible (i.e. not having to do triangle-math).
 class DlVertexPainter final {
  public:
+  DlVertexPainter(std::vector<DlPoint>& vertices_storage,
+                  std::vector<DlColor>& color_storage);
+
   /// Draws a rectangle with the given color to a buffer.
-  void DrawRect(const SkRect& rect, const DlColor& color);
+  void DrawRect(const DlRect& rect, const DlColor& color);
 
   /// Converts the buffered vertices into a |DlVertices| object.
   ///
   /// @note This method clears the buffer.
-  std::shared_ptr<DlVertices> IntoVertices();
+  std::shared_ptr<DlVertices> IntoVertices(const DlRect& bounds_rect);
 
  private:
-  std::vector<SkPoint> vertices_;
-  std::vector<DlColor> colors_;
+  std::vector<DlPoint>& vertices_;
+  std::vector<DlColor>& colors_;
+  size_t vertices_offset_ = 0u;
+  size_t colors_offset_ = 0u;
 };
 
 }  // namespace flutter
diff --git a/engine/src/flutter/flow/stopwatch_dl_unittests.cc b/engine/src/flutter/flow/stopwatch_dl_unittests.cc
index f8d2900..dfb1910 100644
--- a/engine/src/flutter/flow/stopwatch_dl_unittests.cc
+++ b/engine/src/flutter/flow/stopwatch_dl_unittests.cc
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "display_list/dl_color.h"
 #include "flutter/flow/stopwatch_dl.h"
 #include "gtest/gtest.h"
 
@@ -19,16 +20,18 @@
 }
 
 TEST(DlVertexPainter, DrawRectIntoVertices) {
-  auto painter = DlVertexPainter();
+  std::vector<DlPoint> point_storage(12);
+  std::vector<DlColor> color_storage(12);
+  auto painter = DlVertexPainter(point_storage, color_storage);
 
   // Paint a red rectangle.
-  painter.DrawRect(SkRect::MakeLTRB(0, 0, 10, 10), DlColor::kRed());
+  painter.DrawRect(DlRect::MakeLTRB(0, 0, 10, 10), DlColor::kRed());
 
   // Paint a blue rectangle.
-  painter.DrawRect(SkRect::MakeLTRB(10, 10, 20, 20), DlColor::kBlue());
+  painter.DrawRect(DlRect::MakeLTRB(10, 10, 20, 20), DlColor::kBlue());
 
   // Convert the buffered vertices into a |DlVertices| object.
-  auto vertices = painter.IntoVertices();
+  auto vertices = painter.IntoVertices(DlRect::MakeLTRB(0, 0, 20, 20));
 
   // Verify the vertices.
   EXPECT_EQ(vertices->mode(), DlVertexMode::kTriangles);
diff --git a/engine/src/flutter/flow/stopwatch_sk.cc b/engine/src/flutter/flow/stopwatch_sk.cc
index b347f01..4d30371 100644
--- a/engine/src/flutter/flow/stopwatch_sk.cc
+++ b/engine/src/flutter/flow/stopwatch_sk.cc
@@ -86,9 +86,9 @@
 }
 
 void SkStopwatchVisualizer::Visualize(DlCanvas* canvas,
-                                      const SkRect& rect) const {
+                                      const DlRect& rect) const {
   // Initialize visualize cache if it has not yet been initialized.
-  InitVisualizeSurface(SkISize::Make(rect.width(), rect.height()));
+  InitVisualizeSurface(SkISize::Make(rect.GetWidth(), rect.GetHeight()));
 
   SkCanvas* cache_canvas = visualize_cache_surface_->getCanvas();
   SkPaint paint;
@@ -180,7 +180,7 @@
 
   // Draw the cached surface onto the output canvas.
   auto image = DlImage::Make(visualize_cache_surface_->makeImageSnapshot());
-  canvas->DrawImage(image, SkPoint{rect.x(), rect.y()},
+  canvas->DrawImage(image, SkPoint{rect.GetX(), rect.GetY()},
                     DlImageSampling::kNearestNeighbor);
 }
 
diff --git a/engine/src/flutter/flow/stopwatch_sk.h b/engine/src/flutter/flow/stopwatch_sk.h
index c1dfb24..9a73b0d 100644
--- a/engine/src/flutter/flow/stopwatch_sk.h
+++ b/engine/src/flutter/flow/stopwatch_sk.h
@@ -19,7 +19,7 @@
   explicit SkStopwatchVisualizer(const Stopwatch& stopwatch)
       : StopwatchVisualizer(stopwatch) {}
 
-  void Visualize(DlCanvas* canvas, const SkRect& rect) const override;
+  void Visualize(DlCanvas* canvas, const DlRect& rect) const override;
 
  private:
   /// Initializes the |SkSurface| used for drawing the stopwatch.
diff --git a/engine/src/flutter/shell/common/shell.cc b/engine/src/flutter/shell/common/shell.cc
index 9cc5c13..8bd6403 100644
--- a/engine/src/flutter/shell/common/shell.cc
+++ b/engine/src/flutter/shell/common/shell.cc
@@ -1633,12 +1633,17 @@
 }
 
 fml::Milliseconds Shell::GetFrameBudget() {
+  if (cached_display_refresh_rate_.has_value()) {
+    return cached_display_refresh_rate_.value();
+  }
   double display_refresh_rate = display_manager_->GetMainDisplayRefreshRate();
   if (display_refresh_rate > 0) {
-    return fml::RefreshRateToFrameBudget(display_refresh_rate);
+    cached_display_refresh_rate_ =
+        fml::RefreshRateToFrameBudget(display_refresh_rate);
   } else {
-    return fml::kDefaultFrameBudget;
+    cached_display_refresh_rate_ = fml::kDefaultFrameBudget;
   }
+  return cached_display_refresh_rate_.value_or(fml::kDefaultFrameBudget);
 }
 
 fml::TimePoint Shell::GetLatestFrameTargetTime() const {
diff --git a/engine/src/flutter/shell/common/shell.h b/engine/src/flutter/shell/common/shell.h
index 0685bb7..0ff7984 100644
--- a/engine/src/flutter/shell/common/shell.h
+++ b/engine/src/flutter/shell/common/shell.h
@@ -512,6 +512,9 @@
   // Used to communicate the right frame bounds via service protocol.
   double device_pixel_ratio_ = 0.0;
 
+  // Cached refresh rate used by the performance overlay.
+  std::optional<fml::Milliseconds> cached_display_refresh_rate_;
+
   // How many frames have been timed since last report.
   size_t UnreportedFramesCount() const;