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