OLD | NEW |
(Empty) | |
| 1 /* |
| 2 * Copyright (C) 2011 Google Inc. All rights reserved. |
| 3 * |
| 4 * Redistribution and use in source and binary forms, with or without |
| 5 * modification, are permitted provided that the following conditions |
| 6 * are met: |
| 7 * |
| 8 * 1. Redistributions of source code must retain the above copyright |
| 9 * notice, this list of conditions and the following disclaimer. |
| 10 * 2. Redistributions in binary form must reproduce the above copyright |
| 11 * notice, this list of conditions and the following disclaimer in the |
| 12 * documentation and/or other materials provided with the distribution. |
| 13 * |
| 14 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY |
| 15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
| 16 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| 17 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY |
| 18 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
| 19 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
| 20 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
| 21 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
| 23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 24 */ |
| 25 |
| 26 #include "config.h" |
| 27 |
| 28 #if USE(ACCELERATED_COMPOSITING) |
| 29 |
| 30 #include "TiledLayerChromium.h" |
| 31 |
| 32 #include "GraphicsContext3D.h" |
| 33 #include "ManagedTexture.h" |
| 34 #include "Region.h" |
| 35 #include "TextStream.h" |
| 36 |
| 37 #include "cc/CCLayerImpl.h" |
| 38 #include "cc/CCLayerTreeHost.h" |
| 39 #include "cc/CCOverdrawMetrics.h" |
| 40 #include "cc/CCTextureUpdater.h" |
| 41 #include "cc/CCTiledLayerImpl.h" |
| 42 |
| 43 #include <wtf/CurrentTime.h> |
| 44 #include <wtf/MathExtras.h> |
| 45 |
| 46 using namespace std; |
| 47 using WebKit::WebTransformationMatrix; |
| 48 |
| 49 namespace WebCore { |
| 50 |
| 51 class UpdatableTile : public CCLayerTilingData::Tile { |
| 52 WTF_MAKE_NONCOPYABLE(UpdatableTile); |
| 53 public: |
| 54 static PassOwnPtr<UpdatableTile> create(PassOwnPtr<LayerTextureUpdater::Text
ure> texture) |
| 55 { |
| 56 return adoptPtr(new UpdatableTile(texture)); |
| 57 } |
| 58 |
| 59 LayerTextureUpdater::Texture* texture() { return m_texture.get(); } |
| 60 ManagedTexture* managedTexture() { return m_texture->texture(); } |
| 61 |
| 62 bool isDirty() const { return !dirtyRect.isEmpty(); } |
| 63 void copyAndClearDirty() |
| 64 { |
| 65 updateRect = dirtyRect; |
| 66 dirtyRect = IntRect(); |
| 67 } |
| 68 // Returns whether the layer was dirty and not updated in the current frame.
For tiles that were not culled, the |
| 69 // updateRect holds the area of the tile that was updated. Otherwise, the ar
ea that would have been updated. |
| 70 bool isDirtyForCurrentFrame() { return !dirtyRect.isEmpty() && (updateRect.i
sEmpty() || !updated); } |
| 71 |
| 72 IntRect dirtyRect; |
| 73 IntRect updateRect; |
| 74 bool partialUpdate; |
| 75 bool updated; |
| 76 bool isInUseOnImpl; |
| 77 private: |
| 78 explicit UpdatableTile(PassOwnPtr<LayerTextureUpdater::Texture> texture) |
| 79 : partialUpdate(false) |
| 80 , updated(false) |
| 81 , isInUseOnImpl(false) |
| 82 , m_texture(texture) |
| 83 { |
| 84 } |
| 85 |
| 86 OwnPtr<LayerTextureUpdater::Texture> m_texture; |
| 87 }; |
| 88 |
| 89 TiledLayerChromium::TiledLayerChromium() |
| 90 : LayerChromium() |
| 91 , m_textureFormat(GL_INVALID_ENUM) |
| 92 , m_skipsDraw(false) |
| 93 , m_skipsIdlePaint(false) |
| 94 , m_sampledTexelFormat(LayerTextureUpdater::SampledTexelFormatInvalid) |
| 95 , m_didPaint(false) |
| 96 , m_tilingOption(AutoTile) |
| 97 { |
| 98 m_tiler = CCLayerTilingData::create(IntSize(), CCLayerTilingData::HasBorderT
exels); |
| 99 } |
| 100 |
| 101 TiledLayerChromium::~TiledLayerChromium() |
| 102 { |
| 103 } |
| 104 |
| 105 PassOwnPtr<CCLayerImpl> TiledLayerChromium::createCCLayerImpl() |
| 106 { |
| 107 return CCTiledLayerImpl::create(id()); |
| 108 } |
| 109 |
| 110 void TiledLayerChromium::updateTileSizeAndTilingOption() |
| 111 { |
| 112 ASSERT(layerTreeHost()); |
| 113 |
| 114 const IntSize& defaultTileSize = layerTreeHost()->settings().defaultTileSize
; |
| 115 const IntSize& maxUntiledLayerSize = layerTreeHost()->settings().maxUntiledL
ayerSize; |
| 116 int layerWidth = contentBounds().width(); |
| 117 int layerHeight = contentBounds().height(); |
| 118 |
| 119 const IntSize tileSize(min(defaultTileSize.width(), layerWidth), min(default
TileSize.height(), layerHeight)); |
| 120 |
| 121 // Tile if both dimensions large, or any one dimension large and the other |
| 122 // extends into a second tile but the total layer area isn't larger than tha
t |
| 123 // of the largest possible untiled layer. This heuristic allows for long ski
nny layers |
| 124 // (e.g. scrollbars) that are Nx1 tiles to minimize wasted texture space but
still avoids |
| 125 // creating very large tiles. |
| 126 const bool anyDimensionLarge = layerWidth > maxUntiledLayerSize.width() || l
ayerHeight > maxUntiledLayerSize.height(); |
| 127 const bool anyDimensionOneTile = (layerWidth <= defaultTileSize.width() || l
ayerHeight <= defaultTileSize.height()) |
| 128 && (layerWidth * layerHeight) <= (maxUntil
edLayerSize.width() * maxUntiledLayerSize.height()); |
| 129 const bool autoTiled = anyDimensionLarge && !anyDimensionOneTile; |
| 130 |
| 131 bool isTiled; |
| 132 if (m_tilingOption == AlwaysTile) |
| 133 isTiled = true; |
| 134 else if (m_tilingOption == NeverTile) |
| 135 isTiled = false; |
| 136 else |
| 137 isTiled = autoTiled; |
| 138 |
| 139 IntSize requestedSize = isTiled ? tileSize : contentBounds(); |
| 140 const int maxSize = layerTreeHost()->layerRendererCapabilities().maxTextureS
ize; |
| 141 IntSize clampedSize = requestedSize.shrunkTo(IntSize(maxSize, maxSize)); |
| 142 setTileSize(clampedSize); |
| 143 } |
| 144 |
| 145 void TiledLayerChromium::updateBounds() |
| 146 { |
| 147 IntSize oldBounds = m_tiler->bounds(); |
| 148 IntSize newBounds = contentBounds(); |
| 149 if (oldBounds == newBounds) |
| 150 return; |
| 151 m_tiler->setBounds(newBounds); |
| 152 |
| 153 // Invalidate any areas that the new bounds exposes. |
| 154 Region oldRegion(IntRect(IntPoint(), oldBounds)); |
| 155 Region newRegion(IntRect(IntPoint(), newBounds)); |
| 156 newRegion.subtract(oldRegion); |
| 157 Vector<IntRect> rects = newRegion.rects(); |
| 158 for (size_t i = 0; i < rects.size(); ++i) |
| 159 invalidateRect(rects[i]); |
| 160 } |
| 161 |
| 162 void TiledLayerChromium::setTileSize(const IntSize& size) |
| 163 { |
| 164 m_tiler->setTileSize(size); |
| 165 } |
| 166 |
| 167 void TiledLayerChromium::setBorderTexelOption(CCLayerTilingData::BorderTexelOpti
on borderTexelOption) |
| 168 { |
| 169 m_tiler->setBorderTexelOption(borderTexelOption); |
| 170 } |
| 171 |
| 172 bool TiledLayerChromium::drawsContent() const |
| 173 { |
| 174 if (!LayerChromium::drawsContent()) |
| 175 return false; |
| 176 |
| 177 bool hasMoreThanOneTile = m_tiler->numTilesX() > 1 || m_tiler->numTilesY() >
1; |
| 178 if (m_tilingOption == NeverTile && hasMoreThanOneTile) |
| 179 return false; |
| 180 |
| 181 return true; |
| 182 } |
| 183 |
| 184 bool TiledLayerChromium::needsContentsScale() const |
| 185 { |
| 186 return true; |
| 187 } |
| 188 |
| 189 IntSize TiledLayerChromium::contentBounds() const |
| 190 { |
| 191 return IntSize(lroundf(bounds().width() * contentsScale()), lroundf(bounds()
.height() * contentsScale())); |
| 192 } |
| 193 |
| 194 void TiledLayerChromium::setTilingOption(TilingOption tilingOption) |
| 195 { |
| 196 m_tilingOption = tilingOption; |
| 197 } |
| 198 |
| 199 void TiledLayerChromium::setIsMask(bool isMask) |
| 200 { |
| 201 setTilingOption(isMask ? NeverTile : AutoTile); |
| 202 } |
| 203 |
| 204 void TiledLayerChromium::pushPropertiesTo(CCLayerImpl* layer) |
| 205 { |
| 206 LayerChromium::pushPropertiesTo(layer); |
| 207 |
| 208 CCTiledLayerImpl* tiledLayer = static_cast<CCTiledLayerImpl*>(layer); |
| 209 |
| 210 tiledLayer->setSkipsDraw(m_skipsDraw); |
| 211 tiledLayer->setContentsSwizzled(m_sampledTexelFormat != LayerTextureUpdater:
:SampledTexelFormatRGBA); |
| 212 tiledLayer->setTilingData(*m_tiler); |
| 213 Vector<UpdatableTile*> invalidTiles; |
| 214 |
| 215 for (CCLayerTilingData::TileMap::const_iterator iter = m_tiler->tiles().begi
n(); iter != m_tiler->tiles().end(); ++iter) { |
| 216 int i = iter->first.first; |
| 217 int j = iter->first.second; |
| 218 UpdatableTile* tile = static_cast<UpdatableTile*>(iter->second.get()); |
| 219 // FIXME: This should not ever be null. |
| 220 if (!tile) |
| 221 continue; |
| 222 tile->isInUseOnImpl = false; |
| 223 if (!tile->managedTexture()->isValid(m_tiler->tileSize(), m_textureForma
t)) { |
| 224 invalidTiles.append(tile); |
| 225 continue; |
| 226 } |
| 227 if (tile->isDirtyForCurrentFrame()) |
| 228 continue; |
| 229 |
| 230 tiledLayer->pushTileProperties(i, j, tile->managedTexture()->textureId()
, tile->opaqueRect()); |
| 231 tile->isInUseOnImpl = true; |
| 232 } |
| 233 for (Vector<UpdatableTile*>::const_iterator iter = invalidTiles.begin(); ite
r != invalidTiles.end(); ++iter) |
| 234 m_tiler->takeTile((*iter)->i(), (*iter)->j()); |
| 235 } |
| 236 |
| 237 TextureManager* TiledLayerChromium::textureManager() const |
| 238 { |
| 239 if (!layerTreeHost()) |
| 240 return 0; |
| 241 return layerTreeHost()->contentsTextureManager(); |
| 242 } |
| 243 |
| 244 void TiledLayerChromium::setLayerTreeHost(CCLayerTreeHost* host) |
| 245 { |
| 246 if (host && host != layerTreeHost()) { |
| 247 for (CCLayerTilingData::TileMap::const_iterator iter = m_tiler->tiles().
begin(); iter != m_tiler->tiles().end(); ++iter) { |
| 248 UpdatableTile* tile = static_cast<UpdatableTile*>(iter->second.get()
); |
| 249 // FIXME: This should not ever be null. |
| 250 if (!tile) |
| 251 continue; |
| 252 tile->managedTexture()->setTextureManager(host->contentsTextureManag
er()); |
| 253 } |
| 254 } |
| 255 LayerChromium::setLayerTreeHost(host); |
| 256 } |
| 257 |
| 258 UpdatableTile* TiledLayerChromium::tileAt(int i, int j) const |
| 259 { |
| 260 return static_cast<UpdatableTile*>(m_tiler->tileAt(i, j)); |
| 261 } |
| 262 |
| 263 UpdatableTile* TiledLayerChromium::createTile(int i, int j) |
| 264 { |
| 265 OwnPtr<UpdatableTile> tile(UpdatableTile::create(textureUpdater()->createTex
ture(textureManager()))); |
| 266 UpdatableTile* addedTile = tile.get(); |
| 267 m_tiler->addTile(tile.release(), i, j); |
| 268 |
| 269 addedTile->dirtyRect = m_tiler->tileRect(addedTile); |
| 270 |
| 271 // Temporary diagnostic crash. |
| 272 if (!addedTile) |
| 273 CRASH(); |
| 274 if (!tileAt(i, j)) |
| 275 CRASH(); |
| 276 |
| 277 return addedTile; |
| 278 } |
| 279 |
| 280 void TiledLayerChromium::setNeedsDisplayRect(const FloatRect& dirtyRect) |
| 281 { |
| 282 FloatRect scaledDirtyRect(dirtyRect); |
| 283 scaledDirtyRect.scale(contentsScale()); |
| 284 IntRect dirty = enclosingIntRect(scaledDirtyRect); |
| 285 invalidateRect(dirty); |
| 286 LayerChromium::setNeedsDisplayRect(dirtyRect); |
| 287 } |
| 288 |
| 289 void TiledLayerChromium::setIsNonCompositedContent(bool isNonCompositedContent) |
| 290 { |
| 291 LayerChromium::setIsNonCompositedContent(isNonCompositedContent); |
| 292 |
| 293 CCLayerTilingData::BorderTexelOption borderTexelOption; |
| 294 #if OS(ANDROID) |
| 295 // Always want border texels and GL_LINEAR due to pinch zoom. |
| 296 borderTexelOption = CCLayerTilingData::HasBorderTexels; |
| 297 #else |
| 298 borderTexelOption = isNonCompositedContent ? CCLayerTilingData::NoBorderTexe
ls : CCLayerTilingData::HasBorderTexels; |
| 299 #endif |
| 300 setBorderTexelOption(borderTexelOption); |
| 301 } |
| 302 |
| 303 void TiledLayerChromium::invalidateRect(const IntRect& layerRect) |
| 304 { |
| 305 updateBounds(); |
| 306 if (m_tiler->isEmpty() || layerRect.isEmpty() || m_skipsDraw) |
| 307 return; |
| 308 |
| 309 for (CCLayerTilingData::TileMap::const_iterator iter = m_tiler->tiles().begi
n(); iter != m_tiler->tiles().end(); ++iter) { |
| 310 UpdatableTile* tile = static_cast<UpdatableTile*>(iter->second.get()); |
| 311 ASSERT(tile); |
| 312 // FIXME: This should not ever be null. |
| 313 if (!tile) |
| 314 continue; |
| 315 IntRect bound = m_tiler->tileRect(tile); |
| 316 bound.intersect(layerRect); |
| 317 tile->dirtyRect.unite(bound); |
| 318 } |
| 319 } |
| 320 |
| 321 void TiledLayerChromium::protectTileTextures(const IntRect& layerRect) |
| 322 { |
| 323 if (m_tiler->isEmpty() || layerRect.isEmpty()) |
| 324 return; |
| 325 |
| 326 int left, top, right, bottom; |
| 327 m_tiler->layerRectToTileIndices(layerRect, left, top, right, bottom); |
| 328 |
| 329 for (int j = top; j <= bottom; ++j) { |
| 330 for (int i = left; i <= right; ++i) { |
| 331 UpdatableTile* tile = tileAt(i, j); |
| 332 if (!tile || !tile->managedTexture()->isValid(m_tiler->tileSize(), m
_textureFormat)) |
| 333 continue; |
| 334 |
| 335 tile->managedTexture()->reserve(m_tiler->tileSize(), m_textureFormat
); |
| 336 } |
| 337 } |
| 338 } |
| 339 |
| 340 // Returns true if tile is dirty and only part of it needs to be updated. |
| 341 bool TiledLayerChromium::tileOnlyNeedsPartialUpdate(UpdatableTile* tile) |
| 342 { |
| 343 return !tile->dirtyRect.contains(m_tiler->tileRect(tile)); |
| 344 } |
| 345 |
| 346 // Dirty tiles with valid textures needs buffered update to guarantee that |
| 347 // we don't modify textures currently used for drawing by the impl thread. |
| 348 bool TiledLayerChromium::tileNeedsBufferedUpdate(UpdatableTile* tile) |
| 349 { |
| 350 if (!tile->managedTexture()->isValid(m_tiler->tileSize(), m_textureFormat)) |
| 351 return false; |
| 352 |
| 353 if (!tile->isDirty()) |
| 354 return false; |
| 355 |
| 356 if (!tile->isInUseOnImpl) |
| 357 return false; |
| 358 |
| 359 return true; |
| 360 } |
| 361 |
| 362 void TiledLayerChromium::updateTiles(bool idle, int left, int top, int right, in
t bottom, CCTextureUpdater& updater, const CCOcclusionTracker* occlusion) |
| 363 { |
| 364 createTextureUpdaterIfNeeded(); |
| 365 |
| 366 // Create tiles as needed, expanding a dirty rect to contain all |
| 367 // the dirty regions currently being drawn. All dirty tiles that are to be p
ainted |
| 368 // get their updateRect set to dirtyRect and dirtyRect cleared. This way if |
| 369 // invalidateRect is invoked during updateLayerRect we don't lose the reques
t. |
| 370 IntRect paintRect; |
| 371 for (int j = top; j <= bottom; ++j) { |
| 372 for (int i = left; i <= right; ++i) { |
| 373 UpdatableTile* tile = tileAt(i, j); |
| 374 if (!tile) |
| 375 tile = createTile(i, j); |
| 376 |
| 377 // Temporary diagnostic crash |
| 378 if (!m_tiler) |
| 379 CRASH(); |
| 380 |
| 381 if (!tile->managedTexture()->isValid(m_tiler->tileSize(), m_textureF
ormat)) { |
| 382 // Sets the dirty rect to a full-sized tile with border texels. |
| 383 tile->dirtyRect = m_tiler->tileRect(tile); |
| 384 } |
| 385 |
| 386 // When not idle painting, if the visible region of the tile is occl
uded, don't reserve a texture or update the tile. |
| 387 // If any part of the tile is visible, then we need to update it so
the tile is pushed to the impl thread. |
| 388 if (!idle && occlusion) { |
| 389 IntRect visibleTileRect = intersection(m_tiler->tileBounds(i, j)
, visibleLayerRect()); |
| 390 if (occlusion->occluded(this, visibleTileRect)) { |
| 391 ASSERT(!tile->updated); |
| 392 continue; |
| 393 } |
| 394 } |
| 395 |
| 396 // We come through this function multiple times during a commit, and
updated should be true if the tile is not culled |
| 397 // any single time through the function. |
| 398 tile->updated = true; |
| 399 |
| 400 if (layerTreeHost() && layerTreeHost()->bufferedUpdates() && tileNee
dsBufferedUpdate(tile)) { |
| 401 // FIXME: Decide if partial update should be allowed based on co
st |
| 402 // of update. https://bugs.webkit.org/show_bug.cgi?id=77376 |
| 403 if (tileOnlyNeedsPartialUpdate(tile) && layerTreeHost()->request
PartialTextureUpdate()) |
| 404 tile->partialUpdate = true; |
| 405 else { |
| 406 layerTreeHost()->deleteTextureAfterCommit(tile->managedTextu
re()->steal()); |
| 407 // Sets the dirty rect to a full-sized tile with border texe
ls. |
| 408 tile->dirtyRect = m_tiler->tileRect(tile); |
| 409 } |
| 410 } |
| 411 |
| 412 if (!tile->managedTexture()->reserve(m_tiler->tileSize(), m_textureF
ormat)) { |
| 413 m_skipsIdlePaint = true; |
| 414 if (!idle) { |
| 415 m_skipsDraw = true; |
| 416 m_tiler->reset(); |
| 417 } |
| 418 return; |
| 419 } |
| 420 |
| 421 paintRect.unite(tile->dirtyRect); |
| 422 } |
| 423 } |
| 424 |
| 425 // For tiles that were not culled, we are going to update the area currently
marked as dirty. So |
| 426 // clear that dirty area and mark it for update instead. |
| 427 for (int j = top; j <= bottom; ++j) { |
| 428 for (int i = left; i <= right; ++i) { |
| 429 UpdatableTile* tile = tileAt(i, j); |
| 430 // FIXME: This should not ever be null. |
| 431 if (!tile) |
| 432 continue; |
| 433 if (tile->updated) |
| 434 tile->copyAndClearDirty(); |
| 435 else if (!idle && occlusion && tile->isDirty()) |
| 436 occlusion->overdrawMetrics().didCullTileForUpload(); |
| 437 } |
| 438 } |
| 439 |
| 440 if (paintRect.isEmpty()) |
| 441 return; |
| 442 |
| 443 if (occlusion) |
| 444 occlusion->overdrawMetrics().didPaint(paintRect); |
| 445 |
| 446 // The updateRect should be in layer space. So we have to convert the paintR
ect from content space to layer space. |
| 447 m_updateRect = FloatRect(paintRect); |
| 448 float widthScale = bounds().width() / static_cast<float>(contentBounds().wid
th()); |
| 449 float heightScale = bounds().height() / static_cast<float>(contentBounds().h
eight()); |
| 450 m_updateRect.scale(widthScale, heightScale); |
| 451 |
| 452 // Calling prepareToUpdate() calls into WebKit to paint, which may have the
side |
| 453 // effect of disabling compositing, which causes our reference to the textur
e updater to be deleted. |
| 454 // However, we can't free the memory backing the SkCanvas until the paint fi
nishes, |
| 455 // so we grab a local reference here to hold the updater alive until the pai
nt completes. |
| 456 RefPtr<LayerTextureUpdater> protector(textureUpdater()); |
| 457 IntRect paintedOpaqueRect; |
| 458 textureUpdater()->prepareToUpdate(paintRect, m_tiler->tileSize(), contentsSc
ale(), paintedOpaqueRect); |
| 459 m_didPaint = true; |
| 460 |
| 461 for (int j = top; j <= bottom; ++j) { |
| 462 for (int i = left; i <= right; ++i) { |
| 463 UpdatableTile* tile = tileAt(i, j); |
| 464 // FIXME: This should not ever be null. |
| 465 if (!tile) |
| 466 continue; |
| 467 |
| 468 IntRect tileRect = m_tiler->tileBounds(i, j); |
| 469 |
| 470 if (!tile->updated) |
| 471 continue; |
| 472 |
| 473 // Use updateRect as the above loop copied the dirty rect for this f
rame to updateRect. |
| 474 const IntRect& dirtyRect = tile->updateRect; |
| 475 if (dirtyRect.isEmpty()) |
| 476 continue; |
| 477 |
| 478 // 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 |
| 479 // other part of the tile opaque. |
| 480 IntRect tilePaintedRect = intersection(tileRect, paintRect); |
| 481 IntRect tilePaintedOpaqueRect = intersection(tileRect, paintedOpaque
Rect); |
| 482 if (!tilePaintedRect.isEmpty()) { |
| 483 IntRect paintInsideTileOpaqueRect = intersection(tile->opaqueRec
t(), tilePaintedRect); |
| 484 bool paintInsideTileOpaqueRectIsNonOpaque = !tilePaintedOpaqueRe
ct.contains(paintInsideTileOpaqueRect); |
| 485 bool opaquePaintNotInsideTileOpaqueRect = !tilePaintedOpaqueRect
.isEmpty() && !tile->opaqueRect().contains(tilePaintedOpaqueRect); |
| 486 |
| 487 if (paintInsideTileOpaqueRectIsNonOpaque || opaquePaintNotInside
TileOpaqueRect) |
| 488 tile->setOpaqueRect(tilePaintedOpaqueRect); |
| 489 } |
| 490 |
| 491 // sourceRect starts as a full-sized tile with border texels include
d. |
| 492 IntRect sourceRect = m_tiler->tileRect(tile); |
| 493 sourceRect.intersect(dirtyRect); |
| 494 // Paint rect not guaranteed to line up on tile boundaries, so |
| 495 // make sure that sourceRect doesn't extend outside of it. |
| 496 sourceRect.intersect(paintRect); |
| 497 |
| 498 tile->updateRect = sourceRect; |
| 499 |
| 500 if (sourceRect.isEmpty()) |
| 501 continue; |
| 502 |
| 503 tile->texture()->prepareRect(sourceRect); |
| 504 if (occlusion) |
| 505 occlusion->overdrawMetrics().didUpload(WebTransformationMatrix()
, sourceRect, tile->opaqueRect()); |
| 506 |
| 507 const IntPoint anchor = m_tiler->tileRect(tile).location(); |
| 508 |
| 509 // Calculate tile-space rectangle to upload into. |
| 510 IntRect destRect(IntPoint(sourceRect.x() - anchor.x(), sourceRect.y(
) - anchor.y()), sourceRect.size()); |
| 511 if (destRect.x() < 0) |
| 512 CRASH(); |
| 513 if (destRect.y() < 0) |
| 514 CRASH(); |
| 515 |
| 516 // Offset from paint rectangle to this tile's dirty rectangle. |
| 517 IntPoint paintOffset(sourceRect.x() - paintRect.x(), sourceRect.y()
- paintRect.y()); |
| 518 if (paintOffset.x() < 0) |
| 519 CRASH(); |
| 520 if (paintOffset.y() < 0) |
| 521 CRASH(); |
| 522 if (paintOffset.x() + destRect.width() > paintRect.width()) |
| 523 CRASH(); |
| 524 if (paintOffset.y() + destRect.height() > paintRect.height()) |
| 525 CRASH(); |
| 526 |
| 527 if (tile->partialUpdate) |
| 528 updater.appendPartialUpdate(tile->texture(), sourceRect, destRec
t); |
| 529 else |
| 530 updater.appendUpdate(tile->texture(), sourceRect, destRect); |
| 531 } |
| 532 } |
| 533 } |
| 534 |
| 535 void TiledLayerChromium::reserveTextures() |
| 536 { |
| 537 updateBounds(); |
| 538 |
| 539 const IntRect& layerRect = visibleLayerRect(); |
| 540 if (layerRect.isEmpty() || m_tiler->hasEmptyBounds()) |
| 541 return; |
| 542 |
| 543 int left, top, right, bottom; |
| 544 m_tiler->layerRectToTileIndices(layerRect, left, top, right, bottom); |
| 545 |
| 546 createTextureUpdaterIfNeeded(); |
| 547 for (int j = top; j <= bottom; ++j) { |
| 548 for (int i = left; i <= right; ++i) { |
| 549 UpdatableTile* tile = tileAt(i, j); |
| 550 if (!tile) |
| 551 tile = createTile(i, j); |
| 552 |
| 553 if (!tile->managedTexture()->isValid(m_tiler->tileSize(), m_textureF
ormat)) |
| 554 tile->dirtyRect = m_tiler->tileRect(tile); |
| 555 |
| 556 if (!tile->managedTexture()->reserve(m_tiler->tileSize(), m_textureF
ormat)) |
| 557 return; |
| 558 } |
| 559 } |
| 560 } |
| 561 |
| 562 Region TiledLayerChromium::visibleContentOpaqueRegion() const |
| 563 { |
| 564 if (m_skipsDraw) |
| 565 return Region(); |
| 566 if (opaque()) |
| 567 return visibleLayerRect(); |
| 568 return m_tiler->opaqueRegionInLayerRect(visibleLayerRect()); |
| 569 } |
| 570 |
| 571 void TiledLayerChromium::resetUpdateState() |
| 572 { |
| 573 CCLayerTilingData::TileMap::const_iterator end = m_tiler->tiles().end(); |
| 574 for (CCLayerTilingData::TileMap::const_iterator iter = m_tiler->tiles().begi
n(); iter != end; ++iter) { |
| 575 UpdatableTile* tile = static_cast<UpdatableTile*>(iter->second.get()); |
| 576 // FIXME: This should not ever be null. |
| 577 if (!tile) |
| 578 continue; |
| 579 tile->updateRect = IntRect(); |
| 580 tile->partialUpdate = false; |
| 581 tile->updated = false; |
| 582 } |
| 583 } |
| 584 |
| 585 void TiledLayerChromium::updateLayerRect(CCTextureUpdater& updater, const IntRec
t& layerRect, const CCOcclusionTracker* occlusion) |
| 586 { |
| 587 m_skipsDraw = false; |
| 588 m_skipsIdlePaint = false; |
| 589 m_didPaint = false; |
| 590 |
| 591 updateBounds(); |
| 592 |
| 593 resetUpdateState(); |
| 594 |
| 595 if (layerRect.isEmpty() || m_tiler->hasEmptyBounds()) |
| 596 return; |
| 597 |
| 598 int left, top, right, bottom; |
| 599 m_tiler->layerRectToTileIndices(layerRect, left, top, right, bottom); |
| 600 |
| 601 updateTiles(false, left, top, right, bottom, updater, occlusion); |
| 602 } |
| 603 |
| 604 void TiledLayerChromium::idleUpdateLayerRect(CCTextureUpdater& updater, const In
tRect& layerRect, const CCOcclusionTracker* occlusion) |
| 605 { |
| 606 // Abort if we have already painted or run out of memory. |
| 607 if (m_skipsIdlePaint || m_didPaint) |
| 608 return; |
| 609 |
| 610 ASSERT(m_tiler); |
| 611 |
| 612 updateBounds(); |
| 613 |
| 614 if (m_tiler->hasEmptyBounds()) |
| 615 return; |
| 616 |
| 617 IntRect idlePaintLayerRect = idlePaintRect(layerRect); |
| 618 if (idlePaintLayerRect.isEmpty()) |
| 619 return; |
| 620 |
| 621 // Protect any textures in the pre-paint area, as we would steal them from o
ther layers |
| 622 // over time anyhow. This ensures we don't lose tiles in the first rounds of
idle painting |
| 623 // that we have already painted. |
| 624 protectTileTextures(idlePaintLayerRect); |
| 625 |
| 626 int prepaintLeft, prepaintTop, prepaintRight, prepaintBottom; |
| 627 m_tiler->layerRectToTileIndices(idlePaintLayerRect, prepaintLeft, prepaintTo
p, prepaintRight, prepaintBottom); |
| 628 |
| 629 // If the layer is not visible, we have nothing to expand from, so instead w
e prepaint the outer-most set of tiles. |
| 630 if (layerRect.isEmpty()) { |
| 631 updateTiles(true, prepaintLeft, prepaintTop, prepaintRight, prepaintTop,
updater, 0); |
| 632 if (m_didPaint || m_skipsIdlePaint) |
| 633 return; |
| 634 updateTiles(true, prepaintLeft, prepaintBottom, prepaintRight, prepaintB
ottom, updater, 0); |
| 635 if (m_didPaint || m_skipsIdlePaint) |
| 636 return; |
| 637 updateTiles(true, prepaintLeft, prepaintTop, prepaintLeft, prepaintBotto
m, updater, 0); |
| 638 if (m_didPaint || m_skipsIdlePaint) |
| 639 return; |
| 640 updateTiles(true, prepaintRight, prepaintTop, prepaintRight, prepaintBot
tom, updater, 0); |
| 641 return; |
| 642 } |
| 643 |
| 644 int left, top, right, bottom; |
| 645 m_tiler->layerRectToTileIndices(layerRect, left, top, right, bottom); |
| 646 |
| 647 // Otherwise, prepaint anything that was occluded but inside the layer's vis
ible region. |
| 648 updateTiles(true, left, top, right, bottom, updater, 0); |
| 649 if (m_didPaint || m_skipsIdlePaint) |
| 650 return; |
| 651 |
| 652 // Then expand outwards from the visible area until we find a dirty row or c
olumn to update. |
| 653 while (!m_skipsIdlePaint && (left > prepaintLeft || top > prepaintTop || rig
ht < prepaintRight || bottom < prepaintBottom)) { |
| 654 if (bottom < prepaintBottom) { |
| 655 ++bottom; |
| 656 updateTiles(true, left, bottom, right, bottom, updater, 0); |
| 657 if (m_didPaint || m_skipsIdlePaint) |
| 658 break; |
| 659 } |
| 660 if (top > prepaintTop) { |
| 661 --top; |
| 662 updateTiles(true, left, top, right, top, updater, 0); |
| 663 if (m_didPaint || m_skipsIdlePaint) |
| 664 break; |
| 665 } |
| 666 if (left > prepaintLeft) { |
| 667 --left; |
| 668 updateTiles(true, left, top, left, bottom, updater, 0); |
| 669 if (m_didPaint || m_skipsIdlePaint) |
| 670 break; |
| 671 } |
| 672 if (right < prepaintRight) { |
| 673 ++right; |
| 674 updateTiles(true, right, top, right, bottom, updater, 0); |
| 675 if (m_didPaint || m_skipsIdlePaint) |
| 676 break; |
| 677 } |
| 678 } |
| 679 } |
| 680 |
| 681 bool TiledLayerChromium::needsIdlePaint(const IntRect& layerRect) |
| 682 { |
| 683 if (m_skipsIdlePaint) |
| 684 return false; |
| 685 |
| 686 if (m_tiler->hasEmptyBounds()) |
| 687 return false; |
| 688 |
| 689 IntRect idlePaintLayerRect = idlePaintRect(layerRect); |
| 690 if (idlePaintLayerRect.isEmpty()) |
| 691 return false; |
| 692 |
| 693 int left, top, right, bottom; |
| 694 m_tiler->layerRectToTileIndices(idlePaintLayerRect, left, top, right, bottom
); |
| 695 for (int j = top; j <= bottom; ++j) { |
| 696 for (int i = left; i <= right; ++i) { |
| 697 // If the layerRect is empty, then we are painting the outer-most se
t of tiles only. |
| 698 if (layerRect.isEmpty() && i != left && i != right && j != top && j
!= bottom) |
| 699 continue; |
| 700 UpdatableTile* tile = tileAt(i, j); |
| 701 if (!tile || !tile->managedTexture()->isValid(m_tiler->tileSize(), m
_textureFormat) || tile->isDirty()) |
| 702 return true; |
| 703 } |
| 704 } |
| 705 return false; |
| 706 } |
| 707 |
| 708 IntRect TiledLayerChromium::idlePaintRect(const IntRect& visibleLayerRect) |
| 709 { |
| 710 // For layers that are animating transforms but not visible at all, we don't
know what part |
| 711 // of them is going to become visible. For small layers we return the entire
layer, for larger |
| 712 // ones we avoid prepainting the layer at all. |
| 713 if (visibleLayerRect.isEmpty()) { |
| 714 bool isSmallLayer = m_tiler->numTilesX() <= 9 && m_tiler->numTilesY() <=
9 && m_tiler->numTilesX() * m_tiler->numTilesY() <= 9; |
| 715 if ((drawTransformIsAnimating() || screenSpaceTransformIsAnimating()) &&
isSmallLayer) |
| 716 return IntRect(IntPoint(), contentBounds()); |
| 717 return IntRect(); |
| 718 } |
| 719 |
| 720 IntRect prepaintRect = visibleLayerRect; |
| 721 // FIXME: This can be made a lot larger if we can: |
| 722 // - reserve memory at a lower priority than for visible content |
| 723 // - only reserve idle paint tiles up to a memory reclaim threshold and |
| 724 // - insure we play nicely with other layers |
| 725 prepaintRect.inflateX(m_tiler->tileSize().width()); |
| 726 prepaintRect.inflateY(m_tiler->tileSize().height()); |
| 727 prepaintRect.intersect(IntRect(IntPoint::zero(), contentBounds())); |
| 728 return prepaintRect; |
| 729 } |
| 730 |
| 731 } |
| 732 #endif // USE(ACCELERATED_COMPOSITING) |
OLD | NEW |