| // Copyright 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "cc/debug/overdraw_metrics.h" |
| |
| #include "base/debug/trace_event.h" |
| #include "base/metrics/histogram.h" |
| #include "cc/base/math_util.h" |
| #include "cc/trees/layer_tree_host.h" |
| #include "cc/trees/layer_tree_host_impl.h" |
| #include "ui/gfx/quad_f.h" |
| #include "ui/gfx/rect.h" |
| #include "ui/gfx/transform.h" |
| |
| namespace cc { |
| |
| OverdrawMetrics::OverdrawMetrics(bool record_metrics_for_frame) |
| : record_metrics_for_frame_(record_metrics_for_frame), |
| pixels_painted_(0), |
| pixels_uploaded_opaque_(0), |
| pixels_uploaded_translucent_(0), |
| tiles_culled_for_upload_(0), |
| contents_texture_use_bytes_(0), |
| render_surface_texture_use_bytes_(0), |
| pixels_drawn_opaque_(0), |
| pixels_drawn_translucent_(0), |
| pixels_culled_for_drawing_(0) {} |
| |
| static inline float WedgeProduct(gfx::PointF p1, gfx::PointF p2) { |
| return p1.x() * p2.y() - p1.y() * p2.x(); |
| } |
| |
| // Calculates area of an arbitrary convex polygon with up to 8 points. |
| static inline float PolygonArea(gfx::PointF points[8], int num_points) { |
| if (num_points < 3) |
| return 0; |
| |
| float area = 0; |
| for (int i = 0; i < num_points; ++i) |
| area += WedgeProduct(points[i], points[(i+1)%num_points]); |
| return std::abs(0.5f * area); |
| } |
| |
| // Takes a given quad, maps it by the given transformation, and gives the area |
| // of the resulting polygon. |
| static inline float AreaOfMappedQuad(const gfx::Transform& transform, |
| const gfx::QuadF& quad) { |
| gfx::PointF clipped_quad[8]; |
| int num_vertices_in_clipped_quad = 0; |
| MathUtil::MapClippedQuad(transform, |
| quad, |
| clipped_quad, |
| &num_vertices_in_clipped_quad); |
| return PolygonArea(clipped_quad, num_vertices_in_clipped_quad); |
| } |
| |
| void OverdrawMetrics::DidPaint(gfx::Rect painted_rect) { |
| if (!record_metrics_for_frame_) |
| return; |
| |
| pixels_painted_ += |
| static_cast<float>(painted_rect.width()) * painted_rect.height(); |
| } |
| |
| void OverdrawMetrics::DidCullTilesForUpload(int count) { |
| if (record_metrics_for_frame_) |
| tiles_culled_for_upload_ += count; |
| } |
| |
| void OverdrawMetrics::DidUpload(const gfx::Transform& transform_to_target, |
| gfx::Rect upload_rect, |
| gfx::Rect opaque_rect) { |
| if (!record_metrics_for_frame_) |
| return; |
| |
| float upload_area = |
| AreaOfMappedQuad(transform_to_target, gfx::QuadF(upload_rect)); |
| float upload_opaque_area = |
| AreaOfMappedQuad(transform_to_target, |
| gfx::QuadF(gfx::IntersectRects(opaque_rect, |
| upload_rect))); |
| |
| pixels_uploaded_opaque_ += upload_opaque_area; |
| pixels_uploaded_translucent_ += upload_area - upload_opaque_area; |
| } |
| |
| void OverdrawMetrics::DidUseContentsTextureMemoryBytes( |
| size_t contents_texture_use_bytes) { |
| if (!record_metrics_for_frame_) |
| return; |
| |
| contents_texture_use_bytes_ += contents_texture_use_bytes; |
| } |
| |
| void OverdrawMetrics::DidUseRenderSurfaceTextureMemoryBytes( |
| size_t render_surface_use_bytes) { |
| if (!record_metrics_for_frame_) |
| return; |
| |
| render_surface_texture_use_bytes_ += render_surface_use_bytes; |
| } |
| |
| void OverdrawMetrics::DidCullForDrawing( |
| const gfx::Transform& transform_to_target, |
| gfx::Rect before_cull_rect, |
| gfx::Rect after_cull_rect) { |
| if (!record_metrics_for_frame_) |
| return; |
| |
| float before_cull_area = |
| AreaOfMappedQuad(transform_to_target, gfx::QuadF(before_cull_rect)); |
| float after_cull_area = |
| AreaOfMappedQuad(transform_to_target, gfx::QuadF(after_cull_rect)); |
| |
| pixels_culled_for_drawing_ += before_cull_area - after_cull_area; |
| } |
| |
| void OverdrawMetrics::DidDraw(const gfx::Transform& transform_to_target, |
| gfx::Rect after_cull_rect, |
| gfx::Rect opaque_rect) { |
| if (!record_metrics_for_frame_) |
| return; |
| |
| float after_cull_area = |
| AreaOfMappedQuad(transform_to_target, gfx::QuadF(after_cull_rect)); |
| float after_cull_opaque_area = |
| AreaOfMappedQuad(transform_to_target, |
| gfx::QuadF(gfx::IntersectRects(opaque_rect, |
| after_cull_rect))); |
| |
| pixels_drawn_opaque_ += after_cull_opaque_area; |
| pixels_drawn_translucent_ += after_cull_area - after_cull_opaque_area; |
| } |
| |
| void OverdrawMetrics::RecordMetrics( |
| const LayerTreeHost* layer_tree_host) const { |
| if (record_metrics_for_frame_) |
| RecordMetricsInternal<LayerTreeHost>(UpdateAndCommit, layer_tree_host); |
| } |
| |
| void OverdrawMetrics::RecordMetrics( |
| const LayerTreeHostImpl* layer_tree_host_impl) const { |
| if (record_metrics_for_frame_) { |
| RecordMetricsInternal<LayerTreeHostImpl>(DrawingToScreen, |
| layer_tree_host_impl); |
| } |
| } |
| |
| static gfx::Size DrawViewportSize(const LayerTreeHost* host) { |
| return host->device_viewport_size(); |
| } |
| static gfx::Size DrawViewportSize(const LayerTreeHostImpl* host_impl) { |
| return host_impl->DrawViewportSize(); |
| } |
| |
| template <typename LayerTreeHostType> |
| void OverdrawMetrics::RecordMetricsInternal( |
| MetricsType metrics_type, |
| const LayerTreeHostType* layer_tree_host) const { |
| // This gives approximately 10x the percentage of pixels to fill the viewport |
| // once. |
| float normalization = 1000.f / (DrawViewportSize(layer_tree_host).width() * |
| DrawViewportSize(layer_tree_host).height()); |
| // This gives approximately 100x the percentage of tiles to fill the viewport |
| // once, if all tiles were 256x256. |
| float tile_normalization = |
| 10000.f / (DrawViewportSize(layer_tree_host).width() / 256.f * |
| DrawViewportSize(layer_tree_host).height() / 256.f); |
| // This gives approximately 10x the percentage of bytes to fill the viewport |
| // once, assuming 4 bytes per pixel. |
| float byte_normalization = normalization / 4; |
| |
| switch (metrics_type) { |
| case DrawingToScreen: { |
| UMA_HISTOGRAM_CUSTOM_COUNTS( |
| "Renderer4.pixelCountOpaque_Draw", |
| static_cast<int>(normalization * pixels_drawn_opaque_), |
| 100, 1000000, 50); |
| UMA_HISTOGRAM_CUSTOM_COUNTS( |
| "Renderer4.pixelCountTranslucent_Draw", |
| static_cast<int>(normalization * pixels_drawn_translucent_), |
| 100, 1000000, 50); |
| UMA_HISTOGRAM_CUSTOM_COUNTS( |
| "Renderer4.pixelCountCulled_Draw", |
| static_cast<int>(normalization * pixels_culled_for_drawing_), |
| 100, 1000000, 50); |
| |
| TRACE_COUNTER_ID1("cc", |
| "DrawPixelsCulled", |
| layer_tree_host, |
| pixels_culled_for_drawing_); |
| TRACE_EVENT2("cc", |
| "OverdrawMetrics", |
| "PixelsDrawnOpaque", |
| pixels_drawn_opaque_, |
| "PixelsDrawnTranslucent", |
| pixels_drawn_translucent_); |
| break; |
| } |
| case UpdateAndCommit: { |
| UMA_HISTOGRAM_CUSTOM_COUNTS( |
| "Renderer4.pixelCountPainted", |
| static_cast<int>(normalization * pixels_painted_), |
| 100, 1000000, 50); |
| UMA_HISTOGRAM_CUSTOM_COUNTS( |
| "Renderer4.pixelCountOpaque_Upload", |
| static_cast<int>(normalization * pixels_uploaded_opaque_), |
| 100, 1000000, 50); |
| UMA_HISTOGRAM_CUSTOM_COUNTS( |
| "Renderer4.pixelCountTranslucent_Upload", |
| static_cast<int>(normalization * pixels_uploaded_translucent_), |
| 100, 1000000, 50); |
| UMA_HISTOGRAM_CUSTOM_COUNTS( |
| "Renderer4.tileCountCulled_Upload", |
| static_cast<int>(tile_normalization * tiles_culled_for_upload_), |
| 100, 10000000, 50); |
| UMA_HISTOGRAM_CUSTOM_COUNTS( |
| "Renderer4.renderSurfaceTextureBytes_ViewportScaled", |
| static_cast<int>( |
| byte_normalization * render_surface_texture_use_bytes_), |
| 10, 1000000, 50); |
| UMA_HISTOGRAM_CUSTOM_COUNTS( |
| "Renderer4.renderSurfaceTextureBytes_Unscaled", |
| static_cast<int>(render_surface_texture_use_bytes_ / 1000), |
| 1000, 100000000, 50); |
| UMA_HISTOGRAM_CUSTOM_COUNTS( |
| "Renderer4.contentsTextureBytes_ViewportScaled", |
| static_cast<int>(byte_normalization * contents_texture_use_bytes_), |
| 10, 1000000, 50); |
| UMA_HISTOGRAM_CUSTOM_COUNTS( |
| "Renderer4.contentsTextureBytes_Unscaled", |
| static_cast<int>(contents_texture_use_bytes_ / 1000), |
| 1000, 100000000, 50); |
| { |
| TRACE_COUNTER_ID1("cc", |
| "UploadTilesCulled", |
| layer_tree_host, |
| tiles_culled_for_upload_); |
| TRACE_EVENT2("cc", |
| "OverdrawMetrics", |
| "PixelsUploadedOpaque", |
| pixels_uploaded_opaque_, |
| "PixelsUploadedTranslucent", |
| pixels_uploaded_translucent_); |
| } |
| { |
| // This must be in a different scope than the TRACE_EVENT2 above. |
| TRACE_EVENT1("cc", |
| "OverdrawPaintMetrics", |
| "PixelsPainted", |
| pixels_painted_); |
| } |
| { |
| // This must be in a different scope than the TRACE_EVENTs above. |
| TRACE_EVENT2("cc", |
| "OverdrawPaintMetrics", |
| "ContentsTextureBytes", |
| contents_texture_use_bytes_, |
| "RenderSurfaceTextureBytes", |
| render_surface_texture_use_bytes_); |
| } |
| break; |
| } |
| } |
| } |
| |
| } // namespace cc |