1 // Copyright 2012 The Chromium 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 #include "cc/debug/overdraw_metrics.h"
6
7 #include "base/debug/trace_event.h"
8 #include "base/metrics/histogram.h"
9 #include "cc/base/math_util.h"
10 #include "cc/trees/layer_tree_host.h"
11 #include "cc/trees/layer_tree_host_impl.h"
12 #include "ui/gfx/quad_f.h"
13 #include "ui/gfx/rect.h"
14 #include "ui/gfx/transform.h"
15
16 namespace cc {
17
OverdrawMetrics(bool record_metrics_for_frame)18 OverdrawMetrics::OverdrawMetrics(bool record_metrics_for_frame)
19 : record_metrics_for_frame_(record_metrics_for_frame),
20 pixels_painted_(0),
21 pixels_uploaded_opaque_(0),
22 pixels_uploaded_translucent_(0),
23 tiles_culled_for_upload_(0),
24 contents_texture_use_bytes_(0),
25 render_surface_texture_use_bytes_(0),
26 pixels_drawn_opaque_(0),
27 pixels_drawn_translucent_(0),
28 pixels_culled_for_drawing_(0) {}
29
WedgeProduct(gfx::PointF p1,gfx::PointF p2)30 static inline float WedgeProduct(gfx::PointF p1, gfx::PointF p2) {
31 return p1.x() * p2.y() - p1.y() * p2.x();
32 }
33
34 // Calculates area of an arbitrary convex polygon with up to 8 points.
PolygonArea(gfx::PointF points[8],int num_points)35 static inline float PolygonArea(gfx::PointF points[8], int num_points) {
36 if (num_points < 3)
37 return 0;
38
39 float area = 0;
40 for (int i = 0; i < num_points; ++i)
41 area += WedgeProduct(points[i], points[(i+1)%num_points]);
42 return std::abs(0.5f * area);
43 }
44
45 // Takes a given quad, maps it by the given transformation, and gives the area
46 // of the resulting polygon.
AreaOfMappedQuad(const gfx::Transform & transform,const gfx::QuadF & quad)47 static inline float AreaOfMappedQuad(const gfx::Transform& transform,
48 const gfx::QuadF& quad) {
49 gfx::PointF clipped_quad[8];
50 int num_vertices_in_clipped_quad = 0;
51 MathUtil::MapClippedQuad(transform,
52 quad,
53 clipped_quad,
54 &num_vertices_in_clipped_quad);
55 return PolygonArea(clipped_quad, num_vertices_in_clipped_quad);
56 }
57
DidPaint(gfx::Rect painted_rect)58 void OverdrawMetrics::DidPaint(gfx::Rect painted_rect) {
59 if (!record_metrics_for_frame_)
60 return;
61
62 pixels_painted_ +=
63 static_cast<float>(painted_rect.width()) * painted_rect.height();
64 }
65
DidCullTilesForUpload(int count)66 void OverdrawMetrics::DidCullTilesForUpload(int count) {
67 if (record_metrics_for_frame_)
68 tiles_culled_for_upload_ += count;
69 }
70
DidUpload(const gfx::Transform & transform_to_target,gfx::Rect upload_rect,gfx::Rect opaque_rect)71 void OverdrawMetrics::DidUpload(const gfx::Transform& transform_to_target,
72 gfx::Rect upload_rect,
73 gfx::Rect opaque_rect) {
74 if (!record_metrics_for_frame_)
75 return;
76
77 float upload_area =
78 AreaOfMappedQuad(transform_to_target, gfx::QuadF(upload_rect));
79 float upload_opaque_area =
80 AreaOfMappedQuad(transform_to_target,
81 gfx::QuadF(gfx::IntersectRects(opaque_rect,
82 upload_rect)));
83
84 pixels_uploaded_opaque_ += upload_opaque_area;
85 pixels_uploaded_translucent_ += upload_area - upload_opaque_area;
86 }
87
DidUseContentsTextureMemoryBytes(size_t contents_texture_use_bytes)88 void OverdrawMetrics::DidUseContentsTextureMemoryBytes(
89 size_t contents_texture_use_bytes) {
90 if (!record_metrics_for_frame_)
91 return;
92
93 contents_texture_use_bytes_ += contents_texture_use_bytes;
94 }
95
DidUseRenderSurfaceTextureMemoryBytes(size_t render_surface_use_bytes)96 void OverdrawMetrics::DidUseRenderSurfaceTextureMemoryBytes(
97 size_t render_surface_use_bytes) {
98 if (!record_metrics_for_frame_)
99 return;
100
101 render_surface_texture_use_bytes_ += render_surface_use_bytes;
102 }
103
DidCullForDrawing(const gfx::Transform & transform_to_target,gfx::Rect before_cull_rect,gfx::Rect after_cull_rect)104 void OverdrawMetrics::DidCullForDrawing(
105 const gfx::Transform& transform_to_target,
106 gfx::Rect before_cull_rect,
107 gfx::Rect after_cull_rect) {
108 if (!record_metrics_for_frame_)
109 return;
110
111 float before_cull_area =
112 AreaOfMappedQuad(transform_to_target, gfx::QuadF(before_cull_rect));
113 float after_cull_area =
114 AreaOfMappedQuad(transform_to_target, gfx::QuadF(after_cull_rect));
115
116 pixels_culled_for_drawing_ += before_cull_area - after_cull_area;
117 }
118
DidDraw(const gfx::Transform & transform_to_target,gfx::Rect after_cull_rect,gfx::Rect opaque_rect)119 void OverdrawMetrics::DidDraw(const gfx::Transform& transform_to_target,
120 gfx::Rect after_cull_rect,
121 gfx::Rect opaque_rect) {
122 if (!record_metrics_for_frame_)
123 return;
124
125 float after_cull_area =
126 AreaOfMappedQuad(transform_to_target, gfx::QuadF(after_cull_rect));
127 float after_cull_opaque_area =
128 AreaOfMappedQuad(transform_to_target,
129 gfx::QuadF(gfx::IntersectRects(opaque_rect,
130 after_cull_rect)));
131
132 pixels_drawn_opaque_ += after_cull_opaque_area;
133 pixels_drawn_translucent_ += after_cull_area - after_cull_opaque_area;
134 }
135
RecordMetrics(const LayerTreeHost * layer_tree_host) const136 void OverdrawMetrics::RecordMetrics(
137 const LayerTreeHost* layer_tree_host) const {
138 if (record_metrics_for_frame_)
139 RecordMetricsInternal<LayerTreeHost>(UpdateAndCommit, layer_tree_host);
140 }
141
RecordMetrics(const LayerTreeHostImpl * layer_tree_host_impl) const142 void OverdrawMetrics::RecordMetrics(
143 const LayerTreeHostImpl* layer_tree_host_impl) const {
144 if (record_metrics_for_frame_) {
145 RecordMetricsInternal<LayerTreeHostImpl>(DrawingToScreen,
146 layer_tree_host_impl);
147 }
148 }
149
DrawViewportSize(const LayerTreeHost * host)150 static gfx::Size DrawViewportSize(const LayerTreeHost* host) {
151 return host->device_viewport_size();
152 }
DrawViewportSize(const LayerTreeHostImpl * host_impl)153 static gfx::Size DrawViewportSize(const LayerTreeHostImpl* host_impl) {
154 return host_impl->DrawViewportSize();
155 }
156
157 template <typename LayerTreeHostType>
RecordMetricsInternal(MetricsType metrics_type,const LayerTreeHostType * layer_tree_host) const158 void OverdrawMetrics::RecordMetricsInternal(
159 MetricsType metrics_type,
160 const LayerTreeHostType* layer_tree_host) const {
161 // This gives approximately 10x the percentage of pixels to fill the viewport
162 // once.
163 float normalization = 1000.f / (DrawViewportSize(layer_tree_host).width() *
164 DrawViewportSize(layer_tree_host).height());
165 // This gives approximately 100x the percentage of tiles to fill the viewport
166 // once, if all tiles were 256x256.
167 float tile_normalization =
168 10000.f / (DrawViewportSize(layer_tree_host).width() / 256.f *
169 DrawViewportSize(layer_tree_host).height() / 256.f);
170 // This gives approximately 10x the percentage of bytes to fill the viewport
171 // once, assuming 4 bytes per pixel.
172 float byte_normalization = normalization / 4;
173
174 switch (metrics_type) {
175 case DrawingToScreen: {
176 UMA_HISTOGRAM_CUSTOM_COUNTS(
177 "Renderer4.pixelCountOpaque_Draw",
178 static_cast<int>(normalization * pixels_drawn_opaque_),
179 100, 1000000, 50);
180 UMA_HISTOGRAM_CUSTOM_COUNTS(
181 "Renderer4.pixelCountTranslucent_Draw",
182 static_cast<int>(normalization * pixels_drawn_translucent_),
183 100, 1000000, 50);
184 UMA_HISTOGRAM_CUSTOM_COUNTS(
185 "Renderer4.pixelCountCulled_Draw",
186 static_cast<int>(normalization * pixels_culled_for_drawing_),
187 100, 1000000, 50);
188
189 TRACE_COUNTER_ID1("cc",
190 "DrawPixelsCulled",
191 layer_tree_host,
192 pixels_culled_for_drawing_);
193 TRACE_EVENT2("cc",
194 "OverdrawMetrics",
195 "PixelsDrawnOpaque",
196 pixels_drawn_opaque_,
197 "PixelsDrawnTranslucent",
198 pixels_drawn_translucent_);
199 break;
200 }
201 case UpdateAndCommit: {
202 UMA_HISTOGRAM_CUSTOM_COUNTS(
203 "Renderer4.pixelCountPainted",
204 static_cast<int>(normalization * pixels_painted_),
205 100, 1000000, 50);
206 UMA_HISTOGRAM_CUSTOM_COUNTS(
207 "Renderer4.pixelCountOpaque_Upload",
208 static_cast<int>(normalization * pixels_uploaded_opaque_),
209 100, 1000000, 50);
210 UMA_HISTOGRAM_CUSTOM_COUNTS(
211 "Renderer4.pixelCountTranslucent_Upload",
212 static_cast<int>(normalization * pixels_uploaded_translucent_),
213 100, 1000000, 50);
214 UMA_HISTOGRAM_CUSTOM_COUNTS(
215 "Renderer4.tileCountCulled_Upload",
216 static_cast<int>(tile_normalization * tiles_culled_for_upload_),
217 100, 10000000, 50);
218 UMA_HISTOGRAM_CUSTOM_COUNTS(
219 "Renderer4.renderSurfaceTextureBytes_ViewportScaled",
220 static_cast<int>(
221 byte_normalization * render_surface_texture_use_bytes_),
222 10, 1000000, 50);
223 UMA_HISTOGRAM_CUSTOM_COUNTS(
224 "Renderer4.renderSurfaceTextureBytes_Unscaled",
225 static_cast<int>(render_surface_texture_use_bytes_ / 1000),
226 1000, 100000000, 50);
227 UMA_HISTOGRAM_CUSTOM_COUNTS(
228 "Renderer4.contentsTextureBytes_ViewportScaled",
229 static_cast<int>(byte_normalization * contents_texture_use_bytes_),
230 10, 1000000, 50);
231 UMA_HISTOGRAM_CUSTOM_COUNTS(
232 "Renderer4.contentsTextureBytes_Unscaled",
233 static_cast<int>(contents_texture_use_bytes_ / 1000),
234 1000, 100000000, 50);
235 {
236 TRACE_COUNTER_ID1("cc",
237 "UploadTilesCulled",
238 layer_tree_host,
239 tiles_culled_for_upload_);
240 TRACE_EVENT2("cc",
241 "OverdrawMetrics",
242 "PixelsUploadedOpaque",
243 pixels_uploaded_opaque_,
244 "PixelsUploadedTranslucent",
245 pixels_uploaded_translucent_);
246 }
247 {
248 // This must be in a different scope than the TRACE_EVENT2 above.
249 TRACE_EVENT1("cc",
250 "OverdrawPaintMetrics",
251 "PixelsPainted",
252 pixels_painted_);
253 }
254 {
255 // This must be in a different scope than the TRACE_EVENTs above.
256 TRACE_EVENT2("cc",
257 "OverdrawPaintMetrics",
258 "ContentsTextureBytes",
259 contents_texture_use_bytes_,
260 "RenderSurfaceTextureBytes",
261 render_surface_texture_use_bytes_);
262 }
263 break;
264 }
265 }
266 }
267
268 } // namespace cc
269