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 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 65 bool TiledLayerImpl::HasTileAt(int i, int j) const { 66 return !!tiler_->TileAt(i, j); 67 } 68 69 bool TiledLayerImpl::HasResourceIdForTileAt(int i, int j) const { 70 return HasTileAt(i, j) && TileAt(i, j)->resource_id(); 71 } 72 73 DrawableTile* TiledLayerImpl::TileAt(int i, int j) const { 74 return static_cast<DrawableTile*>(tiler_->TileAt(i, j)); 75 } 76 77 DrawableTile* 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 85 void TiledLayerImpl::GetDebugBorderProperties(SkColor* color, 86 float* width) const { 87 *color = DebugColors::TiledContentLayerBorderColor(); 88 *width = DebugColors::TiledContentLayerBorderWidth(layer_tree_impl()); 89 } 90 91 scoped_ptr<LayerImpl> TiledLayerImpl::CreateLayerImpl( 92 LayerTreeImpl* tree_impl) { 93 return TiledLayerImpl::Create(tree_impl, id()).PassAs<LayerImpl>(); 94 } 95 96 void TiledLayerImpl::AsValueInto(base::DictionaryValue* state) const { 97 LayerImpl::AsValueInto(state); 98 state->Set("invalidation", MathUtil::AsValue(update_rect()).release()); 99 } 100 101 size_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 116 void 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 139 bool 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 148 void 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 250 void 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 262 void 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 276 void 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 285 Region 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 293 void TiledLayerImpl::DidLoseOutputSurface() { 294 tiler_->reset(); 295 } 296 297 const char* TiledLayerImpl::LayerTypeAsString() const { 298 return "cc::TiledLayerImpl"; 299 } 300 301 } // namespace cc 302