summaryrefslogtreecommitdiff
path: root/Source/WebCore/platform/graphics/chromium/TiledLayerChromium.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebCore/platform/graphics/chromium/TiledLayerChromium.cpp')
-rw-r--r--Source/WebCore/platform/graphics/chromium/TiledLayerChromium.cpp251
1 files changed, 142 insertions, 109 deletions
diff --git a/Source/WebCore/platform/graphics/chromium/TiledLayerChromium.cpp b/Source/WebCore/platform/graphics/chromium/TiledLayerChromium.cpp
index 68740ef50..ccbd58d32 100644
--- a/Source/WebCore/platform/graphics/chromium/TiledLayerChromium.cpp
+++ b/Source/WebCore/platform/graphics/chromium/TiledLayerChromium.cpp
@@ -36,7 +36,7 @@
#include "cc/CCLayerImpl.h"
#include "cc/CCLayerTreeHost.h"
#include "cc/CCOverdrawMetrics.h"
-#include "cc/CCTextureUpdater.h"
+#include "cc/CCTextureUpdateQueue.h"
#include "cc/CCTiledLayerImpl.h"
#include <wtf/CurrentTime.h>
@@ -59,24 +59,40 @@ public:
CCPrioritizedTexture* managedTexture() { return m_texture->texture(); }
bool isDirty() const { return !dirtyRect.isEmpty(); }
- void copyAndClearDirty()
+
+ // 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();
}
- // Returns whether the layer was dirty and not updated in the current frame. For tiles that were not culled, the
- // updateRect holds the area of the tile that was updated. Otherwise, the area that would have been updated.
- bool isDirtyForCurrentFrame() { return !dirtyRect.isEmpty() && (updateRect.isEmpty() || !updated); }
IntRect dirtyRect;
IntRect updateRect;
bool partialUpdate;
- bool updated;
+ bool validForFrame;
+ bool occluded;
bool isInUseOnImpl;
private:
explicit UpdatableTile(PassOwnPtr<LayerTextureUpdater::Texture> texture)
: partialUpdate(false)
- , updated(false)
+ , validForFrame(false)
+ , occluded(false)
, isInUseOnImpl(false)
, m_texture(texture)
{
@@ -89,9 +105,8 @@ TiledLayerChromium::TiledLayerChromium()
: LayerChromium()
, m_textureFormat(GraphicsContext3D::INVALID_ENUM)
, m_skipsDraw(false)
- , m_skipsIdlePaint(false)
+ , m_failedUpdate(false)
, m_sampledTexelFormat(LayerTextureUpdater::SampledTexelFormatInvalid)
- , m_didPaint(false)
, m_tilingOption(AutoTile)
{
m_tiler = CCLayerTilingData::create(IntSize(), CCLayerTilingData::HasBorderTexels);
@@ -223,7 +238,7 @@ void TiledLayerChromium::pushPropertiesTo(CCLayerImpl* layer)
invalidTiles.append(tile);
continue;
}
- if (tile->isDirtyForCurrentFrame())
+ if (!tile->validForFrame)
continue;
tiledLayer->pushTileProperties(i, j, tile->managedTexture()->resourceId(), tile->opaqueRect());
@@ -291,16 +306,16 @@ void TiledLayerChromium::setNeedsDisplayRect(const FloatRect& dirtyRect)
LayerChromium::setNeedsDisplayRect(dirtyRect);
}
-void TiledLayerChromium::setIsNonCompositedContent(bool isNonCompositedContent)
+void TiledLayerChromium::setUseLCDText(bool useLCDText)
{
- LayerChromium::setIsNonCompositedContent(isNonCompositedContent);
+ 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 = isNonCompositedContent ? CCLayerTilingData::NoBorderTexels : CCLayerTilingData::HasBorderTexels;
+ borderTexelOption = useLCDText ? CCLayerTilingData::NoBorderTexels : CCLayerTilingData::HasBorderTexels;
#endif
setBorderTexelOption(borderTexelOption);
}
@@ -345,86 +360,114 @@ bool TiledLayerChromium::tileNeedsBufferedUpdate(UpdatableTile* tile)
return true;
}
-void TiledLayerChromium::updateTiles(bool idle, int left, int top, int right, int bottom, CCTextureUpdater& updater, const CCOcclusionTracker* occlusion, CCRenderingStats& stats)
+
+bool TiledLayerChromium::updateTiles(int left, int top, int right, int bottom, CCTextureUpdateQueue& queue, const CCOcclusionTracker* occlusion, CCRenderingStats& stats, bool& didPaint)
{
+ didPaint = false;
createTextureUpdaterIfNeeded();
- // We shouldn't track any occlusion metrics during idle painting.
- ASSERT(!idle || !occlusion);
+ bool ignoreOcclusions = !occlusion;
+ if (!haveTexturesForTiles(left, top, right, bottom, ignoreOcclusions)) {
+ m_failedUpdate = true;
+ return false;
+ }
- // Create tiles as needed, expanding a dirty rect to contain all
- // the dirty regions currently being drawn. All dirty tiles that are to be painted
- // get their updateRect set to dirtyRect and dirtyRect cleared. This way if
- // invalidateContentRect is invoked during updateContentRect we don't lose the request.
- IntRect paintRect;
+ 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 setTexturePriorites get skipped?
+ ASSERT(tile); // Did setTexturePriorities get skipped?
+ // FIXME: This should not ever be null.
if (!tile)
- tile = createTile(i, j);
-
- // Temporary diagnostic crash
- if (!m_tiler)
- CRASH();
-
- if (!tile->managedTexture()->haveBackingTexture()) {
- // Sets the dirty rect to a full-sized tile with border texels.
- tile->dirtyRect = m_tiler->tileRect(tile);
+ continue;
+ ASSERT(!tile->occluded); // Did resetUpdateState get skipped? Are we doing more than one occluded 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();
}
+ }
+ }
- // When not idle painting, if the visible region of the tile is occluded, don't reserve a texture or update the tile.
- // If any part of the tile is visible, then we need to update it so the tile is pushed to the impl thread.
- if (!idle && occlusion) {
- IntRect visibleTileRect = intersection(m_tiler->tileBounds(i, j), visibleContentRect());
- if (occlusion->occluded(this, visibleTileRect)) {
- ASSERT(!tile->updated);
- continue;
- }
- }
+ if (!succeeded)
+ return;
- // We come through this function multiple times during a commit, and updated should be true if the tile is not culled
- // any single time through the function.
- tile->updated = true;
+ // FIXME: Remove the loop and just pass the count!
+ for (int i = 0; i < occludedTileCount; i++)
+ occlusion->overdrawMetrics().didCullTileForUpload();
+}
- // Always try to get memory for visible textures.
- if (!idle && !tile->managedTexture()->canAcquireBackingTexture())
- tile->managedTexture()->requestLate();
+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;
- if (!tile->managedTexture()->canAcquireBackingTexture()) {
- m_skipsIdlePaint = true;
- if (!idle) {
- m_skipsDraw = true;
- m_tiler->reset();
- }
- return;
- }
+ // Ensure the entire tile is dirty if we don't have the texture.
+ if (!tile->managedTexture()->haveBackingTexture())
+ tile->dirtyRect = m_tiler->tileRect(tile);
- paintRect.unite(tile->dirtyRect);
+ // 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;
+}
- // For tiles that were not culled, we are going to update the area currently marked as dirty. So
- // clear that dirty area and mark it for update instead.
+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->updated)
- tile->copyAndClearDirty();
- else if (!idle && occlusion && tile->isDirty())
- occlusion->overdrawMetrics().didCullTileForUpload();
+ if (tile->occluded && !ignoreOcclusions)
+ continue;
+ paintRect.unite(tile->dirtyRect);
+ tile->markForUpdate();
}
}
+ return paintRect;
+}
- if (paintRect.isEmpty())
- return;
-
- if (occlusion)
- occlusion->overdrawMetrics().didPaint(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());
@@ -438,20 +481,17 @@ void TiledLayerChromium::updateTiles(bool idle, int left, int top, int right, in
RefPtr<LayerTextureUpdater> protector(textureUpdater());
IntRect paintedOpaqueRect;
textureUpdater()->prepareToUpdate(paintRect, m_tiler->tileSize(), 1 / widthScale, 1 / heightScale, paintedOpaqueRect, stats);
- m_didPaint = true;
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);
- if (!tile->updated)
- continue;
-
// Use updateRect as the above loop copied the dirty rect for this frame to updateRect.
const IntRect& dirtyRect = tile->updateRect;
if (dirtyRect.isEmpty())
@@ -506,10 +546,11 @@ void TiledLayerChromium::updateTiles(bool idle, int left, int top, int right, in
if (paintOffset.y() + destRect.height() > paintRect.height())
CRASH();
+ TextureUploader::Parameters upload = { tile->texture(), sourceRect, destRect };
if (tile->partialUpdate)
- updater.appendPartialUpdate(tile->texture(), sourceRect, destRect);
+ queue.appendPartialUpload(upload);
else
- updater.appendFullUpdate(tile->texture(), sourceRect, destRect);
+ queue.appendFullUpload(upload);
}
}
}
@@ -604,34 +645,33 @@ void TiledLayerChromium::resetUpdateState()
// FIXME: This should not ever be null.
if (!tile)
continue;
- tile->updateRect = IntRect();
- tile->updated = false;
- tile->partialUpdate = false;
+ tile->resetUpdateState();
}
}
-void TiledLayerChromium::updateContentRect(CCTextureUpdater& updater, const IntRect& contentRect, const CCOcclusionTracker* occlusion, CCRenderingStats& stats)
+void TiledLayerChromium::updateContentRect(CCTextureUpdateQueue& queue, const IntRect& contentRect, const CCOcclusionTracker* occlusion, CCRenderingStats& stats)
{
m_skipsDraw = false;
- m_skipsIdlePaint = false;
- m_didPaint = false;
-
+ m_failedUpdate = false;
updateBounds();
if (m_tiler->hasEmptyBounds())
return;
+ bool didPaint = false;
+
// Visible painting. Only paint visible tiles if the visible rect isn't empty.
if (!contentRect.isEmpty()) {
int left, top, right, bottom;
m_tiler->contentRectToTileIndices(contentRect, left, top, right, bottom);
- updateTiles(false, left, top, right, bottom, updater, occlusion, stats);
+ 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;
}
- // Abort if we have already painted or run out of memory.
- if (m_skipsIdlePaint || m_didPaint)
- return;
-
// If we have already painting everything visible. Do some pre-painting while idle.
IntRect idlePaintContentRect = idlePaintRect(contentRect);
if (idlePaintContentRect.isEmpty())
@@ -642,16 +682,13 @@ void TiledLayerChromium::updateContentRect(CCTextureUpdater& updater, const IntR
// If the layer is not visible, we have nothing to expand from, so instead we prepaint the outer-most set of tiles.
if (contentRect.isEmpty()) {
- updateTiles(true, prepaintLeft, prepaintTop, prepaintRight, prepaintTop, updater, 0, stats);
- if (m_didPaint || m_skipsIdlePaint)
+ if (!updateTiles(prepaintLeft, prepaintTop, prepaintRight, prepaintTop, queue, 0, stats, didPaint) || didPaint)
return;
- updateTiles(true, prepaintLeft, prepaintBottom, prepaintRight, prepaintBottom, updater, 0, stats);
- if (m_didPaint || m_skipsIdlePaint)
+ if (!updateTiles(prepaintLeft, prepaintBottom, prepaintRight, prepaintBottom, queue, 0, stats, didPaint) || didPaint)
return;
- updateTiles(true, prepaintLeft, prepaintTop, prepaintLeft, prepaintBottom, updater, 0, stats);
- if (m_didPaint || m_skipsIdlePaint)
+ if (!updateTiles(prepaintLeft, prepaintTop, prepaintLeft, prepaintBottom, queue, 0, stats, didPaint) || didPaint)
return;
- updateTiles(true, prepaintRight, prepaintTop, prepaintRight, prepaintBottom, updater, 0, stats);
+ updateTiles(prepaintRight, prepaintTop, prepaintRight, prepaintBottom, queue, 0, stats, didPaint);
return;
}
@@ -659,42 +696,38 @@ void TiledLayerChromium::updateContentRect(CCTextureUpdater& updater, const IntR
m_tiler->contentRectToTileIndices(contentRect, left, top, right, bottom);
// Otherwise, prepaint anything that was occluded but inside the layer's visible region.
- updateTiles(true, left, top, right, bottom, updater, 0, stats);
- if (m_didPaint || m_skipsIdlePaint)
+ if (!updateTiles(left, top, right, bottom, queue, 0, stats, didPaint) || didPaint)
return;
// Then expand outwards from the visible area until we find a dirty row or column to update.
- while (!m_skipsIdlePaint && (left > prepaintLeft || top > prepaintTop || right < prepaintRight || bottom < prepaintBottom)) {
+ while (left > prepaintLeft || top > prepaintTop || right < prepaintRight || bottom < prepaintBottom) {
if (bottom < prepaintBottom) {
++bottom;
- updateTiles(true, left, bottom, right, bottom, updater, 0, stats);
- if (m_didPaint || m_skipsIdlePaint)
- break;
+ if (!updateTiles(left, bottom, right, bottom, queue, 0, stats, didPaint) || didPaint)
+ return;
}
if (top > prepaintTop) {
--top;
- updateTiles(true, left, top, right, top, updater, 0, stats);
- if (m_didPaint || m_skipsIdlePaint)
- break;
+ if (!updateTiles(left, top, right, top, queue, 0, stats, didPaint) || didPaint)
+ return;
}
if (left > prepaintLeft) {
--left;
- updateTiles(true, left, top, left, bottom, updater, 0, stats);
- if (m_didPaint || m_skipsIdlePaint)
- break;
+ if (!updateTiles(left, top, left, bottom, queue, 0, stats, didPaint) || didPaint)
+ return;
}
if (right < prepaintRight) {
++right;
- updateTiles(true, right, top, right, bottom, updater, 0, stats);
- if (m_didPaint || m_skipsIdlePaint)
- break;
+ if (!updateTiles(right, top, right, bottom, queue, 0, stats, didPaint) || didPaint)
+ return;
}
}
}
bool TiledLayerChromium::needsIdlePaint(const IntRect& visibleContentRect)
{
- if (m_skipsIdlePaint)
+ // Don't trigger more paints if we failed (as we'll just fail again).
+ if (m_failedUpdate)
return false;
if (m_tiler->hasEmptyBounds())
@@ -717,7 +750,7 @@ bool TiledLayerChromium::needsIdlePaint(const IntRect& visibleContentRect)
if (!tile)
continue;
- bool updated = tile->updated;
+ bool updated = !tile->updateRect.isEmpty();
bool canAcquire = tile->managedTexture()->canAcquireBackingTexture();
bool dirty = tile->isDirty() || !tile->managedTexture()->haveBackingTexture();
if (!updated && canAcquire && dirty)