| Index: cc/TiledLayerChromium.cpp
|
| diff --git a/cc/TiledLayerChromium.cpp b/cc/TiledLayerChromium.cpp
|
| deleted file mode 100644
|
| index f2219e624fe7189ded6505c913ae683e0efbe19f..0000000000000000000000000000000000000000
|
| --- a/cc/TiledLayerChromium.cpp
|
| +++ /dev/null
|
| @@ -1,820 +0,0 @@
|
| -// Copyright 2011 The Chromium Authors. All rights reserved.
|
| -// Use of this source code is governed by a BSD-style license that can be
|
| -// found in the LICENSE file.
|
| -
|
| -#include "config.h"
|
| -
|
| -#if USE(ACCELERATED_COMPOSITING)
|
| -
|
| -#include "base/basictypes.h"
|
| -#include "TiledLayerChromium.h"
|
| -
|
| -#include "CCLayerImpl.h"
|
| -#include "CCLayerTreeHost.h"
|
| -#include "CCOverdrawMetrics.h"
|
| -#include "CCTextureUpdateQueue.h"
|
| -#include "CCTiledLayerImpl.h"
|
| -#include "GraphicsContext3D.h"
|
| -#include "Region.h"
|
| -#include <wtf/CurrentTime.h>
|
| -#include <wtf/MathExtras.h>
|
| -
|
| -using namespace std;
|
| -using WebKit::WebTransformationMatrix;
|
| -
|
| -namespace cc {
|
| -
|
| -class UpdatableTile : public CCLayerTilingData::Tile {
|
| -public:
|
| - static PassOwnPtr<UpdatableTile> create(PassOwnPtr<LayerTextureUpdater::Texture> texture)
|
| - {
|
| - return adoptPtr(new UpdatableTile(texture));
|
| - }
|
| -
|
| - LayerTextureUpdater::Texture* texture() { return m_texture.get(); }
|
| - CCPrioritizedTexture* managedTexture() { return m_texture->texture(); }
|
| -
|
| - bool isDirty() const { return !dirtyRect.isEmpty(); }
|
| -
|
| - // Reset update state for the current frame. This should occur before painting
|
| - // for all layers. Since painting one layer can invalidate another layer
|
| - // after it has already painted, mark all non-dirty tiles as valid before painting
|
| - // such that invalidations during painting won't prevent them from being pushed.
|
| - void resetUpdateState()
|
| - {
|
| - updateRect = IntRect();
|
| - occluded = false;
|
| - partialUpdate = false;
|
| - validForFrame = !isDirty();
|
| - }
|
| -
|
| - // This promises to update the tile and therefore also guarantees the tile
|
| - // will be valid for this frame. dirtyRect is copied into updateRect so
|
| - // we can continue to track re-entrant invalidations that occur during painting.
|
| - void markForUpdate()
|
| - {
|
| - validForFrame = true;
|
| - updateRect = dirtyRect;
|
| - dirtyRect = IntRect();
|
| - }
|
| -
|
| - IntRect dirtyRect;
|
| - IntRect updateRect;
|
| - bool partialUpdate;
|
| - bool validForFrame;
|
| - bool occluded;
|
| - bool isInUseOnImpl;
|
| -private:
|
| - explicit UpdatableTile(PassOwnPtr<LayerTextureUpdater::Texture> texture)
|
| - : partialUpdate(false)
|
| - , validForFrame(false)
|
| - , occluded(false)
|
| - , isInUseOnImpl(false)
|
| - , m_texture(texture)
|
| - {
|
| - }
|
| -
|
| - OwnPtr<LayerTextureUpdater::Texture> m_texture;
|
| -
|
| - DISALLOW_COPY_AND_ASSIGN(UpdatableTile);
|
| -};
|
| -
|
| -TiledLayerChromium::TiledLayerChromium()
|
| - : LayerChromium()
|
| - , m_textureFormat(GraphicsContext3D::INVALID_ENUM)
|
| - , m_skipsDraw(false)
|
| - , m_failedUpdate(false)
|
| - , m_sampledTexelFormat(LayerTextureUpdater::SampledTexelFormatInvalid)
|
| - , m_tilingOption(AutoTile)
|
| -{
|
| - m_tiler = CCLayerTilingData::create(IntSize(), CCLayerTilingData::HasBorderTexels);
|
| -}
|
| -
|
| -TiledLayerChromium::~TiledLayerChromium()
|
| -{
|
| -}
|
| -
|
| -scoped_ptr<CCLayerImpl> TiledLayerChromium::createCCLayerImpl()
|
| -{
|
| - return CCTiledLayerImpl::create(id()).PassAs<CCLayerImpl>();
|
| -}
|
| -
|
| -void TiledLayerChromium::updateTileSizeAndTilingOption()
|
| -{
|
| - ASSERT(layerTreeHost());
|
| -
|
| - const IntSize& defaultTileSize = layerTreeHost()->settings().defaultTileSize;
|
| - const IntSize& maxUntiledLayerSize = layerTreeHost()->settings().maxUntiledLayerSize;
|
| - int layerWidth = contentBounds().width();
|
| - int layerHeight = contentBounds().height();
|
| -
|
| - const IntSize tileSize(min(defaultTileSize.width(), layerWidth), min(defaultTileSize.height(), layerHeight));
|
| -
|
| - // Tile if both dimensions large, or any one dimension large and the other
|
| - // extends into a second tile but the total layer area isn't larger than that
|
| - // of the largest possible untiled layer. This heuristic allows for long skinny layers
|
| - // (e.g. scrollbars) that are Nx1 tiles to minimize wasted texture space but still avoids
|
| - // creating very large tiles.
|
| - const bool anyDimensionLarge = layerWidth > maxUntiledLayerSize.width() || layerHeight > maxUntiledLayerSize.height();
|
| - const bool anyDimensionOneTile = (layerWidth <= defaultTileSize.width() || layerHeight <= defaultTileSize.height())
|
| - && (layerWidth * layerHeight) <= (maxUntiledLayerSize.width() * maxUntiledLayerSize.height());
|
| - const bool autoTiled = anyDimensionLarge && !anyDimensionOneTile;
|
| -
|
| - bool isTiled;
|
| - if (m_tilingOption == AlwaysTile)
|
| - isTiled = true;
|
| - else if (m_tilingOption == NeverTile)
|
| - isTiled = false;
|
| - else
|
| - isTiled = autoTiled;
|
| -
|
| - IntSize requestedSize = isTiled ? tileSize : contentBounds();
|
| - const int maxSize = layerTreeHost()->rendererCapabilities().maxTextureSize;
|
| - IntSize clampedSize = requestedSize.shrunkTo(IntSize(maxSize, maxSize));
|
| - setTileSize(clampedSize);
|
| -}
|
| -
|
| -void TiledLayerChromium::updateBounds()
|
| -{
|
| - IntSize oldBounds = m_tiler->bounds();
|
| - IntSize newBounds = contentBounds();
|
| - if (oldBounds == newBounds)
|
| - return;
|
| - m_tiler->setBounds(newBounds);
|
| -
|
| - // Invalidate any areas that the new bounds exposes.
|
| - Region oldRegion(IntRect(IntPoint(), oldBounds));
|
| - Region newRegion(IntRect(IntPoint(), newBounds));
|
| - newRegion.subtract(oldRegion);
|
| - Vector<WebCore::IntRect> rects = newRegion.rects();
|
| - for (size_t i = 0; i < rects.size(); ++i)
|
| - invalidateContentRect(rects[i]);
|
| -}
|
| -
|
| -void TiledLayerChromium::setTileSize(const IntSize& size)
|
| -{
|
| - m_tiler->setTileSize(size);
|
| -}
|
| -
|
| -void TiledLayerChromium::setBorderTexelOption(CCLayerTilingData::BorderTexelOption borderTexelOption)
|
| -{
|
| - m_tiler->setBorderTexelOption(borderTexelOption);
|
| -}
|
| -
|
| -bool TiledLayerChromium::drawsContent() const
|
| -{
|
| - if (!LayerChromium::drawsContent())
|
| - return false;
|
| -
|
| - bool hasMoreThanOneTile = m_tiler->numTilesX() > 1 || m_tiler->numTilesY() > 1;
|
| - if (m_tilingOption == NeverTile && hasMoreThanOneTile)
|
| - return false;
|
| -
|
| - return true;
|
| -}
|
| -
|
| -bool TiledLayerChromium::needsContentsScale() const
|
| -{
|
| - return true;
|
| -}
|
| -
|
| -IntSize TiledLayerChromium::contentBounds() const
|
| -{
|
| - return IntSize(lroundf(bounds().width() * contentsScale()), lroundf(bounds().height() * contentsScale()));
|
| -}
|
| -
|
| -void TiledLayerChromium::setTilingOption(TilingOption tilingOption)
|
| -{
|
| - m_tilingOption = tilingOption;
|
| -}
|
| -
|
| -void TiledLayerChromium::setIsMask(bool isMask)
|
| -{
|
| - setTilingOption(isMask ? NeverTile : AutoTile);
|
| -}
|
| -
|
| -void TiledLayerChromium::pushPropertiesTo(CCLayerImpl* layer)
|
| -{
|
| - LayerChromium::pushPropertiesTo(layer);
|
| -
|
| - CCTiledLayerImpl* tiledLayer = static_cast<CCTiledLayerImpl*>(layer);
|
| -
|
| - tiledLayer->setSkipsDraw(m_skipsDraw);
|
| - tiledLayer->setContentsSwizzled(m_sampledTexelFormat != LayerTextureUpdater::SampledTexelFormatRGBA);
|
| - tiledLayer->setTilingData(*m_tiler);
|
| - Vector<UpdatableTile*> invalidTiles;
|
| -
|
| - for (CCLayerTilingData::TileMap::const_iterator iter = m_tiler->tiles().begin(); iter != m_tiler->tiles().end(); ++iter) {
|
| -#if WTF_NEW_HASHMAP_ITERATORS_INTERFACE
|
| - int i = iter->key.first;
|
| - int j = iter->key.second;
|
| - UpdatableTile* tile = static_cast<UpdatableTile*>(iter->value.get());
|
| -#else
|
| - int i = iter->first.first;
|
| - int j = iter->first.second;
|
| - UpdatableTile* tile = static_cast<UpdatableTile*>(iter->second.get());
|
| -#endif
|
| - // FIXME: This should not ever be null.
|
| - if (!tile)
|
| - continue;
|
| -
|
| - tile->isInUseOnImpl = false;
|
| -
|
| - if (!tile->managedTexture()->haveBackingTexture()) {
|
| - // Evicted tiles get deleted from both layers
|
| - invalidTiles.append(tile);
|
| - continue;
|
| - }
|
| -
|
| - if (!tile->validForFrame) {
|
| - // Invalidated tiles are set so they can get different debug colors.
|
| - tiledLayer->pushInvalidTile(i, j);
|
| - continue;
|
| - }
|
| -
|
| - tiledLayer->pushTileProperties(i, j, tile->managedTexture()->resourceId(), tile->opaqueRect());
|
| - tile->isInUseOnImpl = true;
|
| - }
|
| - for (Vector<UpdatableTile*>::const_iterator iter = invalidTiles.begin(); iter != invalidTiles.end(); ++iter)
|
| - m_tiler->takeTile((*iter)->i(), (*iter)->j());
|
| -}
|
| -
|
| -CCPrioritizedTextureManager* TiledLayerChromium::textureManager() const
|
| -{
|
| - if (!layerTreeHost())
|
| - return 0;
|
| - return layerTreeHost()->contentsTextureManager();
|
| -}
|
| -
|
| -void TiledLayerChromium::setLayerTreeHost(CCLayerTreeHost* host)
|
| -{
|
| - if (host && host != layerTreeHost()) {
|
| - for (CCLayerTilingData::TileMap::const_iterator iter = m_tiler->tiles().begin(); iter != m_tiler->tiles().end(); ++iter) {
|
| -#if WTF_NEW_HASHMAP_ITERATORS_INTERFACE
|
| - UpdatableTile* tile = static_cast<UpdatableTile*>(iter->value.get());
|
| -#else
|
| - UpdatableTile* tile = static_cast<UpdatableTile*>(iter->second.get());
|
| -#endif
|
| - // FIXME: This should not ever be null.
|
| - if (!tile)
|
| - continue;
|
| - tile->managedTexture()->setTextureManager(host->contentsTextureManager());
|
| - }
|
| - }
|
| - LayerChromium::setLayerTreeHost(host);
|
| -}
|
| -
|
| -UpdatableTile* TiledLayerChromium::tileAt(int i, int j) const
|
| -{
|
| - return static_cast<UpdatableTile*>(m_tiler->tileAt(i, j));
|
| -}
|
| -
|
| -UpdatableTile* TiledLayerChromium::createTile(int i, int j)
|
| -{
|
| - createTextureUpdaterIfNeeded();
|
| -
|
| - OwnPtr<UpdatableTile> tile(UpdatableTile::create(textureUpdater()->createTexture(textureManager())));
|
| - tile->managedTexture()->setDimensions(m_tiler->tileSize(), m_textureFormat);
|
| -
|
| - UpdatableTile* addedTile = tile.get();
|
| - m_tiler->addTile(tile.release(), i, j);
|
| -
|
| - addedTile->dirtyRect = m_tiler->tileRect(addedTile);
|
| -
|
| - // Temporary diagnostic crash.
|
| - if (!addedTile)
|
| - CRASH();
|
| - if (!tileAt(i, j))
|
| - CRASH();
|
| -
|
| - return addedTile;
|
| -}
|
| -
|
| -void TiledLayerChromium::setNeedsDisplayRect(const FloatRect& dirtyRect)
|
| -{
|
| - float contentsWidthScale = static_cast<float>(contentBounds().width()) / bounds().width();
|
| - float contentsHeightScale = static_cast<float>(contentBounds().height()) / bounds().height();
|
| - FloatRect scaledDirtyRect(dirtyRect);
|
| - scaledDirtyRect.scale(contentsWidthScale, contentsHeightScale);
|
| - IntRect dirty = enclosingIntRect(scaledDirtyRect);
|
| - invalidateContentRect(dirty);
|
| - LayerChromium::setNeedsDisplayRect(dirtyRect);
|
| -}
|
| -
|
| -void TiledLayerChromium::setUseLCDText(bool useLCDText)
|
| -{
|
| - LayerChromium::setUseLCDText(useLCDText);
|
| -
|
| - CCLayerTilingData::BorderTexelOption borderTexelOption;
|
| -#if OS(ANDROID)
|
| - // Always want border texels and GL_LINEAR due to pinch zoom.
|
| - borderTexelOption = CCLayerTilingData::HasBorderTexels;
|
| -#else
|
| - borderTexelOption = useLCDText ? CCLayerTilingData::NoBorderTexels : CCLayerTilingData::HasBorderTexels;
|
| -#endif
|
| - setBorderTexelOption(borderTexelOption);
|
| -}
|
| -
|
| -void TiledLayerChromium::invalidateContentRect(const IntRect& contentRect)
|
| -{
|
| - updateBounds();
|
| - if (m_tiler->isEmpty() || contentRect.isEmpty() || m_skipsDraw)
|
| - return;
|
| -
|
| - for (CCLayerTilingData::TileMap::const_iterator iter = m_tiler->tiles().begin(); iter != m_tiler->tiles().end(); ++iter) {
|
| -#if WTF_NEW_HASHMAP_ITERATORS_INTERFACE
|
| - UpdatableTile* tile = static_cast<UpdatableTile*>(iter->value.get());
|
| -#else
|
| - UpdatableTile* tile = static_cast<UpdatableTile*>(iter->second.get());
|
| -#endif
|
| - ASSERT(tile);
|
| - // FIXME: This should not ever be null.
|
| - if (!tile)
|
| - continue;
|
| - IntRect bound = m_tiler->tileRect(tile);
|
| - bound.intersect(contentRect);
|
| - tile->dirtyRect.unite(bound);
|
| - }
|
| -}
|
| -
|
| -// Returns true if tile is dirty and only part of it needs to be updated.
|
| -bool TiledLayerChromium::tileOnlyNeedsPartialUpdate(UpdatableTile* tile)
|
| -{
|
| - return !tile->dirtyRect.contains(m_tiler->tileRect(tile));
|
| -}
|
| -
|
| -// Dirty tiles with valid textures needs buffered update to guarantee that
|
| -// we don't modify textures currently used for drawing by the impl thread.
|
| -bool TiledLayerChromium::tileNeedsBufferedUpdate(UpdatableTile* tile)
|
| -{
|
| - if (!tile->managedTexture()->haveBackingTexture())
|
| - return false;
|
| -
|
| - if (!tile->isDirty())
|
| - return false;
|
| -
|
| - if (!tile->isInUseOnImpl)
|
| - return false;
|
| -
|
| - return true;
|
| -}
|
| -
|
| -
|
| -bool TiledLayerChromium::updateTiles(int left, int top, int right, int bottom, CCTextureUpdateQueue& queue, const CCOcclusionTracker* occlusion, CCRenderingStats& stats, bool& didPaint)
|
| -{
|
| - didPaint = false;
|
| - createTextureUpdaterIfNeeded();
|
| -
|
| - bool ignoreOcclusions = !occlusion;
|
| - if (!haveTexturesForTiles(left, top, right, bottom, ignoreOcclusions)) {
|
| - m_failedUpdate = true;
|
| - return false;
|
| - }
|
| -
|
| - IntRect paintRect = markTilesForUpdate(left, top, right, bottom, ignoreOcclusions);
|
| -
|
| - if (occlusion)
|
| - occlusion->overdrawMetrics().didPaint(paintRect);
|
| -
|
| - if (paintRect.isEmpty())
|
| - return true;
|
| -
|
| - didPaint = true;
|
| - updateTileTextures(paintRect, left, top, right, bottom, queue, occlusion, stats);
|
| - return true;
|
| -}
|
| -
|
| -void TiledLayerChromium::markOcclusionsAndRequestTextures(int left, int top, int right, int bottom, const CCOcclusionTracker* occlusion)
|
| -{
|
| - // There is some difficult dependancies between occlusions, recording occlusion metrics
|
| - // and requesting memory so those are encapsulated in this function:
|
| - // - We only want to call requestLate on unoccluded textures (to preserve
|
| - // memory for other layers when near OOM).
|
| - // - We only want to record occlusion metrics if all memory requests succeed.
|
| -
|
| - int occludedTileCount = 0;
|
| - bool succeeded = true;
|
| - for (int j = top; j <= bottom; ++j) {
|
| - for (int i = left; i <= right; ++i) {
|
| - UpdatableTile* tile = tileAt(i, j);
|
| - ASSERT(tile); // Did setTexturePriorities get skipped?
|
| - // FIXME: This should not ever be null.
|
| - if (!tile)
|
| - continue;
|
| - ASSERT(!tile->occluded); // Did resetUpdateState get skipped? Are we doing more than one occlusion pass?
|
| - IntRect visibleTileRect = intersection(m_tiler->tileBounds(i, j), visibleContentRect());
|
| - if (occlusion && occlusion->occluded(this, visibleTileRect)) {
|
| - tile->occluded = true;
|
| - occludedTileCount++;
|
| - } else {
|
| - succeeded &= tile->managedTexture()->requestLate();
|
| - }
|
| - }
|
| - }
|
| -
|
| - if (!succeeded)
|
| - return;
|
| -
|
| - // FIXME: Remove the loop and just pass the count!
|
| - for (int i = 0; i < occludedTileCount; i++)
|
| - occlusion->overdrawMetrics().didCullTileForUpload();
|
| -}
|
| -
|
| -bool TiledLayerChromium::haveTexturesForTiles(int left, int top, int right, int bottom, bool ignoreOcclusions)
|
| -{
|
| - for (int j = top; j <= bottom; ++j) {
|
| - for (int i = left; i <= right; ++i) {
|
| - UpdatableTile* tile = tileAt(i, j);
|
| - ASSERT(tile); // Did setTexturePriorites get skipped?
|
| - // FIXME: This should not ever be null.
|
| - if (!tile)
|
| - continue;
|
| -
|
| - // Ensure the entire tile is dirty if we don't have the texture.
|
| - if (!tile->managedTexture()->haveBackingTexture())
|
| - tile->dirtyRect = m_tiler->tileRect(tile);
|
| -
|
| - // If using occlusion and the visible region of the tile is occluded,
|
| - // don't reserve a texture or update the tile.
|
| - if (tile->occluded && !ignoreOcclusions)
|
| - continue;
|
| -
|
| - if (!tile->managedTexture()->canAcquireBackingTexture())
|
| - return false;
|
| - }
|
| - }
|
| - return true;
|
| -}
|
| -
|
| -IntRect TiledLayerChromium::markTilesForUpdate(int left, int top, int right, int bottom, bool ignoreOcclusions)
|
| -{
|
| - IntRect paintRect;
|
| - for (int j = top; j <= bottom; ++j) {
|
| - for (int i = left; i <= right; ++i) {
|
| - UpdatableTile* tile = tileAt(i, j);
|
| - ASSERT(tile); // Did setTexturePriorites get skipped?
|
| - // FIXME: This should not ever be null.
|
| - if (!tile)
|
| - continue;
|
| - if (tile->occluded && !ignoreOcclusions)
|
| - continue;
|
| - paintRect.unite(tile->dirtyRect);
|
| - tile->markForUpdate();
|
| - }
|
| - }
|
| - return paintRect;
|
| -}
|
| -
|
| -void TiledLayerChromium::updateTileTextures(const IntRect& paintRect, int left, int top, int right, int bottom, CCTextureUpdateQueue& queue, const CCOcclusionTracker* occlusion, CCRenderingStats& stats)
|
| -{
|
| - // The updateRect should be in layer space. So we have to convert the paintRect from content space to layer space.
|
| - m_updateRect = FloatRect(paintRect);
|
| - float widthScale = bounds().width() / static_cast<float>(contentBounds().width());
|
| - float heightScale = bounds().height() / static_cast<float>(contentBounds().height());
|
| - m_updateRect.scale(widthScale, heightScale);
|
| -
|
| - // Calling prepareToUpdate() calls into WebKit to paint, which may have the side
|
| - // effect of disabling compositing, which causes our reference to the texture updater to be deleted.
|
| - // However, we can't free the memory backing the SkCanvas until the paint finishes,
|
| - // so we grab a local reference here to hold the updater alive until the paint completes.
|
| - RefPtr<LayerTextureUpdater> protector(textureUpdater());
|
| - IntRect paintedOpaqueRect;
|
| - textureUpdater()->prepareToUpdate(paintRect, m_tiler->tileSize(), 1 / widthScale, 1 / heightScale, paintedOpaqueRect, stats);
|
| -
|
| - for (int j = top; j <= bottom; ++j) {
|
| - for (int i = left; i <= right; ++i) {
|
| - UpdatableTile* tile = tileAt(i, j);
|
| - ASSERT(tile); // Did setTexturePriorites get skipped?
|
| - // FIXME: This should not ever be null.
|
| - if (!tile)
|
| - continue;
|
| -
|
| - IntRect tileRect = m_tiler->tileBounds(i, j);
|
| -
|
| - // Use updateRect as the above loop copied the dirty rect for this frame to updateRect.
|
| - const IntRect& dirtyRect = tile->updateRect;
|
| - if (dirtyRect.isEmpty())
|
| - continue;
|
| -
|
| - // Save what was painted opaque in the tile. Keep the old area if the paint didn't touch it, and didn't paint some
|
| - // other part of the tile opaque.
|
| - IntRect tilePaintedRect = intersection(tileRect, paintRect);
|
| - IntRect tilePaintedOpaqueRect = intersection(tileRect, paintedOpaqueRect);
|
| - if (!tilePaintedRect.isEmpty()) {
|
| - IntRect paintInsideTileOpaqueRect = intersection(tile->opaqueRect(), tilePaintedRect);
|
| - bool paintInsideTileOpaqueRectIsNonOpaque = !tilePaintedOpaqueRect.contains(paintInsideTileOpaqueRect);
|
| - bool opaquePaintNotInsideTileOpaqueRect = !tilePaintedOpaqueRect.isEmpty() && !tile->opaqueRect().contains(tilePaintedOpaqueRect);
|
| -
|
| - if (paintInsideTileOpaqueRectIsNonOpaque || opaquePaintNotInsideTileOpaqueRect)
|
| - tile->setOpaqueRect(tilePaintedOpaqueRect);
|
| - }
|
| -
|
| - // sourceRect starts as a full-sized tile with border texels included.
|
| - IntRect sourceRect = m_tiler->tileRect(tile);
|
| - sourceRect.intersect(dirtyRect);
|
| - // Paint rect not guaranteed to line up on tile boundaries, so
|
| - // make sure that sourceRect doesn't extend outside of it.
|
| - sourceRect.intersect(paintRect);
|
| -
|
| - tile->updateRect = sourceRect;
|
| -
|
| - if (sourceRect.isEmpty())
|
| - continue;
|
| -
|
| - tile->texture()->prepareRect(sourceRect, stats);
|
| - if (occlusion)
|
| - occlusion->overdrawMetrics().didUpload(WebTransformationMatrix(), sourceRect, tile->opaqueRect());
|
| -
|
| - const IntPoint anchor = m_tiler->tileRect(tile).location();
|
| -
|
| - // Calculate tile-space rectangle to upload into.
|
| - IntSize destOffset(sourceRect.x() - anchor.x(), sourceRect.y() - anchor.y());
|
| - if (destOffset.width() < 0)
|
| - CRASH();
|
| - if (destOffset.height() < 0)
|
| - CRASH();
|
| -
|
| - // Offset from paint rectangle to this tile's dirty rectangle.
|
| - IntPoint paintOffset(sourceRect.x() - paintRect.x(), sourceRect.y() - paintRect.y());
|
| - if (paintOffset.x() < 0)
|
| - CRASH();
|
| - if (paintOffset.y() < 0)
|
| - CRASH();
|
| - if (paintOffset.x() + sourceRect.width() > paintRect.width())
|
| - CRASH();
|
| - if (paintOffset.y() + sourceRect.height() > paintRect.height())
|
| - CRASH();
|
| -
|
| - TextureUploader::Parameters upload = { tile->texture(), sourceRect, destOffset };
|
| - if (tile->partialUpdate)
|
| - queue.appendPartialUpload(upload);
|
| - else
|
| - queue.appendFullUpload(upload);
|
| - }
|
| - }
|
| -}
|
| -
|
| -namespace {
|
| -// This picks a small animated layer to be anything less than one viewport. This
|
| -// is specifically for page transitions which are viewport-sized layers. The extra
|
| -// 64 pixels is due to these layers being slightly larger than the viewport in some cases.
|
| -bool isSmallAnimatedLayer(TiledLayerChromium* layer)
|
| -{
|
| - if (!layer->drawTransformIsAnimating() && !layer->screenSpaceTransformIsAnimating())
|
| - return false;
|
| - IntSize viewportSize = layer->layerTreeHost() ? layer->layerTreeHost()->deviceViewportSize() : IntSize();
|
| - IntRect contentRect(IntPoint::zero(), layer->contentBounds());
|
| - return contentRect.width() <= viewportSize.width() + 64
|
| - && contentRect.height() <= viewportSize.height() + 64;
|
| -}
|
| -
|
| -// FIXME: Remove this and make this based on distance once distance can be calculated
|
| -// for offscreen layers. For now, prioritize all small animated layers after 512
|
| -// pixels of pre-painting.
|
| -void setPriorityForTexture(const IntRect& visibleRect,
|
| - const IntRect& tileRect,
|
| - bool drawsToRoot,
|
| - bool isSmallAnimatedLayer,
|
| - CCPrioritizedTexture* texture)
|
| -{
|
| - int priority = CCPriorityCalculator::lowestPriority();
|
| - if (!visibleRect.isEmpty())
|
| - priority = CCPriorityCalculator::priorityFromDistance(visibleRect, tileRect, drawsToRoot);
|
| - if (isSmallAnimatedLayer)
|
| - priority = CCPriorityCalculator::maxPriority(priority, CCPriorityCalculator::smallAnimatedLayerMinPriority());
|
| - if (priority != CCPriorityCalculator::lowestPriority())
|
| - texture->setRequestPriority(priority);
|
| -}
|
| -}
|
| -
|
| -void TiledLayerChromium::setTexturePriorities(const CCPriorityCalculator& priorityCalc)
|
| -{
|
| - updateBounds();
|
| - resetUpdateState();
|
| -
|
| - if (m_tiler->hasEmptyBounds())
|
| - return;
|
| -
|
| - bool drawsToRoot = !renderTarget()->parent();
|
| - bool smallAnimatedLayer = isSmallAnimatedLayer(this);
|
| -
|
| - // Minimally create the tiles in the desired pre-paint rect.
|
| - IntRect createTilesRect = idlePaintRect();
|
| - if (!createTilesRect.isEmpty()) {
|
| - int left, top, right, bottom;
|
| - m_tiler->contentRectToTileIndices(createTilesRect, left, top, right, bottom);
|
| - for (int j = top; j <= bottom; ++j) {
|
| - for (int i = left; i <= right; ++i) {
|
| - if (!tileAt(i, j))
|
| - createTile(i, j);
|
| - }
|
| - }
|
| - }
|
| -
|
| - // Also, minimally create all tiles for small animated layers and also
|
| - // double-buffer them since we have limited their size to be reasonable.
|
| - IntRect doubleBufferedRect = visibleContentRect();
|
| - if (smallAnimatedLayer)
|
| - doubleBufferedRect = IntRect(IntPoint::zero(), contentBounds());
|
| -
|
| - // Create additional textures for double-buffered updates when needed.
|
| - // These textures must stay alive while the updated textures are incrementally
|
| - // uploaded, swapped atomically via pushProperties, and finally deleted
|
| - // after the commit is complete, after which they can be recycled.
|
| - if (!doubleBufferedRect.isEmpty()) {
|
| - int left, top, right, bottom;
|
| - m_tiler->contentRectToTileIndices(doubleBufferedRect, left, top, right, bottom);
|
| - for (int j = top; j <= bottom; ++j) {
|
| - for (int i = left; i <= right; ++i) {
|
| - UpdatableTile* tile = tileAt(i, j);
|
| - if (!tile)
|
| - tile = createTile(i, j);
|
| - // We need an additional texture if the tile needs a buffered-update and it's not a partial update.
|
| - // FIXME: Decide if partial update should be allowed based on cost
|
| - // of update. https://bugs.webkit.org/show_bug.cgi?id=77376
|
| - if (!layerTreeHost() || !layerTreeHost()->bufferedUpdates() || !tileNeedsBufferedUpdate(tile))
|
| - continue;
|
| - if (tileOnlyNeedsPartialUpdate(tile) && layerTreeHost()->requestPartialTextureUpdate()) {
|
| - tile->partialUpdate = true;
|
| - continue;
|
| - }
|
| -
|
| - IntRect tileRect = m_tiler->tileRect(tile);
|
| - tile->dirtyRect = tileRect;
|
| - LayerTextureUpdater::Texture* backBuffer = tile->texture();
|
| - setPriorityForTexture(visibleContentRect(), tile->dirtyRect, drawsToRoot, smallAnimatedLayer, backBuffer->texture());
|
| - scoped_ptr<CCPrioritizedTexture> frontBuffer = CCPrioritizedTexture::create(backBuffer->texture()->textureManager(),
|
| - backBuffer->texture()->size(),
|
| - backBuffer->texture()->format());
|
| - // Swap backBuffer into frontBuffer and add it to delete after commit queue.
|
| - backBuffer->swapTextureWith(frontBuffer);
|
| - layerTreeHost()->deleteTextureAfterCommit(frontBuffer.Pass());
|
| - }
|
| - }
|
| - }
|
| -
|
| - // Now update priorities on all tiles we have in the layer, no matter where they are.
|
| - for (CCLayerTilingData::TileMap::const_iterator iter = m_tiler->tiles().begin(); iter != m_tiler->tiles().end(); ++iter) {
|
| -#if WTF_NEW_HASHMAP_ITERATORS_INTERFACE
|
| - UpdatableTile* tile = static_cast<UpdatableTile*>(iter->value.get());
|
| -#else
|
| - UpdatableTile* tile = static_cast<UpdatableTile*>(iter->second.get());
|
| -#endif
|
| - // FIXME: This should not ever be null.
|
| - if (!tile)
|
| - continue;
|
| - IntRect tileRect = m_tiler->tileRect(tile);
|
| - setPriorityForTexture(visibleContentRect(), tileRect, drawsToRoot, smallAnimatedLayer, tile->managedTexture());
|
| - }
|
| -}
|
| -
|
| -Region TiledLayerChromium::visibleContentOpaqueRegion() const
|
| -{
|
| - if (m_skipsDraw)
|
| - return Region();
|
| - if (contentsOpaque())
|
| - return visibleContentRect();
|
| - return m_tiler->opaqueRegionInContentRect(visibleContentRect());
|
| -}
|
| -
|
| -void TiledLayerChromium::resetUpdateState()
|
| -{
|
| - m_skipsDraw = false;
|
| - m_failedUpdate = false;
|
| -
|
| - CCLayerTilingData::TileMap::const_iterator end = m_tiler->tiles().end();
|
| - for (CCLayerTilingData::TileMap::const_iterator iter = m_tiler->tiles().begin(); iter != end; ++iter) {
|
| -#if WTF_NEW_HASHMAP_ITERATORS_INTERFACE
|
| - UpdatableTile* tile = static_cast<UpdatableTile*>(iter->value.get());
|
| -#else
|
| - UpdatableTile* tile = static_cast<UpdatableTile*>(iter->second.get());
|
| -#endif
|
| - // FIXME: This should not ever be null.
|
| - if (!tile)
|
| - continue;
|
| - tile->resetUpdateState();
|
| - }
|
| -}
|
| -
|
| -void TiledLayerChromium::update(CCTextureUpdateQueue& queue, const CCOcclusionTracker* occlusion, CCRenderingStats& stats)
|
| -{
|
| - ASSERT(!m_skipsDraw && !m_failedUpdate); // Did resetUpdateState get skipped?
|
| - updateBounds();
|
| - if (m_tiler->hasEmptyBounds() || !drawsContent())
|
| - return;
|
| -
|
| - bool didPaint = false;
|
| -
|
| - // Animation pre-paint. If the layer is small, try to paint it all
|
| - // immediately whether or not it is occluded, to avoid paint/upload
|
| - // hiccups while it is animating.
|
| - if (isSmallAnimatedLayer(this)) {
|
| - int left, top, right, bottom;
|
| - m_tiler->contentRectToTileIndices(IntRect(IntPoint::zero(), contentBounds()), left, top, right, bottom);
|
| - updateTiles(left, top, right, bottom, queue, 0, stats, didPaint);
|
| - if (didPaint)
|
| - return;
|
| - // This was an attempt to paint the entire layer so if we fail it's okay,
|
| - // just fallback on painting visible etc. below.
|
| - m_failedUpdate = false;
|
| - }
|
| -
|
| - if (visibleContentRect().isEmpty())
|
| - return;
|
| -
|
| - // Visible painting. First occlude visible tiles and paint the non-occluded tiles.
|
| - int left, top, right, bottom;
|
| - m_tiler->contentRectToTileIndices(visibleContentRect(), left, top, right, bottom);
|
| - markOcclusionsAndRequestTextures(left, top, right, bottom, occlusion);
|
| - m_skipsDraw = !updateTiles(left, top, right, bottom, queue, occlusion, stats, didPaint);
|
| - if (m_skipsDraw)
|
| - m_tiler->reset();
|
| - if (m_skipsDraw || didPaint)
|
| - return;
|
| -
|
| - // If we have already painting everything visible. Do some pre-painting while idle.
|
| - IntRect idlePaintContentRect = idlePaintRect();
|
| - if (idlePaintContentRect.isEmpty())
|
| - return;
|
| -
|
| - // Prepaint anything that was occluded but inside the layer's visible region.
|
| - if (!updateTiles(left, top, right, bottom, queue, 0, stats, didPaint) || didPaint)
|
| - return;
|
| -
|
| - int prepaintLeft, prepaintTop, prepaintRight, prepaintBottom;
|
| - m_tiler->contentRectToTileIndices(idlePaintContentRect, prepaintLeft, prepaintTop, prepaintRight, prepaintBottom);
|
| -
|
| - // Then expand outwards from the visible area until we find a dirty row or column to update.
|
| - while (left > prepaintLeft || top > prepaintTop || right < prepaintRight || bottom < prepaintBottom) {
|
| - if (bottom < prepaintBottom) {
|
| - ++bottom;
|
| - if (!updateTiles(left, bottom, right, bottom, queue, 0, stats, didPaint) || didPaint)
|
| - return;
|
| - }
|
| - if (top > prepaintTop) {
|
| - --top;
|
| - if (!updateTiles(left, top, right, top, queue, 0, stats, didPaint) || didPaint)
|
| - return;
|
| - }
|
| - if (left > prepaintLeft) {
|
| - --left;
|
| - if (!updateTiles(left, top, left, bottom, queue, 0, stats, didPaint) || didPaint)
|
| - return;
|
| - }
|
| - if (right < prepaintRight) {
|
| - ++right;
|
| - if (!updateTiles(right, top, right, bottom, queue, 0, stats, didPaint) || didPaint)
|
| - return;
|
| - }
|
| - }
|
| -}
|
| -
|
| -bool TiledLayerChromium::needsIdlePaint()
|
| -{
|
| - // Don't trigger more paints if we failed (as we'll just fail again).
|
| - if (m_failedUpdate || visibleContentRect().isEmpty() || m_tiler->hasEmptyBounds() || !drawsContent())
|
| - return false;
|
| -
|
| - IntRect idlePaintContentRect = idlePaintRect();
|
| - if (idlePaintContentRect.isEmpty())
|
| - return false;
|
| -
|
| - int left, top, right, bottom;
|
| - m_tiler->contentRectToTileIndices(idlePaintContentRect, left, top, right, bottom);
|
| -
|
| - for (int j = top; j <= bottom; ++j) {
|
| - for (int i = left; i <= right; ++i) {
|
| - UpdatableTile* tile = tileAt(i, j);
|
| - ASSERT(tile); // Did setTexturePriorities get skipped?
|
| - if (!tile)
|
| - continue;
|
| -
|
| - bool updated = !tile->updateRect.isEmpty();
|
| - bool canAcquire = tile->managedTexture()->canAcquireBackingTexture();
|
| - bool dirty = tile->isDirty() || !tile->managedTexture()->haveBackingTexture();
|
| - if (!updated && canAcquire && dirty)
|
| - return true;
|
| - }
|
| - }
|
| - return false;
|
| -}
|
| -
|
| -IntRect TiledLayerChromium::idlePaintRect()
|
| -{
|
| - // Don't inflate an empty rect.
|
| - if (visibleContentRect().isEmpty())
|
| - return IntRect();
|
| -
|
| - // FIXME: This can be made a lot larger now! We should increase
|
| - // this slowly while insuring it doesn't cause any perf issues.
|
| - IntRect prepaintRect = visibleContentRect();
|
| - prepaintRect.inflateX(m_tiler->tileSize().width());
|
| - prepaintRect.inflateY(m_tiler->tileSize().height() * 2);
|
| - IntRect contentRect(IntPoint::zero(), contentBounds());
|
| - prepaintRect.intersect(contentRect);
|
| -
|
| - return prepaintRect;
|
| -}
|
| -
|
| -}
|
| -#endif // USE(ACCELERATED_COMPOSITING)
|
|
|