diff options
author | Nicolas Roard <nicolasroard@google.com> | 2011-08-17 11:50:35 -0700 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2011-08-17 11:50:35 -0700 |
commit | 345c04734e2d397a46a45343fe387cd11fd8197e (patch) | |
tree | ee53e74a85e8654b0fb8d8a492a295b53740f680 /Source/WebCore/platform | |
parent | 68bf56f88825e64efa5e1521206c7cdea4e1bf5d (diff) | |
parent | fa807bd31774157959640810e564fbe64338e8e3 (diff) | |
download | external_webkit-345c04734e2d397a46a45343fe387cd11fd8197e.zip external_webkit-345c04734e2d397a46a45343fe387cd11fd8197e.tar.gz external_webkit-345c04734e2d397a46a45343fe387cd11fd8197e.tar.bz2 |
Merge "Implement partial repaint for layers (at the tile level) Fixes a scheduling problem with layers"
Diffstat (limited to 'Source/WebCore/platform')
14 files changed, 131 insertions, 72 deletions
diff --git a/Source/WebCore/platform/graphics/android/BaseTile.cpp b/Source/WebCore/platform/graphics/android/BaseTile.cpp index cf769ae..93d00bd 100644 --- a/Source/WebCore/platform/graphics/android/BaseTile.cpp +++ b/Source/WebCore/platform/graphics/android/BaseTile.cpp @@ -66,7 +66,7 @@ BaseTile::BaseTile(bool isLayerTile) , m_repaintPending(false) , m_usable(true) , m_lastDirtyPicture(0) - , m_lastPaintedPicture(0) + , m_isTexturePainted(false) , m_isLayerTile(isLayerTile) { #ifdef DEBUG_COUNT @@ -127,7 +127,7 @@ void BaseTile::reserveTexture() android::AutoMutex lock(m_atomicSync); if (texture && m_texture != texture) { - m_lastPaintedPicture = 0; + m_isTexturePainted = false; fullInval(); } m_texture = texture; @@ -157,6 +157,8 @@ void BaseTile::fullInval() void BaseTile::markAsDirty(int unsigned pictureCount, const SkRegion& dirtyArea) { + if (dirtyArea.isEmpty()) + return; android::AutoMutex lock(m_atomicSync); m_lastDirtyPicture = pictureCount; for (int i = 0; i < m_maxBufferNumber; i++) @@ -219,7 +221,7 @@ void BaseTile::draw(float transparency, SkRect& rect, float scale) // Early return if set to un-usable in purpose! m_atomicSync.lock(); bool usable = m_usable; - bool isTexturePainted = m_lastPaintedPicture; + bool isTexturePainted = m_isTexturePainted; m_atomicSync.unlock(); if (!usable) { XLOG("early return at BaseTile::draw b/c tile set to unusable !"); @@ -272,6 +274,26 @@ bool BaseTile::isTileReady() return false; } +bool BaseTile::intersectWithRect(int x, int y, int tileWidth, int tileHeight, + float scale, const SkRect& dirtyRect, + SkRect& realTileRect) +{ + // compute the rect to corresponds to pixels + realTileRect.fLeft = x * tileWidth; + realTileRect.fTop = y * tileHeight; + realTileRect.fRight = realTileRect.fLeft + tileWidth; + realTileRect.fBottom = realTileRect.fTop + tileHeight; + + // scale the dirtyRect for intersect computation. + SkRect realDirtyRect = SkRect::MakeWH(dirtyRect.width() * scale, + dirtyRect.height() * scale); + realDirtyRect.offset(dirtyRect.fLeft * scale, dirtyRect.fTop * scale); + + if (!realTileRect.intersect(realDirtyRect)) + return false; + return true; +} + // This is called from the texture generation thread void BaseTile::paintBitmap() { @@ -325,37 +347,29 @@ void BaseTile::paintBitmap() bool fullRepaint = false; - // TODO: Implement the partial invalidate in Surface Texture Mode if (m_fullRepaint[m_currentDirtyAreaIndex] || textureInfo->m_width != tileWidth - || textureInfo->m_height != tileHeight - || textureInfo->getSharedTextureMode() == SurfaceTextureMode) { + || textureInfo->m_height != tileHeight) { fullRepaint = true; } - if (!fullRepaint) { - while (!cliperator.done()) { - SkRect dirtyRect; - dirtyRect.set(cliperator.rect()); - - // compute the rect to corresponds to pixels - SkRect realTileRect; - realTileRect.fLeft = x * tileWidth; - realTileRect.fTop = y * tileHeight; - realTileRect.fRight = realTileRect.fLeft + tileWidth; - realTileRect.fBottom = realTileRect.fTop + tileHeight; - - // scale the dirtyRect for intersect computation. - SkRect realDirtyRect = SkRect::MakeWH(dirtyRect.width() * scale, - dirtyRect.height() * scale); - realDirtyRect.offset(dirtyRect.fLeft * scale, dirtyRect.fTop * scale); - - // set realTileRect to the intersection of itself and the dirty rect - if (!realTileRect.intersect(realDirtyRect)) { - cliperator.next(); - continue; - } + bool surfaceTextureMode = textureInfo->getSharedTextureMode() == SurfaceTextureMode; + + while (!fullRepaint && !cliperator.done()) { + SkRect realTileRect; + SkRect dirtyRect; + dirtyRect.set(cliperator.rect()); + bool intersect = intersectWithRect(x, y, tileWidth, tileHeight, + scale, dirtyRect, realTileRect); + + // With SurfaceTexture, just repaint the entire tile if we intersect + // TODO: Implement the partial invalidate in Surface Texture Mode + if (intersect && surfaceTextureMode) { + fullRepaint = true; + break; + } + if (intersect && !surfaceTextureMode) { // initialize finalRealRect to the rounded values of realTileRect SkIRect finalRealRect; realTileRect.roundOut(&finalRealRect); @@ -379,11 +393,12 @@ void BaseTile::paintBitmap() renderInfo.measurePerf = false; pictureCount = m_renderer->renderTiledContent(renderInfo); - - cliperator.next(); } + + cliperator.next(); } + // Do a full repaint if needed if (fullRepaint) { SkIRect rect; rect.set(0, 0, tileWidth, tileHeight); @@ -404,7 +419,7 @@ void BaseTile::paintBitmap() texture->producerReleaseAndSwap(); if (texture == m_texture) { - m_lastPaintedPicture = pictureCount; + m_isTexturePainted = true; // set the fullrepaint flags m_fullRepaint[m_currentDirtyAreaIndex] = false; diff --git a/Source/WebCore/platform/graphics/android/BaseTile.h b/Source/WebCore/platform/graphics/android/BaseTile.h index c8873d4..0770b30 100644 --- a/Source/WebCore/platform/graphics/android/BaseTile.h +++ b/Source/WebCore/platform/graphics/android/BaseTile.h @@ -79,6 +79,10 @@ public: // the only thread-safe function called by the background thread void paintBitmap(); + bool intersectWithRect(int x, int y, int tileWidth, int tileHeight, + float scale, const SkRect& dirtyRect, + SkRect& realTileRect); + void markAsDirty(const unsigned int pictureCount, const SkRegion& dirtyArea); bool isDirty(); @@ -90,7 +94,6 @@ public: int x() const { return m_x; } int y() const { return m_y; } - unsigned int lastPaintedPicture() const { return m_lastPaintedPicture; } BaseTileTexture* texture() { return m_texture; } void setGLWebViewState(GLWebViewState* state) { m_glWebViewState = state; } @@ -131,10 +134,8 @@ private: int m_maxBufferNumber; int m_currentDirtyAreaIndex; - // stores the id of the latest picture painted to the tile. If the id is 0 - // then we know that the picture has not yet been painted an there is nothing - // to display (dirty or otherwise). - unsigned int m_lastPaintedPicture; + // flag used to know if we have a texture that was painted at least once + bool m_isTexturePainted; // This mutex serves two purposes. (1) It ensures that certain operations // happen atomically and (2) it makes sure those operations are synchronized diff --git a/Source/WebCore/platform/graphics/android/BaseTileTexture.cpp b/Source/WebCore/platform/graphics/android/BaseTileTexture.cpp index c964e04..7e6a57d 100644 --- a/Source/WebCore/platform/graphics/android/BaseTileTexture.cpp +++ b/Source/WebCore/platform/graphics/android/BaseTileTexture.cpp @@ -264,8 +264,7 @@ bool BaseTileTexture::readyFor(BaseTile* baseTile) (info->m_x == baseTile->x()) && (info->m_y == baseTile->y()) && (info->m_scale == baseTile->scale()) && - (info->m_painter == baseTile->painter()) && - (info->m_picture == baseTile->lastPaintedPicture())) + (info->m_painter == baseTile->painter())) return true; XLOG("readyFor return false for tile x, y (%d %d) texId %d ," diff --git a/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp b/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp index afd11ff..aa30035 100644 --- a/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp +++ b/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp @@ -35,6 +35,7 @@ #include "ScaleTransformOperation.h" #include "ScrollableLayerAndroid.h" #include "SkCanvas.h" +#include "SkRegion.h" #include "TransformationMatrix.h" #include "TranslateTransformOperation.h" @@ -125,6 +126,7 @@ GraphicsLayerAndroid::GraphicsLayerAndroid(GraphicsLayerClient* client) : { RenderLayer* renderLayer = renderLayerFromClient(m_client); m_contentLayer = new LayerAndroid(renderLayer); + m_dirtyRegion.setEmpty(); gDebugGraphicsLayerAndroidInstances++; } @@ -618,9 +620,10 @@ bool GraphicsLayerAndroid::repaint() m_contentLayer->getSize().width(), m_contentLayer->getSize().height()); + m_contentLayer->markAsDirty(m_dirtyRegion); + m_dirtyRegion.setEmpty(); m_contentLayer->needsRepaint(); m_needsRepaint = false; - m_invalidatedRects.clear(); return true; } @@ -667,26 +670,11 @@ void GraphicsLayerAndroid::setNeedsDisplayInRect(const FloatRect& rect) return; } - bool addInval = true; - const size_t maxDirtyRects = 8; - for (size_t i = 0; i < m_invalidatedRects.size(); ++i) { - if (m_invalidatedRects[i].contains(rect)) { - addInval = false; - break; - } - } - -#ifdef LAYER_DEBUG - LOG("(%x) layer %d setNeedsDisplayInRect(%d) - (%.2f, %.2f, %.2f, %.2f)", this, - m_contentLayer->uniqueId(), m_needsRepaint, rect.x(), rect.y(), rect.width(), rect.height()); -#endif - - if (addInval) { - if (m_invalidatedRects.size() < maxDirtyRects) - m_invalidatedRects.append(rect); - else - m_invalidatedRects[0].unite(rect); - } + SkRegion region; + region.setRect(rect.x(), rect.y(), + rect.x() + rect.width(), + rect.y() + rect.height()); + m_dirtyRegion.op(region, SkRegion::kUnion_Op); m_needsRepaint = true; askForSync(); diff --git a/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.h b/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.h index 10db5a1..a693de3 100644 --- a/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.h +++ b/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.h @@ -31,6 +31,7 @@ class FloatPoint3D; class Image; class SkBitmapRef; +class SkRegion; namespace WebCore { @@ -148,7 +149,7 @@ private: bool m_newImage; SkBitmapRef* m_imageRef; // only used to remember previously passed images - Vector<FloatRect> m_invalidatedRects; + SkRegion m_dirtyRegion; LayerAndroid* m_contentLayer; ScrollableLayerAndroid* m_foregroundLayer; diff --git a/Source/WebCore/platform/graphics/android/LayerAndroid.cpp b/Source/WebCore/platform/graphics/android/LayerAndroid.cpp index 65e0ec1..4b24961 100644 --- a/Source/WebCore/platform/graphics/android/LayerAndroid.cpp +++ b/Source/WebCore/platform/graphics/android/LayerAndroid.cpp @@ -78,6 +78,7 @@ LayerAndroid::LayerAndroid(RenderLayer* owner) : Layer(), m_preserves3D = false; m_dirty = false; m_iframeOffset.set(0,0); + m_dirtyRegion.setEmpty(); #ifdef DEBUG_COUNT ClassTracker::instance()->increment("LayerAndroid"); #endif @@ -120,6 +121,7 @@ LayerAndroid::LayerAndroid(const LayerAndroid& layer) : Layer(layer), m_childrenTransform = layer.m_childrenTransform; m_dirty = layer.m_dirty; m_pictureUsed = layer.m_pictureUsed; + m_dirtyRegion = layer.m_dirtyRegion; m_scale = layer.m_scale; m_lastComputeTextureSize = 0; @@ -155,6 +157,7 @@ LayerAndroid::LayerAndroid(SkPicture* picture) : Layer(), m_dirty = false; SkSafeRef(m_recordingPicture); m_iframeOffset.set(0,0); + m_dirtyRegion.setEmpty(); #ifdef DEBUG_COUNT ClassTracker::instance()->increment("LayerAndroid"); #endif @@ -739,8 +742,15 @@ void LayerAndroid::createTexture() for (int i = 0; i < count; i++) this->getChild(i)->createTexture(); - if (needsTexture() && !m_texture) + if (!needsTexture()) + return; + + if (!m_texture) m_texture = new PaintedSurface(this); + + // pass the invalidated regions to the PaintedSurface + m_texture->markAsDirty(m_dirtyRegion); + m_dirtyRegion.setEmpty(); } static inline bool compareLayerZ(const LayerAndroid* a, const LayerAndroid* b) @@ -748,6 +758,24 @@ static inline bool compareLayerZ(const LayerAndroid* a, const LayerAndroid* b) return a->zValue() > b->zValue(); } +void LayerAndroid::markAsDirty(const SkRegion& dirtyArea) +{ + m_dirtyRegion.op(dirtyArea, SkRegion::kUnion_Op); +} + +// We call this in WebViewCore, when copying the tree of layers. +// As we construct a new tree that will be passed on the UI, +// we mark the webkit-side tree as having no more dirty region +// (otherwise we would continuously have those dirty region UI-side) +void LayerAndroid::clearDirtyRegion() +{ + int count = this->countChildren(); + for (int i = 0; i < count; i++) + this->getChild(i)->clearDirtyRegion(); + + m_dirtyRegion.setEmpty(); +} + bool LayerAndroid::drawGL(GLWebViewState* glWebViewState, SkMatrix& matrix) { TilesManager::instance()->shader()->clip(m_clippingRect); diff --git a/Source/WebCore/platform/graphics/android/LayerAndroid.h b/Source/WebCore/platform/graphics/android/LayerAndroid.h index 8ad52e0..a28f1e7 100644 --- a/Source/WebCore/platform/graphics/android/LayerAndroid.h +++ b/Source/WebCore/platform/graphics/android/LayerAndroid.h @@ -27,6 +27,7 @@ #include "RefPtr.h" #include "SkBitmap.h" #include "SkColor.h" +#include "SkRegion.h" #include "SkStream.h" #include "TextureOwner.h" #include "TransformationMatrix.h" @@ -237,6 +238,11 @@ public: void needsRepaint() { m_pictureUsed++; } unsigned int pictureUsed() { return m_pictureUsed; } + + void markAsDirty(const SkRegion& dirtyArea); + void clearDirtyRegion(); + const SkRegion& dirtyRegion() { return m_dirtyRegion; } + void contentDraw(SkCanvas*); void extraDraw(SkCanvas*); @@ -337,6 +343,9 @@ private: bool m_dirty; unsigned int m_pictureUsed; + // dirty regions + SkRegion m_dirtyRegion; + // used to signal the framework we need a repaint bool m_hasRunningAnimations; diff --git a/Source/WebCore/platform/graphics/android/PaintedSurface.cpp b/Source/WebCore/platform/graphics/android/PaintedSurface.cpp index fd4475b..306eeb5 100644 --- a/Source/WebCore/platform/graphics/android/PaintedSurface.cpp +++ b/Source/WebCore/platform/graphics/android/PaintedSurface.cpp @@ -108,9 +108,6 @@ void PaintedSurface::prepare(GLWebViewState* state) XLOG("layer %d %x prepared at size (%d, %d) @ scale %.2f", m_layer->uniqueId(), m_layer, w, h, scale); - if (!m_tiledTexture) - m_tiledTexture = new TiledTexture(this); - m_tiledTexture->prepare(state, m_pictureUsed != m_layer->pictureUsed()); } @@ -139,6 +136,11 @@ void PaintedSurface::endPaint() m_layerLock.unlock(); } +void PaintedSurface::markAsDirty(const SkRegion& dirtyArea) +{ + m_tiledTexture->markAsDirty(dirtyArea); +} + bool PaintedSurface::paint(BaseTile* tile, SkCanvas* canvas, unsigned int* pictureUsed) { m_layerLock.lock(); diff --git a/Source/WebCore/platform/graphics/android/PaintedSurface.h b/Source/WebCore/platform/graphics/android/PaintedSurface.h index 6b6c74f..ffb609e 100644 --- a/Source/WebCore/platform/graphics/android/PaintedSurface.h +++ b/Source/WebCore/platform/graphics/android/PaintedSurface.h @@ -38,6 +38,7 @@ #include "TransformationMatrix.h" class SkCanvas; +class SkRegion; namespace WebCore { @@ -55,6 +56,7 @@ public: #ifdef DEBUG_COUNT ClassTracker::instance()->increment("PaintedSurface"); #endif + m_tiledTexture = new TiledTexture(this); } virtual ~PaintedSurface() { @@ -70,6 +72,7 @@ public: LayerAndroid* layer() { return m_layer; } void prepare(GLWebViewState*); bool draw(); + void markAsDirty(const SkRegion& dirtyArea); bool paint(SkCanvas*); void removeLayer(LayerAndroid* layer); void replaceLayer(LayerAndroid* layer); diff --git a/Source/WebCore/platform/graphics/android/TextureOwner.h b/Source/WebCore/platform/graphics/android/TextureOwner.h index 35d3389..d0c60fb 100644 --- a/Source/WebCore/platform/graphics/android/TextureOwner.h +++ b/Source/WebCore/platform/graphics/android/TextureOwner.h @@ -42,6 +42,7 @@ public: virtual TiledPage* page() = 0; virtual GLWebViewState* state() = 0; virtual bool samePageAs(Layer* root) { return false; } + virtual bool isRepaintPending() = 0; }; } diff --git a/Source/WebCore/platform/graphics/android/TexturesGenerator.cpp b/Source/WebCore/platform/graphics/android/TexturesGenerator.cpp index 3f7d6a3..0820688 100644 --- a/Source/WebCore/platform/graphics/android/TexturesGenerator.cpp +++ b/Source/WebCore/platform/graphics/android/TexturesGenerator.cpp @@ -148,7 +148,9 @@ QueuedOperation* TexturesGenerator::popNext() mRequestedOperations.remove(i); return next; } - if (nextPriority < currentPriority) { + // pick items preferrably by priority, or if equal, by order of + // insertion (as we add items at the back of the queue) + if (nextPriority <= currentPriority) { current = next; currentPriority = nextPriority; currentIndex = i; diff --git a/Source/WebCore/platform/graphics/android/TiledTexture.cpp b/Source/WebCore/platform/graphics/android/TiledTexture.cpp index 0efcfc3..1aac44d 100644 --- a/Source/WebCore/platform/graphics/android/TiledTexture.cpp +++ b/Source/WebCore/platform/graphics/android/TiledTexture.cpp @@ -69,7 +69,10 @@ void TiledTexture::prepare(GLWebViewState* state, bool repaint) for (unsigned int i = 0; i < m_tiles.size(); i++) { BaseTile* tile = m_tiles[i]; tile->setUsedLevel(-1); + if (!m_dirtyRegion.isEmpty()) + tile->markAsDirty(1, m_dirtyRegion); } + m_dirtyRegion.setEmpty(); if (area.width() == 0 && area.height() == 0) { m_area.setWidth(0); @@ -115,6 +118,11 @@ void TiledTexture::prepare(GLWebViewState* state, bool repaint) } } +void TiledTexture::markAsDirty(const SkRegion& dirtyArea) +{ + m_dirtyRegion.op(dirtyArea, SkRegion::kUnion_Op); +} + void TiledTexture::prepareTile(bool repaint, int x, int y) { BaseTile* tile = getTile(x, y); @@ -130,11 +138,7 @@ void TiledTexture::prepareTile(bool repaint, int x, int y) tile->setUsedLevel(0); bool schedule = false; - if (repaint) - tile->fullInval(); - if (!tile->isTileReady()) - schedule = true; - if (repaint || tile->isDirty()) + if (tile->isDirty()) schedule = true; LayerAndroid* layer = m_surface->layer(); @@ -183,7 +187,7 @@ bool TiledTexture::draw() rect.fTop = tile->y() * tileHeight; rect.fRight = rect.fLeft + tileWidth; rect.fBottom = rect.fTop + tileHeight; - XLOG(" - [%d], { painter %x vs %x }, tile %x %d,%d at scale %.2f [ready: %d]", i, this, tile->painter(), tile, tile->x(), tile->y(), tile->scale(), tile->isTileReady()); + XLOG(" - [%d], { painter %x vs %x }, tile %x %d,%d at scale %.2f [ready: %d] dirty: %d", i, this, tile->painter(), tile, tile->x(), tile->y(), tile->scale(), tile->isTileReady(), tile->isDirty()); askRedraw |= !tile->isTileReady(); tile->draw(m_surface->opacity(), rect, m_surface->scale()); #ifdef DEBUG diff --git a/Source/WebCore/platform/graphics/android/TiledTexture.h b/Source/WebCore/platform/graphics/android/TiledTexture.h index 532cc2c..6ebfc05 100644 --- a/Source/WebCore/platform/graphics/android/TiledTexture.h +++ b/Source/WebCore/platform/graphics/android/TiledTexture.h @@ -26,12 +26,13 @@ #ifndef TiledTexture_h #define TiledTexture_h +#include "BaseTile.h" #include "BaseTileTexture.h" #include "ClassTracker.h" #include "IntRect.h" #include "LayerAndroid.h" +#include "SkRegion.h" #include "TextureOwner.h" -#include "BaseTile.h" #include "TilePainter.h" class SkCanvas; @@ -48,6 +49,7 @@ public: , m_prevTileY(0) , m_prevScale(1) { + m_dirtyRegion.setEmpty(); #ifdef DEBUG_COUNT ClassTracker::instance()->increment("TiledTexture"); #endif @@ -64,6 +66,7 @@ public: bool draw(); void prepareTile(bool repaint, int x, int y); + void markAsDirty(const SkRegion& dirtyArea); BaseTile* getTile(int x, int y); @@ -82,6 +85,7 @@ private: Vector<BaseTile*> m_tiles; IntRect m_area; + SkRegion m_dirtyRegion; int m_prevTileX; int m_prevTileY; diff --git a/Source/WebCore/platform/graphics/android/TilesManager.cpp b/Source/WebCore/platform/graphics/android/TilesManager.cpp index 4ada041..c634be0 100644 --- a/Source/WebCore/platform/graphics/android/TilesManager.cpp +++ b/Source/WebCore/platform/graphics/android/TilesManager.cpp @@ -228,6 +228,8 @@ BaseTileTexture* TilesManager::getAvailableTexture(BaseTile* owner) unsigned int max = m_tilesTextures.size(); for (unsigned int i = 0; i < max; i++) { BaseTileTexture* texture = m_tilesTextures[i]; + if (texture->owner() && texture->owner()->isRepaintPending()) + continue; if (!texture->owner() && texture->acquire(owner)) { return texture; } |