| OLD | NEW |
| 1 // Copyright 2011 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "config.h" | 5 #include "config.h" |
| 6 | 6 |
| 7 #include "cc/tiled_layer.h" | 7 #include "cc/tiled_layer.h" |
| 8 | 8 |
| 9 #include "Region.h" | 9 #include "Region.h" |
| 10 #include "base/basictypes.h" | 10 #include "base/basictypes.h" |
| 11 #include "cc/geometry.h" |
| 11 #include "cc/layer_impl.h" | 12 #include "cc/layer_impl.h" |
| 12 #include "cc/layer_tree_host.h" | 13 #include "cc/layer_tree_host.h" |
| 13 #include "cc/overdraw_metrics.h" | 14 #include "cc/overdraw_metrics.h" |
| 14 #include "cc/tiled_layer_impl.h" | 15 #include "cc/tiled_layer_impl.h" |
| 15 #include "third_party/khronos/GLES2/gl2.h" | 16 #include "third_party/khronos/GLES2/gl2.h" |
| 17 #include "ui/gfx/rect_conversions.h" |
| 18 #include "ui/gfx/size_conversions.h" |
| 16 | 19 |
| 17 using namespace std; | 20 using namespace std; |
| 18 using WebKit::WebTransformationMatrix; | 21 using WebKit::WebTransformationMatrix; |
| 19 | 22 |
| 20 namespace cc { | 23 namespace cc { |
| 21 | 24 |
| 22 // Maximum predictive expansion of the visible area. | 25 // Maximum predictive expansion of the visible area. |
| 23 static const int maxPredictiveTilesCount = 2; | 26 static const int maxPredictiveTilesCount = 2; |
| 24 | 27 |
| 25 // Number of rows/columns of tiles to pre-paint. | 28 // Number of rows/columns of tiles to pre-paint. |
| 26 // We should increase these further as all textures are | 29 // We should increase these further as all textures are |
| 27 // prioritized and we insure performance doesn't suffer. | 30 // prioritized and we insure performance doesn't suffer. |
| 28 static const int prepaintRows = 4; | 31 static const int prepaintRows = 4; |
| 29 static const int prepaintColumns = 2; | 32 static const int prepaintColumns = 2; |
| 30 | 33 |
| 31 | 34 |
| 32 class UpdatableTile : public LayerTilingData::Tile { | 35 class UpdatableTile : public LayerTilingData::Tile { |
| 33 public: | 36 public: |
| 34 static scoped_ptr<UpdatableTile> create(scoped_ptr<LayerUpdater::Resource> u
pdaterResource) | 37 static scoped_ptr<UpdatableTile> create(scoped_ptr<LayerUpdater::Resource> u
pdaterResource) |
| 35 { | 38 { |
| 36 return make_scoped_ptr(new UpdatableTile(updaterResource.Pass())); | 39 return make_scoped_ptr(new UpdatableTile(updaterResource.Pass())); |
| 37 } | 40 } |
| 38 | 41 |
| 39 LayerUpdater::Resource* updaterResource() { return m_updaterResource.get();
} | 42 LayerUpdater::Resource* updaterResource() { return m_updaterResource.get();
} |
| 40 PrioritizedTexture* managedTexture() { return m_updaterResource->texture();
} | 43 PrioritizedTexture* managedTexture() { return m_updaterResource->texture();
} |
| 41 | 44 |
| 42 bool isDirty() const { return !dirtyRect.isEmpty(); } | 45 bool isDirty() const { return !dirtyRect.IsEmpty(); } |
| 43 | 46 |
| 44 // Reset update state for the current frame. This should occur before painti
ng | 47 // Reset update state for the current frame. This should occur before painti
ng |
| 45 // for all layers. Since painting one layer can invalidate another layer | 48 // for all layers. Since painting one layer can invalidate another layer |
| 46 // after it has already painted, mark all non-dirty tiles as valid before pa
inting | 49 // after it has already painted, mark all non-dirty tiles as valid before pa
inting |
| 47 // such that invalidations during painting won't prevent them from being pus
hed. | 50 // such that invalidations during painting won't prevent them from being pus
hed. |
| 48 void resetUpdateState() | 51 void resetUpdateState() |
| 49 { | 52 { |
| 50 updateRect = IntRect(); | 53 updateRect = gfx::Rect(); |
| 51 occluded = false; | 54 occluded = false; |
| 52 partialUpdate = false; | 55 partialUpdate = false; |
| 53 validForFrame = !isDirty(); | 56 validForFrame = !isDirty(); |
| 54 } | 57 } |
| 55 | 58 |
| 56 // This promises to update the tile and therefore also guarantees the tile | 59 // This promises to update the tile and therefore also guarantees the tile |
| 57 // will be valid for this frame. dirtyRect is copied into updateRect so | 60 // will be valid for this frame. dirtyRect is copied into updateRect so |
| 58 // we can continue to track re-entrant invalidations that occur during paint
ing. | 61 // we can continue to track re-entrant invalidations that occur during paint
ing. |
| 59 void markForUpdate() | 62 void markForUpdate() |
| 60 { | 63 { |
| 61 validForFrame = true; | 64 validForFrame = true; |
| 62 updateRect = dirtyRect; | 65 updateRect = dirtyRect; |
| 63 dirtyRect = IntRect(); | 66 dirtyRect = gfx::Rect(); |
| 64 } | 67 } |
| 65 | 68 |
| 66 IntRect dirtyRect; | 69 gfx::Rect dirtyRect; |
| 67 IntRect updateRect; | 70 gfx::Rect updateRect; |
| 68 bool partialUpdate; | 71 bool partialUpdate; |
| 69 bool validForFrame; | 72 bool validForFrame; |
| 70 bool occluded; | 73 bool occluded; |
| 71 bool isInUseOnImpl; | 74 bool isInUseOnImpl; |
| 72 | 75 |
| 73 private: | 76 private: |
| 74 explicit UpdatableTile(scoped_ptr<LayerUpdater::Resource> updaterResource) | 77 explicit UpdatableTile(scoped_ptr<LayerUpdater::Resource> updaterResource) |
| 75 : partialUpdate(false) | 78 : partialUpdate(false) |
| 76 , validForFrame(false) | 79 , validForFrame(false) |
| 77 , occluded(false) | 80 , occluded(false) |
| 78 , isInUseOnImpl(false) | 81 , isInUseOnImpl(false) |
| 79 , m_updaterResource(updaterResource.Pass()) | 82 , m_updaterResource(updaterResource.Pass()) |
| 80 { | 83 { |
| 81 } | 84 } |
| 82 | 85 |
| 83 scoped_ptr<LayerUpdater::Resource> m_updaterResource; | 86 scoped_ptr<LayerUpdater::Resource> m_updaterResource; |
| 84 | 87 |
| 85 DISALLOW_COPY_AND_ASSIGN(UpdatableTile); | 88 DISALLOW_COPY_AND_ASSIGN(UpdatableTile); |
| 86 }; | 89 }; |
| 87 | 90 |
| 88 TiledLayer::TiledLayer() | 91 TiledLayer::TiledLayer() |
| 89 : Layer() | 92 : Layer() |
| 90 , m_textureFormat(GL_INVALID_ENUM) | 93 , m_textureFormat(GL_INVALID_ENUM) |
| 91 , m_skipsDraw(false) | 94 , m_skipsDraw(false) |
| 92 , m_failedUpdate(false) | 95 , m_failedUpdate(false) |
| 93 , m_tilingOption(AutoTile) | 96 , m_tilingOption(AutoTile) |
| 94 { | 97 { |
| 95 m_tiler = LayerTilingData::create(IntSize(), LayerTilingData::HasBorderTexel
s); | 98 m_tiler = LayerTilingData::create(gfx::Size(), LayerTilingData::HasBorderTex
els); |
| 96 } | 99 } |
| 97 | 100 |
| 98 TiledLayer::~TiledLayer() | 101 TiledLayer::~TiledLayer() |
| 99 { | 102 { |
| 100 } | 103 } |
| 101 | 104 |
| 102 scoped_ptr<LayerImpl> TiledLayer::createLayerImpl() | 105 scoped_ptr<LayerImpl> TiledLayer::createLayerImpl() |
| 103 { | 106 { |
| 104 return TiledLayerImpl::create(id()).PassAs<LayerImpl>(); | 107 return TiledLayerImpl::create(id()).PassAs<LayerImpl>(); |
| 105 } | 108 } |
| 106 | 109 |
| 107 void TiledLayer::updateTileSizeAndTilingOption() | 110 void TiledLayer::updateTileSizeAndTilingOption() |
| 108 { | 111 { |
| 109 DCHECK(layerTreeHost()); | 112 DCHECK(layerTreeHost()); |
| 110 | 113 |
| 111 const IntSize& defaultTileSize = layerTreeHost()->settings().defaultTileSize
; | 114 gfx::Size defaultTileSize = layerTreeHost()->settings().defaultTileSize; |
| 112 const IntSize& maxUntiledLayerSize = layerTreeHost()->settings().maxUntiledL
ayerSize; | 115 gfx::Size maxUntiledLayerSize = layerTreeHost()->settings().maxUntiledLayerS
ize; |
| 113 int layerWidth = contentBounds().width(); | 116 int layerWidth = contentBounds().width(); |
| 114 int layerHeight = contentBounds().height(); | 117 int layerHeight = contentBounds().height(); |
| 115 | 118 |
| 116 const IntSize tileSize(min(defaultTileSize.width(), layerWidth), min(default
TileSize.height(), layerHeight)); | 119 gfx::Size tileSize(min(defaultTileSize.width(), layerWidth), min(defaultTile
Size.height(), layerHeight)); |
| 117 | 120 |
| 118 // Tile if both dimensions large, or any one dimension large and the other | 121 // 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 tha
t | 122 // extends into a second tile but the total layer area isn't larger than tha
t |
| 120 // of the largest possible untiled layer. This heuristic allows for long ski
nny layers | 123 // of the largest possible untiled layer. This heuristic allows for long ski
nny layers |
| 121 // (e.g. scrollbars) that are Nx1 tiles to minimize wasted texture space but
still avoids | 124 // (e.g. scrollbars) that are Nx1 tiles to minimize wasted texture space but
still avoids |
| 122 // creating very large tiles. | 125 // creating very large tiles. |
| 123 const bool anyDimensionLarge = layerWidth > maxUntiledLayerSize.width() || l
ayerHeight > maxUntiledLayerSize.height(); | 126 bool anyDimensionLarge = layerWidth > maxUntiledLayerSize.width() || layerHe
ight > maxUntiledLayerSize.height(); |
| 124 const bool anyDimensionOneTile = (layerWidth <= defaultTileSize.width() || l
ayerHeight <= defaultTileSize.height()) | 127 bool anyDimensionOneTile = (layerWidth <= defaultTileSize.width() || layerHe
ight <= defaultTileSize.height()) |
| 125 && (layerWidth * layerHeight) <= (maxUntil
edLayerSize.width() * maxUntiledLayerSize.height()); | 128 && (layerWidth * layerHeight) <= (maxUntil
edLayerSize.width() * maxUntiledLayerSize.height()); |
| 126 const bool autoTiled = anyDimensionLarge && !anyDimensionOneTile; | 129 bool autoTiled = anyDimensionLarge && !anyDimensionOneTile; |
| 127 | 130 |
| 128 bool isTiled; | 131 bool isTiled; |
| 129 if (m_tilingOption == AlwaysTile) | 132 if (m_tilingOption == AlwaysTile) |
| 130 isTiled = true; | 133 isTiled = true; |
| 131 else if (m_tilingOption == NeverTile) | 134 else if (m_tilingOption == NeverTile) |
| 132 isTiled = false; | 135 isTiled = false; |
| 133 else | 136 else |
| 134 isTiled = autoTiled; | 137 isTiled = autoTiled; |
| 135 | 138 |
| 136 IntSize requestedSize = isTiled ? tileSize : contentBounds(); | 139 gfx::Size requestedSize = isTiled ? tileSize : contentBounds(); |
| 137 const int maxSize = layerTreeHost()->rendererCapabilities().maxTextureSize; | 140 const int maxSize = layerTreeHost()->rendererCapabilities().maxTextureSize; |
| 138 IntSize clampedSize = requestedSize.shrunkTo(IntSize(maxSize, maxSize)); | 141 gfx::Size clampedSize = ClampSizeFromAbove(requestedSize, gfx::Size(maxSize,
maxSize)); |
| 139 setTileSize(clampedSize); | 142 setTileSize(clampedSize); |
| 140 } | 143 } |
| 141 | 144 |
| 142 void TiledLayer::updateBounds() | 145 void TiledLayer::updateBounds() |
| 143 { | 146 { |
| 144 IntSize oldBounds = m_tiler->bounds(); | 147 gfx::Size oldBounds = m_tiler->bounds(); |
| 145 IntSize newBounds = contentBounds(); | 148 gfx::Size newBounds = contentBounds(); |
| 146 if (oldBounds == newBounds) | 149 if (oldBounds == newBounds) |
| 147 return; | 150 return; |
| 148 m_tiler->setBounds(newBounds); | 151 m_tiler->setBounds(newBounds); |
| 149 | 152 |
| 150 // Invalidate any areas that the new bounds exposes. | 153 // Invalidate any areas that the new bounds exposes. |
| 151 Region oldRegion(IntRect(IntPoint(), oldBounds)); | 154 Region oldRegion = IntRect(IntPoint(), cc::IntSize(oldBounds)); |
| 152 Region newRegion(IntRect(IntPoint(), newBounds)); | 155 Region newRegion = IntRect(IntPoint(), cc::IntSize(newBounds)); |
| 153 newRegion.subtract(oldRegion); | 156 newRegion.subtract(oldRegion); |
| 154 Vector<WebCore::IntRect> rects = newRegion.rects(); | 157 Vector<WebCore::IntRect> rects = newRegion.rects(); |
| 155 for (size_t i = 0; i < rects.size(); ++i) | 158 for (size_t i = 0; i < rects.size(); ++i) |
| 156 invalidateContentRect(rects[i]); | 159 invalidateContentRect(cc::IntRect(rects[i])); |
| 157 } | 160 } |
| 158 | 161 |
| 159 void TiledLayer::setTileSize(const IntSize& size) | 162 void TiledLayer::setTileSize(const gfx::Size& size) |
| 160 { | 163 { |
| 161 m_tiler->setTileSize(size); | 164 m_tiler->setTileSize(size); |
| 162 } | 165 } |
| 163 | 166 |
| 164 void TiledLayer::setBorderTexelOption(LayerTilingData::BorderTexelOption borderT
exelOption) | 167 void TiledLayer::setBorderTexelOption(LayerTilingData::BorderTexelOption borderT
exelOption) |
| 165 { | 168 { |
| 166 m_tiler->setBorderTexelOption(borderTexelOption); | 169 m_tiler->setBorderTexelOption(borderTexelOption); |
| 167 } | 170 } |
| 168 | 171 |
| 169 bool TiledLayer::drawsContent() const | 172 bool TiledLayer::drawsContent() const |
| 170 { | 173 { |
| 171 if (!Layer::drawsContent()) | 174 if (!Layer::drawsContent()) |
| 172 return false; | 175 return false; |
| 173 | 176 |
| 174 bool hasMoreThanOneTile = m_tiler->numTilesX() > 1 || m_tiler->numTilesY() >
1; | 177 bool hasMoreThanOneTile = m_tiler->numTilesX() > 1 || m_tiler->numTilesY() >
1; |
| 175 if (m_tilingOption == NeverTile && hasMoreThanOneTile) | 178 if (m_tilingOption == NeverTile && hasMoreThanOneTile) |
| 176 return false; | 179 return false; |
| 177 | 180 |
| 178 return true; | 181 return true; |
| 179 } | 182 } |
| 180 | 183 |
| 181 bool TiledLayer::needsContentsScale() const | 184 bool TiledLayer::needsContentsScale() const |
| 182 { | 185 { |
| 183 return true; | 186 return true; |
| 184 } | 187 } |
| 185 | 188 |
| 186 IntSize TiledLayer::contentBounds() const | 189 gfx::Size TiledLayer::contentBounds() const |
| 187 { | 190 { |
| 188 return IntSize(lroundf(bounds().width() * contentsScale()), lroundf(bounds()
.height() * contentsScale())); | 191 return gfx::ToRoundedSize(bounds().Scale(contentsScale())); |
| 189 } | 192 } |
| 190 | 193 |
| 191 void TiledLayer::setTilingOption(TilingOption tilingOption) | 194 void TiledLayer::setTilingOption(TilingOption tilingOption) |
| 192 { | 195 { |
| 193 m_tilingOption = tilingOption; | 196 m_tilingOption = tilingOption; |
| 194 } | 197 } |
| 195 | 198 |
| 196 void TiledLayer::setIsMask(bool isMask) | 199 void TiledLayer::setIsMask(bool isMask) |
| 197 { | 200 { |
| 198 setTilingOption(isMask ? NeverTile : AutoTile); | 201 setTilingOption(isMask ? NeverTile : AutoTile); |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 277 | 280 |
| 278 // Temporary diagnostic crash. | 281 // Temporary diagnostic crash. |
| 279 if (!addedTile) | 282 if (!addedTile) |
| 280 CRASH(); | 283 CRASH(); |
| 281 if (!tileAt(i, j)) | 284 if (!tileAt(i, j)) |
| 282 CRASH(); | 285 CRASH(); |
| 283 | 286 |
| 284 return addedTile; | 287 return addedTile; |
| 285 } | 288 } |
| 286 | 289 |
| 287 void TiledLayer::setNeedsDisplayRect(const FloatRect& dirtyRect) | 290 void TiledLayer::setNeedsDisplayRect(const gfx::RectF& dirtyRect) |
| 288 { | 291 { |
| 289 float contentsWidthScale = static_cast<float>(contentBounds().width()) / bou
nds().width(); | 292 float contentsWidthScale = static_cast<float>(contentBounds().width()) / bou
nds().width(); |
| 290 float contentsHeightScale = static_cast<float>(contentBounds().height()) / b
ounds().height(); | 293 float contentsHeightScale = static_cast<float>(contentBounds().height()) / b
ounds().height(); |
| 291 FloatRect scaledDirtyRect(dirtyRect); | 294 gfx::RectF scaledDirtyRect = gfx::ScaleRect(dirtyRect, contentsWidthScale, c
ontentsHeightScale); |
| 292 scaledDirtyRect.scale(contentsWidthScale, contentsHeightScale); | 295 gfx::Rect dirty = gfx::ToEnclosingRect(scaledDirtyRect); |
| 293 IntRect dirty = enclosingIntRect(scaledDirtyRect); | |
| 294 invalidateContentRect(dirty); | 296 invalidateContentRect(dirty); |
| 295 Layer::setNeedsDisplayRect(dirtyRect); | 297 Layer::setNeedsDisplayRect(dirtyRect); |
| 296 } | 298 } |
| 297 | 299 |
| 298 void TiledLayer::setUseLCDText(bool useLCDText) | 300 void TiledLayer::setUseLCDText(bool useLCDText) |
| 299 { | 301 { |
| 300 Layer::setUseLCDText(useLCDText); | 302 Layer::setUseLCDText(useLCDText); |
| 301 | 303 |
| 302 LayerTilingData::BorderTexelOption borderTexelOption; | 304 LayerTilingData::BorderTexelOption borderTexelOption; |
| 303 #if OS(ANDROID) | 305 #if OS(ANDROID) |
| 304 // Always want border texels and GL_LINEAR due to pinch zoom. | 306 // Always want border texels and GL_LINEAR due to pinch zoom. |
| 305 borderTexelOption = LayerTilingData::HasBorderTexels; | 307 borderTexelOption = LayerTilingData::HasBorderTexels; |
| 306 #else | 308 #else |
| 307 borderTexelOption = useLCDText ? LayerTilingData::NoBorderTexels : LayerTili
ngData::HasBorderTexels; | 309 borderTexelOption = useLCDText ? LayerTilingData::NoBorderTexels : LayerTili
ngData::HasBorderTexels; |
| 308 #endif | 310 #endif |
| 309 setBorderTexelOption(borderTexelOption); | 311 setBorderTexelOption(borderTexelOption); |
| 310 } | 312 } |
| 311 | 313 |
| 312 void TiledLayer::invalidateContentRect(const IntRect& contentRect) | 314 void TiledLayer::invalidateContentRect(const gfx::Rect& contentRect) |
| 313 { | 315 { |
| 314 updateBounds(); | 316 updateBounds(); |
| 315 if (m_tiler->isEmpty() || contentRect.isEmpty() || m_skipsDraw) | 317 if (m_tiler->isEmpty() || contentRect.IsEmpty() || m_skipsDraw) |
| 316 return; | 318 return; |
| 317 | 319 |
| 318 for (LayerTilingData::TileMap::const_iterator iter = m_tiler->tiles().begin(
); iter != m_tiler->tiles().end(); ++iter) { | 320 for (LayerTilingData::TileMap::const_iterator iter = m_tiler->tiles().begin(
); iter != m_tiler->tiles().end(); ++iter) { |
| 319 UpdatableTile* tile = static_cast<UpdatableTile*>(iter->second); | 321 UpdatableTile* tile = static_cast<UpdatableTile*>(iter->second); |
| 320 DCHECK(tile); | 322 DCHECK(tile); |
| 321 // FIXME: This should not ever be null. | 323 // FIXME: This should not ever be null. |
| 322 if (!tile) | 324 if (!tile) |
| 323 continue; | 325 continue; |
| 324 IntRect bound = m_tiler->tileRect(tile); | 326 gfx::Rect bound = m_tiler->tileRect(tile); |
| 325 bound.intersect(contentRect); | 327 bound.Intersect(contentRect); |
| 326 tile->dirtyRect.unite(bound); | 328 tile->dirtyRect.Union(bound); |
| 327 } | 329 } |
| 328 } | 330 } |
| 329 | 331 |
| 330 // Returns true if tile is dirty and only part of it needs to be updated. | 332 // Returns true if tile is dirty and only part of it needs to be updated. |
| 331 bool TiledLayer::tileOnlyNeedsPartialUpdate(UpdatableTile* tile) | 333 bool TiledLayer::tileOnlyNeedsPartialUpdate(UpdatableTile* tile) |
| 332 { | 334 { |
| 333 return !tile->dirtyRect.contains(m_tiler->tileRect(tile)); | 335 return !tile->dirtyRect.Contains(m_tiler->tileRect(tile)); |
| 334 } | 336 } |
| 335 | 337 |
| 336 // Dirty tiles with valid textures needs buffered update to guarantee that | 338 // Dirty tiles with valid textures needs buffered update to guarantee that |
| 337 // we don't modify textures currently used for drawing by the impl thread. | 339 // we don't modify textures currently used for drawing by the impl thread. |
| 338 bool TiledLayer::tileNeedsBufferedUpdate(UpdatableTile* tile) | 340 bool TiledLayer::tileNeedsBufferedUpdate(UpdatableTile* tile) |
| 339 { | 341 { |
| 340 if (!tile->managedTexture()->haveBackingTexture()) | 342 if (!tile->managedTexture()->haveBackingTexture()) |
| 341 return false; | 343 return false; |
| 342 | 344 |
| 343 if (!tile->isDirty()) | 345 if (!tile->isDirty()) |
| (...skipping 10 matching lines...) Expand all Loading... |
| 354 { | 356 { |
| 355 didPaint = false; | 357 didPaint = false; |
| 356 createUpdaterIfNeeded(); | 358 createUpdaterIfNeeded(); |
| 357 | 359 |
| 358 bool ignoreOcclusions = !occlusion; | 360 bool ignoreOcclusions = !occlusion; |
| 359 if (!haveTexturesForTiles(left, top, right, bottom, ignoreOcclusions)) { | 361 if (!haveTexturesForTiles(left, top, right, bottom, ignoreOcclusions)) { |
| 360 m_failedUpdate = true; | 362 m_failedUpdate = true; |
| 361 return false; | 363 return false; |
| 362 } | 364 } |
| 363 | 365 |
| 364 IntRect paintRect = markTilesForUpdate(left, top, right, bottom, ignoreOcclu
sions); | 366 gfx::Rect paintRect = markTilesForUpdate(left, top, right, bottom, ignoreOcc
lusions); |
| 365 | 367 |
| 366 if (occlusion) | 368 if (occlusion) |
| 367 occlusion->overdrawMetrics().didPaint(paintRect); | 369 occlusion->overdrawMetrics().didPaint(cc::IntRect(paintRect)); |
| 368 | 370 |
| 369 if (paintRect.isEmpty()) | 371 if (paintRect.IsEmpty()) |
| 370 return true; | 372 return true; |
| 371 | 373 |
| 372 didPaint = true; | 374 didPaint = true; |
| 373 updateTileTextures(paintRect, left, top, right, bottom, queue, occlusion, st
ats); | 375 updateTileTextures(paintRect, left, top, right, bottom, queue, occlusion, st
ats); |
| 374 return true; | 376 return true; |
| 375 } | 377 } |
| 376 | 378 |
| 377 void TiledLayer::markOcclusionsAndRequestTextures(int left, int top, int right,
int bottom, const OcclusionTracker* occlusion) | 379 void TiledLayer::markOcclusionsAndRequestTextures(int left, int top, int right,
int bottom, const OcclusionTracker* occlusion) |
| 378 { | 380 { |
| 379 // There is some difficult dependancies between occlusions, recording occlus
ion metrics | 381 // There is some difficult dependancies between occlusions, recording occlus
ion metrics |
| 380 // and requesting memory so those are encapsulated in this function: | 382 // and requesting memory so those are encapsulated in this function: |
| 381 // - We only want to call requestLate on unoccluded textures (to preserve | 383 // - We only want to call requestLate on unoccluded textures (to preserve |
| 382 // memory for other layers when near OOM). | 384 // memory for other layers when near OOM). |
| 383 // - We only want to record occlusion metrics if all memory requests succeed
. | 385 // - We only want to record occlusion metrics if all memory requests succeed
. |
| 384 | 386 |
| 385 int occludedTileCount = 0; | 387 int occludedTileCount = 0; |
| 386 bool succeeded = true; | 388 bool succeeded = true; |
| 387 for (int j = top; j <= bottom; ++j) { | 389 for (int j = top; j <= bottom; ++j) { |
| 388 for (int i = left; i <= right; ++i) { | 390 for (int i = left; i <= right; ++i) { |
| 389 UpdatableTile* tile = tileAt(i, j); | 391 UpdatableTile* tile = tileAt(i, j); |
| 390 DCHECK(tile); // Did setTexturePriorities get skipped? | 392 DCHECK(tile); // Did setTexturePriorities get skipped? |
| 391 // FIXME: This should not ever be null. | 393 // FIXME: This should not ever be null. |
| 392 if (!tile) | 394 if (!tile) |
| 393 continue; | 395 continue; |
| 394 DCHECK(!tile->occluded); // Did resetUpdateState get skipped? Are we
doing more than one occlusion pass? | 396 DCHECK(!tile->occluded); // Did resetUpdateState get skipped? Are we
doing more than one occlusion pass? |
| 395 IntRect visibleTileRect = intersection(m_tiler->tileBounds(i, j), vi
sibleContentRect()); | 397 gfx::Rect visibleTileRect = gfx::IntersectRects(m_tiler->tileBounds(
i, j), visibleContentRect()); |
| 396 if (occlusion && occlusion->occluded(this, visibleTileRect)) { | 398 if (occlusion && occlusion->occluded(this, visibleTileRect)) { |
| 397 tile->occluded = true; | 399 tile->occluded = true; |
| 398 occludedTileCount++; | 400 occludedTileCount++; |
| 399 } else { | 401 } else { |
| 400 succeeded &= tile->managedTexture()->requestLate(); | 402 succeeded &= tile->managedTexture()->requestLate(); |
| 401 } | 403 } |
| 402 } | 404 } |
| 403 } | 405 } |
| 404 | 406 |
| 405 if (!succeeded) | 407 if (!succeeded) |
| (...skipping 23 matching lines...) Expand all Loading... |
| 429 if (tile->occluded && !ignoreOcclusions) | 431 if (tile->occluded && !ignoreOcclusions) |
| 430 continue; | 432 continue; |
| 431 | 433 |
| 432 if (!tile->managedTexture()->canAcquireBackingTexture()) | 434 if (!tile->managedTexture()->canAcquireBackingTexture()) |
| 433 return false; | 435 return false; |
| 434 } | 436 } |
| 435 } | 437 } |
| 436 return true; | 438 return true; |
| 437 } | 439 } |
| 438 | 440 |
| 439 IntRect TiledLayer::markTilesForUpdate(int left, int top, int right, int bottom,
bool ignoreOcclusions) | 441 gfx::Rect TiledLayer::markTilesForUpdate(int left, int top, int right, int botto
m, bool ignoreOcclusions) |
| 440 { | 442 { |
| 441 IntRect paintRect; | 443 gfx::Rect paintRect; |
| 442 for (int j = top; j <= bottom; ++j) { | 444 for (int j = top; j <= bottom; ++j) { |
| 443 for (int i = left; i <= right; ++i) { | 445 for (int i = left; i <= right; ++i) { |
| 444 UpdatableTile* tile = tileAt(i, j); | 446 UpdatableTile* tile = tileAt(i, j); |
| 445 DCHECK(tile); // Did setTexturePriorites get skipped? | 447 DCHECK(tile); // Did setTexturePriorites get skipped? |
| 446 // FIXME: This should not ever be null. | 448 // FIXME: This should not ever be null. |
| 447 if (!tile) | 449 if (!tile) |
| 448 continue; | 450 continue; |
| 449 if (tile->occluded && !ignoreOcclusions) | 451 if (tile->occluded && !ignoreOcclusions) |
| 450 continue; | 452 continue; |
| 451 paintRect.unite(tile->dirtyRect); | 453 paintRect.Union(tile->dirtyRect); |
| 452 tile->markForUpdate(); | 454 tile->markForUpdate(); |
| 453 } | 455 } |
| 454 } | 456 } |
| 455 return paintRect; | 457 return paintRect; |
| 456 } | 458 } |
| 457 | 459 |
| 458 void TiledLayer::updateTileTextures(const IntRect& paintRect, int left, int top,
int right, int bottom, TextureUpdateQueue& queue, const OcclusionTracker* occlu
sion, RenderingStats& stats) | 460 void TiledLayer::updateTileTextures(const gfx::Rect& paintRect, int left, int to
p, int right, int bottom, TextureUpdateQueue& queue, const OcclusionTracker* occ
lusion, RenderingStats& stats) |
| 459 { | 461 { |
| 460 // The updateRect should be in layer space. So we have to convert the paintR
ect from content space to layer space. | 462 // The updateRect should be in layer space. So we have to convert the paintR
ect from content space to layer space. |
| 461 m_updateRect = FloatRect(paintRect); | |
| 462 float widthScale = bounds().width() / static_cast<float>(contentBounds().wid
th()); | 463 float widthScale = bounds().width() / static_cast<float>(contentBounds().wid
th()); |
| 463 float heightScale = bounds().height() / static_cast<float>(contentBounds().h
eight()); | 464 float heightScale = bounds().height() / static_cast<float>(contentBounds().h
eight()); |
| 464 m_updateRect.scale(widthScale, heightScale); | 465 m_updateRect = gfx::ScaleRect(paintRect, widthScale, heightScale); |
| 465 | 466 |
| 466 // Calling prepareToUpdate() calls into WebKit to paint, which may have the
side | 467 // Calling prepareToUpdate() calls into WebKit to paint, which may have the
side |
| 467 // effect of disabling compositing, which causes our reference to the textur
e updater to be deleted. | 468 // effect of disabling compositing, which causes our reference to the textur
e updater to be deleted. |
| 468 // However, we can't free the memory backing the SkCanvas until the paint fi
nishes, | 469 // However, we can't free the memory backing the SkCanvas until the paint fi
nishes, |
| 469 // so we grab a local reference here to hold the updater alive until the pai
nt completes. | 470 // so we grab a local reference here to hold the updater alive until the pai
nt completes. |
| 470 scoped_refptr<LayerUpdater> protector(updater()); | 471 scoped_refptr<LayerUpdater> protector(updater()); |
| 471 gfx::Rect paintedOpaqueRect; | 472 gfx::Rect paintedOpaqueRect; |
| 472 updater()->prepareToUpdate(paintRect, m_tiler->tileSize(), 1 / widthScale, 1
/ heightScale, paintedOpaqueRect, stats); | 473 updater()->prepareToUpdate(paintRect, m_tiler->tileSize(), 1 / widthScale, 1
/ heightScale, paintedOpaqueRect, stats); |
| 473 | 474 |
| 474 for (int j = top; j <= bottom; ++j) { | 475 for (int j = top; j <= bottom; ++j) { |
| 475 for (int i = left; i <= right; ++i) { | 476 for (int i = left; i <= right; ++i) { |
| 476 UpdatableTile* tile = tileAt(i, j); | 477 UpdatableTile* tile = tileAt(i, j); |
| 477 DCHECK(tile); // Did setTexturePriorites get skipped? | 478 DCHECK(tile); // Did setTexturePriorites get skipped? |
| 478 // FIXME: This should not ever be null. | 479 // FIXME: This should not ever be null. |
| 479 if (!tile) | 480 if (!tile) |
| 480 continue; | 481 continue; |
| 481 | 482 |
| 482 IntRect tileRect = m_tiler->tileBounds(i, j); | 483 gfx::Rect tileRect = m_tiler->tileBounds(i, j); |
| 483 | 484 |
| 484 // Use updateRect as the above loop copied the dirty rect for this f
rame to updateRect. | 485 // Use updateRect as the above loop copied the dirty rect for this f
rame to updateRect. |
| 485 const IntRect& dirtyRect = tile->updateRect; | 486 const gfx::Rect& dirtyRect = tile->updateRect; |
| 486 if (dirtyRect.isEmpty()) | 487 if (dirtyRect.IsEmpty()) |
| 487 continue; | 488 continue; |
| 488 | 489 |
| 489 // Save what was painted opaque in the tile. Keep the old area if th
e paint didn't touch it, and didn't paint some | 490 // Save what was painted opaque in the tile. Keep the old area if th
e paint didn't touch it, and didn't paint some |
| 490 // other part of the tile opaque. | 491 // other part of the tile opaque. |
| 491 IntRect tilePaintedRect = intersection(tileRect, paintRect); | 492 gfx::Rect tilePaintedRect = gfx::IntersectRects(tileRect, paintRect)
; |
| 492 IntRect tilePaintedOpaqueRect = intersection(tileRect, cc::IntRect(p
aintedOpaqueRect)); | 493 gfx::Rect tilePaintedOpaqueRect = gfx::IntersectRects(tileRect, pain
tedOpaqueRect); |
| 493 if (!tilePaintedRect.isEmpty()) { | 494 if (!tilePaintedRect.IsEmpty()) { |
| 494 IntRect paintInsideTileOpaqueRect = intersection(tile->opaqueRec
t(), tilePaintedRect); | 495 gfx::Rect paintInsideTileOpaqueRect = gfx::IntersectRects(tile->
opaqueRect(), tilePaintedRect); |
| 495 bool paintInsideTileOpaqueRectIsNonOpaque = !tilePaintedOpaqueRe
ct.contains(paintInsideTileOpaqueRect); | 496 bool paintInsideTileOpaqueRectIsNonOpaque = !tilePaintedOpaqueRe
ct.Contains(paintInsideTileOpaqueRect); |
| 496 bool opaquePaintNotInsideTileOpaqueRect = !tilePaintedOpaqueRect
.isEmpty() && !tile->opaqueRect().contains(tilePaintedOpaqueRect); | 497 bool opaquePaintNotInsideTileOpaqueRect = !tilePaintedOpaqueRect
.IsEmpty() && !tile->opaqueRect().Contains(tilePaintedOpaqueRect); |
| 497 | 498 |
| 498 if (paintInsideTileOpaqueRectIsNonOpaque || opaquePaintNotInside
TileOpaqueRect) | 499 if (paintInsideTileOpaqueRectIsNonOpaque || opaquePaintNotInside
TileOpaqueRect) |
| 499 tile->setOpaqueRect(tilePaintedOpaqueRect); | 500 tile->setOpaqueRect(tilePaintedOpaqueRect); |
| 500 } | 501 } |
| 501 | 502 |
| 502 // sourceRect starts as a full-sized tile with border texels include
d. | 503 // sourceRect starts as a full-sized tile with border texels include
d. |
| 503 IntRect sourceRect = m_tiler->tileRect(tile); | 504 gfx::Rect sourceRect = m_tiler->tileRect(tile); |
| 504 sourceRect.intersect(dirtyRect); | 505 sourceRect.Intersect(dirtyRect); |
| 505 // Paint rect not guaranteed to line up on tile boundaries, so | 506 // Paint rect not guaranteed to line up on tile boundaries, so |
| 506 // make sure that sourceRect doesn't extend outside of it. | 507 // make sure that sourceRect doesn't extend outside of it. |
| 507 sourceRect.intersect(paintRect); | 508 sourceRect.Intersect(paintRect); |
| 508 | 509 |
| 509 tile->updateRect = sourceRect; | 510 tile->updateRect = sourceRect; |
| 510 | 511 |
| 511 if (sourceRect.isEmpty()) | 512 if (sourceRect.IsEmpty()) |
| 512 continue; | 513 continue; |
| 513 | 514 |
| 514 const IntPoint anchor = m_tiler->tileRect(tile).location(); | 515 const gfx::Point anchor = m_tiler->tileRect(tile).origin(); |
| 515 | 516 |
| 516 // Calculate tile-space rectangle to upload into. | 517 // Calculate tile-space rectangle to upload into. |
| 517 gfx::Vector2d destOffset(sourceRect.x() - anchor.x(), sourceRect.y()
- anchor.y()); | 518 gfx::Vector2d destOffset(sourceRect.x() - anchor.x(), sourceRect.y()
- anchor.y()); |
| 518 if (destOffset.x() < 0) | 519 if (destOffset.x() < 0) |
| 519 CRASH(); | 520 CRASH(); |
| 520 if (destOffset.y() < 0) | 521 if (destOffset.y() < 0) |
| 521 CRASH(); | 522 CRASH(); |
| 522 | 523 |
| 523 // Offset from paint rectangle to this tile's dirty rectangle. | 524 // Offset from paint rectangle to this tile's dirty rectangle. |
| 524 gfx::Vector2d paintOffset(sourceRect.x() - paintRect.x(), sourceRect
.y() - paintRect.y()); | 525 gfx::Vector2d paintOffset(sourceRect.x() - paintRect.x(), sourceRect
.y() - paintRect.y()); |
| 525 if (paintOffset.x() < 0) | 526 if (paintOffset.x() < 0) |
| 526 CRASH(); | 527 CRASH(); |
| 527 if (paintOffset.y() < 0) | 528 if (paintOffset.y() < 0) |
| 528 CRASH(); | 529 CRASH(); |
| 529 if (paintOffset.x() + sourceRect.width() > paintRect.width()) | 530 if (paintOffset.x() + sourceRect.width() > paintRect.width()) |
| 530 CRASH(); | 531 CRASH(); |
| 531 if (paintOffset.y() + sourceRect.height() > paintRect.height()) | 532 if (paintOffset.y() + sourceRect.height() > paintRect.height()) |
| 532 CRASH(); | 533 CRASH(); |
| 533 | 534 |
| 534 tile->updaterResource()->update(queue, sourceRect, destOffset, tile-
>partialUpdate, stats); | 535 tile->updaterResource()->update(queue, sourceRect, destOffset, tile-
>partialUpdate, stats); |
| 535 if (occlusion) | 536 if (occlusion) |
| 536 occlusion->overdrawMetrics().didUpload(WebTransformationMatrix()
, sourceRect, tile->opaqueRect()); | 537 occlusion->overdrawMetrics().didUpload(WebTransformationMatrix()
, cc::IntRect(sourceRect), cc::IntRect(tile->opaqueRect())); |
| 537 | 538 |
| 538 } | 539 } |
| 539 } | 540 } |
| 540 } | 541 } |
| 541 | 542 |
| 542 namespace { | 543 namespace { |
| 543 // This picks a small animated layer to be anything less than one viewport. This | 544 // This picks a small animated layer to be anything less than one viewport. This |
| 544 // is specifically for page transitions which are viewport-sized layers. The ext
ra | 545 // is specifically for page transitions which are viewport-sized layers. The ext
ra |
| 545 // 64 pixels is due to these layers being slightly larger than the viewport in s
ome cases. | 546 // 64 pixels is due to these layers being slightly larger than the viewport in s
ome cases. |
| 546 bool isSmallAnimatedLayer(TiledLayer* layer) | 547 bool isSmallAnimatedLayer(TiledLayer* layer) |
| 547 { | 548 { |
| 548 if (!layer->drawTransformIsAnimating() && !layer->screenSpaceTransformIsAnim
ating()) | 549 if (!layer->drawTransformIsAnimating() && !layer->screenSpaceTransformIsAnim
ating()) |
| 549 return false; | 550 return false; |
| 550 IntSize viewportSize = layer->layerTreeHost() ? layer->layerTreeHost()->devi
ceViewportSize() : IntSize(); | 551 gfx::Size viewportSize = layer->layerTreeHost() ? layer->layerTreeHost()->de
viceViewportSize() : gfx::Size(); |
| 551 IntRect contentRect(IntPoint::zero(), layer->contentBounds()); | 552 gfx::Rect contentRect(gfx::Point(), layer->contentBounds()); |
| 552 return contentRect.width() <= viewportSize.width() + 64 | 553 return contentRect.width() <= viewportSize.width() + 64 |
| 553 && contentRect.height() <= viewportSize.height() + 64; | 554 && contentRect.height() <= viewportSize.height() + 64; |
| 554 } | 555 } |
| 555 | 556 |
| 556 // FIXME: Remove this and make this based on distance once distance can be calcu
lated | 557 // FIXME: Remove this and make this based on distance once distance can be calcu
lated |
| 557 // for offscreen layers. For now, prioritize all small animated layers after 512 | 558 // for offscreen layers. For now, prioritize all small animated layers after 512 |
| 558 // pixels of pre-painting. | 559 // pixels of pre-painting. |
| 559 void setPriorityForTexture(const IntRect& visibleRect, | 560 void setPriorityForTexture(const gfx::Rect& visibleRect, |
| 560 const IntRect& tileRect, | 561 const gfx::Rect& tileRect, |
| 561 bool drawsToRoot, | 562 bool drawsToRoot, |
| 562 bool isSmallAnimatedLayer, | 563 bool isSmallAnimatedLayer, |
| 563 PrioritizedTexture* texture) | 564 PrioritizedTexture* texture) |
| 564 { | 565 { |
| 565 int priority = PriorityCalculator::lowestPriority(); | 566 int priority = PriorityCalculator::lowestPriority(); |
| 566 if (!visibleRect.isEmpty()) | 567 if (!visibleRect.IsEmpty()) |
| 567 priority = PriorityCalculator::priorityFromDistance(visibleRect, tileRec
t, drawsToRoot); | 568 priority = PriorityCalculator::priorityFromDistance(visibleRect, tileRec
t, drawsToRoot); |
| 568 if (isSmallAnimatedLayer) | 569 if (isSmallAnimatedLayer) |
| 569 priority = PriorityCalculator::maxPriority(priority, PriorityCalculator:
:smallAnimatedLayerMinPriority()); | 570 priority = PriorityCalculator::maxPriority(priority, PriorityCalculator:
:smallAnimatedLayerMinPriority()); |
| 570 if (priority != PriorityCalculator::lowestPriority()) | 571 if (priority != PriorityCalculator::lowestPriority()) |
| 571 texture->setRequestPriority(priority); | 572 texture->setRequestPriority(priority); |
| 572 } | 573 } |
| 573 } | 574 } |
| 574 | 575 |
| 575 void TiledLayer::setTexturePriorities(const PriorityCalculator& priorityCalc) | 576 void TiledLayer::setTexturePriorities(const PriorityCalculator& priorityCalc) |
| 576 { | 577 { |
| 577 updateBounds(); | 578 updateBounds(); |
| 578 resetUpdateState(); | 579 resetUpdateState(); |
| 579 updateScrollPrediction(); | 580 updateScrollPrediction(); |
| 580 | 581 |
| 581 if (m_tiler->hasEmptyBounds()) | 582 if (m_tiler->hasEmptyBounds()) |
| 582 return; | 583 return; |
| 583 | 584 |
| 584 bool drawsToRoot = !renderTarget()->parent(); | 585 bool drawsToRoot = !renderTarget()->parent(); |
| 585 bool smallAnimatedLayer = isSmallAnimatedLayer(this); | 586 bool smallAnimatedLayer = isSmallAnimatedLayer(this); |
| 586 | 587 |
| 587 // Minimally create the tiles in the desired pre-paint rect. | 588 // Minimally create the tiles in the desired pre-paint rect. |
| 588 IntRect createTilesRect = idlePaintRect(); | 589 gfx::Rect createTilesRect = idlePaintRect(); |
| 589 if (!createTilesRect.isEmpty()) { | 590 if (!createTilesRect.IsEmpty()) { |
| 590 int left, top, right, bottom; | 591 int left, top, right, bottom; |
| 591 m_tiler->contentRectToTileIndices(createTilesRect, left, top, right, bot
tom); | 592 m_tiler->contentRectToTileIndices(createTilesRect, left, top, right, bot
tom); |
| 592 for (int j = top; j <= bottom; ++j) { | 593 for (int j = top; j <= bottom; ++j) { |
| 593 for (int i = left; i <= right; ++i) { | 594 for (int i = left; i <= right; ++i) { |
| 594 if (!tileAt(i, j)) | 595 if (!tileAt(i, j)) |
| 595 createTile(i, j); | 596 createTile(i, j); |
| 596 } | 597 } |
| 597 } | 598 } |
| 598 } | 599 } |
| 599 | 600 |
| 600 // Also, minimally create all tiles for small animated layers and also | 601 // Also, minimally create all tiles for small animated layers and also |
| 601 // double-buffer them since we have limited their size to be reasonable. | 602 // double-buffer them since we have limited their size to be reasonable. |
| 602 IntRect doubleBufferedRect = visibleContentRect(); | 603 gfx::Rect doubleBufferedRect = visibleContentRect(); |
| 603 if (smallAnimatedLayer) | 604 if (smallAnimatedLayer) |
| 604 doubleBufferedRect = IntRect(IntPoint::zero(), contentBounds()); | 605 doubleBufferedRect = gfx::Rect(gfx::Point(), contentBounds()); |
| 605 | 606 |
| 606 // Create additional textures for double-buffered updates when needed. | 607 // Create additional textures for double-buffered updates when needed. |
| 607 // These textures must stay alive while the updated textures are incremental
ly | 608 // These textures must stay alive while the updated textures are incremental
ly |
| 608 // uploaded, swapped atomically via pushProperties, and finally deleted | 609 // uploaded, swapped atomically via pushProperties, and finally deleted |
| 609 // after the commit is complete, after which they can be recycled. | 610 // after the commit is complete, after which they can be recycled. |
| 610 if (!doubleBufferedRect.isEmpty()) { | 611 if (!doubleBufferedRect.IsEmpty()) { |
| 611 int left, top, right, bottom; | 612 int left, top, right, bottom; |
| 612 m_tiler->contentRectToTileIndices(doubleBufferedRect, left, top, right,
bottom); | 613 m_tiler->contentRectToTileIndices(doubleBufferedRect, left, top, right,
bottom); |
| 613 for (int j = top; j <= bottom; ++j) { | 614 for (int j = top; j <= bottom; ++j) { |
| 614 for (int i = left; i <= right; ++i) { | 615 for (int i = left; i <= right; ++i) { |
| 615 UpdatableTile* tile = tileAt(i, j); | 616 UpdatableTile* tile = tileAt(i, j); |
| 616 if (!tile) | 617 if (!tile) |
| 617 tile = createTile(i, j); | 618 tile = createTile(i, j); |
| 618 // We need an additional texture if the tile needs a buffered-up
date and it's not a partial update. | 619 // We need an additional texture if the tile needs a buffered-up
date and it's not a partial update. |
| 619 // FIXME: Decide if partial update should be allowed based on co
st | 620 // FIXME: Decide if partial update should be allowed based on co
st |
| 620 // of update. https://bugs.webkit.org/show_bug.cgi?id=77376 | 621 // of update. https://bugs.webkit.org/show_bug.cgi?id=77376 |
| 621 if (!layerTreeHost() || !layerTreeHost()->bufferedUpdates() || !
tileNeedsBufferedUpdate(tile)) | 622 if (!layerTreeHost() || !layerTreeHost()->bufferedUpdates() || !
tileNeedsBufferedUpdate(tile)) |
| 622 continue; | 623 continue; |
| 623 if (tileOnlyNeedsPartialUpdate(tile) && layerTreeHost()->request
PartialTextureUpdate()) { | 624 if (tileOnlyNeedsPartialUpdate(tile) && layerTreeHost()->request
PartialTextureUpdate()) { |
| 624 tile->partialUpdate = true; | 625 tile->partialUpdate = true; |
| 625 continue; | 626 continue; |
| 626 } | 627 } |
| 627 | 628 |
| 628 IntRect tileRect = m_tiler->tileRect(tile); | 629 gfx::Rect tileRect = m_tiler->tileRect(tile); |
| 629 tile->dirtyRect = tileRect; | 630 tile->dirtyRect = tileRect; |
| 630 LayerUpdater::Resource* backBuffer = tile->updaterResource(); | 631 LayerUpdater::Resource* backBuffer = tile->updaterResource(); |
| 631 setPriorityForTexture(visibleContentRect(), tile->dirtyRect, dra
wsToRoot, smallAnimatedLayer, backBuffer->texture()); | 632 setPriorityForTexture(visibleContentRect(), tile->dirtyRect, dra
wsToRoot, smallAnimatedLayer, backBuffer->texture()); |
| 632 scoped_ptr<PrioritizedTexture> frontBuffer = PrioritizedTexture:
:create(backBuffer->texture()->textureManager(), | 633 scoped_ptr<PrioritizedTexture> frontBuffer = PrioritizedTexture:
:create(backBuffer->texture()->textureManager(), |
| 633
backBuffer->texture()->size(), | 634
backBuffer->texture()->size(), |
| 634
backBuffer->texture()->format()); | 635
backBuffer->texture()->format()); |
| 635 // Swap backBuffer into frontBuffer and add it to delete after c
ommit queue. | 636 // Swap backBuffer into frontBuffer and add it to delete after c
ommit queue. |
| 636 backBuffer->swapTextureWith(frontBuffer); | 637 backBuffer->swapTextureWith(frontBuffer); |
| 637 layerTreeHost()->deleteTextureAfterCommit(frontBuffer.Pass()); | 638 layerTreeHost()->deleteTextureAfterCommit(frontBuffer.Pass()); |
| 638 } | 639 } |
| 639 } | 640 } |
| 640 } | 641 } |
| 641 | 642 |
| 642 // Now update priorities on all tiles we have in the layer, no matter where
they are. | 643 // Now update priorities on all tiles we have in the layer, no matter where
they are. |
| 643 for (LayerTilingData::TileMap::const_iterator iter = m_tiler->tiles().begin(
); iter != m_tiler->tiles().end(); ++iter) { | 644 for (LayerTilingData::TileMap::const_iterator iter = m_tiler->tiles().begin(
); iter != m_tiler->tiles().end(); ++iter) { |
| 644 UpdatableTile* tile = static_cast<UpdatableTile*>(iter->second); | 645 UpdatableTile* tile = static_cast<UpdatableTile*>(iter->second); |
| 645 // FIXME: This should not ever be null. | 646 // FIXME: This should not ever be null. |
| 646 if (!tile) | 647 if (!tile) |
| 647 continue; | 648 continue; |
| 648 IntRect tileRect = m_tiler->tileRect(tile); | 649 gfx::Rect tileRect = m_tiler->tileRect(tile); |
| 649 setPriorityForTexture(m_predictedVisibleRect, tileRect, drawsToRoot, sma
llAnimatedLayer, tile->managedTexture()); | 650 setPriorityForTexture(m_predictedVisibleRect, tileRect, drawsToRoot, sma
llAnimatedLayer, tile->managedTexture()); |
| 650 } | 651 } |
| 651 } | 652 } |
| 652 | 653 |
| 653 Region TiledLayer::visibleContentOpaqueRegion() const | 654 Region TiledLayer::visibleContentOpaqueRegion() const |
| 654 { | 655 { |
| 655 if (m_skipsDraw) | 656 if (m_skipsDraw) |
| 656 return Region(); | 657 return Region(); |
| 657 if (contentsOpaque()) | 658 if (contentsOpaque()) |
| 658 return visibleContentRect(); | 659 return cc::IntRect(visibleContentRect()); |
| 659 return m_tiler->opaqueRegionInContentRect(visibleContentRect()); | 660 return m_tiler->opaqueRegionInContentRect(visibleContentRect()); |
| 660 } | 661 } |
| 661 | 662 |
| 662 void TiledLayer::resetUpdateState() | 663 void TiledLayer::resetUpdateState() |
| 663 { | 664 { |
| 664 m_skipsDraw = false; | 665 m_skipsDraw = false; |
| 665 m_failedUpdate = false; | 666 m_failedUpdate = false; |
| 666 | 667 |
| 667 LayerTilingData::TileMap::const_iterator end = m_tiler->tiles().end(); | 668 LayerTilingData::TileMap::const_iterator end = m_tiler->tiles().end(); |
| 668 for (LayerTilingData::TileMap::const_iterator iter = m_tiler->tiles().begin(
); iter != end; ++iter) { | 669 for (LayerTilingData::TileMap::const_iterator iter = m_tiler->tiles().begin(
); iter != end; ++iter) { |
| 669 UpdatableTile* tile = static_cast<UpdatableTile*>(iter->second); | 670 UpdatableTile* tile = static_cast<UpdatableTile*>(iter->second); |
| 670 // FIXME: This should not ever be null. | 671 // FIXME: This should not ever be null. |
| 671 if (!tile) | 672 if (!tile) |
| 672 continue; | 673 continue; |
| 673 tile->resetUpdateState(); | 674 tile->resetUpdateState(); |
| 674 } | 675 } |
| 675 } | 676 } |
| 676 | 677 |
| 677 namespace { | 678 namespace { |
| 678 IntRect expandRectByDelta(IntRect rect, IntSize delta) { | 679 gfx::Rect expandRectByDelta(gfx::Rect rect, gfx::Vector2d delta) { |
| 679 int width = rect.width() + abs(delta.width()); | 680 int width = rect.width() + abs(delta.x()); |
| 680 int height = rect.height() + abs(delta.height()); | 681 int height = rect.height() + abs(delta.y()); |
| 681 int x = rect.x() + ((delta.width() < 0) ? delta.width() : 0); | 682 int x = rect.x() + ((delta.x() < 0) ? delta.x() : 0); |
| 682 int y = rect.y() + ((delta.height() < 0) ? delta.height() : 0); | 683 int y = rect.y() + ((delta.y() < 0) ? delta.y() : 0); |
| 683 return IntRect(x, y, width, height); | 684 return gfx::Rect(x, y, width, height); |
| 684 } | 685 } |
| 685 } | 686 } |
| 686 | 687 |
| 687 void TiledLayer::updateScrollPrediction() | 688 void TiledLayer::updateScrollPrediction() |
| 688 { | 689 { |
| 689 // This scroll prediction is very primitive and should be replaced by a | 690 // This scroll prediction is very primitive and should be replaced by a |
| 690 // a recursive calculation on all layers which uses actual scroll/animation | 691 // a recursive calculation on all layers which uses actual scroll/animation |
| 691 // velocities. To insure this doesn't miss-predict, we only use it to predic
t | 692 // velocities. To insure this doesn't miss-predict, we only use it to predic
t |
| 692 // the visibleRect if: | 693 // the visibleRect if: |
| 693 // - contentBounds() hasn't changed. | 694 // - contentBounds() hasn't changed. |
| 694 // - visibleRect.size() hasn't changed. | 695 // - visibleRect.size() hasn't changed. |
| 695 // These two conditions prevent rotations, scales, pinch-zooms etc. where | 696 // These two conditions prevent rotations, scales, pinch-zooms etc. where |
| 696 // the prediction would be incorrect. | 697 // the prediction would be incorrect. |
| 697 IntSize delta = visibleContentRect().center() - m_previousVisibleRect.center
(); | 698 gfx::Vector2d delta = visibleContentRect().CenterPoint() - m_previousVisible
Rect.CenterPoint(); |
| 698 m_predictedScroll = -delta; | 699 m_predictedScroll = -delta; |
| 699 m_predictedVisibleRect = visibleContentRect(); | 700 m_predictedVisibleRect = visibleContentRect(); |
| 700 if (m_previousContentBounds == contentBounds() && m_previousVisibleRect.size
() == visibleContentRect().size()) { | 701 if (m_previousContentBounds == contentBounds() && m_previousVisibleRect.size
() == visibleContentRect().size()) { |
| 701 // Only expand the visible rect in the major scroll direction, to preven
t | 702 // Only expand the visible rect in the major scroll direction, to preven
t |
| 702 // massive paints due to diagonal scrolls. | 703 // massive paints due to diagonal scrolls. |
| 703 IntSize majorScrollDelta = (abs(delta.width()) > abs(delta.height())) ?
IntSize(delta.width(), 0) : IntSize(0, delta.height()); | 704 gfx::Vector2d majorScrollDelta = (abs(delta.x()) > abs(delta.y())) ? gfx
::Vector2d(delta.x(), 0) : gfx::Vector2d(0, delta.y()); |
| 704 m_predictedVisibleRect = expandRectByDelta(visibleContentRect(), majorSc
rollDelta); | 705 m_predictedVisibleRect = expandRectByDelta(visibleContentRect(), majorSc
rollDelta); |
| 705 | 706 |
| 706 // Bound the prediction to prevent unbounded paints, and clamp to conten
t bounds. | 707 // Bound the prediction to prevent unbounded paints, and clamp to conten
t bounds. |
| 707 IntRect bound = visibleContentRect(); | 708 gfx::Rect bound = visibleContentRect(); |
| 708 bound.inflateX(m_tiler->tileSize().width() * maxPredictiveTilesCount); | 709 bound.Inset(-m_tiler->tileSize().width() * maxPredictiveTilesCount, |
| 709 bound.inflateY(m_tiler->tileSize().height() * maxPredictiveTilesCount); | 710 -m_tiler->tileSize().height() * maxPredictiveTilesCount); |
| 710 bound.intersect(IntRect(IntPoint::zero(), contentBounds())); | 711 bound.Intersect(gfx::Rect(gfx::Point(), contentBounds())); |
| 711 m_predictedVisibleRect.intersect(bound); | 712 m_predictedVisibleRect.Intersect(bound); |
| 712 } | 713 } |
| 713 m_previousContentBounds = contentBounds(); | 714 m_previousContentBounds = contentBounds(); |
| 714 m_previousVisibleRect = visibleContentRect(); | 715 m_previousVisibleRect = visibleContentRect(); |
| 715 } | 716 } |
| 716 | 717 |
| 717 void TiledLayer::update(TextureUpdateQueue& queue, const OcclusionTracker* occlu
sion, RenderingStats& stats) | 718 void TiledLayer::update(TextureUpdateQueue& queue, const OcclusionTracker* occlu
sion, RenderingStats& stats) |
| 718 { | 719 { |
| 719 DCHECK(!m_skipsDraw && !m_failedUpdate); // Did resetUpdateState get skipped
? | 720 DCHECK(!m_skipsDraw && !m_failedUpdate); // Did resetUpdateState get skipped
? |
| 720 updateBounds(); | 721 updateBounds(); |
| 721 if (m_tiler->hasEmptyBounds() || !drawsContent()) | 722 if (m_tiler->hasEmptyBounds() || !drawsContent()) |
| 722 return; | 723 return; |
| 723 | 724 |
| 724 bool didPaint = false; | 725 bool didPaint = false; |
| 725 | 726 |
| 726 // Animation pre-paint. If the layer is small, try to paint it all | 727 // Animation pre-paint. If the layer is small, try to paint it all |
| 727 // immediately whether or not it is occluded, to avoid paint/upload | 728 // immediately whether or not it is occluded, to avoid paint/upload |
| 728 // hiccups while it is animating. | 729 // hiccups while it is animating. |
| 729 if (isSmallAnimatedLayer(this)) { | 730 if (isSmallAnimatedLayer(this)) { |
| 730 int left, top, right, bottom; | 731 int left, top, right, bottom; |
| 731 m_tiler->contentRectToTileIndices(IntRect(IntPoint::zero(), contentBound
s()), left, top, right, bottom); | 732 m_tiler->contentRectToTileIndices(gfx::Rect(gfx::Point(), contentBounds(
)), left, top, right, bottom); |
| 732 updateTiles(left, top, right, bottom, queue, 0, stats, didPaint); | 733 updateTiles(left, top, right, bottom, queue, 0, stats, didPaint); |
| 733 if (didPaint) | 734 if (didPaint) |
| 734 return; | 735 return; |
| 735 // This was an attempt to paint the entire layer so if we fail it's okay
, | 736 // This was an attempt to paint the entire layer so if we fail it's okay
, |
| 736 // just fallback on painting visible etc. below. | 737 // just fallback on painting visible etc. below. |
| 737 m_failedUpdate = false; | 738 m_failedUpdate = false; |
| 738 } | 739 } |
| 739 | 740 |
| 740 if (m_predictedVisibleRect.isEmpty()) | 741 if (m_predictedVisibleRect.IsEmpty()) |
| 741 return; | 742 return; |
| 742 | 743 |
| 743 // Visible painting. First occlude visible tiles and paint the non-occluded
tiles. | 744 // Visible painting. First occlude visible tiles and paint the non-occluded
tiles. |
| 744 int left, top, right, bottom; | 745 int left, top, right, bottom; |
| 745 m_tiler->contentRectToTileIndices(m_predictedVisibleRect, left, top, right,
bottom); | 746 m_tiler->contentRectToTileIndices(m_predictedVisibleRect, left, top, right,
bottom); |
| 746 markOcclusionsAndRequestTextures(left, top, right, bottom, occlusion); | 747 markOcclusionsAndRequestTextures(left, top, right, bottom, occlusion); |
| 747 m_skipsDraw = !updateTiles(left, top, right, bottom, queue, occlusion, stats
, didPaint); | 748 m_skipsDraw = !updateTiles(left, top, right, bottom, queue, occlusion, stats
, didPaint); |
| 748 if (m_skipsDraw) | 749 if (m_skipsDraw) |
| 749 m_tiler->reset(); | 750 m_tiler->reset(); |
| 750 if (m_skipsDraw || didPaint) | 751 if (m_skipsDraw || didPaint) |
| 751 return; | 752 return; |
| 752 | 753 |
| 753 // If we have already painting everything visible. Do some pre-painting whil
e idle. | 754 // If we have already painting everything visible. Do some pre-painting whil
e idle. |
| 754 IntRect idlePaintContentRect = idlePaintRect(); | 755 gfx::Rect idlePaintContentRect = idlePaintRect(); |
| 755 if (idlePaintContentRect.isEmpty()) | 756 if (idlePaintContentRect.IsEmpty()) |
| 756 return; | 757 return; |
| 757 | 758 |
| 758 // Prepaint anything that was occluded but inside the layer's visible region
. | 759 // Prepaint anything that was occluded but inside the layer's visible region
. |
| 759 if (!updateTiles(left, top, right, bottom, queue, 0, stats, didPaint) || did
Paint) | 760 if (!updateTiles(left, top, right, bottom, queue, 0, stats, didPaint) || did
Paint) |
| 760 return; | 761 return; |
| 761 | 762 |
| 762 int prepaintLeft, prepaintTop, prepaintRight, prepaintBottom; | 763 int prepaintLeft, prepaintTop, prepaintRight, prepaintBottom; |
| 763 m_tiler->contentRectToTileIndices(idlePaintContentRect, prepaintLeft, prepai
ntTop, prepaintRight, prepaintBottom); | 764 m_tiler->contentRectToTileIndices(idlePaintContentRect, prepaintLeft, prepai
ntTop, prepaintRight, prepaintBottom); |
| 764 | 765 |
| 765 // Then expand outwards one row/column at a time until we find a dirty row/c
olumn | 766 // Then expand outwards one row/column at a time until we find a dirty row/c
olumn |
| 766 // to update. Increment along the major and minor scroll directions first. | 767 // to update. Increment along the major and minor scroll directions first. |
| 767 IntSize delta = -m_predictedScroll; | 768 gfx::Vector2d delta = -m_predictedScroll; |
| 768 delta = IntSize(delta.width() == 0 ? 1 : delta.width(), | 769 delta = gfx::Vector2d(delta.x() == 0 ? 1 : delta.x(), |
| 769 delta.height() == 0 ? 1 : delta.height()); | 770 delta.y() == 0 ? 1 : delta.y()); |
| 770 IntSize majorDelta = (abs(delta.width()) > abs(delta.height())) ? IntSize(d
elta.width(), 0) : IntSize(0, delta.height()); | 771 gfx::Vector2d majorDelta = (abs(delta.x()) > abs(delta.y())) ? gfx::Vector2
d(delta.x(), 0) : gfx::Vector2d(0, delta.y()); |
| 771 IntSize minorDelta = (abs(delta.width()) <= abs(delta.height())) ? IntSize(d
elta.width(), 0) : IntSize(0, delta.height()); | 772 gfx::Vector2d minorDelta = (abs(delta.x()) <= abs(delta.y())) ? gfx::Vector2
d(delta.x(), 0) : gfx::Vector2d(0, delta.y()); |
| 772 IntSize deltas[4] = {majorDelta, minorDelta, -majorDelta, -minorDelta}; | 773 gfx::Vector2d deltas[4] = {majorDelta, minorDelta, -majorDelta, -minorDelta}
; |
| 773 for(int i = 0; i < 4; i++) { | 774 for(int i = 0; i < 4; i++) { |
| 774 if (deltas[i].height() > 0) { | 775 if (deltas[i].y() > 0) { |
| 775 while (bottom < prepaintBottom) { | 776 while (bottom < prepaintBottom) { |
| 776 ++bottom; | 777 ++bottom; |
| 777 if (!updateTiles(left, bottom, right, bottom, queue, 0, stats, d
idPaint) || didPaint) | 778 if (!updateTiles(left, bottom, right, bottom, queue, 0, stats, d
idPaint) || didPaint) |
| 778 return; | 779 return; |
| 779 } | 780 } |
| 780 } | 781 } |
| 781 if (deltas[i].height() < 0) { | 782 if (deltas[i].y() < 0) { |
| 782 while (top > prepaintTop) { | 783 while (top > prepaintTop) { |
| 783 --top; | 784 --top; |
| 784 if (!updateTiles(left, top, right, top, queue, 0, stats, didPain
t) || didPaint) | 785 if (!updateTiles(left, top, right, top, queue, 0, stats, didPain
t) || didPaint) |
| 785 return; | 786 return; |
| 786 } | 787 } |
| 787 } | 788 } |
| 788 if (deltas[i].width() < 0) { | 789 if (deltas[i].x() < 0) { |
| 789 while (left > prepaintLeft) { | 790 while (left > prepaintLeft) { |
| 790 --left; | 791 --left; |
| 791 if (!updateTiles(left, top, left, bottom, queue, 0, stats, didPa
int) || didPaint) | 792 if (!updateTiles(left, top, left, bottom, queue, 0, stats, didPa
int) || didPaint) |
| 792 return; | 793 return; |
| 793 } | 794 } |
| 794 } | 795 } |
| 795 if (deltas[i].width() > 0) { | 796 if (deltas[i].x() > 0) { |
| 796 while (right < prepaintRight) { | 797 while (right < prepaintRight) { |
| 797 ++right; | 798 ++right; |
| 798 if (!updateTiles(right, top, right, bottom, queue, 0, stats, did
Paint) || didPaint) | 799 if (!updateTiles(right, top, right, bottom, queue, 0, stats, did
Paint) || didPaint) |
| 799 return; | 800 return; |
| 800 } | 801 } |
| 801 } | 802 } |
| 802 } | 803 } |
| 803 } | 804 } |
| 804 | 805 |
| 805 bool TiledLayer::needsIdlePaint() | 806 bool TiledLayer::needsIdlePaint() |
| 806 { | 807 { |
| 807 // Don't trigger more paints if we failed (as we'll just fail again). | 808 // Don't trigger more paints if we failed (as we'll just fail again). |
| 808 if (m_failedUpdate || visibleContentRect().isEmpty() || m_tiler->hasEmptyBou
nds() || !drawsContent()) | 809 if (m_failedUpdate || visibleContentRect().IsEmpty() || m_tiler->hasEmptyBou
nds() || !drawsContent()) |
| 809 return false; | 810 return false; |
| 810 | 811 |
| 811 IntRect idlePaintContentRect = idlePaintRect(); | 812 gfx::Rect idlePaintContentRect = idlePaintRect(); |
| 812 if (idlePaintContentRect.isEmpty()) | 813 if (idlePaintContentRect.IsEmpty()) |
| 813 return false; | 814 return false; |
| 814 | 815 |
| 815 int left, top, right, bottom; | 816 int left, top, right, bottom; |
| 816 m_tiler->contentRectToTileIndices(idlePaintContentRect, left, top, right, bo
ttom); | 817 m_tiler->contentRectToTileIndices(idlePaintContentRect, left, top, right, bo
ttom); |
| 817 | 818 |
| 818 for (int j = top; j <= bottom; ++j) { | 819 for (int j = top; j <= bottom; ++j) { |
| 819 for (int i = left; i <= right; ++i) { | 820 for (int i = left; i <= right; ++i) { |
| 820 UpdatableTile* tile = tileAt(i, j); | 821 UpdatableTile* tile = tileAt(i, j); |
| 821 DCHECK(tile); // Did setTexturePriorities get skipped? | 822 DCHECK(tile); // Did setTexturePriorities get skipped? |
| 822 if (!tile) | 823 if (!tile) |
| 823 continue; | 824 continue; |
| 824 | 825 |
| 825 bool updated = !tile->updateRect.isEmpty(); | 826 bool updated = !tile->updateRect.IsEmpty(); |
| 826 bool canAcquire = tile->managedTexture()->canAcquireBackingTexture()
; | 827 bool canAcquire = tile->managedTexture()->canAcquireBackingTexture()
; |
| 827 bool dirty = tile->isDirty() || !tile->managedTexture()->haveBacking
Texture(); | 828 bool dirty = tile->isDirty() || !tile->managedTexture()->haveBacking
Texture(); |
| 828 if (!updated && canAcquire && dirty) | 829 if (!updated && canAcquire && dirty) |
| 829 return true; | 830 return true; |
| 830 } | 831 } |
| 831 } | 832 } |
| 832 return false; | 833 return false; |
| 833 } | 834 } |
| 834 | 835 |
| 835 IntRect TiledLayer::idlePaintRect() | 836 gfx::Rect TiledLayer::idlePaintRect() |
| 836 { | 837 { |
| 837 // Don't inflate an empty rect. | 838 // Don't inflate an empty rect. |
| 838 if (visibleContentRect().isEmpty()) | 839 if (visibleContentRect().IsEmpty()) |
| 839 return IntRect(); | 840 return gfx::Rect(); |
| 840 | 841 |
| 841 IntRect prepaintRect = visibleContentRect(); | 842 gfx::Rect prepaintRect = visibleContentRect(); |
| 842 prepaintRect.inflateX(m_tiler->tileSize().width() * prepaintColumns); | 843 prepaintRect.Inset(-m_tiler->tileSize().width() * prepaintColumns, |
| 843 prepaintRect.inflateY(m_tiler->tileSize().height() * prepaintRows); | 844 -m_tiler->tileSize().height() * prepaintRows); |
| 844 IntRect contentRect(IntPoint::zero(), contentBounds()); | 845 gfx::Rect contentRect(gfx::Point(), contentBounds()); |
| 845 prepaintRect.intersect(contentRect); | 846 prepaintRect.Intersect(contentRect); |
| 846 | 847 |
| 847 return prepaintRect; | 848 return prepaintRect; |
| 848 } | 849 } |
| 849 | 850 |
| 850 } | 851 } |
| OLD | NEW |