blob: 8f4df245ed0a6a5ff181d3d6a509d86a57bce357 [file] [log] [blame]
// 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/overdraw_metrics.h"
#include "base/debug/trace_event.h"
#include "base/metrics/histogram.h"
#include "cc/layer_tree_host.h"
#include "cc/layer_tree_host_impl.h"
#include "cc/math_util.h"
#include "ui/gfx/quad_f.h"
#include "ui/gfx/rect.h"
#include "ui/gfx/transform.h"
namespace cc {
OverdrawMetrics::OverdrawMetrics(bool recordMetricsForFrame)
: m_recordMetricsForFrame(recordMetricsForFrame)
, m_pixelsPainted(0)
, m_pixelsUploadedOpaque(0)
, m_pixelsUploadedTranslucent(0)
, m_tilesCulledForUpload(0)
, m_contentsTextureUseBytes(0)
, m_renderSurfaceTextureUseBytes(0)
, m_pixelsDrawnOpaque(0)
, m_pixelsDrawnTranslucent(0)
, m_pixelsCulledForDrawing(0)
{
}
static inline float wedgeProduct(const gfx::PointF& p1, const 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(const gfx::PointF points[8], int numPoints)
{
if (numPoints < 3)
return 0;
float area = 0;
for (int i = 0; i < numPoints; ++i)
area += wedgeProduct(points[i], points[(i+1)%numPoints]);
return fabs(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 clippedQuad[8];
int numVerticesInClippedQuad = 0;
MathUtil::mapClippedQuad(transform, quad, clippedQuad, numVerticesInClippedQuad);
return polygonArea(clippedQuad, numVerticesInClippedQuad);
}
void OverdrawMetrics::didPaint(const gfx::Rect& paintedRect)
{
if (!m_recordMetricsForFrame)
return;
m_pixelsPainted += static_cast<float>(paintedRect.width()) * paintedRect.height();
}
void OverdrawMetrics::didCullTilesForUpload(int count)
{
if (m_recordMetricsForFrame)
m_tilesCulledForUpload += count;
}
void OverdrawMetrics::didUpload(const gfx::Transform& transformToTarget, const gfx::Rect& uploadRect, const gfx::Rect& opaqueRect)
{
if (!m_recordMetricsForFrame)
return;
float uploadArea = areaOfMappedQuad(transformToTarget, gfx::QuadF(uploadRect));
float uploadOpaqueArea = areaOfMappedQuad(transformToTarget, gfx::QuadF(gfx::IntersectRects(opaqueRect, uploadRect)));
m_pixelsUploadedOpaque += uploadOpaqueArea;
m_pixelsUploadedTranslucent += uploadArea - uploadOpaqueArea;
}
void OverdrawMetrics::didUseContentsTextureMemoryBytes(size_t contentsTextureUseBytes)
{
if (!m_recordMetricsForFrame)
return;
m_contentsTextureUseBytes += contentsTextureUseBytes;
}
void OverdrawMetrics::didUseRenderSurfaceTextureMemoryBytes(size_t renderSurfaceUseBytes)
{
if (!m_recordMetricsForFrame)
return;
m_renderSurfaceTextureUseBytes += renderSurfaceUseBytes;
}
void OverdrawMetrics::didCullForDrawing(const gfx::Transform& transformToTarget, const gfx::Rect& beforeCullRect, const gfx::Rect& afterCullRect)
{
if (!m_recordMetricsForFrame)
return;
float beforeCullArea = areaOfMappedQuad(transformToTarget, gfx::QuadF(beforeCullRect));
float afterCullArea = areaOfMappedQuad(transformToTarget, gfx::QuadF(afterCullRect));
m_pixelsCulledForDrawing += beforeCullArea - afterCullArea;
}
void OverdrawMetrics::didDraw(const gfx::Transform& transformToTarget, const gfx::Rect& afterCullRect, const gfx::Rect& opaqueRect)
{
if (!m_recordMetricsForFrame)
return;
float afterCullArea = areaOfMappedQuad(transformToTarget, gfx::QuadF(afterCullRect));
float afterCullOpaqueArea = areaOfMappedQuad(transformToTarget, gfx::QuadF(gfx::IntersectRects(opaqueRect, afterCullRect)));
m_pixelsDrawnOpaque += afterCullOpaqueArea;
m_pixelsDrawnTranslucent += afterCullArea - afterCullOpaqueArea;
}
void OverdrawMetrics::recordMetrics(const LayerTreeHost* layerTreeHost) const
{
if (m_recordMetricsForFrame)
recordMetricsInternal<LayerTreeHost>(UpdateAndCommit, layerTreeHost);
}
void OverdrawMetrics::recordMetrics(const LayerTreeHostImpl* layerTreeHost) const
{
if (m_recordMetricsForFrame)
recordMetricsInternal<LayerTreeHostImpl>(DrawingToScreen, layerTreeHost);
}
template<typename LayerTreeHostType>
void OverdrawMetrics::recordMetricsInternal(MetricsType metricsType, const LayerTreeHostType* layerTreeHost) const
{
// This gives approximately 10x the percentage of pixels to fill the viewport once.
float normalization = 1000.f / (layerTreeHost->deviceViewportSize().width() * layerTreeHost->deviceViewportSize().height());
// This gives approximately 100x the percentage of tiles to fill the viewport once, if all tiles were 256x256.
float tileNormalization = 10000.f / (layerTreeHost->deviceViewportSize().width() / 256.f * layerTreeHost->deviceViewportSize().height() / 256.f);
// This gives approximately 10x the percentage of bytes to fill the viewport once, assuming 4 bytes per pixel.
float byteNormalization = normalization / 4;
switch (metricsType) {
case DrawingToScreen: {
HISTOGRAM_CUSTOM_COUNTS("Renderer4.pixelCountOpaque_Draw", static_cast<int>(normalization * m_pixelsDrawnOpaque), 100, 1000000, 50);
HISTOGRAM_CUSTOM_COUNTS("Renderer4.pixelCountTranslucent_Draw", static_cast<int>(normalization * m_pixelsDrawnTranslucent), 100, 1000000, 50);
HISTOGRAM_CUSTOM_COUNTS("Renderer4.pixelCountCulled_Draw", static_cast<int>(normalization * m_pixelsCulledForDrawing), 100, 1000000, 50);
TRACE_COUNTER_ID1("cc", "DrawPixelsCulled", layerTreeHost, m_pixelsCulledForDrawing);
TRACE_EVENT2("cc", "OverdrawMetrics", "PixelsDrawnOpaque", m_pixelsDrawnOpaque, "PixelsDrawnTranslucent", m_pixelsDrawnTranslucent);
break;
}
case UpdateAndCommit: {
HISTOGRAM_CUSTOM_COUNTS("Renderer4.pixelCountPainted", static_cast<int>(normalization * m_pixelsPainted), 100, 1000000, 50);
HISTOGRAM_CUSTOM_COUNTS("Renderer4.pixelCountOpaque_Upload", static_cast<int>(normalization * m_pixelsUploadedOpaque), 100, 1000000, 50);
HISTOGRAM_CUSTOM_COUNTS("Renderer4.pixelCountTranslucent_Upload", static_cast<int>(normalization * m_pixelsUploadedTranslucent), 100, 1000000, 50);
HISTOGRAM_CUSTOM_COUNTS("Renderer4.tileCountCulled_Upload", static_cast<int>(tileNormalization * m_tilesCulledForUpload), 100, 10000000, 50);
HISTOGRAM_CUSTOM_COUNTS("Renderer4.renderSurfaceTextureBytes_ViewportScaled", static_cast<int>(byteNormalization * m_renderSurfaceTextureUseBytes), 10, 1000000, 50);
HISTOGRAM_CUSTOM_COUNTS("Renderer4.renderSurfaceTextureBytes_Unscaled", static_cast<int>(m_renderSurfaceTextureUseBytes / 1000), 1000, 100000000, 50);
HISTOGRAM_CUSTOM_COUNTS("Renderer4.contentsTextureBytes_ViewportScaled", static_cast<int>(byteNormalization * m_contentsTextureUseBytes), 10, 1000000, 50);
HISTOGRAM_CUSTOM_COUNTS("Renderer4.contentsTextureBytes_Unscaled", static_cast<int>(m_contentsTextureUseBytes / 1000), 1000, 100000000, 50);
{
TRACE_COUNTER_ID1("cc", "UploadTilesCulled", layerTreeHost, m_tilesCulledForUpload);
TRACE_EVENT2("cc", "OverdrawMetrics", "PixelsUploadedOpaque", m_pixelsUploadedOpaque, "PixelsUploadedTranslucent", m_pixelsUploadedTranslucent);
}
{
// This must be in a different scope than the TRACE_EVENT2 above.
TRACE_EVENT1("cc", "OverdrawPaintMetrics", "PixelsPainted", m_pixelsPainted);
}
{
// This must be in a different scope than the TRACE_EVENTs above.
TRACE_EVENT2("cc", "OverdrawPaintMetrics", "ContentsTextureBytes", m_contentsTextureUseBytes, "RenderSurfaceTextureBytes", m_renderSurfaceTextureUseBytes);
}
break;
}
}
}
} // namespace cc