• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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