tiled_layer_impl.cc revision 4e180b6a0b4720a9b8e9e959a882386f690f08ff
1// Copyright 2011 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.
4
5#include "cc/layers/tiled_layer_impl.h"
6
7#include "base/basictypes.h"
8#include "base/strings/stringprintf.h"
9#include "cc/base/math_util.h"
10#include "cc/debug/debug_colors.h"
11#include "cc/layers/append_quads_data.h"
12#include "cc/layers/quad_sink.h"
13#include "cc/quads/checkerboard_draw_quad.h"
14#include "cc/quads/debug_border_draw_quad.h"
15#include "cc/quads/solid_color_draw_quad.h"
16#include "cc/quads/tile_draw_quad.h"
17#include "cc/resources/layer_tiling_data.h"
18#include "third_party/khronos/GLES2/gl2.h"
19#include "third_party/skia/include/core/SkColor.h"
20#include "ui/gfx/quad_f.h"
21
22namespace cc {
23
24class DrawableTile : public LayerTilingData::Tile {
25 public:
26  static scoped_ptr<DrawableTile> Create() {
27    return make_scoped_ptr(new DrawableTile());
28  }
29
30  ResourceProvider::ResourceId resource_id() const { return resource_id_; }
31  void set_resource_id(ResourceProvider::ResourceId resource_id) {
32    resource_id_ = resource_id;
33  }
34  bool contents_swizzled() { return contents_swizzled_; }
35  void set_contents_swizzled(bool contents_swizzled) {
36    contents_swizzled_ = contents_swizzled;
37  }
38
39 private:
40  DrawableTile() : resource_id_(0), contents_swizzled_(false) {}
41
42  ResourceProvider::ResourceId resource_id_;
43  bool contents_swizzled_;
44
45  DISALLOW_COPY_AND_ASSIGN(DrawableTile);
46};
47
48TiledLayerImpl::TiledLayerImpl(LayerTreeImpl* tree_impl, int id)
49    : LayerImpl(tree_impl, id), skips_draw_(true) {}
50
51TiledLayerImpl::~TiledLayerImpl() {
52}
53
54ResourceProvider::ResourceId TiledLayerImpl::ContentsResourceId() const {
55  // This function is only valid for single texture layers, e.g. masks.
56  DCHECK(tiler_);
57  DCHECK_EQ(tiler_->num_tiles_x(), 1);
58  DCHECK_EQ(tiler_->num_tiles_y(), 1);
59
60  DrawableTile* tile = TileAt(0, 0);
61  ResourceProvider::ResourceId resource_id = tile ? tile->resource_id() : 0;
62  return resource_id;
63}
64
65bool TiledLayerImpl::HasTileAt(int i, int j) const {
66  return !!tiler_->TileAt(i, j);
67}
68
69bool TiledLayerImpl::HasResourceIdForTileAt(int i, int j) const {
70  return HasTileAt(i, j) && TileAt(i, j)->resource_id();
71}
72
73DrawableTile* TiledLayerImpl::TileAt(int i, int j) const {
74  return static_cast<DrawableTile*>(tiler_->TileAt(i, j));
75}
76
77DrawableTile* TiledLayerImpl::CreateTile(int i, int j) {
78  scoped_ptr<DrawableTile> tile(DrawableTile::Create());
79  DrawableTile* added_tile = tile.get();
80  tiler_->AddTile(tile.PassAs<LayerTilingData::Tile>(), i, j);
81
82  return added_tile;
83}
84
85void TiledLayerImpl::GetDebugBorderProperties(SkColor* color,
86                                              float* width) const {
87  *color = DebugColors::TiledContentLayerBorderColor();
88  *width = DebugColors::TiledContentLayerBorderWidth(layer_tree_impl());
89}
90
91scoped_ptr<LayerImpl> TiledLayerImpl::CreateLayerImpl(
92    LayerTreeImpl* tree_impl) {
93  return TiledLayerImpl::Create(tree_impl, id()).PassAs<LayerImpl>();
94}
95
96void TiledLayerImpl::AsValueInto(base::DictionaryValue* state) const {
97  LayerImpl::AsValueInto(state);
98  state->Set("invalidation", MathUtil::AsValue(update_rect()).release());
99}
100
101size_t TiledLayerImpl::GPUMemoryUsageInBytes() const {
102  size_t amount = 0;
103  const size_t kMemoryUsagePerTileInBytes =
104      4 * tiler_->tile_size().width() * tiler_->tile_size().height();
105  for (LayerTilingData::TileMap::const_iterator iter = tiler_->tiles().begin();
106       iter != tiler_->tiles().end();
107       ++iter) {
108    const DrawableTile* tile = static_cast<DrawableTile*>(iter->second);
109    if (!tile || !tile->resource_id())
110      continue;
111    amount += kMemoryUsagePerTileInBytes;
112  }
113  return amount;
114}
115
116void TiledLayerImpl::PushPropertiesTo(LayerImpl* layer) {
117  LayerImpl::PushPropertiesTo(layer);
118
119  TiledLayerImpl* tiled_layer = static_cast<TiledLayerImpl*>(layer);
120
121  tiled_layer->set_skips_draw(skips_draw_);
122  tiled_layer->SetTilingData(*tiler_);
123
124  for (LayerTilingData::TileMap::const_iterator iter = tiler_->tiles().begin();
125       iter != tiler_->tiles().end();
126       ++iter) {
127    int i = iter->first.first;
128    int j = iter->first.second;
129    DrawableTile* tile = static_cast<DrawableTile*>(iter->second);
130
131    tiled_layer->PushTileProperties(i,
132                                    j,
133                                    tile->resource_id(),
134                                    tile->opaque_rect(),
135                                    tile->contents_swizzled());
136  }
137}
138
139bool TiledLayerImpl::WillDraw(DrawMode draw_mode,
140                              ResourceProvider* resource_provider) {
141  if (!tiler_ || tiler_->has_empty_bounds() ||
142      visible_content_rect().IsEmpty() ||
143      draw_mode == DRAW_MODE_RESOURCELESS_SOFTWARE)
144    return false;
145  return LayerImpl::WillDraw(draw_mode, resource_provider);
146}
147
148void TiledLayerImpl::AppendQuads(QuadSink* quad_sink,
149                                 AppendQuadsData* append_quads_data) {
150  DCHECK(tiler_);
151  DCHECK(!tiler_->has_empty_bounds());
152  DCHECK(!visible_content_rect().IsEmpty());
153
154  gfx::Rect content_rect = visible_content_rect();
155  SharedQuadState* shared_quad_state =
156      quad_sink->UseSharedQuadState(CreateSharedQuadState());
157  AppendDebugBorderQuad(quad_sink, shared_quad_state, append_quads_data);
158
159  int left, top, right, bottom;
160  tiler_->ContentRectToTileIndices(content_rect, &left, &top, &right, &bottom);
161
162  if (ShowDebugBorders()) {
163    for (int j = top; j <= bottom; ++j) {
164      for (int i = left; i <= right; ++i) {
165        DrawableTile* tile = TileAt(i, j);
166        gfx::Rect tile_rect = tiler_->tile_bounds(i, j);
167        SkColor border_color;
168        float border_width;
169
170        if (skips_draw_ || !tile || !tile->resource_id()) {
171          border_color = DebugColors::MissingTileBorderColor();
172          border_width = DebugColors::MissingTileBorderWidth(layer_tree_impl());
173        } else {
174          border_color = DebugColors::HighResTileBorderColor();
175          border_width = DebugColors::HighResTileBorderWidth(layer_tree_impl());
176        }
177        scoped_ptr<DebugBorderDrawQuad> debug_border_quad =
178            DebugBorderDrawQuad::Create();
179        debug_border_quad->SetNew(
180            shared_quad_state, tile_rect, border_color, border_width);
181        quad_sink->Append(debug_border_quad.PassAs<DrawQuad>(),
182                          append_quads_data);
183      }
184    }
185  }
186
187  if (skips_draw_)
188    return;
189
190  for (int j = top; j <= bottom; ++j) {
191    for (int i = left; i <= right; ++i) {
192      DrawableTile* tile = TileAt(i, j);
193      gfx::Rect tile_rect = tiler_->tile_bounds(i, j);
194      gfx::Rect display_rect = tile_rect;
195      tile_rect.Intersect(content_rect);
196
197      // Skip empty tiles.
198      if (tile_rect.IsEmpty())
199        continue;
200
201      if (!tile || !tile->resource_id()) {
202        SkColor checker_color;
203        if (ShowDebugBorders()) {
204          checker_color =
205              tile ? DebugColors::InvalidatedTileCheckerboardColor()
206                   : DebugColors::EvictedTileCheckerboardColor();
207        } else {
208          checker_color = DebugColors::DefaultCheckerboardColor();
209        }
210
211        scoped_ptr<CheckerboardDrawQuad> checkerboard_quad =
212            CheckerboardDrawQuad::Create();
213        checkerboard_quad->SetNew(
214            shared_quad_state, tile_rect, checker_color);
215        if (quad_sink->Append(checkerboard_quad.PassAs<DrawQuad>(),
216                              append_quads_data))
217          append_quads_data->num_missing_tiles++;
218
219        continue;
220      }
221
222      gfx::Rect tile_opaque_rect =
223          contents_opaque() ? tile_rect : gfx::IntersectRects(
224                                              tile->opaque_rect(), tile_rect);
225
226      // Keep track of how the top left has moved, so the texture can be
227      // offset the same amount.
228      gfx::Vector2d display_offset = tile_rect.origin() - display_rect.origin();
229      gfx::Vector2d texture_offset =
230          tiler_->texture_offset(i, j) + display_offset;
231      gfx::RectF tex_coord_rect = gfx::RectF(tile_rect.size()) + texture_offset;
232
233      float tile_width = static_cast<float>(tiler_->tile_size().width());
234      float tile_height = static_cast<float>(tiler_->tile_size().height());
235      gfx::Size texture_size(tile_width, tile_height);
236
237      scoped_ptr<TileDrawQuad> quad = TileDrawQuad::Create();
238      quad->SetNew(shared_quad_state,
239                   tile_rect,
240                   tile_opaque_rect,
241                   tile->resource_id(),
242                   tex_coord_rect,
243                   texture_size,
244                   tile->contents_swizzled());
245      quad_sink->Append(quad.PassAs<DrawQuad>(), append_quads_data);
246    }
247  }
248}
249
250void TiledLayerImpl::SetTilingData(const LayerTilingData& tiler) {
251  if (tiler_) {
252    tiler_->reset();
253  } else {
254    tiler_ = LayerTilingData::Create(tiler.tile_size(),
255                                     tiler.has_border_texels()
256                                         ? LayerTilingData::HAS_BORDER_TEXELS
257                                         : LayerTilingData::NO_BORDER_TEXELS);
258  }
259  *tiler_ = tiler;
260}
261
262void TiledLayerImpl::PushTileProperties(
263    int i,
264    int j,
265    ResourceProvider::ResourceId resource_id,
266    gfx::Rect opaque_rect,
267    bool contents_swizzled) {
268  DrawableTile* tile = TileAt(i, j);
269  if (!tile)
270    tile = CreateTile(i, j);
271  tile->set_resource_id(resource_id);
272  tile->set_opaque_rect(opaque_rect);
273  tile->set_contents_swizzled(contents_swizzled);
274}
275
276void TiledLayerImpl::PushInvalidTile(int i, int j) {
277  DrawableTile* tile = TileAt(i, j);
278  if (!tile)
279    tile = CreateTile(i, j);
280  tile->set_resource_id(0);
281  tile->set_opaque_rect(gfx::Rect());
282  tile->set_contents_swizzled(false);
283}
284
285Region TiledLayerImpl::VisibleContentOpaqueRegion() const {
286  if (skips_draw_)
287    return Region();
288  if (contents_opaque())
289    return visible_content_rect();
290  return tiler_->OpaqueRegionInContentRect(visible_content_rect());
291}
292
293void TiledLayerImpl::DidLoseOutputSurface() {
294  tiler_->reset();
295}
296
297const char* TiledLayerImpl::LayerTypeAsString() const {
298  return "cc::TiledLayerImpl";
299}
300
301}  // namespace cc
302