普通文本  |  269行  |  9.5 KB

// 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