1 | // Copyright 2014 The Flutter Authors. All rights reserved. |
2 | // Use of this source code is governed by a BSD-style license that can be |
3 | // found in the LICENSE file. |
4 | |
5 | /// @docImport 'package:flutter/material.dart'; |
6 | library; |
7 | |
8 | import 'package:flutter/foundation.dart'; |
9 | |
10 | import 'box.dart'; |
11 | import 'layer.dart'; |
12 | import 'object.dart'; |
13 | |
14 | /// The options that control whether the performance overlay displays certain |
15 | /// aspects of the compositor. |
16 | enum PerformanceOverlayOption { |
17 | // these must be in the order needed for their index values to match the |
18 | // constants in //engine/src/sky/compositor/performance_overlay_layer.h |
19 | |
20 | /// Display the frame time and FPS of the last frame rendered. This field is |
21 | /// updated every frame. |
22 | /// |
23 | /// This is the time spent by the rasterizer as it tries |
24 | /// to convert the layer tree obtained from the widgets into OpenGL commands |
25 | /// and tries to flush them onto the screen. When the total time taken by this |
26 | /// step exceeds the frame slice, a frame is lost. |
27 | displayRasterizerStatistics, |
28 | |
29 | /// Display the rasterizer frame times as they change over a set period of |
30 | /// time in the form of a graph. The y axis of the graph denotes the total |
31 | /// time spent by the rasterizer as a fraction of the total frame slice. When |
32 | /// the bar turns red, a frame is lost. |
33 | visualizeRasterizerStatistics, |
34 | |
35 | /// Display the frame time and FPS at which the interface can construct a |
36 | /// layer tree for the rasterizer (whose behavior is described above) to |
37 | /// consume. |
38 | /// |
39 | /// This involves all layout, animations, etc. When the total time taken by |
40 | /// this step exceeds the frame slice, a frame is lost. |
41 | displayEngineStatistics, |
42 | |
43 | /// Display the engine frame times as they change over a set period of time |
44 | /// in the form of a graph. The y axis of the graph denotes the total time |
45 | /// spent by the engine as a fraction of the total frame slice. When the bar |
46 | /// turns red, a frame is lost. |
47 | visualizeEngineStatistics, |
48 | } |
49 | |
50 | /// Displays performance statistics. |
51 | /// |
52 | /// The overlay shows two time series. The first shows how much time was |
53 | /// required on this thread to produce each frame. The second shows how much |
54 | /// time was required on the raster thread (formerly known as the GPU thread) |
55 | /// to produce each frame. Ideally, both these values would be less than |
56 | /// the total frame budget for the hardware on which the app is running. |
57 | /// For example, if the hardware has a screen that updates at 60 Hz, each |
58 | /// thread should ideally spend less than 16ms producing each frame. |
59 | /// This ideal condition is indicated by a green vertical line for each thread. |
60 | /// Otherwise, the performance overlay shows a red vertical line. |
61 | /// |
62 | /// The simplest way to show the performance overlay is to set |
63 | /// [MaterialApp.showPerformanceOverlay] or [WidgetsApp.showPerformanceOverlay] |
64 | /// to true. |
65 | class RenderPerformanceOverlay extends RenderBox { |
66 | /// Creates a performance overlay render object. |
67 | RenderPerformanceOverlay({int optionsMask = 0}) : _optionsMask = optionsMask; |
68 | |
69 | /// The mask is created by shifting 1 by the index of the specific |
70 | /// [PerformanceOverlayOption] to enable. |
71 | int get optionsMask => _optionsMask; |
72 | int _optionsMask; |
73 | set optionsMask(int value) { |
74 | if (value == _optionsMask) { |
75 | return; |
76 | } |
77 | _optionsMask = value; |
78 | markNeedsPaint(); |
79 | } |
80 | |
81 | @override |
82 | bool get sizedByParent => true; |
83 | |
84 | @override |
85 | bool get alwaysNeedsCompositing => true; |
86 | |
87 | @override |
88 | double computeMinIntrinsicWidth(double height) { |
89 | return 0.0; |
90 | } |
91 | |
92 | @override |
93 | double computeMaxIntrinsicWidth(double height) { |
94 | return 0.0; |
95 | } |
96 | |
97 | double get _intrinsicHeight { |
98 | const double kDefaultGraphHeight = 80.0; |
99 | double result = 0.0; |
100 | if ((optionsMask | (1 << PerformanceOverlayOption.displayRasterizerStatistics.index) > 0) || |
101 | (optionsMask | (1 << PerformanceOverlayOption.visualizeRasterizerStatistics.index) > 0)) { |
102 | result += kDefaultGraphHeight; |
103 | } |
104 | if ((optionsMask | (1 << PerformanceOverlayOption.displayEngineStatistics.index) > 0) || |
105 | (optionsMask | (1 << PerformanceOverlayOption.visualizeEngineStatistics.index) > 0)) { |
106 | result += kDefaultGraphHeight; |
107 | } |
108 | return result; |
109 | } |
110 | |
111 | @override |
112 | double computeMinIntrinsicHeight(double width) { |
113 | return _intrinsicHeight; |
114 | } |
115 | |
116 | @override |
117 | double computeMaxIntrinsicHeight(double width) { |
118 | return _intrinsicHeight; |
119 | } |
120 | |
121 | @override |
122 | @protected |
123 | Size computeDryLayout(covariant BoxConstraints constraints) { |
124 | return constraints.constrain(Size(double.infinity, _intrinsicHeight)); |
125 | } |
126 | |
127 | @override |
128 | void paint(PaintingContext context, Offset offset) { |
129 | assert(needsCompositing); |
130 | context.addLayer( |
131 | PerformanceOverlayLayer( |
132 | overlayRect: Rect.fromLTWH(offset.dx, offset.dy, size.width, size.height), |
133 | optionsMask: optionsMask, |
134 | ), |
135 | ); |
136 | } |
137 | } |
138 | |