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
16namespace cc {
17
18OverdrawMetrics::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
30static 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.
35static 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.
47static 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
58void 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
66void OverdrawMetrics::DidCullTilesForUpload(int count) {
67  if (record_metrics_for_frame_)
68    tiles_culled_for_upload_ += count;
69}
70
71void 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
88void 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
96void 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
104void 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
119void 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
136void OverdrawMetrics::RecordMetrics(
137    const LayerTreeHost* layer_tree_host) const {
138  if (record_metrics_for_frame_)
139    RecordMetricsInternal<LayerTreeHost>(UpdateAndCommit, layer_tree_host);
140}
141
142void 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
150static gfx::Size DrawViewportSize(const LayerTreeHost* host) {
151  return host->device_viewport_size();
152}
153static gfx::Size DrawViewportSize(const LayerTreeHostImpl* host_impl) {
154  return host_impl->DrawViewportSize();
155}
156
157template <typename LayerTreeHostType>
158void 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