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.
5 #include "cc/overdraw_metrics.h"
7 #include "base/debug/trace_event.h"
8 #include "base/metrics/histogram.h"
9 #include "cc/layer_tree_host.h"
10 #include "cc/layer_tree_host_impl.h"
11 #include "cc/math_util.h"
12 #include "ui/gfx/quad_f.h"
13 #include "ui/gfx/rect.h"
14 #include "ui/gfx/transform.h"
18 OverdrawMetrics::OverdrawMetrics(bool recordMetricsForFrame
)
19 : m_recordMetricsForFrame(recordMetricsForFrame
)
21 , m_pixelsUploadedOpaque(0)
22 , m_pixelsUploadedTranslucent(0)
23 , m_tilesCulledForUpload(0)
24 , m_contentsTextureUseBytes(0)
25 , m_renderSurfaceTextureUseBytes(0)
26 , m_pixelsDrawnOpaque(0)
27 , m_pixelsDrawnTranslucent(0)
28 , m_pixelsCulledForDrawing(0)
32 static inline float wedgeProduct(const gfx::PointF
& p1
, const gfx::PointF
& p2
)
34 return p1
.x() * p2
.y() - p1
.y() * p2
.x();
37 // Calculates area of an arbitrary convex polygon with up to 8 points.
38 static inline float polygonArea(const gfx::PointF points
[8], int numPoints
)
44 for (int i
= 0; i
< numPoints
; ++i
)
45 area
+= wedgeProduct(points
[i
], points
[(i
+1)%numPoints
]);
46 return fabs(0.5f
* area
);
49 // Takes a given quad, maps it by the given transformation, and gives the area of the resulting polygon.
50 static inline float areaOfMappedQuad(const gfx::Transform
& transform
, const gfx::QuadF
& quad
)
52 gfx::PointF clippedQuad
[8];
53 int numVerticesInClippedQuad
= 0;
54 MathUtil::mapClippedQuad(transform
, quad
, clippedQuad
, numVerticesInClippedQuad
);
55 return polygonArea(clippedQuad
, numVerticesInClippedQuad
);
58 void OverdrawMetrics::didPaint(const gfx::Rect
& paintedRect
)
60 if (!m_recordMetricsForFrame
)
63 m_pixelsPainted
+= static_cast<float>(paintedRect
.width()) * paintedRect
.height();
66 void OverdrawMetrics::didCullTilesForUpload(int count
)
68 if (m_recordMetricsForFrame
)
69 m_tilesCulledForUpload
+= count
;
72 void OverdrawMetrics::didUpload(const gfx::Transform
& transformToTarget
, const gfx::Rect
& uploadRect
, const gfx::Rect
& opaqueRect
)
74 if (!m_recordMetricsForFrame
)
77 float uploadArea
= areaOfMappedQuad(transformToTarget
, gfx::QuadF(uploadRect
));
78 float uploadOpaqueArea
= areaOfMappedQuad(transformToTarget
, gfx::QuadF(gfx::IntersectRects(opaqueRect
, uploadRect
)));
80 m_pixelsUploadedOpaque
+= uploadOpaqueArea
;
81 m_pixelsUploadedTranslucent
+= uploadArea
- uploadOpaqueArea
;
84 void OverdrawMetrics::didUseContentsTextureMemoryBytes(size_t contentsTextureUseBytes
)
86 if (!m_recordMetricsForFrame
)
89 m_contentsTextureUseBytes
+= contentsTextureUseBytes
;
92 void OverdrawMetrics::didUseRenderSurfaceTextureMemoryBytes(size_t renderSurfaceUseBytes
)
94 if (!m_recordMetricsForFrame
)
97 m_renderSurfaceTextureUseBytes
+= renderSurfaceUseBytes
;
100 void OverdrawMetrics::didCullForDrawing(const gfx::Transform
& transformToTarget
, const gfx::Rect
& beforeCullRect
, const gfx::Rect
& afterCullRect
)
102 if (!m_recordMetricsForFrame
)
105 float beforeCullArea
= areaOfMappedQuad(transformToTarget
, gfx::QuadF(beforeCullRect
));
106 float afterCullArea
= areaOfMappedQuad(transformToTarget
, gfx::QuadF(afterCullRect
));
108 m_pixelsCulledForDrawing
+= beforeCullArea
- afterCullArea
;
111 void OverdrawMetrics::didDraw(const gfx::Transform
& transformToTarget
, const gfx::Rect
& afterCullRect
, const gfx::Rect
& opaqueRect
)
113 if (!m_recordMetricsForFrame
)
116 float afterCullArea
= areaOfMappedQuad(transformToTarget
, gfx::QuadF(afterCullRect
));
117 float afterCullOpaqueArea
= areaOfMappedQuad(transformToTarget
, gfx::QuadF(gfx::IntersectRects(opaqueRect
, afterCullRect
)));
119 m_pixelsDrawnOpaque
+= afterCullOpaqueArea
;
120 m_pixelsDrawnTranslucent
+= afterCullArea
- afterCullOpaqueArea
;
123 void OverdrawMetrics::recordMetrics(const LayerTreeHost
* layerTreeHost
) const
125 if (m_recordMetricsForFrame
)
126 recordMetricsInternal
<LayerTreeHost
>(UpdateAndCommit
, layerTreeHost
);
129 void OverdrawMetrics::recordMetrics(const LayerTreeHostImpl
* layerTreeHost
) const
131 if (m_recordMetricsForFrame
)
132 recordMetricsInternal
<LayerTreeHostImpl
>(DrawingToScreen
, layerTreeHost
);
135 template<typename LayerTreeHostType
>
136 void OverdrawMetrics::recordMetricsInternal(MetricsType metricsType
, const LayerTreeHostType
* layerTreeHost
) const
138 // This gives approximately 10x the percentage of pixels to fill the viewport once.
139 float normalization
= 1000.f
/ (layerTreeHost
->deviceViewportSize().width() * layerTreeHost
->deviceViewportSize().height());
140 // This gives approximately 100x the percentage of tiles to fill the viewport once, if all tiles were 256x256.
141 float tileNormalization
= 10000.f
/ (layerTreeHost
->deviceViewportSize().width() / 256.f
* layerTreeHost
->deviceViewportSize().height() / 256.f
);
142 // This gives approximately 10x the percentage of bytes to fill the viewport once, assuming 4 bytes per pixel.
143 float byteNormalization
= normalization
/ 4;
145 switch (metricsType
) {
146 case DrawingToScreen
: {
147 UMA_HISTOGRAM_CUSTOM_COUNTS(
148 "Renderer4.pixelCountOpaque_Draw",
149 static_cast<int>(normalization
* m_pixelsDrawnOpaque
),
151 UMA_HISTOGRAM_CUSTOM_COUNTS(
152 "Renderer4.pixelCountTranslucent_Draw",
153 static_cast<int>(normalization
* m_pixelsDrawnTranslucent
),
155 UMA_HISTOGRAM_CUSTOM_COUNTS(
156 "Renderer4.pixelCountCulled_Draw",
157 static_cast<int>(normalization
* m_pixelsCulledForDrawing
),
160 TRACE_COUNTER_ID1("cc", "DrawPixelsCulled", layerTreeHost
, m_pixelsCulledForDrawing
);
161 TRACE_EVENT2("cc", "OverdrawMetrics", "PixelsDrawnOpaque", m_pixelsDrawnOpaque
, "PixelsDrawnTranslucent", m_pixelsDrawnTranslucent
);
164 case UpdateAndCommit
: {
165 UMA_HISTOGRAM_CUSTOM_COUNTS(
166 "Renderer4.pixelCountPainted",
167 static_cast<int>(normalization
* m_pixelsPainted
),
169 UMA_HISTOGRAM_CUSTOM_COUNTS(
170 "Renderer4.pixelCountOpaque_Upload",
171 static_cast<int>(normalization
* m_pixelsUploadedOpaque
),
173 UMA_HISTOGRAM_CUSTOM_COUNTS(
174 "Renderer4.pixelCountTranslucent_Upload",
175 static_cast<int>(normalization
* m_pixelsUploadedTranslucent
),
177 UMA_HISTOGRAM_CUSTOM_COUNTS(
178 "Renderer4.tileCountCulled_Upload",
179 static_cast<int>(tileNormalization
* m_tilesCulledForUpload
),
181 UMA_HISTOGRAM_CUSTOM_COUNTS(
182 "Renderer4.renderSurfaceTextureBytes_ViewportScaled",
184 byteNormalization
* m_renderSurfaceTextureUseBytes
),
186 UMA_HISTOGRAM_CUSTOM_COUNTS(
187 "Renderer4.renderSurfaceTextureBytes_Unscaled",
188 static_cast<int>(m_renderSurfaceTextureUseBytes
/ 1000),
189 1000, 100000000, 50);
190 UMA_HISTOGRAM_CUSTOM_COUNTS(
191 "Renderer4.contentsTextureBytes_ViewportScaled",
192 static_cast<int>(byteNormalization
* m_contentsTextureUseBytes
),
194 UMA_HISTOGRAM_CUSTOM_COUNTS(
195 "Renderer4.contentsTextureBytes_Unscaled",
196 static_cast<int>(m_contentsTextureUseBytes
/ 1000),
197 1000, 100000000, 50);
200 TRACE_COUNTER_ID1("cc", "UploadTilesCulled", layerTreeHost
, m_tilesCulledForUpload
);
201 TRACE_EVENT2("cc", "OverdrawMetrics", "PixelsUploadedOpaque", m_pixelsUploadedOpaque
, "PixelsUploadedTranslucent", m_pixelsUploadedTranslucent
);
204 // This must be in a different scope than the TRACE_EVENT2 above.
205 TRACE_EVENT1("cc", "OverdrawPaintMetrics", "PixelsPainted", m_pixelsPainted
);
208 // This must be in a different scope than the TRACE_EVENTs above.
209 TRACE_EVENT2("cc", "OverdrawPaintMetrics", "ContentsTextureBytes", m_contentsTextureUseBytes
, "RenderSurfaceTextureBytes", m_renderSurfaceTextureUseBytes
);