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