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 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 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. 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. 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 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 66 void OverdrawMetrics::DidCullTilesForUpload(int count) { 67 if (record_metrics_for_frame_) 68 tiles_culled_for_upload_ += count; 69 } 70 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 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 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 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 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 136 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 142 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 150 static gfx::Size DrawViewportSize(const LayerTreeHost* host) { 151 return host->device_viewport_size(); 152 } 153 static gfx::Size DrawViewportSize(const LayerTreeHostImpl* host_impl) { 154 return host_impl->DrawViewportSize(); 155 } 156 157 template <typename LayerTreeHostType> 158 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