普通文本  |  316行  |  10.3 KB

// Copyright 2011 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/layers/tiled_layer_impl.h"

#include "base/basictypes.h"
#include "base/debug/trace_event_argument.h"
#include "base/strings/stringprintf.h"
#include "cc/base/math_util.h"
#include "cc/base/simple_enclosed_region.h"
#include "cc/debug/debug_colors.h"
#include "cc/layers/append_quads_data.h"
#include "cc/quads/checkerboard_draw_quad.h"
#include "cc/quads/debug_border_draw_quad.h"
#include "cc/quads/solid_color_draw_quad.h"
#include "cc/quads/tile_draw_quad.h"
#include "cc/resources/layer_tiling_data.h"
#include "cc/trees/occlusion_tracker.h"
#include "third_party/khronos/GLES2/gl2.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/gfx/quad_f.h"

namespace cc {

class DrawableTile : public LayerTilingData::Tile {
 public:
  static scoped_ptr<DrawableTile> Create() {
    return make_scoped_ptr(new DrawableTile());
  }

  ResourceProvider::ResourceId resource_id() const { return resource_id_; }
  void set_resource_id(ResourceProvider::ResourceId resource_id) {
    resource_id_ = resource_id;
  }
  bool contents_swizzled() { return contents_swizzled_; }
  void set_contents_swizzled(bool contents_swizzled) {
    contents_swizzled_ = contents_swizzled;
  }

 private:
  DrawableTile() : resource_id_(0), contents_swizzled_(false) {}

  ResourceProvider::ResourceId resource_id_;
  bool contents_swizzled_;

  DISALLOW_COPY_AND_ASSIGN(DrawableTile);
};

TiledLayerImpl::TiledLayerImpl(LayerTreeImpl* tree_impl, int id)
    : LayerImpl(tree_impl, id), skips_draw_(true) {}

TiledLayerImpl::~TiledLayerImpl() {
}

ResourceProvider::ResourceId TiledLayerImpl::ContentsResourceId() const {
  // This function is only valid for single texture layers, e.g. masks.
  DCHECK(tiler_);
  // It's possible the mask layer is created but has no size or otherwise
  // can't draw.
  if (tiler_->num_tiles_x() == 0 || tiler_->num_tiles_y() == 0)
    return 0;

  // Any other number of tiles other than 0 or 1 is incorrect for masks.
  DCHECK_EQ(tiler_->num_tiles_x(), 1);
  DCHECK_EQ(tiler_->num_tiles_y(), 1);

  DrawableTile* tile = TileAt(0, 0);
  ResourceProvider::ResourceId resource_id = tile ? tile->resource_id() : 0;
  return resource_id;
}

bool TiledLayerImpl::HasTileAt(int i, int j) const {
  return !!tiler_->TileAt(i, j);
}

bool TiledLayerImpl::HasResourceIdForTileAt(int i, int j) const {
  return HasTileAt(i, j) && TileAt(i, j)->resource_id();
}

DrawableTile* TiledLayerImpl::TileAt(int i, int j) const {
  return static_cast<DrawableTile*>(tiler_->TileAt(i, j));
}

DrawableTile* TiledLayerImpl::CreateTile(int i, int j) {
  scoped_ptr<DrawableTile> tile(DrawableTile::Create());
  DrawableTile* added_tile = tile.get();
  tiler_->AddTile(tile.PassAs<LayerTilingData::Tile>(), i, j);

  return added_tile;
}

void TiledLayerImpl::GetDebugBorderProperties(SkColor* color,
                                              float* width) const {
  *color = DebugColors::TiledContentLayerBorderColor();
  *width = DebugColors::TiledContentLayerBorderWidth(layer_tree_impl());
}

scoped_ptr<LayerImpl> TiledLayerImpl::CreateLayerImpl(
    LayerTreeImpl* tree_impl) {
  return TiledLayerImpl::Create(tree_impl, id()).PassAs<LayerImpl>();
}

void TiledLayerImpl::AsValueInto(base::debug::TracedValue* state) const {
  LayerImpl::AsValueInto(state);
  state->BeginArray("invalidation");
  MathUtil::AddToTracedValue(update_rect(), state);
  state->EndArray();
}

size_t TiledLayerImpl::GPUMemoryUsageInBytes() const {
  size_t amount = 0;
  const size_t kMemoryUsagePerTileInBytes =
      4 * tiler_->tile_size().width() * tiler_->tile_size().height();
  for (LayerTilingData::TileMap::const_iterator iter = tiler_->tiles().begin();
       iter != tiler_->tiles().end();
       ++iter) {
    const DrawableTile* tile = static_cast<DrawableTile*>(iter->second);
    DCHECK(tile);
    if (!tile->resource_id())
      continue;
    amount += kMemoryUsagePerTileInBytes;
  }
  return amount;
}

void TiledLayerImpl::PushPropertiesTo(LayerImpl* layer) {
  LayerImpl::PushPropertiesTo(layer);

  TiledLayerImpl* tiled_layer = static_cast<TiledLayerImpl*>(layer);

  tiled_layer->set_skips_draw(skips_draw_);
  tiled_layer->SetTilingData(*tiler_);

  for (LayerTilingData::TileMap::const_iterator iter = tiler_->tiles().begin();
       iter != tiler_->tiles().end();
       ++iter) {
    int i = iter->first.first;
    int j = iter->first.second;
    DrawableTile* tile = static_cast<DrawableTile*>(iter->second);
    DCHECK(tile);
    tiled_layer->PushTileProperties(i,
                                    j,
                                    tile->resource_id(),
                                    tile->contents_swizzled());
  }
}

bool TiledLayerImpl::WillDraw(DrawMode draw_mode,
                              ResourceProvider* resource_provider) {
  if (!tiler_ || tiler_->has_empty_bounds() ||
      visible_content_rect().IsEmpty() ||
      draw_mode == DRAW_MODE_RESOURCELESS_SOFTWARE)
    return false;
  return LayerImpl::WillDraw(draw_mode, resource_provider);
}

void TiledLayerImpl::AppendQuads(
    RenderPass* render_pass,
    const OcclusionTracker<LayerImpl>& occlusion_tracker,
    AppendQuadsData* append_quads_data) {
  DCHECK(tiler_);
  DCHECK(!tiler_->has_empty_bounds());
  DCHECK(!visible_content_rect().IsEmpty());

  gfx::Rect content_rect = visible_content_rect();
  SharedQuadState* shared_quad_state =
      render_pass->CreateAndAppendSharedQuadState();
  PopulateSharedQuadState(shared_quad_state);

  AppendDebugBorderQuad(
      render_pass, content_bounds(), shared_quad_state, append_quads_data);

  int left, top, right, bottom;
  tiler_->ContentRectToTileIndices(content_rect, &left, &top, &right, &bottom);

  if (ShowDebugBorders()) {
    for (int j = top; j <= bottom; ++j) {
      for (int i = left; i <= right; ++i) {
        DrawableTile* tile = TileAt(i, j);
        gfx::Rect tile_rect = tiler_->tile_bounds(i, j);
        gfx::Rect visible_tile_rect = tile_rect;
        SkColor border_color;
        float border_width;

        if (skips_draw_ || !tile || !tile->resource_id()) {
          border_color = DebugColors::MissingTileBorderColor();
          border_width = DebugColors::MissingTileBorderWidth(layer_tree_impl());
        } else {
          border_color = DebugColors::HighResTileBorderColor();
          border_width = DebugColors::HighResTileBorderWidth(layer_tree_impl());
        }
        DebugBorderDrawQuad* debug_border_quad =
            render_pass->CreateAndAppendDrawQuad<DebugBorderDrawQuad>();
        debug_border_quad->SetNew(shared_quad_state,
                                  tile_rect,
                                  visible_tile_rect,
                                  border_color,
                                  border_width);
      }
    }
  }

  if (skips_draw_)
    return;

  Occlusion occlusion =
      occlusion_tracker.GetCurrentOcclusionForLayer(draw_transform());
  for (int j = top; j <= bottom; ++j) {
    for (int i = left; i <= right; ++i) {
      DrawableTile* tile = TileAt(i, j);
      gfx::Rect tile_rect = tiler_->tile_bounds(i, j);
      gfx::Rect display_rect = tile_rect;
      tile_rect.Intersect(content_rect);

      // Skip empty tiles.
      if (tile_rect.IsEmpty())
        continue;

      gfx::Rect visible_tile_rect =
          occlusion.GetUnoccludedContentRect(tile_rect);
      if (visible_tile_rect.IsEmpty())
        continue;

      if (!tile || !tile->resource_id()) {
        SkColor checker_color;
        if (ShowDebugBorders()) {
          checker_color =
              tile ? DebugColors::InvalidatedTileCheckerboardColor()
                   : DebugColors::EvictedTileCheckerboardColor();
        } else {
          checker_color = DebugColors::DefaultCheckerboardColor();
        }

        CheckerboardDrawQuad* checkerboard_quad =
            render_pass->CreateAndAppendDrawQuad<CheckerboardDrawQuad>();
        checkerboard_quad->SetNew(
            shared_quad_state, tile_rect, visible_tile_rect, checker_color);
        append_quads_data->num_missing_tiles++;
        continue;
      }

      gfx::Rect tile_opaque_rect = contents_opaque() ? tile_rect : gfx::Rect();

      // Keep track of how the top left has moved, so the texture can be
      // offset the same amount.
      gfx::Vector2d display_offset = tile_rect.origin() - display_rect.origin();
      gfx::Vector2d texture_offset =
          tiler_->texture_offset(i, j) + display_offset;
      gfx::RectF tex_coord_rect = gfx::RectF(tile_rect.size()) + texture_offset;

      float tile_width = static_cast<float>(tiler_->tile_size().width());
      float tile_height = static_cast<float>(tiler_->tile_size().height());
      gfx::Size texture_size(tile_width, tile_height);

      TileDrawQuad* quad = render_pass->CreateAndAppendDrawQuad<TileDrawQuad>();
      quad->SetNew(shared_quad_state,
                   tile_rect,
                   tile_opaque_rect,
                   visible_tile_rect,
                   tile->resource_id(),
                   tex_coord_rect,
                   texture_size,
                   tile->contents_swizzled());
    }
  }
}

void TiledLayerImpl::SetTilingData(const LayerTilingData& tiler) {
  if (tiler_) {
    tiler_->reset();
  } else {
    tiler_ = LayerTilingData::Create(tiler.tile_size(),
                                     tiler.has_border_texels()
                                         ? LayerTilingData::HAS_BORDER_TEXELS
                                         : LayerTilingData::NO_BORDER_TEXELS);
  }
  *tiler_ = tiler;
}

void TiledLayerImpl::PushTileProperties(
    int i,
    int j,
    ResourceProvider::ResourceId resource_id,
    bool contents_swizzled) {
  DrawableTile* tile = TileAt(i, j);
  if (!tile)
    tile = CreateTile(i, j);
  tile->set_resource_id(resource_id);
  tile->set_contents_swizzled(contents_swizzled);
}

void TiledLayerImpl::PushInvalidTile(int i, int j) {
  DrawableTile* tile = TileAt(i, j);
  if (!tile)
    tile = CreateTile(i, j);
  tile->set_resource_id(0);
  tile->set_contents_swizzled(false);
}

SimpleEnclosedRegion TiledLayerImpl::VisibleContentOpaqueRegion() const {
  if (skips_draw_)
    return SimpleEnclosedRegion();
  return LayerImpl::VisibleContentOpaqueRegion();
}

void TiledLayerImpl::ReleaseResources() {
  tiler_->reset();
}

const char* TiledLayerImpl::LayerTypeAsString() const {
  return "cc::TiledLayerImpl";
}

}  // namespace cc