OSDN Git Service

Support partial invalidation of tiles based on webkit's inval rect.
authorDerek Sollenberger <djsollen@google.com>
Tue, 2 Nov 2010 15:15:08 +0000 (11:15 -0400)
committerDerek Sollenberger <djsollen@google.com>
Thu, 4 Nov 2010 13:53:33 +0000 (09:53 -0400)
This CL causes the selective repainting of BaseTiles (and their
associated GL textures) using the information provided by Webkit.
If tiles need repainted they are marked with as dirty and the
thread painting and uploading the textures will only operate on
dirty tiles. This change resulted in some significant refactoring
most of which revolved around these changes...

(1) Removed PaintingInfo from the Texture object and instead track
the state of the tile in Tile object.
(2) Removed all pending TileSets for a TiledPage when the page
produces a new set. This ensures that the tiles currently visible
to the user are painted instead of ones that may already be offscreen.

Change-Id: I93845d8e6e7b066e6bab84bcde11be4a6940002f

13 files changed:
WebCore/platform/graphics/android/BackedDoubleBufferedTexture.cpp
WebCore/platform/graphics/android/BackedDoubleBufferedTexture.h
WebCore/platform/graphics/android/BaseTile.cpp
WebCore/platform/graphics/android/BaseTile.h
WebCore/platform/graphics/android/DoubleBufferedTexture.h
WebCore/platform/graphics/android/GLWebViewState.cpp
WebCore/platform/graphics/android/GLWebViewState.h
WebCore/platform/graphics/android/TexturesGenerator.cpp
WebCore/platform/graphics/android/TileSet.cpp
WebCore/platform/graphics/android/TileSet.h
WebCore/platform/graphics/android/TiledPage.cpp
WebCore/platform/graphics/android/TiledPage.h
WebCore/platform/graphics/android/TilesManager.cpp

index 7cecddd..1a8e686 100644 (file)
@@ -56,28 +56,27 @@ BackedDoubleBufferedTexture::~BackedDoubleBufferedTexture()
 
 TextureInfo* BackedDoubleBufferedTexture::producerLock()
 {
-    m_varLock.lock();
+    m_busyLock.lock();
     m_busy = true;
-    m_varLock.unlock();
+    m_busyLock.unlock();
     return DoubleBufferedTexture::producerLock();
 }
 
 void BackedDoubleBufferedTexture::producerRelease()
 {
     DoubleBufferedTexture::producerRelease();
-    android::Mutex::Autolock lock(m_varLock);
+    android::Mutex::Autolock lock(m_busyLock);
     m_busy = false;
 }
 
 void BackedDoubleBufferedTexture::producerReleaseAndSwap()
 {
     DoubleBufferedTexture::producerReleaseAndSwap();
-    android::Mutex::Autolock lock(m_varLock);
+    android::Mutex::Autolock lock(m_busyLock);
     m_busy = false;
 }
 
-void BackedDoubleBufferedTexture::producerUpdate(BaseTile* painter,
-        TextureInfo* textureInfo, PaintingInfo& info)
+void BackedDoubleBufferedTexture::producerUpdate(TextureInfo* textureInfo)
 {
     // no need to upload a texture since the bitmap is empty
     if (!m_bitmap.width() && !m_bitmap.height()) {
@@ -93,34 +92,9 @@ void BackedDoubleBufferedTexture::producerUpdate(BaseTile* painter,
         textureInfo->m_height = m_bitmap.height();
     }
 
-    m_varLock.lock();
-    // set the painting information for this texture
-    if (equalsIdTextureA(textureInfo->m_textureId))
-        m_paintingInfoA = info;
-    else if (equalsIdTextureB(textureInfo->m_textureId))
-        m_paintingInfoB = info;
-    m_varLock.unlock();
-
     producerReleaseAndSwap();
 }
 
-// Compare the current texture displayed with some PaintingInfo.
-bool BackedDoubleBufferedTexture::consumerTextureUpToDate(PaintingInfo& info)
-{
-    android::Mutex::Autolock lock(m_varLock);
-    if (isTextureAReadable())
-        return info == m_paintingInfoA;
-    return info == m_paintingInfoB;
-}
-
-bool BackedDoubleBufferedTexture::consumerTextureSimilar(PaintingInfo& info)
-{
-    android::Mutex::Autolock lock(m_varLock);
-    if (isTextureAReadable())
-        return info.similar(m_paintingInfoA);
-    return info.similar(m_paintingInfoB);
-}
-
 bool BackedDoubleBufferedTexture::acquire(BaseTile* owner)
 {
     if (m_owner == owner)
@@ -128,7 +102,7 @@ bool BackedDoubleBufferedTexture::acquire(BaseTile* owner)
 
     // if the writable texture is busy (i.e. currently being written to) then we
     // can't change the owner out from underneath that texture
-    android::Mutex::Autolock lock(m_varLock);
+    android::Mutex::Autolock lock(m_busyLock);
     if (!m_busy) {
         if (m_owner)
             m_owner->removeTexture();
index 1faa110..6bbb97a 100644 (file)
@@ -36,42 +36,6 @@ namespace WebCore {
 
 class BaseTile;
 
-class PaintingInfo {
-public:
-    PaintingInfo() : m_x(-1), m_y(-1), m_webview(0), m_picture(0) { }
-    PaintingInfo(int x, int y, GLWebViewState* webview)
-        : m_x(x)
-        , m_y(y)
-        , m_webview(webview)
-        , m_picture(0)
-    {
-        if(webview)
-            m_picture = webview->currentPictureCounter();
-    }
-    bool operator==(const PaintingInfo& info)
-    {
-        return m_webview == info.m_webview
-            && m_x == info.m_x
-            && m_y == info.m_y
-            && m_picture == info.m_picture;
-    }
-    bool similar(const PaintingInfo& info)
-    {
-        return m_webview == info.m_webview
-            && m_x == info.m_x
-            && m_y == info.m_y;
-    }
-    void setPosition(int x, int y) { m_x = x; m_y = y; }
-    void setGLWebViewState(GLWebViewState* webview) { m_webview = webview; }
-    void setPictureUsed(unsigned int picture) { m_picture = picture; }
-
-private:
-    int m_x;
-    int m_y;
-    GLWebViewState* m_webview;
-    unsigned int m_picture;
-};
-
 // DoubleBufferedTexture using a SkBitmap as backing mechanism
 class BackedDoubleBufferedTexture : public DoubleBufferedTexture {
 public:
@@ -88,7 +52,7 @@ public:
 
     // updates the texture with current bitmap and releases (and if needed also
     // swaps) the texture.
-    void producerUpdate(BaseTile* painter, TextureInfo* textureInfo, PaintingInfo& info);
+    void producerUpdate(TextureInfo* textureInfo);
 
     // The level can be one of the following values:
     //  * -1 for an unused texture.
@@ -107,11 +71,7 @@ public:
     BaseTile* owner() { return m_owner; } // only used by the consumer thread
     SkCanvas* canvas() { return m_canvas; } // only used by the producer thread
 
-    // checks to see if the current readable texture equals the provided PaintingInfo
-    bool consumerTextureUpToDate(PaintingInfo& info);
-    // checks to see if the current readable texture is similar to the provided PaintingInfo
-    bool consumerTextureSimilar(PaintingInfo& info);
-
+    // This is to be only used for debugging on the producer thread
     bool busy() { return m_busy; }
 
 private:
@@ -120,12 +80,13 @@ private:
     int m_usedLevel;
     BaseTile* m_owner;
 
-    //The following values are shared among threads and use m_varLock to stay synced
-    PaintingInfo m_paintingInfoA;
-    PaintingInfo m_paintingInfoB;
+    // This values signals that the texture is currently in use by the consumer.
+    // This allows us to prevent the owner of the texture from changing while the
+    // consumer is holding a lock on the texture.
     bool m_busy;
-
-    android::Mutex m_varLock;
+    // We mutex protect the reads/writes of m_busy to ensure that we are reading
+    // the most up-to-date value even across processors in an SMP system.
+    android::Mutex m_busyLock;
 };
 
 } // namespace WebCore
index 5ab801e..1c81634 100644 (file)
@@ -72,6 +72,9 @@ BaseTile::BaseTile(TiledPage* page, int x, int y)
     , m_y(y)
     , m_texture(0)
     , m_scale(1)
+    , m_dirty(true)
+    , m_lastDirtyPicture(0)
+    , m_lastPaintedPicture(0)
 {
 #ifdef DEBUG_COUNT
     gBaseTileCount++;
@@ -80,6 +83,7 @@ BaseTile::BaseTile(TiledPage* page, int x, int y)
 
 BaseTile::~BaseTile()
 {
+    setUsedLevel(-1);
 #ifdef DEBUG_COUNT
     gBaseTileCount--;
 #endif
@@ -90,26 +94,43 @@ BaseTile::~BaseTile()
 void BaseTile::reserveTexture()
 {
     BackedDoubleBufferedTexture* texture = TilesManager::instance()->getAvailableTexture(this);
-    // We update atomically, so paintBitmap() can see the correct value
-    android_atomic_acquire_store((int32_t)texture, (int32_t*)&m_texture);
-    XLOG("%x (%d, %d) reserveTexture res: %x...", this, x(), y(), m_texture);
+
+    android::AutoMutex lock(m_atomicSync);
+    if (m_texture != texture) {
+        m_lastPaintedPicture = 0;
+        m_dirty = true;
+    }
+    m_texture = texture;
 }
 
 void BaseTile::removeTexture()
 {
     XLOG("%x removeTexture res: %x...", this, m_texture);
     // We update atomically, so paintBitmap() can see the correct value
-    android_atomic_acquire_store(0, (int32_t*)&m_texture);
+    android::AutoMutex lock(m_atomicSync);
+    m_texture = 0;
 }
 
 void BaseTile::setScale(float scale)
 {
+    android::AutoMutex lock(m_atomicSync);
+    if (m_scale != scale)
+        m_dirty = true;
     m_scale = scale;
-    // FIXME: the following two lines force a memory barrier which causes
-    // m_scale to be observable on other cores. We should replace this
-    // with a dedicated system function if/when available.
-    int32_t tempValue = 0;
-    android_atomic_acquire_load(&tempValue);
+}
+
+void BaseTile::markAsDirty(int pictureCount)
+{
+    android::AutoMutex lock(m_atomicSync);
+    m_lastDirtyPicture = pictureCount;
+    if (m_lastPaintedPicture < m_lastDirtyPicture)
+        m_dirty = true;
+}
+
+bool BaseTile::isDirty()
+{
+    android::AutoMutex lock(m_atomicSync);
+    return m_dirty;
 }
 
 void BaseTile::setUsedLevel(int usedLevel)
@@ -120,13 +141,13 @@ void BaseTile::setUsedLevel(int usedLevel)
 
 void BaseTile::draw(float transparency, SkRect& rect)
 {
+    // No need to mutex protect reads of m_texture as it is only written to by
+    // the consumer thread.
     if (!m_texture) {
         XLOG("%x (%d, %d) trying to draw, but no m_texture!", this, x(), y());
         return;
     }
 
-    PaintingInfo info(m_x, m_y, m_page->glWebViewState());
-
     TextureInfo* textureInfo = m_texture->consumerLock();
     if (!textureInfo) {
         XLOG("%x (%d, %d) trying to draw, but no textureInfo!", this, x(), y());
@@ -134,61 +155,57 @@ void BaseTile::draw(float transparency, SkRect& rect)
         return;
     }
 
-    if (m_texture->consumerTextureSimilar(info)) {
+    m_atomicSync.lock();
+    bool isTexturePainted = m_lastPaintedPicture;
+    m_atomicSync.unlock();
+
+    if (isTexturePainted)
         TilesManager::instance()->shader()->drawQuad(rect, textureInfo->m_textureId,
                                                      transparency);
-    }
 
     m_texture->consumerRelease();
 }
 
-bool BaseTile::isBitmapReady()
+bool BaseTile::isTileReady()
 {
     if (!m_texture)
         return false;
     if (m_texture->owner() != this)
         return false;
-    PaintingInfo info(m_x, m_y, m_page->glWebViewState());
-    return m_texture->consumerTextureUpToDate(info);
+
+    android::AutoMutex lock(m_atomicSync);
+    return !m_dirty;
 }
 
 // This is called from the texture generation thread
 void BaseTile::paintBitmap()
 {
-    const int x = m_x;
-    const int y = m_y;
-    TiledPage* tiledPage = m_page;
-
-    // We acquire the texture atomically. Once we have it, we
-    // can continue with it, and m_texture can be updated without
-    // consequences.
-    BackedDoubleBufferedTexture* texture = reinterpret_cast<BackedDoubleBufferedTexture*>(
-        android_atomic_release_load((int32_t*)&m_texture));
 
-    // The loading of m_texture forces the execution of a memory barrier,
-    // which ensures that we are observing the most recent value of m_scale
-    // written by another core.
+    // We acquire the values below atomically. This ensures that we are reading
+    // values correctly across cores. Further, once we have these values they
+    // can be updated by other threads without consequence.
+    m_atomicSync.lock();
+    bool dirty = m_dirty;
+    BackedDoubleBufferedTexture* texture = m_texture;
     float scale = m_scale;
+    m_atomicSync.unlock();
 
-    if (!texture)
+    if(!dirty || !texture)
         return;
 
+    const int x = m_x;
+    const int y = m_y;
+    TiledPage* tiledPage = m_page;
+
     TextureInfo* textureInfo = texture->producerLock();
 
-    // at this point we can safely check the ownership
-    // (if the texture got transferred to another BaseTile
-    // under us)
+    // at this point we can safely check the ownership (if the texture got
+    // transferred to another BaseTile under us)
     if (texture->owner() != this || texture->usedLevel() > 1) {
         texture->producerRelease();
         return;
     }
 
-    PaintingInfo info(x, y, tiledPage->glWebViewState());
-    if (texture->consumerTextureUpToDate(info)) {
-        texture->producerRelease();
-        return;
-    }
-
     float tileWidth = textureInfo->m_width;
     float tileHeight = textureInfo->m_height;
 
@@ -203,7 +220,7 @@ void BaseTile::paintBitmap()
     canvas->scale(scale, scale);
     canvas->translate(-x * w, -y * h);
 
-    tiledPage->paintBaseLayerContent(canvas);
+    int pictureCount = tiledPage->paintBaseLayerContent(canvas);
 
     canvas->restore();
 
@@ -219,7 +236,13 @@ void BaseTile::paintBitmap()
     canvas->drawLine(tileWidth, 0, tileWidth, tileHeight, paint);
 #endif
 
-    texture->producerUpdate(this, textureInfo, info);
+    texture->producerUpdate(textureInfo);
+
+    m_atomicSync.lock();
+    m_lastPaintedPicture = pictureCount;
+    if (m_lastPaintedPicture >= m_lastDirtyPicture)
+        m_dirty = false;
+    m_atomicSync.unlock();
 }
 
 } // namespace WebCore
index 429d950..896edb3 100644 (file)
@@ -36,6 +36,7 @@
 #include <EGL/egl.h>
 #include <EGL/eglext.h>
 #include <GLES2/gl2.h>
+#include <utils/threads.h>
 
 namespace WebCore {
 
@@ -69,12 +70,15 @@ public:
     void reserveTexture();
     void removeTexture();
     void setUsedLevel(int);
-    bool isBitmapReady();
+    bool isTileReady();
     void draw(float transparency, SkRect& rect);
 
     // the only thread-safe function called by the background thread
     void paintBitmap();
 
+    void markAsDirty(int pictureCount);
+    bool isDirty();
+
     float scale() const { return m_scale; }
     void setScale(float scale);
 
@@ -89,9 +93,25 @@ private:
     int m_x;
     int m_y;
 
-    // these variables can be updated throughout the lifetime of the object
+    // The remaining variables can be updated throughout the lifetime of the object
     BackedDoubleBufferedTexture* m_texture;
     float m_scale;
+    // used to signal that the that the tile is out-of-date and needs to be redrawn
+    bool m_dirty;
+    // stores the id of the latest picture from webkit that caused this tile to
+    // become dirty. A tile is no longer dirty when it has been painted with a
+    // picture that is newer than this value.
+    int m_lastDirtyPicture;
+    // 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).
+    int m_lastPaintedPicture;
+
+    // This mutex serves two purposes. (1) It ensures that certain operations
+    // happen atomically and (2) it makes sure those operations are synchronized
+    // across all threads and cores.
+    android::Mutex m_atomicSync;
+
 };
 
 } // namespace WebCore
index d16d5f3..2b2fd03 100644 (file)
@@ -50,11 +50,6 @@ public:
     TextureInfo* consumerLock();
     void consumerRelease();
 
-protected:
-    bool equalsIdTextureA(GLuint id) { return id == m_textureA.getSourceTextureId(); }
-    bool equalsIdTextureB(GLuint id) { return id == m_textureB.getSourceTextureId(); }
-    bool isTextureAReadable() { return getReadableTexture() == &m_textureA; }
-
 private:
     SharedTexture* getReadableTexture();
     SharedTexture* getWriteableTexture();
index e1e517c..814e590 100644 (file)
@@ -81,7 +81,6 @@ GLWebViewState::GLWebViewState()
     , m_extra(0)
     , m_navLayer(0)
 {
-    m_invalidatedRect.setEmpty();
     m_tiledPageA = new TiledPage(FIRST_TILED_PAGE_ID, this);
     m_tiledPageB = new TiledPage(SECOND_TILED_PAGE_ID, this);
 #ifdef DEBUG_COUNT
@@ -108,8 +107,13 @@ void GLWebViewState::setBaseLayer(BaseLayerAndroid* layer, IntRect& rect)
     m_navLayer = 0;
     if (m_baseLayer) {
         m_baseLayer->setGLWebViewState(this);
-        m_invalidatedRect.set(rect);
         m_currentPictureCounter++;
+
+        if (!rect.isEmpty()) {
+            // find which tiles fall within the invalRect and mark them as dirty
+            m_tiledPageA->invalidateRect(rect, m_currentPictureCounter);
+            m_tiledPageB->invalidateRect(rect, m_currentPictureCounter);
+        }
     }
 }
 
@@ -132,7 +136,7 @@ void GLWebViewState::resetExtra(bool repaint)
     m_navLayer = 0;
 }
 
-void GLWebViewState::paintBaseLayerContent(SkCanvas* canvas)
+int GLWebViewState::paintBaseLayerContent(SkCanvas* canvas)
 {
     android::Mutex::Autolock lock(m_baseLayerLock);
     if (m_baseLayer) {
@@ -140,6 +144,7 @@ void GLWebViewState::paintBaseLayerContent(SkCanvas* canvas)
         if (m_extra && m_navLayer)
             m_extra->draw(canvas, m_navLayer);
     }
+    return m_currentPictureCounter;
 }
 
 void GLWebViewState::scheduleUpdate(const double& currentTime, float scale)
index 95bc07d..04dea6d 100644 (file)
@@ -95,8 +95,9 @@ class LayerAndroid;
 // get the GL textures from an existing pool, and reuse them.
 //
 // The way we do it is that when we call TiledPage::prepare(), we group the
-// tiles we need into a TilesSet, call TilesSet::reserveTextures() (which
-// associates the GL textures to the BaseTiles).
+// tiles we need (i.e. in the viewport and dirty) into a TilesSet and call
+// BaseTile::reserveTexture() for each tile (which ensures there is a specific
+// GL textures backing the BaseTiles).
 //
 // reserveTexture() will ask the TilesManager for a texture. The allocation
 // mechanism goal is to (in order):
@@ -104,8 +105,22 @@ class LayerAndroid;
 // - prefers to allocate textures that are as far from the viewport as possible
 // - prefers to allocate textures that are used by different TiledPages
 //
-// Note that to compute the distance of tiles, each time we prepare() a
-// TiledPage, we compute the distance of the tiles in it from the viewport.
+// Note that to compute the distance of each tile from the viewport, each time
+// we prepare() a TiledPage. Also during each prepare() we compute which tiles
+// are dirty based on the info we have received from webkit.
+//
+// BaseTile Invalidation
+// ------------------
+//
+// We do not want to redraw a tile if the tile is up-to-date. A tile is
+// considered to be dirty an in need of redrawing in the following cases
+//  - the tile has acquires a new texture
+//  - webkit invalidates all or part of the tiles contents
+//
+// To handle the case of webkit invalidation we store two ids (counters) of the
+// pictureSets in the tile.  The first id (A) represents the pictureSet used to
+// paint the tile and the second id (B) represents the pictureSet in which the
+// tile was invalidated by webkit. Thus, if A < B then tile is dirty.
 //
 // Painting scheduling
 // -------------------
@@ -155,7 +170,7 @@ public:
     int originalTilesPosY() const { return m_originalTilesPosY; }
     void setOriginalTilesPosY(int pos) { m_originalTilesPosY = pos; }
 
-    void paintBaseLayerContent(SkCanvas* canvas);
+    int paintBaseLayerContent(SkCanvas* canvas);
     void setBaseLayer(BaseLayerAndroid* layer, IntRect& rect);
     void setExtra(android::DrawExtra* extra, LayerAndroid* navLayer);
     void resetExtra(bool repaint);
@@ -176,7 +191,6 @@ public:
     int firstTileY() const { return m_firstTileY; }
 
     unsigned int currentPictureCounter() const { return m_currentPictureCounter; }
-    SkRect& invalidatedRect() { return m_invalidatedRect; }
 
 private:
 
@@ -207,7 +221,6 @@ private:
     android::Mutex m_baseLayerLock;
     BaseLayerAndroid* m_baseLayer;
     unsigned int m_currentPictureCounter;
-    SkRect m_invalidatedRect;
     bool m_usePageA;
     TiledPage* m_tiledPageA;
     TiledPage* m_tiledPageB;
index f81a297..193ca46 100644 (file)
@@ -53,10 +53,13 @@ void TexturesGenerator::schedulePaintForTileSet(TileSet* set)
 {
     android::Mutex::Autolock lock(mRequestedPixmapsLock);
     for (unsigned int i = 0; i < mRequestedPixmaps.size(); i++) {
-        TileSet* s = mRequestedPixmaps[i];
-        if (s && *s == *set) {
-            // Similar set already in the queue
-            delete set;
+        TileSet** s = &mRequestedPixmaps[i];
+        // A similar set is already in the queue. The newer set may have additional
+        // dirty tiles so delete the existing set and replace it with the new one.
+        if (*s && **s == *set) {
+            TileSet* oldSet = *s;
+            *s = set;
+            delete oldSet;
             return;
         }
     }
index fe13ef3..4530640 100644 (file)
@@ -56,10 +56,8 @@ int TileSet::count()
 }
 #endif
 
-TileSet::TileSet(int id, int firstTileX, int firstTileY, int rows, int cols)
-    : m_id(id)
-    , m_firstTileX(firstTileX)
-    , m_firstTileY(firstTileY)
+TileSet::TileSet(TiledPage* tiledPage, int rows, int cols)
+    : m_tiledPage(tiledPage)
     , m_nbRows(rows)
     , m_nbCols(cols)
 {
@@ -77,36 +75,12 @@ TileSet::~TileSet()
 
 bool TileSet::operator==(const TileSet& set)
 {
-    return m_id == set.m_id
-           && m_firstTileX == set.m_firstTileX
-           && m_firstTileY == set.m_firstTileY
+    return m_tiledPage == set.m_tiledPage
            && m_nbRows == set.m_nbRows
            && m_nbCols == set.m_nbCols;
 }
 
 
-void TileSet::reserveTextures()
-{
-#ifdef DEBUG
-    if (m_tiles.size()) {
-        TiledPage* page = m_tiles[0]->page();
-        XLOG("reserveTextures (%d tiles) for page %x (sibling: %x)", m_tiles.size(), page, page->sibling());
-        TilesManager::instance()->printTextures();
-    }
-#endif // DEBUG
-
-    for (unsigned int i = 0; i < m_tiles.size(); i++)
-        m_tiles[i]->reserveTexture();
-
-#ifdef DEBUG
-    if (m_tiles.size()) {
-        TiledPage* page = m_tiles[0]->page();
-        XLOG(" DONE reserveTextures (%d tiles) for page %x (sibling: %x)", m_tiles.size(), page, page->sibling());
-        TilesManager::instance()->printTextures();
-    }
-#endif // DEBUG
-}
-
 void TileSet::paint()
 {
     XLOG("%x, painting %d tiles", this, m_tiles.size());
index adf6d13..fd65ad7 100644 (file)
@@ -45,11 +45,10 @@ public:
 #ifdef DEBUG_COUNT
     static int count();
 #endif
-    TileSet(int id, int firstTileX, int firstTileY, int rows, int cols);
+    TileSet(TiledPage* tiledPage, int nbRows, int nbCols);
     ~TileSet();
 
     bool operator==(const TileSet& set);
-    void reserveTextures();
     void paint();
 
     void add(BaseTile* texture)
@@ -59,17 +58,13 @@ public:
 
     TiledPage* page()
     {
-        if (m_tiles.size())
-            return m_tiles[0]->page();
-        return 0;
+        return m_tiledPage;
     }
 
 private:
     Vector<BaseTile*> m_tiles;
 
-    int m_id;
-    int m_firstTileX;
-    int m_firstTileY;
+    TiledPage* m_tiledPage;
     int m_nbRows;
     int m_nbCols;
 };
index 6430b02..6b11c52 100644 (file)
@@ -29,6 +29,7 @@
 #if USE(ACCELERATED_COMPOSITING)
 
 #include "GLUtils.h"
+#include "IntRect.h"
 #include "TilesManager.h"
 
 #ifdef DEBUG
@@ -64,6 +65,7 @@ TiledPage::TiledPage(int id, GLWebViewState* state)
     , m_scale(1)
     , m_invScale(1)
     , m_glWebViewState(state)
+    , m_latestPictureInval(0)
 {
 #ifdef DEBUG_COUNT
     gTilePageCount++;
@@ -94,6 +96,24 @@ BaseTile* TiledPage::getBaseTile(int x, int y)
     return m_baseTiles.get(key);
 }
 
+void TiledPage::invalidateRect(const IntRect& inval, const int pictureCount)
+{
+    // Given the current scale level we need to mark the appropriate tiles as dirty
+    TilesManager* manager = TilesManager::instance();
+    const float invTileContentWidth = m_scale / manager->tileWidth();
+    const float invTileContentHeight = m_scale / manager->tileHeight();
+
+    const int firstDirtyTileX = static_cast<int>(floorf(inval.x() * invTileContentWidth));
+    const int firstDirtyTileY = static_cast<int>(floorf(inval.y() * invTileContentHeight));
+    const int lastDirtyTileX = static_cast<int>(ceilf(inval.right() * invTileContentWidth));
+    const int lastDirtyTileY = static_cast<int>(ceilf(inval.bottom() * invTileContentHeight));
+
+    // We defer marking the tile as dirty until the next time we need to prepare
+    // to draw.
+    m_invalRegion.op(firstDirtyTileX, firstDirtyTileY, lastDirtyTileX, lastDirtyTileY, SkRegion::kUnion_Op);
+    m_latestPictureInval = pictureCount;
+}
+
 void TiledPage::prepareRow(bool goingLeft, int tilesInRow, int firstTileX, int y, TileSet* set)
 {
     if (y < 0)
@@ -119,11 +139,16 @@ void TiledPage::prepareRow(bool goingLeft, int tilesInRow, int firstTileX, int y
         }
         tile = m_baseTiles.get(key);
         tile->setScale(m_scale);
-        set->add(tile);
+
+        // ensure there is a texture associated with the tile and then check to
+        // see if the texture is dirty and in need of repainting
+        tile->reserveTexture();
+        if(tile->isDirty())
+            set->add(tile);
     }
 }
 
-void TiledPage::setTileLevels(int firstTileX, int firstTileY)
+void TiledPage::updateTileState(int firstTileX, int firstTileY)
 {
     if (!m_glWebViewState)
         return;
@@ -138,6 +163,11 @@ void TiledPage::setTileLevels(int firstTileX, int firstTileY)
         if(!tile)
             continue;
 
+        // if the tile is in the dirty region then we must invalidate it
+        if (m_invalRegion.contains(tile->x(), tile->y()))
+            tile->markAsDirty(m_latestPictureInval);
+
+        // set the used level of the tile (e.g. distance from the viewport)
         int dx = 0;
         int dy = 0;
 
@@ -156,6 +186,10 @@ void TiledPage::setTileLevels(int firstTileX, int firstTileY)
         XLOG("setTileLevel tile: %x, fxy(%d, %d), level: %d", tile, firstTileX, firstTileY, d);
         tile->setUsedLevel(d);
     }
+
+    // clear the invalidated region as all tiles within that region have now
+    // been marked as dirty.
+    m_invalRegion.setEmpty();
 }
 
 void TiledPage::prepare(bool goingDown, bool goingLeft, int firstTileX, int firstTileY)
@@ -163,10 +197,13 @@ void TiledPage::prepare(bool goingDown, bool goingLeft, int firstTileX, int firs
     if (!m_glWebViewState)
         return;
 
+    // update the tiles distance from the viewport
+    updateTileState(firstTileX, firstTileY);
+
     int nbTilesWidth = m_glWebViewState->nbTilesWidth();
     int nbTilesHeight = m_glWebViewState->nbTilesHeight();
 
-    TileSet* highResSet = new TileSet(m_id, firstTileX, firstTileY, nbTilesHeight, nbTilesWidth);
+    TileSet* highResSet = new TileSet(this, nbTilesHeight, nbTilesWidth);
 
     // We chose to display tiles depending on the scroll direction:
     if (goingDown) {
@@ -178,23 +215,6 @@ void TiledPage::prepare(bool goingDown, bool goingLeft, int firstTileX, int firs
             prepareRow(goingLeft, nbTilesWidth, firstTileX, startingTileY - i, highResSet);
     }
 
-    // update the tiles distance from the viewport
-    setTileLevels(firstTileX, firstTileY);
-
-
-#ifdef DEBUG
-    XLOG("+++ BEFORE RESERVE TEXTURES (%d x %d) at (%d, %d), TiledPage %x",
-         nbTilesWidth, nbTilesHeight, firstTileX, firstTileY, this);
-    TilesManager::instance()->printTextures();
-#endif // DEBUG
-    highResSet->reserveTextures();
-
-#ifdef DEBUG
-    TilesManager::instance()->printTextures();
-    XLOG("--- AFTER RESERVE TEXTURES (%d x %d) at (%d, %d), TiledPage %x",
-         nbTilesWidth, nbTilesHeight, firstTileX, firstTileY, this);
-#endif // DEBUG
-
     // schedulePaintForTileSet will take ownership of the highResSet here,
     // so no delete necessary.
     TilesManager::instance()->schedulePaintForTileSet(highResSet);
@@ -213,7 +233,7 @@ bool TiledPage::ready(int firstTileX, int firstTileY)
             int x = j + firstTileX;
             int y = i + firstTileY;
             BaseTile* t = getBaseTile(x, y);
-            if (!t || !t->isBitmapReady())
+            if (!t || !t->isTileReady())
                 return false;
         }
     }
@@ -260,10 +280,11 @@ void TiledPage::draw(float transparency, SkRect& viewport, int firstTileX, int f
 #endif // DEBUG
 }
 
-void TiledPage::paintBaseLayerContent(SkCanvas* canvas)
+int TiledPage::paintBaseLayerContent(SkCanvas* canvas)
 {
     if (m_glWebViewState)
-        m_glWebViewState->paintBaseLayerContent(canvas);
+        return m_glWebViewState->paintBaseLayerContent(canvas);
+    return 0;
 }
 
 TiledPage* TiledPage::sibling()
index 8be2361..62756ff 100644 (file)
 
 #include "BaseTile.h"
 #include "SkCanvas.h"
+#include "SkRegion.h"
 #include "TileSet.h"
 
 namespace WebCore {
 
 class GLWebViewState;
+class IntRect;
 
 typedef std::pair<int, int> TileKey;
 typedef HashMap<TileKey, BaseTile*> TileMap;
@@ -68,15 +70,17 @@ public:
     void draw(float transparency, SkRect& viewport, int firstTileX, int firstTileY);
 
     // used by individual tiles to generate the bitmap for their tile
-    void paintBaseLayerContent(SkCanvas*);
+    int paintBaseLayerContent(SkCanvas*);
     // used by individual tiles to get the information about the current picture
     GLWebViewState* glWebViewState() { return m_glWebViewState; }
 
     float scale() const { return m_scale; }
     void setScale(float scale) { m_scale = scale; m_invScale = 1 / scale; }
 
+    void invalidateRect(const IntRect& invalRect, const int pictureCount);
+
 private:
-    void setTileLevels(int firstTileX, int firstTileY);
+    void updateTileState(int firstTileX, int firstTileY);
     void prepareRow(bool goingLeft, int tilesInRow, int firstTileX, int y, TileSet* set);
 
     BaseTile* getBaseTile(int x, int y);
@@ -86,6 +90,13 @@ private:
     float m_scale;
     float m_invScale;
     GLWebViewState* m_glWebViewState;
+
+    // used to identify the tiles that have been invalidated (marked dirty) since
+    // the last time updateTileState() has been called. The region is stored in
+    // terms of the (x,y) coordinates used to determine the location of the tile
+    // within the page, not in content/view pixel coordinates.
+    SkRegion m_invalRegion;
+    int m_latestPictureInval;
 };
 
 } // namespace WebCore
index 54ca9ad..9ebfe02 100644 (file)
@@ -136,8 +136,7 @@ void TilesManager::paintTexturesDefault()
 #else
             canvas->drawARGB(255, 255, 255, 255);
 #endif // DEBUG
-            PaintingInfo info;
-            texture->producerUpdate(0, textureInfo, info);
+            texture->producerUpdate(textureInfo);
         }
     }
 }
@@ -186,9 +185,9 @@ BackedDoubleBufferedTexture* TilesManager::getAvailableTexture(BaseTile* owner)
         }
     }
     if (farthestTexture && farthestTexture->acquire(owner)) {
-        farthestTexture->setUsedLevel(0);
         XLOG("farthest texture, getAvailableTexture(%x) => texture %x (level %d)",
              owner, farthestTexture, farthestTexture->usedLevel());
+        farthestTexture->setUsedLevel(0);
         return farthestTexture;
     }