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