[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 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 "config.h" |
| 6 | |
[email protected] | a8461d8 | 2012-10-16 21:11:14 | [diff] [blame] | 7 | #include "cc/tiled_layer.h" |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 8 | |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 9 | #include "Region.h" |
[email protected] | a8461d8 | 2012-10-16 21:11:14 | [diff] [blame] | 10 | #include "base/basictypes.h" |
[email protected] | aad0a007 | 2012-11-01 18:15:58 | [diff] [blame] | 11 | #include "cc/geometry.h" |
[email protected] | d50c686 | 2012-10-23 02:08:31 | [diff] [blame] | 12 | #include "cc/layer_impl.h" |
| 13 | #include "cc/layer_tree_host.h" |
[email protected] | 55a124d0 | 2012-10-22 03:07:13 | [diff] [blame] | 14 | #include "cc/overdraw_metrics.h" |
[email protected] | da2c912 | 2012-10-20 23:13:06 | [diff] [blame] | 15 | #include "cc/tiled_layer_impl.h" |
[email protected] | d9c2852 | 2012-10-18 23:35:43 | [diff] [blame] | 16 | #include "third_party/khronos/GLES2/gl2.h" |
[email protected] | aad0a007 | 2012-11-01 18:15:58 | [diff] [blame] | 17 | #include "ui/gfx/rect_conversions.h" |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 18 | |
| 19 | using namespace std; |
| 20 | using WebKit::WebTransformationMatrix; |
| 21 | |
[email protected] | 9c88e56 | 2012-09-14 22:21:30 | [diff] [blame] | 22 | namespace cc { |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 23 | |
[email protected] | 8d93172 | 2012-10-23 20:26:46 | [diff] [blame] | 24 | // Maximum predictive expansion of the visible area. |
| 25 | static const int maxPredictiveTilesCount = 2; |
| 26 | |
| 27 | // Number of rows/columns of tiles to pre-paint. |
| 28 | // We should increase these further as all textures are |
| 29 | // prioritized and we insure performance doesn't suffer. |
| 30 | static const int prepaintRows = 4; |
| 31 | static const int prepaintColumns = 2; |
| 32 | |
| 33 | |
[email protected] | 96baf3e | 2012-10-22 23:09:55 | [diff] [blame] | 34 | class UpdatableTile : public LayerTilingData::Tile { |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 35 | public: |
[email protected] | f33db56 | 2012-10-25 03:25:55 | [diff] [blame] | 36 | static scoped_ptr<UpdatableTile> create(scoped_ptr<LayerUpdater::Resource> updaterResource) |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 37 | { |
[email protected] | f33db56 | 2012-10-25 03:25:55 | [diff] [blame] | 38 | return make_scoped_ptr(new UpdatableTile(updaterResource.Pass())); |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 39 | } |
| 40 | |
[email protected] | f33db56 | 2012-10-25 03:25:55 | [diff] [blame] | 41 | LayerUpdater::Resource* updaterResource() { return m_updaterResource.get(); } |
| 42 | PrioritizedTexture* managedTexture() { return m_updaterResource->texture(); } |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 43 | |
[email protected] | aad0a007 | 2012-11-01 18:15:58 | [diff] [blame] | 44 | bool isDirty() const { return !dirtyRect.IsEmpty(); } |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 45 | |
| 46 | // Reset update state for the current frame. This should occur before painting |
| 47 | // for all layers. Since painting one layer can invalidate another layer |
| 48 | // after it has already painted, mark all non-dirty tiles as valid before painting |
| 49 | // such that invalidations during painting won't prevent them from being pushed. |
| 50 | void resetUpdateState() |
| 51 | { |
[email protected] | aad0a007 | 2012-11-01 18:15:58 | [diff] [blame] | 52 | updateRect = gfx::Rect(); |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 53 | occluded = false; |
| 54 | partialUpdate = false; |
| 55 | validForFrame = !isDirty(); |
| 56 | } |
| 57 | |
| 58 | // This promises to update the tile and therefore also guarantees the tile |
| 59 | // will be valid for this frame. dirtyRect is copied into updateRect so |
| 60 | // we can continue to track re-entrant invalidations that occur during painting. |
| 61 | void markForUpdate() |
| 62 | { |
| 63 | validForFrame = true; |
| 64 | updateRect = dirtyRect; |
[email protected] | aad0a007 | 2012-11-01 18:15:58 | [diff] [blame] | 65 | dirtyRect = gfx::Rect(); |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 66 | } |
| 67 | |
[email protected] | aad0a007 | 2012-11-01 18:15:58 | [diff] [blame] | 68 | gfx::Rect dirtyRect; |
| 69 | gfx::Rect updateRect; |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 70 | bool partialUpdate; |
| 71 | bool validForFrame; |
| 72 | bool occluded; |
[email protected] | 321fe370 | 2012-10-16 17:32:48 | [diff] [blame] | 73 | |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 74 | private: |
[email protected] | f33db56 | 2012-10-25 03:25:55 | [diff] [blame] | 75 | explicit UpdatableTile(scoped_ptr<LayerUpdater::Resource> updaterResource) |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 76 | : partialUpdate(false) |
| 77 | , validForFrame(false) |
| 78 | , occluded(false) |
[email protected] | f33db56 | 2012-10-25 03:25:55 | [diff] [blame] | 79 | , m_updaterResource(updaterResource.Pass()) |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 80 | { |
| 81 | } |
| 82 | |
[email protected] | f33db56 | 2012-10-25 03:25:55 | [diff] [blame] | 83 | scoped_ptr<LayerUpdater::Resource> m_updaterResource; |
[email protected] | fd2d4f2 | 2012-09-28 22:57:20 | [diff] [blame] | 84 | |
| 85 | DISALLOW_COPY_AND_ASSIGN(UpdatableTile); |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 86 | }; |
| 87 | |
[email protected] | 96baf3e | 2012-10-22 23:09:55 | [diff] [blame] | 88 | TiledLayer::TiledLayer() |
[email protected] | 904e913 | 2012-11-01 00:12:47 | [diff] [blame] | 89 | : ContentsScalingLayer() |
[email protected] | d9c2852 | 2012-10-18 23:35:43 | [diff] [blame] | 90 | , m_textureFormat(GL_INVALID_ENUM) |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 91 | , m_skipsDraw(false) |
| 92 | , m_failedUpdate(false) |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 93 | , m_tilingOption(AutoTile) |
| 94 | { |
[email protected] | aad0a007 | 2012-11-01 18:15:58 | [diff] [blame] | 95 | m_tiler = LayerTilingData::create(gfx::Size(), LayerTilingData::HasBorderTexels); |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 96 | } |
| 97 | |
[email protected] | 96baf3e | 2012-10-22 23:09:55 | [diff] [blame] | 98 | TiledLayer::~TiledLayer() |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 99 | { |
| 100 | } |
| 101 | |
[email protected] | 96baf3e | 2012-10-22 23:09:55 | [diff] [blame] | 102 | scoped_ptr<LayerImpl> TiledLayer::createLayerImpl() |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 103 | { |
[email protected] | 96baf3e | 2012-10-22 23:09:55 | [diff] [blame] | 104 | return TiledLayerImpl::create(id()).PassAs<LayerImpl>(); |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 105 | } |
| 106 | |
[email protected] | 96baf3e | 2012-10-22 23:09:55 | [diff] [blame] | 107 | void TiledLayer::updateTileSizeAndTilingOption() |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 108 | { |
[email protected] | 1d99317 | 2012-10-18 18:15:04 | [diff] [blame] | 109 | DCHECK(layerTreeHost()); |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 110 | |
[email protected] | aad0a007 | 2012-11-01 18:15:58 | [diff] [blame] | 111 | gfx::Size defaultTileSize = layerTreeHost()->settings().defaultTileSize; |
| 112 | gfx::Size maxUntiledLayerSize = layerTreeHost()->settings().maxUntiledLayerSize; |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 113 | int layerWidth = contentBounds().width(); |
| 114 | int layerHeight = contentBounds().height(); |
| 115 | |
[email protected] | aad0a007 | 2012-11-01 18:15:58 | [diff] [blame] | 116 | gfx::Size tileSize(min(defaultTileSize.width(), layerWidth), min(defaultTileSize.height(), layerHeight)); |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 117 | |
| 118 | // Tile if both dimensions large, or any one dimension large and the other |
| 119 | // extends into a second tile but the total layer area isn't larger than that |
| 120 | // of the largest possible untiled layer. This heuristic allows for long skinny layers |
| 121 | // (e.g. scrollbars) that are Nx1 tiles to minimize wasted texture space but still avoids |
| 122 | // creating very large tiles. |
[email protected] | aad0a007 | 2012-11-01 18:15:58 | [diff] [blame] | 123 | bool anyDimensionLarge = layerWidth > maxUntiledLayerSize.width() || layerHeight > maxUntiledLayerSize.height(); |
| 124 | bool anyDimensionOneTile = (layerWidth <= defaultTileSize.width() || layerHeight <= defaultTileSize.height()) |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 125 | && (layerWidth * layerHeight) <= (maxUntiledLayerSize.width() * maxUntiledLayerSize.height()); |
[email protected] | aad0a007 | 2012-11-01 18:15:58 | [diff] [blame] | 126 | bool autoTiled = anyDimensionLarge && !anyDimensionOneTile; |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 127 | |
| 128 | bool isTiled; |
| 129 | if (m_tilingOption == AlwaysTile) |
| 130 | isTiled = true; |
| 131 | else if (m_tilingOption == NeverTile) |
| 132 | isTiled = false; |
| 133 | else |
| 134 | isTiled = autoTiled; |
| 135 | |
[email protected] | aad0a007 | 2012-11-01 18:15:58 | [diff] [blame] | 136 | gfx::Size requestedSize = isTiled ? tileSize : contentBounds(); |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 137 | const int maxSize = layerTreeHost()->rendererCapabilities().maxTextureSize; |
[email protected] | aad0a007 | 2012-11-01 18:15:58 | [diff] [blame] | 138 | gfx::Size clampedSize = ClampSizeFromAbove(requestedSize, gfx::Size(maxSize, maxSize)); |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 139 | setTileSize(clampedSize); |
| 140 | } |
| 141 | |
[email protected] | 96baf3e | 2012-10-22 23:09:55 | [diff] [blame] | 142 | void TiledLayer::updateBounds() |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 143 | { |
[email protected] | aad0a007 | 2012-11-01 18:15:58 | [diff] [blame] | 144 | gfx::Size oldBounds = m_tiler->bounds(); |
| 145 | gfx::Size newBounds = contentBounds(); |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 146 | if (oldBounds == newBounds) |
| 147 | return; |
| 148 | m_tiler->setBounds(newBounds); |
| 149 | |
| 150 | // Invalidate any areas that the new bounds exposes. |
[email protected] | d0f9836 | 2012-11-01 23:02:38 | [diff] [blame] | 151 | Region oldRegion = gfx::Rect(gfx::Point(), oldBounds); |
| 152 | Region newRegion = gfx::Rect(gfx::Point(), newBounds); |
| 153 | newRegion.Subtract(oldRegion); |
[email protected] | 0d8a3050 | 2012-11-03 02:59:15 | [diff] [blame] | 154 | for (Region::Iterator newRects(newRegion); newRects.has_rect(); newRects.next()) |
| 155 | invalidateContentRect(newRects.rect()); |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 156 | } |
| 157 | |
[email protected] | aad0a007 | 2012-11-01 18:15:58 | [diff] [blame] | 158 | void TiledLayer::setTileSize(const gfx::Size& size) |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 159 | { |
| 160 | m_tiler->setTileSize(size); |
| 161 | } |
| 162 | |
[email protected] | 96baf3e | 2012-10-22 23:09:55 | [diff] [blame] | 163 | void TiledLayer::setBorderTexelOption(LayerTilingData::BorderTexelOption borderTexelOption) |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 164 | { |
| 165 | m_tiler->setBorderTexelOption(borderTexelOption); |
| 166 | } |
| 167 | |
[email protected] | 96baf3e | 2012-10-22 23:09:55 | [diff] [blame] | 168 | bool TiledLayer::drawsContent() const |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 169 | { |
[email protected] | 904e913 | 2012-11-01 00:12:47 | [diff] [blame] | 170 | if (!ContentsScalingLayer::drawsContent()) |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 171 | return false; |
| 172 | |
| 173 | bool hasMoreThanOneTile = m_tiler->numTilesX() > 1 || m_tiler->numTilesY() > 1; |
| 174 | if (m_tilingOption == NeverTile && hasMoreThanOneTile) |
| 175 | return false; |
| 176 | |
| 177 | return true; |
| 178 | } |
| 179 | |
[email protected] | 96baf3e | 2012-10-22 23:09:55 | [diff] [blame] | 180 | void TiledLayer::setTilingOption(TilingOption tilingOption) |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 181 | { |
| 182 | m_tilingOption = tilingOption; |
| 183 | } |
| 184 | |
[email protected] | 96baf3e | 2012-10-22 23:09:55 | [diff] [blame] | 185 | void TiledLayer::setIsMask(bool isMask) |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 186 | { |
| 187 | setTilingOption(isMask ? NeverTile : AutoTile); |
| 188 | } |
| 189 | |
[email protected] | 96baf3e | 2012-10-22 23:09:55 | [diff] [blame] | 190 | void TiledLayer::pushPropertiesTo(LayerImpl* layer) |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 191 | { |
[email protected] | 904e913 | 2012-11-01 00:12:47 | [diff] [blame] | 192 | ContentsScalingLayer::pushPropertiesTo(layer); |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 193 | |
[email protected] | 96baf3e | 2012-10-22 23:09:55 | [diff] [blame] | 194 | TiledLayerImpl* tiledLayer = static_cast<TiledLayerImpl*>(layer); |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 195 | |
| 196 | tiledLayer->setSkipsDraw(m_skipsDraw); |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 197 | tiledLayer->setTilingData(*m_tiler); |
[email protected] | 787465c | 2012-10-29 01:12:27 | [diff] [blame] | 198 | std::vector<UpdatableTile*> invalidTiles; |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 199 | |
[email protected] | 96baf3e | 2012-10-22 23:09:55 | [diff] [blame] | 200 | for (LayerTilingData::TileMap::const_iterator iter = m_tiler->tiles().begin(); iter != m_tiler->tiles().end(); ++iter) { |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 201 | int i = iter->first.first; |
| 202 | int j = iter->first.second; |
[email protected] | 0def90d | 2012-10-15 23:16:49 | [diff] [blame] | 203 | UpdatableTile* tile = static_cast<UpdatableTile*>(iter->second); |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 204 | // FIXME: This should not ever be null. |
| 205 | if (!tile) |
| 206 | continue; |
[email protected] | a416a0be | 2012-09-28 22:00:10 | [diff] [blame] | 207 | |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 208 | if (!tile->managedTexture()->haveBackingTexture()) { |
[email protected] | a416a0be | 2012-09-28 22:00:10 | [diff] [blame] | 209 | // Evicted tiles get deleted from both layers |
[email protected] | 787465c | 2012-10-29 01:12:27 | [diff] [blame] | 210 | invalidTiles.push_back(tile); |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 211 | continue; |
| 212 | } |
[email protected] | a416a0be | 2012-09-28 22:00:10 | [diff] [blame] | 213 | |
| 214 | if (!tile->validForFrame) { |
| 215 | // Invalidated tiles are set so they can get different debug colors. |
| 216 | tiledLayer->pushInvalidTile(i, j); |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 217 | continue; |
[email protected] | a416a0be | 2012-09-28 22:00:10 | [diff] [blame] | 218 | } |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 219 | |
[email protected] | fdc7693 | 2012-10-22 19:51:31 | [diff] [blame] | 220 | tiledLayer->pushTileProperties(i, j, tile->managedTexture()->resourceId(), tile->opaqueRect(), tile->managedTexture()->contentsSwizzled()); |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 221 | } |
[email protected] | 787465c | 2012-10-29 01:12:27 | [diff] [blame] | 222 | for (std::vector<UpdatableTile*>::const_iterator iter = invalidTiles.begin(); iter != invalidTiles.end(); ++iter) |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 223 | m_tiler->takeTile((*iter)->i(), (*iter)->j()); |
| 224 | } |
| 225 | |
[email protected] | 96baf3e | 2012-10-22 23:09:55 | [diff] [blame] | 226 | PrioritizedTextureManager* TiledLayer::textureManager() const |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 227 | { |
| 228 | if (!layerTreeHost()) |
| 229 | return 0; |
| 230 | return layerTreeHost()->contentsTextureManager(); |
| 231 | } |
| 232 | |
[email protected] | 96baf3e | 2012-10-22 23:09:55 | [diff] [blame] | 233 | void TiledLayer::setLayerTreeHost(LayerTreeHost* host) |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 234 | { |
| 235 | if (host && host != layerTreeHost()) { |
[email protected] | 96baf3e | 2012-10-22 23:09:55 | [diff] [blame] | 236 | for (LayerTilingData::TileMap::const_iterator iter = m_tiler->tiles().begin(); iter != m_tiler->tiles().end(); ++iter) { |
[email protected] | 0def90d | 2012-10-15 23:16:49 | [diff] [blame] | 237 | UpdatableTile* tile = static_cast<UpdatableTile*>(iter->second); |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 238 | // FIXME: This should not ever be null. |
| 239 | if (!tile) |
| 240 | continue; |
| 241 | tile->managedTexture()->setTextureManager(host->contentsTextureManager()); |
| 242 | } |
| 243 | } |
[email protected] | 904e913 | 2012-11-01 00:12:47 | [diff] [blame] | 244 | ContentsScalingLayer::setLayerTreeHost(host); |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 245 | } |
| 246 | |
[email protected] | 96baf3e | 2012-10-22 23:09:55 | [diff] [blame] | 247 | UpdatableTile* TiledLayer::tileAt(int i, int j) const |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 248 | { |
| 249 | return static_cast<UpdatableTile*>(m_tiler->tileAt(i, j)); |
| 250 | } |
| 251 | |
[email protected] | 96baf3e | 2012-10-22 23:09:55 | [diff] [blame] | 252 | UpdatableTile* TiledLayer::createTile(int i, int j) |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 253 | { |
[email protected] | 64d8d39 | 2012-10-23 18:34:51 | [diff] [blame] | 254 | createUpdaterIfNeeded(); |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 255 | |
[email protected] | f33db56 | 2012-10-25 03:25:55 | [diff] [blame] | 256 | scoped_ptr<UpdatableTile> tile(UpdatableTile::create(updater()->createResource(textureManager()))); |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 257 | tile->managedTexture()->setDimensions(m_tiler->tileSize(), m_textureFormat); |
| 258 | |
| 259 | UpdatableTile* addedTile = tile.get(); |
[email protected] | 96baf3e | 2012-10-22 23:09:55 | [diff] [blame] | 260 | m_tiler->addTile(tile.PassAs<LayerTilingData::Tile>(), i, j); |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 261 | |
| 262 | addedTile->dirtyRect = m_tiler->tileRect(addedTile); |
| 263 | |
| 264 | // Temporary diagnostic crash. |
| 265 | if (!addedTile) |
| 266 | CRASH(); |
| 267 | if (!tileAt(i, j)) |
| 268 | CRASH(); |
| 269 | |
| 270 | return addedTile; |
| 271 | } |
| 272 | |
[email protected] | aad0a007 | 2012-11-01 18:15:58 | [diff] [blame] | 273 | void TiledLayer::setNeedsDisplayRect(const gfx::RectF& dirtyRect) |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 274 | { |
[email protected] | 904e913 | 2012-11-01 00:12:47 | [diff] [blame] | 275 | invalidateContentRect(layerRectToContentRect(dirtyRect)); |
| 276 | ContentsScalingLayer::setNeedsDisplayRect(dirtyRect); |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 277 | } |
| 278 | |
[email protected] | 96baf3e | 2012-10-22 23:09:55 | [diff] [blame] | 279 | void TiledLayer::setUseLCDText(bool useLCDText) |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 280 | { |
[email protected] | 904e913 | 2012-11-01 00:12:47 | [diff] [blame] | 281 | ContentsScalingLayer::setUseLCDText(useLCDText); |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 282 | |
[email protected] | 96baf3e | 2012-10-22 23:09:55 | [diff] [blame] | 283 | LayerTilingData::BorderTexelOption borderTexelOption; |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 284 | #if OS(ANDROID) |
| 285 | // Always want border texels and GL_LINEAR due to pinch zoom. |
[email protected] | 96baf3e | 2012-10-22 23:09:55 | [diff] [blame] | 286 | borderTexelOption = LayerTilingData::HasBorderTexels; |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 287 | #else |
[email protected] | 96baf3e | 2012-10-22 23:09:55 | [diff] [blame] | 288 | borderTexelOption = useLCDText ? LayerTilingData::NoBorderTexels : LayerTilingData::HasBorderTexels; |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 289 | #endif |
| 290 | setBorderTexelOption(borderTexelOption); |
| 291 | } |
| 292 | |
[email protected] | aad0a007 | 2012-11-01 18:15:58 | [diff] [blame] | 293 | void TiledLayer::invalidateContentRect(const gfx::Rect& contentRect) |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 294 | { |
| 295 | updateBounds(); |
[email protected] | aad0a007 | 2012-11-01 18:15:58 | [diff] [blame] | 296 | if (m_tiler->isEmpty() || contentRect.IsEmpty() || m_skipsDraw) |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 297 | return; |
| 298 | |
[email protected] | 96baf3e | 2012-10-22 23:09:55 | [diff] [blame] | 299 | for (LayerTilingData::TileMap::const_iterator iter = m_tiler->tiles().begin(); iter != m_tiler->tiles().end(); ++iter) { |
[email protected] | 0def90d | 2012-10-15 23:16:49 | [diff] [blame] | 300 | UpdatableTile* tile = static_cast<UpdatableTile*>(iter->second); |
[email protected] | 1d99317 | 2012-10-18 18:15:04 | [diff] [blame] | 301 | DCHECK(tile); |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 302 | // FIXME: This should not ever be null. |
| 303 | if (!tile) |
| 304 | continue; |
[email protected] | aad0a007 | 2012-11-01 18:15:58 | [diff] [blame] | 305 | gfx::Rect bound = m_tiler->tileRect(tile); |
| 306 | bound.Intersect(contentRect); |
| 307 | tile->dirtyRect.Union(bound); |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 308 | } |
| 309 | } |
| 310 | |
| 311 | // Returns true if tile is dirty and only part of it needs to be updated. |
[email protected] | 96baf3e | 2012-10-22 23:09:55 | [diff] [blame] | 312 | bool TiledLayer::tileOnlyNeedsPartialUpdate(UpdatableTile* tile) |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 313 | { |
[email protected] | aad0a007 | 2012-11-01 18:15:58 | [diff] [blame] | 314 | return !tile->dirtyRect.Contains(m_tiler->tileRect(tile)) && tile->managedTexture()->haveBackingTexture(); |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 315 | } |
| 316 | |
[email protected] | b4da203 | 2012-10-25 21:22:55 | [diff] [blame] | 317 | bool TiledLayer::updateTiles(int left, int top, int right, int bottom, ResourceUpdateQueue& queue, const OcclusionTracker* occlusion, RenderingStats& stats, bool& didPaint) |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 318 | { |
| 319 | didPaint = false; |
[email protected] | 64d8d39 | 2012-10-23 18:34:51 | [diff] [blame] | 320 | createUpdaterIfNeeded(); |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 321 | |
| 322 | bool ignoreOcclusions = !occlusion; |
| 323 | if (!haveTexturesForTiles(left, top, right, bottom, ignoreOcclusions)) { |
| 324 | m_failedUpdate = true; |
| 325 | return false; |
| 326 | } |
| 327 | |
[email protected] | aad0a007 | 2012-11-01 18:15:58 | [diff] [blame] | 328 | gfx::Rect paintRect = markTilesForUpdate(left, top, right, bottom, ignoreOcclusions); |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 329 | |
| 330 | if (occlusion) |
[email protected] | d0f9836 | 2012-11-01 23:02:38 | [diff] [blame] | 331 | occlusion->overdrawMetrics().didPaint(paintRect); |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 332 | |
[email protected] | aad0a007 | 2012-11-01 18:15:58 | [diff] [blame] | 333 | if (paintRect.IsEmpty()) |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 334 | return true; |
| 335 | |
| 336 | didPaint = true; |
| 337 | updateTileTextures(paintRect, left, top, right, bottom, queue, occlusion, stats); |
| 338 | return true; |
| 339 | } |
| 340 | |
[email protected] | 96baf3e | 2012-10-22 23:09:55 | [diff] [blame] | 341 | void TiledLayer::markOcclusionsAndRequestTextures(int left, int top, int right, int bottom, const OcclusionTracker* occlusion) |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 342 | { |
| 343 | // There is some difficult dependancies between occlusions, recording occlusion metrics |
| 344 | // and requesting memory so those are encapsulated in this function: |
| 345 | // - We only want to call requestLate on unoccluded textures (to preserve |
| 346 | // memory for other layers when near OOM). |
| 347 | // - We only want to record occlusion metrics if all memory requests succeed. |
| 348 | |
| 349 | int occludedTileCount = 0; |
| 350 | bool succeeded = true; |
| 351 | for (int j = top; j <= bottom; ++j) { |
| 352 | for (int i = left; i <= right; ++i) { |
| 353 | UpdatableTile* tile = tileAt(i, j); |
[email protected] | 1d99317 | 2012-10-18 18:15:04 | [diff] [blame] | 354 | DCHECK(tile); // Did setTexturePriorities get skipped? |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 355 | // FIXME: This should not ever be null. |
| 356 | if (!tile) |
| 357 | continue; |
[email protected] | 1d99317 | 2012-10-18 18:15:04 | [diff] [blame] | 358 | DCHECK(!tile->occluded); // Did resetUpdateState get skipped? Are we doing more than one occlusion pass? |
[email protected] | aad0a007 | 2012-11-01 18:15:58 | [diff] [blame] | 359 | gfx::Rect visibleTileRect = gfx::IntersectRects(m_tiler->tileBounds(i, j), visibleContentRect()); |
[email protected] | 710ffc0 | 2012-10-30 21:42:02 | [diff] [blame] | 360 | if (occlusion && occlusion->occluded(renderTarget(), visibleTileRect, drawTransform(), drawTransformIsAnimating(), drawableContentRect())) { |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 361 | tile->occluded = true; |
| 362 | occludedTileCount++; |
| 363 | } else { |
| 364 | succeeded &= tile->managedTexture()->requestLate(); |
| 365 | } |
| 366 | } |
| 367 | } |
| 368 | |
| 369 | if (!succeeded) |
| 370 | return; |
[email protected] | 4b685d3 | 2012-10-25 19:06:40 | [diff] [blame] | 371 | if (occlusion) |
| 372 | occlusion->overdrawMetrics().didCullTilesForUpload(occludedTileCount); |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 373 | } |
| 374 | |
[email protected] | 96baf3e | 2012-10-22 23:09:55 | [diff] [blame] | 375 | bool TiledLayer::haveTexturesForTiles(int left, int top, int right, int bottom, bool ignoreOcclusions) |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 376 | { |
| 377 | for (int j = top; j <= bottom; ++j) { |
| 378 | for (int i = left; i <= right; ++i) { |
| 379 | UpdatableTile* tile = tileAt(i, j); |
[email protected] | 1d99317 | 2012-10-18 18:15:04 | [diff] [blame] | 380 | DCHECK(tile); // Did setTexturePriorites get skipped? |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 381 | // FIXME: This should not ever be null. |
| 382 | if (!tile) |
| 383 | continue; |
| 384 | |
| 385 | // Ensure the entire tile is dirty if we don't have the texture. |
| 386 | if (!tile->managedTexture()->haveBackingTexture()) |
| 387 | tile->dirtyRect = m_tiler->tileRect(tile); |
| 388 | |
| 389 | // If using occlusion and the visible region of the tile is occluded, |
| 390 | // don't reserve a texture or update the tile. |
| 391 | if (tile->occluded && !ignoreOcclusions) |
| 392 | continue; |
| 393 | |
| 394 | if (!tile->managedTexture()->canAcquireBackingTexture()) |
| 395 | return false; |
| 396 | } |
| 397 | } |
| 398 | return true; |
| 399 | } |
| 400 | |
[email protected] | aad0a007 | 2012-11-01 18:15:58 | [diff] [blame] | 401 | gfx::Rect TiledLayer::markTilesForUpdate(int left, int top, int right, int bottom, bool ignoreOcclusions) |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 402 | { |
[email protected] | aad0a007 | 2012-11-01 18:15:58 | [diff] [blame] | 403 | gfx::Rect paintRect; |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 404 | for (int j = top; j <= bottom; ++j) { |
| 405 | for (int i = left; i <= right; ++i) { |
| 406 | UpdatableTile* tile = tileAt(i, j); |
[email protected] | 1d99317 | 2012-10-18 18:15:04 | [diff] [blame] | 407 | DCHECK(tile); // Did setTexturePriorites get skipped? |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 408 | // FIXME: This should not ever be null. |
| 409 | if (!tile) |
| 410 | continue; |
| 411 | if (tile->occluded && !ignoreOcclusions) |
| 412 | continue; |
[email protected] | 4b685d3 | 2012-10-25 19:06:40 | [diff] [blame] | 413 | // FIXME: Decide if partial update should be allowed based on cost |
| 414 | // of update. https://bugs.webkit.org/show_bug.cgi?id=77376 |
| 415 | if (tile->isDirty() && layerTreeHost() && layerTreeHost()->bufferedUpdates()) { |
| 416 | // If we get a partial update, we use the same texture, otherwise return the |
| 417 | // current texture backing, so we don't update visible textures non-atomically. |
| 418 | // If the current backing is in-use, it won't be deleted until after the commit |
| 419 | // as the texture manager will not allow deletion or recycling of in-use textures. |
| 420 | if (tileOnlyNeedsPartialUpdate(tile) && layerTreeHost()->requestPartialTextureUpdate()) |
| 421 | tile->partialUpdate = true; |
| 422 | else { |
| 423 | tile->dirtyRect = m_tiler->tileRect(tile); |
| 424 | tile->managedTexture()->returnBackingTexture(); |
| 425 | } |
| 426 | } |
| 427 | |
[email protected] | aad0a007 | 2012-11-01 18:15:58 | [diff] [blame] | 428 | paintRect.Union(tile->dirtyRect); |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 429 | tile->markForUpdate(); |
| 430 | } |
| 431 | } |
| 432 | return paintRect; |
| 433 | } |
| 434 | |
[email protected] | aad0a007 | 2012-11-01 18:15:58 | [diff] [blame] | 435 | void TiledLayer::updateTileTextures(const gfx::Rect& paintRect, int left, int top, int right, int bottom, ResourceUpdateQueue& queue, const OcclusionTracker* occlusion, RenderingStats& stats) |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 436 | { |
| 437 | // The updateRect should be in layer space. So we have to convert the paintRect from content space to layer space. |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 438 | float widthScale = bounds().width() / static_cast<float>(contentBounds().width()); |
| 439 | float heightScale = bounds().height() / static_cast<float>(contentBounds().height()); |
[email protected] | aad0a007 | 2012-11-01 18:15:58 | [diff] [blame] | 440 | m_updateRect = gfx::ScaleRect(paintRect, widthScale, heightScale); |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 441 | |
| 442 | // Calling prepareToUpdate() calls into WebKit to paint, which may have the side |
| 443 | // effect of disabling compositing, which causes our reference to the texture updater to be deleted. |
| 444 | // However, we can't free the memory backing the SkCanvas until the paint finishes, |
| 445 | // so we grab a local reference here to hold the updater alive until the paint completes. |
[email protected] | 64d8d39 | 2012-10-23 18:34:51 | [diff] [blame] | 446 | scoped_refptr<LayerUpdater> protector(updater()); |
[email protected] | f809d3bb | 2012-10-31 20:52:25 | [diff] [blame] | 447 | gfx::Rect paintedOpaqueRect; |
[email protected] | 64d8d39 | 2012-10-23 18:34:51 | [diff] [blame] | 448 | updater()->prepareToUpdate(paintRect, m_tiler->tileSize(), 1 / widthScale, 1 / heightScale, paintedOpaqueRect, stats); |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 449 | |
| 450 | for (int j = top; j <= bottom; ++j) { |
| 451 | for (int i = left; i <= right; ++i) { |
| 452 | UpdatableTile* tile = tileAt(i, j); |
[email protected] | 1d99317 | 2012-10-18 18:15:04 | [diff] [blame] | 453 | DCHECK(tile); // Did setTexturePriorites get skipped? |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 454 | // FIXME: This should not ever be null. |
| 455 | if (!tile) |
| 456 | continue; |
| 457 | |
[email protected] | aad0a007 | 2012-11-01 18:15:58 | [diff] [blame] | 458 | gfx::Rect tileRect = m_tiler->tileBounds(i, j); |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 459 | |
| 460 | // Use updateRect as the above loop copied the dirty rect for this frame to updateRect. |
[email protected] | aad0a007 | 2012-11-01 18:15:58 | [diff] [blame] | 461 | const gfx::Rect& dirtyRect = tile->updateRect; |
| 462 | if (dirtyRect.IsEmpty()) |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 463 | continue; |
| 464 | |
| 465 | // Save what was painted opaque in the tile. Keep the old area if the paint didn't touch it, and didn't paint some |
| 466 | // other part of the tile opaque. |
[email protected] | aad0a007 | 2012-11-01 18:15:58 | [diff] [blame] | 467 | gfx::Rect tilePaintedRect = gfx::IntersectRects(tileRect, paintRect); |
| 468 | gfx::Rect tilePaintedOpaqueRect = gfx::IntersectRects(tileRect, paintedOpaqueRect); |
| 469 | if (!tilePaintedRect.IsEmpty()) { |
| 470 | gfx::Rect paintInsideTileOpaqueRect = gfx::IntersectRects(tile->opaqueRect(), tilePaintedRect); |
| 471 | bool paintInsideTileOpaqueRectIsNonOpaque = !tilePaintedOpaqueRect.Contains(paintInsideTileOpaqueRect); |
| 472 | bool opaquePaintNotInsideTileOpaqueRect = !tilePaintedOpaqueRect.IsEmpty() && !tile->opaqueRect().Contains(tilePaintedOpaqueRect); |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 473 | |
| 474 | if (paintInsideTileOpaqueRectIsNonOpaque || opaquePaintNotInsideTileOpaqueRect) |
| 475 | tile->setOpaqueRect(tilePaintedOpaqueRect); |
| 476 | } |
| 477 | |
| 478 | // sourceRect starts as a full-sized tile with border texels included. |
[email protected] | aad0a007 | 2012-11-01 18:15:58 | [diff] [blame] | 479 | gfx::Rect sourceRect = m_tiler->tileRect(tile); |
| 480 | sourceRect.Intersect(dirtyRect); |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 481 | // Paint rect not guaranteed to line up on tile boundaries, so |
| 482 | // make sure that sourceRect doesn't extend outside of it. |
[email protected] | aad0a007 | 2012-11-01 18:15:58 | [diff] [blame] | 483 | sourceRect.Intersect(paintRect); |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 484 | |
| 485 | tile->updateRect = sourceRect; |
| 486 | |
[email protected] | aad0a007 | 2012-11-01 18:15:58 | [diff] [blame] | 487 | if (sourceRect.IsEmpty()) |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 488 | continue; |
| 489 | |
[email protected] | aad0a007 | 2012-11-01 18:15:58 | [diff] [blame] | 490 | const gfx::Point anchor = m_tiler->tileRect(tile).origin(); |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 491 | |
| 492 | // Calculate tile-space rectangle to upload into. |
[email protected] | aad0a007 | 2012-11-01 18:15:58 | [diff] [blame] | 493 | gfx::Vector2d destOffset = sourceRect.origin() - anchor; |
[email protected] | f809d3bb | 2012-10-31 20:52:25 | [diff] [blame] | 494 | if (destOffset.x() < 0) |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 495 | CRASH(); |
[email protected] | f809d3bb | 2012-10-31 20:52:25 | [diff] [blame] | 496 | if (destOffset.y() < 0) |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 497 | CRASH(); |
| 498 | |
| 499 | // Offset from paint rectangle to this tile's dirty rectangle. |
[email protected] | aad0a007 | 2012-11-01 18:15:58 | [diff] [blame] | 500 | gfx::Vector2d paintOffset = sourceRect.origin() - paintRect.origin(); |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 501 | if (paintOffset.x() < 0) |
| 502 | CRASH(); |
| 503 | if (paintOffset.y() < 0) |
| 504 | CRASH(); |
| 505 | if (paintOffset.x() + sourceRect.width() > paintRect.width()) |
| 506 | CRASH(); |
| 507 | if (paintOffset.y() + sourceRect.height() > paintRect.height()) |
| 508 | CRASH(); |
| 509 | |
[email protected] | f33db56 | 2012-10-25 03:25:55 | [diff] [blame] | 510 | tile->updaterResource()->update(queue, sourceRect, destOffset, tile->partialUpdate, stats); |
[email protected] | ea8af90e | 2012-10-13 10:20:27 | [diff] [blame] | 511 | if (occlusion) |
[email protected] | d0f9836 | 2012-11-01 23:02:38 | [diff] [blame] | 512 | occlusion->overdrawMetrics().didUpload(WebTransformationMatrix(), sourceRect, tile->opaqueRect()); |
[email protected] | ea8af90e | 2012-10-13 10:20:27 | [diff] [blame] | 513 | |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 514 | } |
| 515 | } |
| 516 | } |
| 517 | |
| 518 | namespace { |
| 519 | // This picks a small animated layer to be anything less than one viewport. This |
| 520 | // is specifically for page transitions which are viewport-sized layers. The extra |
| 521 | // 64 pixels is due to these layers being slightly larger than the viewport in some cases. |
[email protected] | 96baf3e | 2012-10-22 23:09:55 | [diff] [blame] | 522 | bool isSmallAnimatedLayer(TiledLayer* layer) |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 523 | { |
| 524 | if (!layer->drawTransformIsAnimating() && !layer->screenSpaceTransformIsAnimating()) |
| 525 | return false; |
[email protected] | aad0a007 | 2012-11-01 18:15:58 | [diff] [blame] | 526 | gfx::Size viewportSize = layer->layerTreeHost() ? layer->layerTreeHost()->deviceViewportSize() : gfx::Size(); |
| 527 | gfx::Rect contentRect(gfx::Point(), layer->contentBounds()); |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 528 | return contentRect.width() <= viewportSize.width() + 64 |
| 529 | && contentRect.height() <= viewportSize.height() + 64; |
| 530 | } |
| 531 | |
| 532 | // FIXME: Remove this and make this based on distance once distance can be calculated |
| 533 | // for offscreen layers. For now, prioritize all small animated layers after 512 |
| 534 | // pixels of pre-painting. |
[email protected] | aad0a007 | 2012-11-01 18:15:58 | [diff] [blame] | 535 | void setPriorityForTexture(const gfx::Rect& visibleRect, |
| 536 | const gfx::Rect& tileRect, |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 537 | bool drawsToRoot, |
| 538 | bool isSmallAnimatedLayer, |
[email protected] | 96baf3e | 2012-10-22 23:09:55 | [diff] [blame] | 539 | PrioritizedTexture* texture) |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 540 | { |
[email protected] | 96baf3e | 2012-10-22 23:09:55 | [diff] [blame] | 541 | int priority = PriorityCalculator::lowestPriority(); |
[email protected] | aad0a007 | 2012-11-01 18:15:58 | [diff] [blame] | 542 | if (!visibleRect.IsEmpty()) |
[email protected] | 96baf3e | 2012-10-22 23:09:55 | [diff] [blame] | 543 | priority = PriorityCalculator::priorityFromDistance(visibleRect, tileRect, drawsToRoot); |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 544 | if (isSmallAnimatedLayer) |
[email protected] | 96baf3e | 2012-10-22 23:09:55 | [diff] [blame] | 545 | priority = PriorityCalculator::maxPriority(priority, PriorityCalculator::smallAnimatedLayerMinPriority()); |
| 546 | if (priority != PriorityCalculator::lowestPriority()) |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 547 | texture->setRequestPriority(priority); |
| 548 | } |
| 549 | } |
| 550 | |
[email protected] | 96baf3e | 2012-10-22 23:09:55 | [diff] [blame] | 551 | void TiledLayer::setTexturePriorities(const PriorityCalculator& priorityCalc) |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 552 | { |
| 553 | updateBounds(); |
| 554 | resetUpdateState(); |
[email protected] | 8d93172 | 2012-10-23 20:26:46 | [diff] [blame] | 555 | updateScrollPrediction(); |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 556 | |
| 557 | if (m_tiler->hasEmptyBounds()) |
| 558 | return; |
| 559 | |
| 560 | bool drawsToRoot = !renderTarget()->parent(); |
| 561 | bool smallAnimatedLayer = isSmallAnimatedLayer(this); |
| 562 | |
| 563 | // Minimally create the tiles in the desired pre-paint rect. |
[email protected] | aad0a007 | 2012-11-01 18:15:58 | [diff] [blame] | 564 | gfx::Rect createTilesRect = idlePaintRect(); |
[email protected] | 4b685d3 | 2012-10-25 19:06:40 | [diff] [blame] | 565 | if (smallAnimatedLayer) |
[email protected] | aad0a007 | 2012-11-01 18:15:58 | [diff] [blame] | 566 | createTilesRect = gfx::Rect(gfx::Point(), contentBounds()); |
| 567 | if (!createTilesRect.IsEmpty()) { |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 568 | int left, top, right, bottom; |
| 569 | m_tiler->contentRectToTileIndices(createTilesRect, left, top, right, bottom); |
| 570 | for (int j = top; j <= bottom; ++j) { |
| 571 | for (int i = left; i <= right; ++i) { |
| 572 | if (!tileAt(i, j)) |
| 573 | createTile(i, j); |
| 574 | } |
| 575 | } |
| 576 | } |
| 577 | |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 578 | // Now update priorities on all tiles we have in the layer, no matter where they are. |
[email protected] | 96baf3e | 2012-10-22 23:09:55 | [diff] [blame] | 579 | for (LayerTilingData::TileMap::const_iterator iter = m_tiler->tiles().begin(); iter != m_tiler->tiles().end(); ++iter) { |
[email protected] | 0def90d | 2012-10-15 23:16:49 | [diff] [blame] | 580 | UpdatableTile* tile = static_cast<UpdatableTile*>(iter->second); |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 581 | // FIXME: This should not ever be null. |
| 582 | if (!tile) |
| 583 | continue; |
[email protected] | aad0a007 | 2012-11-01 18:15:58 | [diff] [blame] | 584 | gfx::Rect tileRect = m_tiler->tileRect(tile); |
[email protected] | 8d93172 | 2012-10-23 20:26:46 | [diff] [blame] | 585 | setPriorityForTexture(m_predictedVisibleRect, tileRect, drawsToRoot, smallAnimatedLayer, tile->managedTexture()); |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 586 | } |
| 587 | } |
| 588 | |
[email protected] | 96baf3e | 2012-10-22 23:09:55 | [diff] [blame] | 589 | Region TiledLayer::visibleContentOpaqueRegion() const |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 590 | { |
| 591 | if (m_skipsDraw) |
| 592 | return Region(); |
[email protected] | 048634c | 2012-10-02 22:33:14 | [diff] [blame] | 593 | if (contentsOpaque()) |
[email protected] | d0f9836 | 2012-11-01 23:02:38 | [diff] [blame] | 594 | return visibleContentRect(); |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 595 | return m_tiler->opaqueRegionInContentRect(visibleContentRect()); |
| 596 | } |
| 597 | |
[email protected] | 96baf3e | 2012-10-22 23:09:55 | [diff] [blame] | 598 | void TiledLayer::resetUpdateState() |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 599 | { |
| 600 | m_skipsDraw = false; |
| 601 | m_failedUpdate = false; |
| 602 | |
[email protected] | 96baf3e | 2012-10-22 23:09:55 | [diff] [blame] | 603 | LayerTilingData::TileMap::const_iterator end = m_tiler->tiles().end(); |
| 604 | for (LayerTilingData::TileMap::const_iterator iter = m_tiler->tiles().begin(); iter != end; ++iter) { |
[email protected] | 0def90d | 2012-10-15 23:16:49 | [diff] [blame] | 605 | UpdatableTile* tile = static_cast<UpdatableTile*>(iter->second); |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 606 | // FIXME: This should not ever be null. |
| 607 | if (!tile) |
| 608 | continue; |
| 609 | tile->resetUpdateState(); |
| 610 | } |
| 611 | } |
| 612 | |
[email protected] | 8d93172 | 2012-10-23 20:26:46 | [diff] [blame] | 613 | namespace { |
[email protected] | aad0a007 | 2012-11-01 18:15:58 | [diff] [blame] | 614 | gfx::Rect expandRectByDelta(gfx::Rect rect, gfx::Vector2d delta) { |
| 615 | int width = rect.width() + abs(delta.x()); |
| 616 | int height = rect.height() + abs(delta.y()); |
| 617 | int x = rect.x() + ((delta.x() < 0) ? delta.x() : 0); |
| 618 | int y = rect.y() + ((delta.y() < 0) ? delta.y() : 0); |
| 619 | return gfx::Rect(x, y, width, height); |
[email protected] | 8d93172 | 2012-10-23 20:26:46 | [diff] [blame] | 620 | } |
| 621 | } |
| 622 | |
| 623 | void TiledLayer::updateScrollPrediction() |
| 624 | { |
| 625 | // This scroll prediction is very primitive and should be replaced by a |
| 626 | // a recursive calculation on all layers which uses actual scroll/animation |
| 627 | // velocities. To insure this doesn't miss-predict, we only use it to predict |
| 628 | // the visibleRect if: |
| 629 | // - contentBounds() hasn't changed. |
| 630 | // - visibleRect.size() hasn't changed. |
| 631 | // These two conditions prevent rotations, scales, pinch-zooms etc. where |
| 632 | // the prediction would be incorrect. |
[email protected] | aad0a007 | 2012-11-01 18:15:58 | [diff] [blame] | 633 | gfx::Vector2d delta = visibleContentRect().CenterPoint() - m_previousVisibleRect.CenterPoint(); |
[email protected] | 8d93172 | 2012-10-23 20:26:46 | [diff] [blame] | 634 | m_predictedScroll = -delta; |
| 635 | m_predictedVisibleRect = visibleContentRect(); |
| 636 | if (m_previousContentBounds == contentBounds() && m_previousVisibleRect.size() == visibleContentRect().size()) { |
| 637 | // Only expand the visible rect in the major scroll direction, to prevent |
| 638 | // massive paints due to diagonal scrolls. |
[email protected] | aad0a007 | 2012-11-01 18:15:58 | [diff] [blame] | 639 | gfx::Vector2d majorScrollDelta = (abs(delta.x()) > abs(delta.y())) ? gfx::Vector2d(delta.x(), 0) : gfx::Vector2d(0, delta.y()); |
[email protected] | 8d93172 | 2012-10-23 20:26:46 | [diff] [blame] | 640 | m_predictedVisibleRect = expandRectByDelta(visibleContentRect(), majorScrollDelta); |
| 641 | |
| 642 | // Bound the prediction to prevent unbounded paints, and clamp to content bounds. |
[email protected] | aad0a007 | 2012-11-01 18:15:58 | [diff] [blame] | 643 | gfx::Rect bound = visibleContentRect(); |
| 644 | bound.Inset(-m_tiler->tileSize().width() * maxPredictiveTilesCount, |
| 645 | -m_tiler->tileSize().height() * maxPredictiveTilesCount); |
| 646 | bound.Intersect(gfx::Rect(gfx::Point(), contentBounds())); |
| 647 | m_predictedVisibleRect.Intersect(bound); |
[email protected] | 8d93172 | 2012-10-23 20:26:46 | [diff] [blame] | 648 | } |
| 649 | m_previousContentBounds = contentBounds(); |
| 650 | m_previousVisibleRect = visibleContentRect(); |
| 651 | } |
| 652 | |
[email protected] | b4da203 | 2012-10-25 21:22:55 | [diff] [blame] | 653 | void TiledLayer::update(ResourceUpdateQueue& queue, const OcclusionTracker* occlusion, RenderingStats& stats) |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 654 | { |
[email protected] | 1d99317 | 2012-10-18 18:15:04 | [diff] [blame] | 655 | DCHECK(!m_skipsDraw && !m_failedUpdate); // Did resetUpdateState get skipped? |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 656 | updateBounds(); |
| 657 | if (m_tiler->hasEmptyBounds() || !drawsContent()) |
| 658 | return; |
| 659 | |
| 660 | bool didPaint = false; |
| 661 | |
| 662 | // Animation pre-paint. If the layer is small, try to paint it all |
| 663 | // immediately whether or not it is occluded, to avoid paint/upload |
| 664 | // hiccups while it is animating. |
| 665 | if (isSmallAnimatedLayer(this)) { |
| 666 | int left, top, right, bottom; |
[email protected] | aad0a007 | 2012-11-01 18:15:58 | [diff] [blame] | 667 | m_tiler->contentRectToTileIndices(gfx::Rect(gfx::Point(), contentBounds()), left, top, right, bottom); |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 668 | updateTiles(left, top, right, bottom, queue, 0, stats, didPaint); |
| 669 | if (didPaint) |
| 670 | return; |
| 671 | // This was an attempt to paint the entire layer so if we fail it's okay, |
| 672 | // just fallback on painting visible etc. below. |
| 673 | m_failedUpdate = false; |
| 674 | } |
| 675 | |
[email protected] | aad0a007 | 2012-11-01 18:15:58 | [diff] [blame] | 676 | if (m_predictedVisibleRect.IsEmpty()) |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 677 | return; |
| 678 | |
| 679 | // Visible painting. First occlude visible tiles and paint the non-occluded tiles. |
| 680 | int left, top, right, bottom; |
[email protected] | 8d93172 | 2012-10-23 20:26:46 | [diff] [blame] | 681 | m_tiler->contentRectToTileIndices(m_predictedVisibleRect, left, top, right, bottom); |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 682 | markOcclusionsAndRequestTextures(left, top, right, bottom, occlusion); |
| 683 | m_skipsDraw = !updateTiles(left, top, right, bottom, queue, occlusion, stats, didPaint); |
| 684 | if (m_skipsDraw) |
| 685 | m_tiler->reset(); |
| 686 | if (m_skipsDraw || didPaint) |
| 687 | return; |
| 688 | |
| 689 | // If we have already painting everything visible. Do some pre-painting while idle. |
[email protected] | aad0a007 | 2012-11-01 18:15:58 | [diff] [blame] | 690 | gfx::Rect idlePaintContentRect = idlePaintRect(); |
| 691 | if (idlePaintContentRect.IsEmpty()) |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 692 | return; |
| 693 | |
| 694 | // Prepaint anything that was occluded but inside the layer's visible region. |
| 695 | if (!updateTiles(left, top, right, bottom, queue, 0, stats, didPaint) || didPaint) |
| 696 | return; |
| 697 | |
| 698 | int prepaintLeft, prepaintTop, prepaintRight, prepaintBottom; |
| 699 | m_tiler->contentRectToTileIndices(idlePaintContentRect, prepaintLeft, prepaintTop, prepaintRight, prepaintBottom); |
| 700 | |
[email protected] | 8d93172 | 2012-10-23 20:26:46 | [diff] [blame] | 701 | // Then expand outwards one row/column at a time until we find a dirty row/column |
| 702 | // to update. Increment along the major and minor scroll directions first. |
[email protected] | aad0a007 | 2012-11-01 18:15:58 | [diff] [blame] | 703 | gfx::Vector2d delta = -m_predictedScroll; |
| 704 | delta = gfx::Vector2d(delta.x() == 0 ? 1 : delta.x(), |
| 705 | delta.y() == 0 ? 1 : delta.y()); |
| 706 | gfx::Vector2d majorDelta = (abs(delta.x()) > abs(delta.y())) ? gfx::Vector2d(delta.x(), 0) : gfx::Vector2d(0, delta.y()); |
| 707 | gfx::Vector2d minorDelta = (abs(delta.x()) <= abs(delta.y())) ? gfx::Vector2d(delta.x(), 0) : gfx::Vector2d(0, delta.y()); |
| 708 | gfx::Vector2d deltas[4] = {majorDelta, minorDelta, -majorDelta, -minorDelta}; |
[email protected] | 8d93172 | 2012-10-23 20:26:46 | [diff] [blame] | 709 | for(int i = 0; i < 4; i++) { |
[email protected] | aad0a007 | 2012-11-01 18:15:58 | [diff] [blame] | 710 | if (deltas[i].y() > 0) { |
[email protected] | 8d93172 | 2012-10-23 20:26:46 | [diff] [blame] | 711 | while (bottom < prepaintBottom) { |
| 712 | ++bottom; |
| 713 | if (!updateTiles(left, bottom, right, bottom, queue, 0, stats, didPaint) || didPaint) |
| 714 | return; |
| 715 | } |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 716 | } |
[email protected] | aad0a007 | 2012-11-01 18:15:58 | [diff] [blame] | 717 | if (deltas[i].y() < 0) { |
[email protected] | 8d93172 | 2012-10-23 20:26:46 | [diff] [blame] | 718 | while (top > prepaintTop) { |
| 719 | --top; |
| 720 | if (!updateTiles(left, top, right, top, queue, 0, stats, didPaint) || didPaint) |
| 721 | return; |
| 722 | } |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 723 | } |
[email protected] | aad0a007 | 2012-11-01 18:15:58 | [diff] [blame] | 724 | if (deltas[i].x() < 0) { |
[email protected] | 8d93172 | 2012-10-23 20:26:46 | [diff] [blame] | 725 | while (left > prepaintLeft) { |
| 726 | --left; |
| 727 | if (!updateTiles(left, top, left, bottom, queue, 0, stats, didPaint) || didPaint) |
| 728 | return; |
| 729 | } |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 730 | } |
[email protected] | aad0a007 | 2012-11-01 18:15:58 | [diff] [blame] | 731 | if (deltas[i].x() > 0) { |
[email protected] | 8d93172 | 2012-10-23 20:26:46 | [diff] [blame] | 732 | while (right < prepaintRight) { |
| 733 | ++right; |
| 734 | if (!updateTiles(right, top, right, bottom, queue, 0, stats, didPaint) || didPaint) |
| 735 | return; |
| 736 | } |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 737 | } |
| 738 | } |
| 739 | } |
| 740 | |
[email protected] | 96baf3e | 2012-10-22 23:09:55 | [diff] [blame] | 741 | bool TiledLayer::needsIdlePaint() |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 742 | { |
| 743 | // Don't trigger more paints if we failed (as we'll just fail again). |
[email protected] | aad0a007 | 2012-11-01 18:15:58 | [diff] [blame] | 744 | if (m_failedUpdate || visibleContentRect().IsEmpty() || m_tiler->hasEmptyBounds() || !drawsContent()) |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 745 | return false; |
| 746 | |
[email protected] | aad0a007 | 2012-11-01 18:15:58 | [diff] [blame] | 747 | gfx::Rect idlePaintContentRect = idlePaintRect(); |
| 748 | if (idlePaintContentRect.IsEmpty()) |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 749 | return false; |
| 750 | |
| 751 | int left, top, right, bottom; |
| 752 | m_tiler->contentRectToTileIndices(idlePaintContentRect, left, top, right, bottom); |
| 753 | |
| 754 | for (int j = top; j <= bottom; ++j) { |
| 755 | for (int i = left; i <= right; ++i) { |
| 756 | UpdatableTile* tile = tileAt(i, j); |
[email protected] | 1d99317 | 2012-10-18 18:15:04 | [diff] [blame] | 757 | DCHECK(tile); // Did setTexturePriorities get skipped? |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 758 | if (!tile) |
| 759 | continue; |
| 760 | |
[email protected] | aad0a007 | 2012-11-01 18:15:58 | [diff] [blame] | 761 | bool updated = !tile->updateRect.IsEmpty(); |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 762 | bool canAcquire = tile->managedTexture()->canAcquireBackingTexture(); |
| 763 | bool dirty = tile->isDirty() || !tile->managedTexture()->haveBackingTexture(); |
| 764 | if (!updated && canAcquire && dirty) |
| 765 | return true; |
| 766 | } |
| 767 | } |
| 768 | return false; |
| 769 | } |
| 770 | |
[email protected] | aad0a007 | 2012-11-01 18:15:58 | [diff] [blame] | 771 | gfx::Rect TiledLayer::idlePaintRect() |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 772 | { |
| 773 | // Don't inflate an empty rect. |
[email protected] | aad0a007 | 2012-11-01 18:15:58 | [diff] [blame] | 774 | if (visibleContentRect().IsEmpty()) |
| 775 | return gfx::Rect(); |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 776 | |
[email protected] | aad0a007 | 2012-11-01 18:15:58 | [diff] [blame] | 777 | gfx::Rect prepaintRect = visibleContentRect(); |
| 778 | prepaintRect.Inset(-m_tiler->tileSize().width() * prepaintColumns, |
| 779 | -m_tiler->tileSize().height() * prepaintRows); |
| 780 | gfx::Rect contentRect(gfx::Point(), contentBounds()); |
| 781 | prepaintRect.Intersect(contentRect); |
[email protected] | 94f206c1 | 2012-08-25 00:09:14 | [diff] [blame] | 782 | |
| 783 | return prepaintRect; |
| 784 | } |
| 785 | |
[email protected] | bc5e77c | 2012-11-05 20:00:49 | [diff] [blame^] | 786 | } // namespace cc |