performance_overlay.dart 6.36 KB
Newer Older
Ian Hickson's avatar
Ian Hickson committed
1
// Copyright 2014 The Flutter Authors. All rights reserved.
2 3 4
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

5 6
import 'package:flutter/foundation.dart';

7
import 'box.dart';
8
import 'layer.dart';
9
import 'object.dart';
10

11 12 13 14 15 16
/// The options that control whether the performance overlay displays certain
/// aspects of the compositor.
enum PerformanceOverlayOption {
  // these must be in the order needed for their index values to match the
  // constants in //engine/src/sky/compositor/performance_overlay_layer.h

17 18 19 20 21 22 23 24
  /// Display the frame time and FPS of the last frame rendered. This field is
  /// updated every frame.
  ///
  /// This is the time spent by the rasterizer as it tries
  /// to convert the layer tree obtained from the widgets into OpenGL commands
  /// and tries to flush them onto the screen. When the total time taken by this
  /// step exceeds the frame slice, a frame is lost.
  displayRasterizerStatistics,
25

26 27 28 29 30
  /// Display the rasterizer frame times as they change over a set period of
  /// time in the form of a graph. The y axis of the graph denotes the total
  /// time spent by the rasterizer as a fraction of the total frame slice. When
  /// the bar turns red, a frame is lost.
  visualizeRasterizerStatistics,
31

32 33 34 35 36 37 38
  /// Display the frame time and FPS at which the interface can construct a
  /// layer tree for the rasterizer (whose behavior is described above) to
  /// consume.
  ///
  /// This involves all layout, animations, etc. When the total time taken by
  /// this step exceeds the frame slice, a frame is lost.
  displayEngineStatistics,
39

40 41
  /// Display the engine frame times as they change over a set period of time
  /// in the form of a graph. The y axis of the graph denotes the total time
42
  /// spent by the engine as a fraction of the total frame slice. When the bar
43 44 45
  /// turns red, a frame is lost.
  visualizeEngineStatistics,
}
46

47 48
/// Displays performance statistics.
///
Sigurd Meldgaard's avatar
Sigurd Meldgaard committed
49 50
/// The overlay shows two time series. The first shows how much time was
/// required on this thread to produce each frame. The second shows how much
51 52 53 54 55 56 57
/// time was required on the raster thread (formerly known as the GPU thread)
/// to produce each frame. Ideally, both these values would be less than
/// the total frame budget for the hardware on which the app is running.
/// For example, if the hardware has a screen that updates at 60 Hz, each
/// thread should ideally spend less than 16ms producing each frame.
/// This ideal condition is indicated by a green vertical line for each thread.
/// Otherwise, the performance overlay shows a red vertical line.
58 59 60
///
/// The simplest way to show the performance overlay is to set
/// [MaterialApp.showPerformanceOverlay] or [WidgetsApp.showPerformanceOverlay]
61
/// to true.
62
class RenderPerformanceOverlay extends RenderBox {
63 64
  /// Creates a performance overlay render object.
  RenderPerformanceOverlay({
65 66 67 68
    int optionsMask = 0,
    int rasterizerThreshold = 0,
    bool checkerboardRasterCacheImages = false,
    bool checkerboardOffscreenLayers = false,
69
  }) : _optionsMask = optionsMask,
70 71 72
       _rasterizerThreshold = rasterizerThreshold,
       _checkerboardRasterCacheImages = checkerboardRasterCacheImages,
       _checkerboardOffscreenLayers = checkerboardOffscreenLayers;
73

74
  /// The mask is created by shifting 1 by the index of the specific
75
  /// [PerformanceOverlayOption] to enable.
76
  int get optionsMask => _optionsMask;
77
  int _optionsMask;
78
  set optionsMask(int value) {
79
    if (value == _optionsMask) {
80
      return;
81
    }
82
    _optionsMask = value;
83 84 85
    markNeedsPaint();
  }

86 87 88
  /// The rasterizer threshold is an integer specifying the number of frame
  /// intervals that the rasterizer must miss before it decides that the frame
  /// is suitable for capturing an SkPicture trace for further analysis.
89
  int get rasterizerThreshold => _rasterizerThreshold;
90
  int _rasterizerThreshold;
91
  set rasterizerThreshold(int value) {
92
    if (value == _rasterizerThreshold) {
93
      return;
94
    }
95
    _rasterizerThreshold = value;
96 97 98
    markNeedsPaint();
  }

99 100 101
  /// Whether the raster cache should checkerboard cached entries.
  bool get checkerboardRasterCacheImages => _checkerboardRasterCacheImages;
  bool _checkerboardRasterCacheImages;
102
  set checkerboardRasterCacheImages(bool value) {
103
    if (value == _checkerboardRasterCacheImages) {
104
      return;
105
    }
106
    _checkerboardRasterCacheImages = value;
107 108 109
    markNeedsPaint();
  }

110 111 112 113
  /// Whether the compositor should checkerboard layers rendered to offscreen bitmaps.
  bool get checkerboardOffscreenLayers => _checkerboardOffscreenLayers;
  bool _checkerboardOffscreenLayers;
  set checkerboardOffscreenLayers(bool value) {
114
    if (value == _checkerboardOffscreenLayers) {
115
      return;
116
    }
117 118 119 120
    _checkerboardOffscreenLayers = value;
    markNeedsPaint();
  }

121
  @override
122
  bool get sizedByParent => true;
123 124

  @override
125
  bool get alwaysNeedsCompositing => true;
126

127
  @override
128
  double computeMinIntrinsicWidth(double height) {
129
    return 0.0;
130 131
  }

132
  @override
133
  double computeMaxIntrinsicWidth(double height) {
134
    return 0.0;
135 136
  }

137
  double get _intrinsicHeight {
Hixie's avatar
Hixie committed
138
    const double kDefaultGraphHeight = 80.0;
139
    double result = 0.0;
140
    if ((optionsMask | (1 << PerformanceOverlayOption.displayRasterizerStatistics.index) > 0) ||
141
        (optionsMask | (1 << PerformanceOverlayOption.visualizeRasterizerStatistics.index) > 0)) {
Hixie's avatar
Hixie committed
142
      result += kDefaultGraphHeight;
143
    }
144
    if ((optionsMask | (1 << PerformanceOverlayOption.displayEngineStatistics.index) > 0) ||
145
        (optionsMask | (1 << PerformanceOverlayOption.visualizeEngineStatistics.index) > 0)) {
Hixie's avatar
Hixie committed
146
      result += kDefaultGraphHeight;
147
    }
148
    return result;
149 150
  }

151
  @override
152
  double computeMinIntrinsicHeight(double width) {
153
    return _intrinsicHeight;
154 155
  }

156
  @override
157
  double computeMaxIntrinsicHeight(double width) {
158
    return _intrinsicHeight;
159 160
  }

161
  @override
162 163
  @protected
  Size computeDryLayout(covariant BoxConstraints constraints) {
164
    return constraints.constrain(Size(double.infinity, _intrinsicHeight));
165 166
  }

167
  @override
168
  void paint(PaintingContext context, Offset offset) {
169
    assert(needsCompositing);
170 171
    context.addLayer(PerformanceOverlayLayer(
      overlayRect: Rect.fromLTWH(offset.dx, offset.dy, size.width, size.height),
172
      optionsMask: optionsMask,
173 174
      rasterizerThreshold: rasterizerThreshold,
      checkerboardRasterCacheImages: checkerboardRasterCacheImages,
175
      checkerboardOffscreenLayers: checkerboardOffscreenLayers,
176
    ));
177 178
  }
}