OSDN Git Service

Enable double buffering via base tiles
authorChris Craik <ccraik@google.com>
Mon, 29 Aug 2011 02:15:00 +0000 (19:15 -0700)
committerChris Craik <ccraik@google.com>
Fri, 2 Sep 2011 23:12:04 +0000 (16:12 -0700)
bug:2522049
allocate textures and tiles using the gldraw count when they were most recently
prepared

remaining issues:
-layers still flicker (presumably from texture stealing)
-layers aren't double buffered yet

Change-Id: Iccdf68326d7d476269d4e3a13903aaab249ee92d

19 files changed:
Source/WebCore/platform/graphics/android/BaseLayerAndroid.cpp
Source/WebCore/platform/graphics/android/BaseLayerAndroid.h
Source/WebCore/platform/graphics/android/BaseTile.cpp
Source/WebCore/platform/graphics/android/BaseTile.h
Source/WebCore/platform/graphics/android/BaseTileTexture.cpp
Source/WebCore/platform/graphics/android/BaseTileTexture.h
Source/WebCore/platform/graphics/android/GLWebViewState.cpp
Source/WebCore/platform/graphics/android/GLWebViewState.h
Source/WebCore/platform/graphics/android/PaintTileOperation.cpp
Source/WebCore/platform/graphics/android/PaintTileOperation.h
Source/WebCore/platform/graphics/android/TextureOwner.h
Source/WebCore/platform/graphics/android/TiledPage.cpp
Source/WebCore/platform/graphics/android/TiledPage.h
Source/WebCore/platform/graphics/android/TiledTexture.cpp
Source/WebCore/platform/graphics/android/TilesManager.cpp
Source/WebCore/platform/graphics/android/TilesManager.h
Source/WebCore/platform/graphics/android/TilesProfiler.cpp
Source/WebCore/platform/graphics/android/TransferQueue.cpp
Source/WebKit/android/jni/PictureSet.cpp

index ca679fb..573ad6b 100644 (file)
 #include <wtf/CurrentTime.h>
 #endif // USE(ACCELERATED_COMPOSITING)
 
-#ifdef DEBUG
-
 #include <cutils/log.h>
 #include <wtf/text/CString.h>
 
+#undef XLOGC
+#define XLOGC(...) android_printLog(ANDROID_LOG_DEBUG, "BaseLayerAndroid", __VA_ARGS__)
+
+#ifdef DEBUG
+
 #undef XLOG
 #define XLOG(...) android_printLog(ANDROID_LOG_DEBUG, "BaseLayerAndroid", __VA_ARGS__)
 
@@ -57,8 +60,9 @@ using namespace android;
 
 BaseLayerAndroid::BaseLayerAndroid()
 #if USE(ACCELERATED_COMPOSITING)
-    : m_glWebViewState(0),
-      m_color(Color::white)
+    : m_glWebViewState(0)
+    , m_color(Color::white)
+    , m_scrollState(NotScrolling)
 #endif
 {
 #ifdef DEBUG_COUNT
@@ -113,7 +117,7 @@ void BaseLayerAndroid::drawCanvas(SkCanvas* canvas)
 
 #if USE(ACCELERATED_COMPOSITING)
 bool BaseLayerAndroid::drawBasePictureInGL(SkRect& viewport, float scale,
-                                           double currentTime, bool* pagesSwapped)
+                                           double currentTime, bool* buffersSwappedPtr)
 {
     ZoomManager* zoomManager = m_glWebViewState->zoomManager();
 
@@ -126,94 +130,109 @@ bool BaseLayerAndroid::drawBasePictureInGL(SkRect& viewport, float scale,
 
     // Query the resulting state from the zoom manager
     bool prepareNextTiledPage = zoomManager->needPrepareNextTiledPage();
-    bool zooming = zoomManager->zooming();
 
     // Display the current page
     TiledPage* tiledPage = m_glWebViewState->frontPage();
     TiledPage* nextTiledPage = m_glWebViewState->backPage();
     tiledPage->setScale(zoomManager->currentScale());
 
-    // Let's prepare the page if needed
+    // Let's prepare the page if needed so that it will start painting
     if (prepareNextTiledPage) {
         nextTiledPage->setScale(scale);
         m_glWebViewState->setFutureViewport(viewportTileBounds);
         m_glWebViewState->lockBaseLayerUpdate();
-        nextTiledPage->prepare(goingDown, goingLeft, viewportTileBounds, TiledPage::kVisibleBounds);
+        nextTiledPage->updateTileState(viewportTileBounds);
+        nextTiledPage->prepare(goingDown, goingLeft, viewportTileBounds,
+                               TiledPage::VisibleBounds);
         // Cancel pending paints for the foreground page
         TilesManager::instance()->removePaintOperationsForPage(tiledPage, false);
     }
 
     // If we fired a request, let's check if it's ready to use
     if (zoomManager->didFireRequest()) {
-        if (nextTiledPage->ready(viewportTileBounds, zoomManager->futureScale()))
+        if (nextTiledPage->swapBuffersIfReady(viewportTileBounds,
+                                              zoomManager->futureScale(),
+                                              TiledPage::SwapWholePage))
             zoomManager->setReceivedRequest(); // transition to received request state
     }
 
     float transparency = 1;
-    bool doSwap = false;
+    bool doZoomPageSwap = false;
 
     // If the page is ready, display it. We do a short transition between
     // the two pages (current one and future one with the new scale factor)
     if (zoomManager->didReceivedRequest()) {
         float nextTiledPageTransparency = 1;
-        zoomManager->processTransition(currentTime, scale, &doSwap,
+        zoomManager->processTransition(currentTime, scale, &doZoomPageSwap,
                                        &nextTiledPageTransparency, &transparency);
         nextTiledPage->draw(nextTiledPageTransparency, viewportTileBounds);
     }
 
     const SkIRect& preZoomBounds = m_glWebViewState->preZoomBounds();
 
-    bool needsRedraw = false;
-
-    static bool waitOnScrollFinish = false;
-
-    if (m_glWebViewState->isScrolling()) {
-        if (!waitOnScrollFinish) {
-            waitOnScrollFinish = true;
-
-            //started scrolling, lock updates
-            m_glWebViewState->lockBaseLayerUpdate();
-        }
-    } else {
-        // wait until all tiles are rendered before anything else
-        if (waitOnScrollFinish) {
-            //wait for the page to finish rendering, then go into swap mode
-            if (tiledPage->ready(preZoomBounds, zoomManager->currentScale())) {
-                m_glWebViewState->resetFrameworkInval();
-                m_glWebViewState->unlockBaseLayerUpdate();
-                waitOnScrollFinish = false;
-            }
-            //should be prepared, simply draw
-        }
-
-        if (!waitOnScrollFinish) {
-            //completed page post-scroll
-            if (!tiledPage->ready(preZoomBounds, zoomManager->currentScale())) {
-                m_glWebViewState->lockBaseLayerUpdate();
+    // update scrolling state machine by querying glwebviewstate - note that the
+    // NotScrolling state is only set below
+    if (m_glWebViewState->isScrolling())
+        m_scrollState = Scrolling;
+    else if (m_scrollState == Scrolling)
+        m_scrollState = ScrollingFinishPaint;
+
+    bool scrolling = m_scrollState != NotScrolling;
+    bool zooming = ZoomManager::kNoScaleRequest != zoomManager->scaleRequestState();
+
+    // When we aren't zooming, we should TRY and swap tile buffers if they're
+    // ready. When scrolling, we swap whatever's ready. Otherwise, buffer until
+    // the entire page is ready and then swap.
+    bool buffersSwapped = false;
+    if (!zooming) {
+        TiledPage::SwapMethod swapMethod;
+        if (scrolling)
+            swapMethod = TiledPage::SwapWhateverIsReady;
+        else
+            swapMethod = TiledPage::SwapWholePage;
+
+        buffersSwapped = tiledPage->swapBuffersIfReady(preZoomBounds,
+                                                       zoomManager->currentScale(),
+                                                       swapMethod);
+
+        if (buffersSwappedPtr && buffersSwapped)
+            *buffersSwappedPtr = true;
+        if (buffersSwapped) {
+            if (m_scrollState == ScrollingFinishPaint) {
+                m_scrollState = NotScrolling;
+                scrolling = false;
             }
         }
     }
 
-    if (!prepareNextTiledPage || tiledPage->ready(preZoomBounds, zoomManager->currentScale()))
-        tiledPage->prepare(goingDown, goingLeft, preZoomBounds, TiledPage::kExpandedBounds);
-    tiledPage->draw(transparency, preZoomBounds);
-
-    if (zoomManager->scaleRequestState() != ZoomManager::kNoScaleRequest
-        || !tiledPage->ready(preZoomBounds, zoomManager->currentScale()))
-        needsRedraw = true;
-
-    if (doSwap) {
+    if (doZoomPageSwap) {
         zoomManager->setCurrentScale(scale);
         m_glWebViewState->swapPages();
-        if (pagesSwapped)
-            *pagesSwapped = true;
+        if (buffersSwappedPtr)
+            *buffersSwappedPtr = true;
     }
 
-    // if no longer trailing behind invalidates, unlock (so invalidates can
-    // go directly to the the TiledPages without deferral)
-    if (!needsRedraw && !waitOnScrollFinish)
+    // If stuff is happening such that we need a redraw, lock updates to the
+    // base layer, and only then start painting.
+    bool needsRedraw = scrolling || zooming || !buffersSwapped;
+    if (needsRedraw)
+        m_glWebViewState->lockBaseLayerUpdate();
+    else
         m_glWebViewState->unlockBaseLayerUpdate();
 
+    XLOG("scrolling %d, zooming %d, buffersSwapped %d, needsRedraw %d",
+         scrolling, zooming, buffersSwapped, needsRedraw);
+
+    tiledPage->updateTileState(preZoomBounds);
+
+    // Only paint new textures if the base layer has been locked, but not if
+    // we're zooming since the new tiles won't be relevant soon anyway
+    if (needsRedraw && !zooming)
+        tiledPage->prepare(goingDown, goingLeft, preZoomBounds,
+                           TiledPage::ExpandedBounds);
+
+    tiledPage->draw(transparency, preZoomBounds);
+
     m_glWebViewState->paintExtras();
     return needsRedraw;
 }
@@ -221,13 +240,13 @@ bool BaseLayerAndroid::drawBasePictureInGL(SkRect& viewport, float scale,
 
 bool BaseLayerAndroid::drawGL(double currentTime, LayerAndroid* compositedRoot,
                               IntRect& viewRect, SkRect& visibleRect, float scale,
-                              bool* pagesSwapped)
+                              bool* buffersSwappedPtr)
 {
     bool needsRedraw = false;
 #if USE(ACCELERATED_COMPOSITING)
 
     needsRedraw = drawBasePictureInGL(visibleRect, scale, currentTime,
-                                      pagesSwapped);
+                                      buffersSwappedPtr);
 
     if (!needsRedraw)
         m_glWebViewState->resetFrameworkInval();
index 35ce24c..a42a372 100644 (file)
@@ -38,6 +38,12 @@ namespace WebCore {
 class BaseLayerAndroid : public Layer {
 
 public:
+    enum ScrollState {
+        NotScrolling = 0,
+        Scrolling = 1,
+        ScrollingFinishPaint = 2
+    };
+
     BaseLayerAndroid();
     virtual ~BaseLayerAndroid();
 
@@ -56,12 +62,12 @@ public:
     void drawCanvas(SkCanvas* canvas);
 
     bool drawGL(double currentTime, LayerAndroid* compositedRoot, IntRect& rect,
-                SkRect& viewport, float scale, bool* pagesSwapped);
+                SkRect& viewport, float scale, bool* buffersSwappedPtr);
     void swapExtra(BaseLayerAndroid* base) { m_extra.swap(base->m_extra); }
 private:
 #if USE(ACCELERATED_COMPOSITING)
     bool drawBasePictureInGL(SkRect& viewport, float scale, double currentTime,
-                             bool* pagesSwapped);
+                             bool* buffersSwappedPtr);
 
     GLWebViewState* m_glWebViewState;
     android::Mutex m_drawLock;
@@ -70,6 +76,8 @@ private:
     android::PictureSet m_content;
     SkPicture m_extra;
     SkRect m_previousVisible;
+
+    ScrollState m_scrollState;
 };
 
 } // namespace WebCore
index 2963ca7..0a87ffe 100644 (file)
@@ -59,15 +59,16 @@ BaseTile::BaseTile(bool isLayerTile)
     , m_x(-1)
     , m_y(-1)
     , m_page(0)
-    , m_usedLevel(-1)
-    , m_texture(0)
+    , m_frontTexture(0)
+    , m_backTexture(0)
     , m_scale(1)
     , m_dirty(true)
     , m_repaintPending(false)
-    , m_usable(true)
     , m_lastDirtyPicture(0)
     , m_isTexturePainted(false)
     , m_isLayerTile(isLayerTile)
+    , m_isSwapNeeded(false)
+    , m_drawCount(0)
 {
 #ifdef DEBUG_COUNT
     ClassTracker::instance()->increment("BaseTile");
@@ -91,9 +92,10 @@ BaseTile::BaseTile(bool isLayerTile)
 
 BaseTile::~BaseTile()
 {
-    setUsedLevel(-1);
-    if (m_texture)
-        m_texture->release(this);
+    if (m_backTexture)
+        m_backTexture->release(this);
+    if (m_frontTexture)
+        m_frontTexture->release(this);
 
     delete m_renderer;
     delete[] m_dirtyArea;
@@ -119,6 +121,7 @@ void BaseTile::setContents(TilePainter* painter, int x, int y, float scale)
     m_x = x;
     m_y = y;
     m_scale = scale;
+    m_drawCount = TilesManager::instance()->getDrawGLCount();
 }
 
 void BaseTile::reserveTexture()
@@ -126,22 +129,30 @@ void BaseTile::reserveTexture()
     BaseTileTexture* texture = TilesManager::instance()->getAvailableTexture(this);
 
     android::AutoMutex lock(m_atomicSync);
-    if (texture && m_texture != texture) {
-        m_isTexturePainted = false;
-        fullInval();
+    if (texture && m_backTexture != texture) {
+        m_isSwapNeeded = false; // no longer ready to swap
+        m_backTexture = texture;
+
+        // this is to catch when the front texture is stolen from beneath us. We
+        // should refine the stealing method to be simpler, and not require last
+        // moment checks like this
+        if (!m_frontTexture)
+            m_dirty = true;
     }
-    m_texture = texture;
-    if (m_texture)
-        m_texture->setUsedLevel(m_usedLevel);
 }
 
 bool BaseTile::removeTexture(BaseTileTexture* texture)
 {
-    XLOG("%x removeTexture res: %x... page %x", this, m_texture, m_page);
+    XLOG("%x removeTexture back %x front %x... page %x",
+         this, m_backTexture, m_frontTexture, m_page);
     // We update atomically, so paintBitmap() can see the correct value
     android::AutoMutex lock(m_atomicSync);
-    if (m_texture == texture)
-        m_texture = 0;
+    if (m_frontTexture == texture) {
+        m_frontTexture = 0;
+        m_dirty = true;
+    }
+    if (m_backTexture == texture)
+        m_backTexture = 0;
     return true;
 }
 
@@ -166,13 +177,6 @@ void BaseTile::markAsDirty(int unsigned pictureCount,
     m_dirty = true;
 }
 
-void BaseTile::setUsable(bool usable)
-{
-    android::AutoMutex lock(m_atomicSync);
-    m_usable = usable;
-}
-
-
 bool BaseTile::isDirty()
 {
     android::AutoMutex lock(m_atomicSync);
@@ -191,81 +195,62 @@ void BaseTile::setRepaintPending(bool pending)
     m_repaintPending = pending;
 }
 
-void BaseTile::setUsedLevel(int usedLevel)
-{
-    if (m_texture)
-        m_texture->setUsedLevel(usedLevel);
-    m_usedLevel = usedLevel;
-}
-
-int BaseTile::usedLevel()
-{
-    if (m_texture)
-        return m_texture->usedLevel();
-    return m_usedLevel;
-}
-
-
 void BaseTile::draw(float transparency, SkRect& rect, float scale)
 {
     if (m_x < 0 || m_y < 0 || m_scale != scale)
         return;
 
-    // No need to mutex protect reads of m_texture as it is only written to by
+    // No need to mutex protect reads of m_backTexture as it is only written to by
     // the consumer thread.
-    if (!m_texture) {
-        XLOG("%x on page %x (%d, %d) trying to draw, but no m_texture!", this, m_page, x(), y());
+    if (!m_frontTexture)
         return;
-    }
 
     // Early return if set to un-usable in purpose!
     m_atomicSync.lock();
-    bool usable = m_usable;
     bool isTexturePainted = m_isTexturePainted;
     m_atomicSync.unlock();
-    if (!usable) {
-        XLOG("early return at BaseTile::draw b/c tile set to unusable !");
-        return;
-    }
-    if (!isTexturePainted) {
-        XLOG("early return at BaseTile::draw b/c tile is not painted !");
+
+    if (!isTexturePainted)
         return;
-    }
 
-    TextureInfo* textureInfo = m_texture->consumerLock();
+    TextureInfo* textureInfo = m_frontTexture->consumerLock();
     if (!textureInfo) {
-        XLOG("%x (%d, %d) trying to draw, but no textureInfo!", this, x(), y());
-        m_texture->consumerRelease();
+        m_frontTexture->consumerRelease();
         return;
     }
 
-    if (m_texture->readyFor(this)) {
-        XLOG("draw tile %x : %d, %d, %.2f with texture %x", this, x(), y(), m_scale, m_texture);
+    if (m_frontTexture->readyFor(this)) {
         if (isLayerTile())
             TilesManager::instance()->shader()->drawLayerQuad(*m_painter->transform(),
-                                                              rect, m_texture->m_ownTextureId,
+                                                              rect, m_frontTexture->m_ownTextureId,
                                                               transparency, true);
         else
-            TilesManager::instance()->shader()->drawQuad(rect, m_texture->m_ownTextureId,
+            TilesManager::instance()->shader()->drawQuad(rect, m_frontTexture->m_ownTextureId,
                                                          transparency);
-    }
-    m_texture->consumerRelease();
+    } else
+        m_dirty = true;
+
+    m_frontTexture->consumerRelease();
 }
 
 bool BaseTile::isTileReady()
 {
-    if (!m_texture)
+    // Return true if the tile's most recently drawn texture is up to date
+    android::AutoMutex lock(m_atomicSync);
+    BaseTileTexture * texture = m_isSwapNeeded ? m_backTexture : m_frontTexture;
+
+    if (!texture)
         return false;
-    if (m_texture->owner() != this)
+
+    if (texture->owner() != this)
         return false;
 
-    android::AutoMutex lock(m_atomicSync);
     if (m_dirty)
         return false;
 
-    m_texture->consumerLock();
-    bool ready = m_texture->readyFor(this);
-    m_texture->consumerRelease();
+    texture->consumerLock();
+    bool ready = texture->readyFor(this);
+    texture->consumerRelease();
 
     if (ready)
         return true;
@@ -302,7 +287,7 @@ void BaseTile::paintBitmap()
     // can be updated by other threads without consequence.
     m_atomicSync.lock();
     bool dirty = m_dirty;
-    BaseTileTexture* texture = m_texture;
+    BaseTileTexture* texture = m_backTexture;
     SkRegion dirtyArea = m_dirtyArea[m_currentDirtyAreaIndex];
     float scale = m_scale;
     const int x = m_x;
@@ -320,7 +305,7 @@ void BaseTile::paintBitmap()
 
     // 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) {
+    if (texture->owner() != this) {
         texture->producerRelease();
         return;
     }
@@ -412,16 +397,13 @@ void BaseTile::paintBitmap()
         pictureCount = m_renderer->renderTiledContent(renderInfo);
     }
 
-    XLOG("%x update texture %x for tile %d, %d scale %.2f (m_scale: %.2f)", this, textureInfo, x, y, scale, m_scale);
-
     m_atomicSync.lock();
 
 #if DEPRECATED_SURFACE_TEXTURE_MODE
     texture->setTile(textureInfo, x, y, scale, painter, pictureCount);
 #endif
     texture->producerReleaseAndSwap();
-
-    if (texture == m_texture) {
+    if (texture == m_backTexture) {
         m_isTexturePainted = true;
 
         // set the fullrepaint flags
@@ -451,12 +433,43 @@ void BaseTile::paintBitmap()
             m_dirty = true;
 
         if (!m_dirty)
-            m_usable = true;
+            m_isSwapNeeded = true;
     }
 
     m_atomicSync.unlock();
 }
 
+void BaseTile::discardTextures() {
+    android::AutoMutex lock(m_atomicSync);
+    if (m_frontTexture) {
+        m_frontTexture->release(this);
+        m_frontTexture = 0;
+    }
+    if (m_backTexture) {
+        m_backTexture->release(this);
+        m_backTexture = 0;
+    }
+    m_dirty = true;
+}
+
+bool BaseTile::swapTexturesIfNeeded() {
+    android::AutoMutex lock(m_atomicSync);
+    if (m_isSwapNeeded) {
+        // discard old texture and swap the new one in its place
+        if (m_frontTexture)
+            m_frontTexture->release(this);
+
+        XLOG("%p's frontTexture was %p, now becoming %p", this, m_frontTexture, m_backTexture);
+        m_frontTexture = m_backTexture;
+        m_backTexture = 0;
+        m_isSwapNeeded = false;
+        XLOG("display texture for %d, %d front is now %p, texture is %p",
+             m_x, m_y, m_frontTexture, m_backTexture);
+        return true;
+    }
+    return false;
+}
+
 } // namespace WebCore
 
 #endif // USE(ACCELERATED_COMPOSITING)
index 0770b30..4c9650f 100644 (file)
@@ -68,12 +68,11 @@ public:
 
     void setContents(TilePainter* painter, int x, int y, float scale);
     void setPage(TiledPage* page) { m_page = page; }
-    bool isAvailable() const { return !m_texture; }
 
     void reserveTexture();
-    void setUsedLevel(int);
-    int usedLevel();
+
     bool isTileReady();
+
     void draw(float transparency, SkRect& rect, float scale);
 
     // the only thread-safe function called by the background thread
@@ -88,13 +87,16 @@ public:
     bool isDirty();
     bool isRepaintPending();
     void setRepaintPending(bool pending);
-    void setUsable(bool usable);
     float scale() const { return m_scale; }
     void fullInval();
 
     int x() const { return m_x; }
     int y() const { return m_y; }
-    BaseTileTexture* texture() { return m_texture; }
+    BaseTileTexture* frontTexture() { return m_frontTexture; }
+    BaseTileTexture* backTexture() { return m_backTexture; }
+    void discardTextures();
+    bool swapTexturesIfNeeded();
+    unsigned long long drawCount() { return m_drawCount; }
 
     void setGLWebViewState(GLWebViewState* state) { m_glWebViewState = state; }
 
@@ -114,15 +116,16 @@ private:
     TiledPage* m_page;
 
     // The remaining variables can be updated throughout the lifetime of the object
-    int m_usedLevel;
-    BaseTileTexture* m_texture;
+
+    BaseTileTexture* m_frontTexture;
+    BaseTileTexture* m_backTexture;
     float m_scale;
-    // used to signal that the that the tile is out-of-date and needs to be redrawn
+
+    // used to signal that the that the tile is out-of-date and needs to be
+    // redrawn in the backTexture
     bool m_dirty;
     // used to signal that a repaint is pending
     bool m_repaintPending;
-    // used to signal whether or not the draw can use this tile.
-    bool m_usable;
     // 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.
@@ -145,6 +148,12 @@ private:
     BaseRenderer* m_renderer;
 
     bool m_isLayerTile;
+    bool m_isSwapNeeded;
+
+    // the most recent GL draw before this tile was prepared. used for
+    // prioritization and caching. tiles with old drawcounts and textures they
+    // own are used for new tiles and rendering
+    unsigned long long m_drawCount;
 };
 
 } // namespace WebCore
index 7c6fb7a..9db819c 100644 (file)
@@ -52,7 +52,6 @@ namespace WebCore {
 BaseTileTexture::BaseTileTexture(uint32_t w, uint32_t h)
     : DoubleBufferedTexture(eglGetCurrentContext(),
                             TilesManager::instance()->getSharedTextureMode())
-    , m_usedLevel(-1)
     , m_owner(0)
     , m_delayedReleaseOwner(0)
     , m_delayedRelease(false)
@@ -269,10 +268,10 @@ bool BaseTileTexture::readyFor(BaseTile* baseTile)
         (info->m_inverted == TilesManager::instance()->invertedScreen()))
         return true;
 
-    XLOG("readyFor return false for tile x, y (%d %d) texId %d ,"
-         " BaseTileTexture %p, BaseTile is %p",
-         baseTile->x(), baseTile->y(), m_ownTextureId, this, baseTile);
-
+    XLOG("texture %p readyFor return false for tile x, y (%d %d) texId %d ,"
+         " BaseTileTexture %p, BaseTile is %p, SCALE %f, painter %p, inv %d",
+         this, baseTile->x(), baseTile->y(), m_ownTextureId, this, baseTile,
+         baseTile->scale(), baseTile->painter(), TilesManager::instance()->invertedScreen());
     return false;
 }
 
index bc66195..9c94a53 100644 (file)
@@ -105,15 +105,6 @@ public:
     // swaps) the texture.
     virtual void producerUpdate(TextureInfo* textureInfo, const SkBitmap& bitmap);
 
-    // The level can be one of the following values:
-    //  * -1 for an unused texture.
-    //  *  0 for the tiles intersecting with the viewport.
-    //  *  n where n > 0 for the distance between the viewport and the tile.
-    // We use this to prioritize the order in which we reclaim textures, see
-    // TilesManager::getAvailableTexture() for more information.
-    int usedLevel() { return m_usedLevel; }
-    void setUsedLevel(int used) { m_usedLevel = used; }
-
     // allows consumer thread to assign ownership of the texture to the tile. It
     // returns false if ownership cannot be transferred because the tile is busy
     bool acquire(TextureOwner* owner, bool force = false);
@@ -149,7 +140,6 @@ private:
     TextureTileInfo m_ownTextureTileInfo;
 
     SkSize m_size;
-    int m_usedLevel;
     SkBitmap::Config m_config;
     TextureOwner* m_owner;
 
index bc07925..f030e52 100644 (file)
@@ -131,8 +131,8 @@ void GLWebViewState::setBaseLayer(BaseLayerAndroid* layer, const SkRegion& inval
 {
     android::Mutex::Autolock lock(m_baseLayerLock);
     if (!layer || isPictureAfterFirstLayout) {
-        m_tiledPageA->setUsable(false);
-        m_tiledPageB->setUsable(false);
+        m_tiledPageA->discardTextures();
+        m_tiledPageB->discardTextures();
     }
     if (isPictureAfterFirstLayout) {
         m_baseLayerUpdate = true;
@@ -355,9 +355,9 @@ void GLWebViewState::swapPages()
 {
     android::Mutex::Autolock lock(m_tiledPageLock);
     m_usePageA ^= true;
-    TiledPage* working = m_usePageA ? m_tiledPageB : m_tiledPageA;
-    if (zoomManager()->swapPages())
-        TilesManager::instance()->resetTextureUsage(working);
+    TiledPage* oldPage = m_usePageA ? m_tiledPageB : m_tiledPageA;
+    zoomManager()->swapPages();
+    oldPage->discardTextures();
 }
 
 int GLWebViewState::baseContentWidth()
@@ -489,15 +489,16 @@ double GLWebViewState::setupDrawing(IntRect& viewRect, SkRect& visibleRect,
 
 bool GLWebViewState::drawGL(IntRect& rect, SkRect& viewport, IntRect* invalRect,
                             IntRect& webViewRect, int titleBarHeight,
-                            IntRect& clip, float scale, bool* pagesSwapped)
+                            IntRect& clip, float scale, bool* buffersSwappedPtr)
 {
     glFinish();
-    TilesManager::instance()->registerGLWebViewState(this);
+
     TilesManager::instance()->getProfiler()->nextFrame(viewport.fLeft,
                                                        viewport.fTop,
                                                        viewport.fRight,
                                                        viewport.fBottom,
                                                        scale);
+    TilesManager::instance()->incDrawGLCount();
 
 #ifdef DEBUG
     TilesManager::instance()->getTilesTracker()->clear();
@@ -552,7 +553,8 @@ bool GLWebViewState::drawGL(IntRect& rect, SkRect& viewport, IntRect* invalRect,
     // set up zoom manager, shaders, etc.
     m_backgroundColor = baseLayer->getBackgroundColor();
     double currentTime = setupDrawing(rect, viewport, webViewRect, titleBarHeight, clip, scale);
-    bool ret = baseLayer->drawGL(currentTime, compositedRoot, rect, viewport, scale, pagesSwapped);
+    bool ret = baseLayer->drawGL(currentTime, compositedRoot, rect,
+                                 viewport, scale, buffersSwappedPtr);
 
     glBindBuffer(GL_ARRAY_BUFFER, 0);
 
index 9bda481..a7803de 100644 (file)
@@ -212,7 +212,7 @@ public:
 
     bool drawGL(IntRect& rect, SkRect& viewport, IntRect* invalRect,
                 IntRect& webViewRect, int titleBarHeight,
-                IntRect& clip, float scale, bool* pagesSwapped);
+                IntRect& clip, float scale, bool* buffersSwappedPtr);
 
 #ifdef MEASURES_PERF
     void dumpMeasures();
index 3aac918..4366ad6 100644 (file)
@@ -73,26 +73,32 @@ void PaintTileOperation::run()
 
 int PaintTileOperation::priority()
 {
-    if (!m_tile || m_tile->usedLevel() < 0)
+    if (!m_tile)
         return -1;
 
-    // for now, use a constant value for layers,
-    // lower than the base layer tiles (as layers
-    // will always be on top of the base surface)
+    int priority;
     if (m_tile->isLayerTile())
-        return -2;
+        priority = -2;
+    else {
+        bool goingDown = m_tile->page()->scrollingDown();
+        SkIRect *rect = m_tile->page()->expandedTileBounds();
+        int firstTileX = rect->fLeft;
+        int nbTilesWidth = rect->width();
+        priority = m_tile->x() - firstTileX;
+        if (goingDown)
+            priority += (rect->fBottom - m_tile->y()) * nbTilesWidth;
+        else
+            priority += (m_tile->y() - rect->fTop) * nbTilesWidth;
+    }
 
+    if (m_tile->frontTexture()) {
+        // de-prioritize old tiles that have something visible
+        unsigned long long currentDraw = TilesManager::instance()->getDrawGLCount();
+        unsigned long long drawDelta = currentDraw - m_tile->drawCount();
+        int cappedDrawDelta = (int)std::max(drawDelta, (unsigned long long)1000);
+        priority += cappedDrawDelta * 100000;
+    }
 
-    bool goingDown = m_tile->page()->scrollingDown();
-    SkIRect *rect = m_tile->page()->expandedTileBounds();
-    int firstTileX = rect->fLeft;
-    int nbTilesWidth = rect->width();
-    int priority = m_tile->x() - firstTileX;
-    if (goingDown)
-        priority += (rect->fBottom - m_tile->y()) * nbTilesWidth;
-    else
-        priority += (m_tile->y() - rect->fTop) * nbTilesWidth;
-    priority += m_tile->usedLevel() * 100000;
     return priority;
 }
 
index 72a4125..57bbd8b 100644 (file)
@@ -39,6 +39,7 @@ public:
     virtual ~PaintTileOperation();
     virtual bool operator==(const QueuedOperation* operation);
     virtual void run();
+    // returns a rendering priority for m_tile, lower values are processed faster
     virtual int priority();
     TilePainter* painter() { return m_tile->painter(); }
     float scale() { return m_tile->scale(); }
index d0c60fb..5434dbf 100644 (file)
@@ -43,6 +43,7 @@ public:
     virtual GLWebViewState* state() = 0;
     virtual bool samePageAs(Layer* root) { return false; }
     virtual bool isRepaintPending() = 0;
+    virtual unsigned long long drawCount() = 0;
 };
 
 }
index 95603af..b6a0c47 100644 (file)
@@ -100,19 +100,20 @@ TiledPage::~TiledPage()
 
 BaseTile* TiledPage::getBaseTile(int x, int y) const
 {
+    // TODO: replace loop over array with HashMap indexing
     for (int j = 0; j < m_baseTileSize; j++) {
         BaseTile& tile = m_baseTiles[j];
-        if (tile.x() == x && tile.y() == y && !tile.isAvailable())
+        if (tile.x() == x && tile.y() == y)
             return &tile;
     }
     return 0;
 }
 
-void TiledPage::setUsable(bool usable)
+void TiledPage::discardTextures()
 {
     for (int j = 0; j < m_baseTileSize; j++) {
         BaseTile& tile = m_baseTiles[j];
-        tile.setUsable(usable);
+        tile.discardTextures();
     }
     return;
 }
@@ -163,57 +164,44 @@ void TiledPage::prepareRow(bool goingLeft, int tilesInRow, int firstTileX, int y
                 currentTile = &tile;
                 break;
             }
-            if (!availableTile && tile.isAvailable())
+
+            if (!availableTile || (tile.drawCount() < availableTile->drawCount()))
                 availableTile = &tile;
         }
 
         if (!currentTile && availableTile) {
+            XLOG("STEALING tile %d, %d (draw count %llu) for tile %d, %d",
+                  availableTile->x(), availableTile->y(), availableTile->drawCount(), x, y);
             currentTile = availableTile;
         }
 
+        if (!currentTile) {
+            XLOG("ERROR: No tile available for tile %d %d", x, y);
+        }
+
         if (currentTile) {
             currentTile->setGLWebViewState(m_glWebViewState);
-            currentTile->setContents(this, x, y, m_scale);
             currentTile->setPage(this);
 
+            currentTile->setContents(this, x, y, m_scale);
+
+            // TODO: move below (which is largely the same for layers / tiled
+            // page) into prepare() function
+
             // ensure there is a texture associated with the tile and then check to
             // see if the texture is dirty and in need of repainting
-            currentTile->reserveTexture();
-            updateTileUsedLevel(tileBounds, *currentTile);
-            if (currentTile->isDirty() && !currentTile->isRepaintPending()) {
+            if (currentTile->isDirty() || !currentTile->frontTexture())
+                currentTile->reserveTexture();
+            if (currentTile->backTexture()
+                    && currentTile->isDirty()
+                    && !currentTile->isRepaintPending()) {
                 PaintTileOperation *operation = new PaintTileOperation(currentTile);
                 TilesManager::instance()->scheduleOperation(operation);
-            } else if (currentTile->isDirty()) {
-                XLOG("Tile %dx%d is dirty, but awaiting repaint", currentTile->x(), currentTile->y());
             }
         }
     }
 }
 
-void TiledPage::updateTileUsedLevel(const SkIRect& tileBounds, BaseTile& tile)
-{
-    const int lastTileX = tileBounds.fRight - 1;
-    const int lastTileY = tileBounds.fBottom - 1;
-
-    // set the used level of the tile (e.g. distance from the viewport)
-    int dx = 0;
-    int dy = 0;
-
-    if (tileBounds.fLeft > tile.x())
-        dx = tileBounds.fLeft - tile.x();
-    else if (lastTileX < tile.x())
-        dx = tile.x() - lastTileX;
-
-    if (tileBounds.fTop > tile.y())
-        dy = tileBounds.fTop - tile.y();
-    else if (lastTileY < tile.y())
-        dy = tile.y() - lastTileY;
-
-    int d = std::max(dx, dy);
-
-    tile.setUsedLevel(d);
-}
-
 void TiledPage::updateTileState(const SkIRect& tileBounds)
 {
     if (!m_glWebViewState || tileBounds.isEmpty()) {
@@ -226,15 +214,9 @@ void TiledPage::updateTileState(const SkIRect& tileBounds)
 
         BaseTile& tile = m_baseTiles[x];
 
-        // if the tile no longer has a texture then proceed to the next tile
-        if (tile.isAvailable())
-            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, m_invalTilesRegion);
-
-        updateTileUsedLevel(tileBounds, tile);
     }
 
     // clear the invalidated region as all tiles within that region have now
@@ -266,7 +248,7 @@ void TiledPage::prepare(bool goingDown, bool goingLeft, const SkIRect& tileBound
     int nTilesToPrepare = nbTilesWidth * nbTilesHeight;
     int nMaxTilesPerPage = m_baseTileSize / 2;
 
-    if (bounds == kExpandedBounds) {
+    if (bounds == ExpandedBounds) {
         // prepare tiles outside of the visible bounds
         int expandX = m_glWebViewState->expandedTileBoundsX();
         int expandY = m_glWebViewState->expandedTileBoundsY();
@@ -296,7 +278,7 @@ void TiledPage::prepare(bool goingDown, bool goingLeft, const SkIRect& tileBound
     m_prepare = true;
 }
 
-bool TiledPage::ready(const SkIRect& tileBounds, float scale)
+bool TiledPage::swapBuffersIfReady(const SkIRect& tileBounds, float scale, SwapMethod swap)
 {
     if (!m_glWebViewState)
         return false;
@@ -307,17 +289,43 @@ bool TiledPage::ready(const SkIRect& tileBounds, float scale)
     if (m_scale != scale)
         return false;
 
-    for (int x = tileBounds.fLeft; x < tileBounds.fRight; x++) {
-        for (int y = tileBounds.fTop; y < tileBounds.fBottom; y++) {
-            BaseTile* t = getBaseTile(x, y);
-            if (!t || !t->isTileReady())
-                return false;
+    int swaps = 0;
+    if (swap == SwapWholePage) {
+        for (int x = tileBounds.fLeft; x < tileBounds.fRight; x++) {
+            for (int y = tileBounds.fTop; y < tileBounds.fBottom; y++) {
+                BaseTile* t = getBaseTile(x, y);
+                if (!t || !t->isTileReady())
+                    return false;
+            }
+        }
+        for (int x = tileBounds.fLeft; x < tileBounds.fRight; x++) {
+            for (int y = tileBounds.fTop; y < tileBounds.fBottom; y++) {
+                BaseTile* t = getBaseTile(x, y);
+                if (t->swapTexturesIfNeeded())
+                    swaps++;
+            }
         }
+        XLOG("%p whole page swapped %d textures, returning true", this, swaps);
+        return true;
+    } else { // SwapWhateveryIsReady
+        bool fullSwap = true;
+        for (int x = tileBounds.fLeft; x < tileBounds.fRight; x++) {
+            for (int y = tileBounds.fTop; y < tileBounds.fBottom; y++) {
+                BaseTile* t = getBaseTile(x, y);
+                if (!t || !t->isTileReady())
+                    fullSwap = false;
+                else {
+                    if (t->swapTexturesIfNeeded())
+                        swaps++;
+                }
+            }
+        }
+        XLOG("%p greedy swap swapped %d tiles, returning %d", this, swaps, fullSwap);
+        return fullSwap;
     }
-    m_prepare = false;
-    return true;
 }
 
+
 void TiledPage::draw(float transparency, const SkIRect& tileBounds)
 {
     if (!m_glWebViewState)
@@ -332,11 +340,13 @@ void TiledPage::draw(float transparency, const SkIRect& tileBounds)
     actualTileBounds.fLeft -= m_glWebViewState->expandedTileBoundsX();
     actualTileBounds.fRight += m_glWebViewState->expandedTileBoundsX();
 
+    actualTileBounds.fTop = std::max(0, actualTileBounds.fTop);
+    actualTileBounds.fLeft = std::max(0, actualTileBounds.fLeft);
+
     for (int j = 0; j < m_baseTileSize; j++) {
         BaseTile& tile = m_baseTiles[j];
         bool tileInView = actualTileBounds.contains(tile.x(), tile.y());
         if (tileInView) {
-
             SkRect rect;
             rect.fLeft = tile.x() * tileWidth;
             rect.fTop = tile.y() * tileHeight;
index 56a34f4..14306eb 100644 (file)
@@ -52,8 +52,12 @@ class IntRect;
 class TiledPage : public TilePainter {
 public:
     enum PrepareBounds {
-        kExpandedBounds = 0,
-        kVisibleBounds = 1
+        ExpandedBounds = 0,
+        VisibleBounds = 1
+    };
+    enum SwapMethod {
+        SwapWhateverIsReady = 0,
+        SwapWholePage = 1
     };
 
     TiledPage(int id, GLWebViewState* state);
@@ -64,8 +68,12 @@ public:
 
     // prepare the page for display on the screen
     void prepare(bool goingDown, bool goingLeft, const SkIRect& tileBounds, PrepareBounds bounds);
+    void updateTileState(const SkIRect& tileBounds);
+
     // check to see if the page is ready for display
-    bool ready(const SkIRect& tileBounds, float scale);
+
+    // swap 'buffers' by swapping each modified texture
+    bool swapBuffersIfReady(const SkIRect& tileBounds, float scale, SwapMethod swap);
     // draw the page on the screen
     void draw(float transparency, const SkIRect& tileBounds);
 
@@ -83,15 +91,13 @@ public:
     void setScale(float scale) { m_scale = scale; m_invScale = 1 / scale; }
 
     void invalidateRect(const IntRect& invalRect, const unsigned int pictureCount);
-    void setUsable(bool usable);
+    void discardTextures();
     void updateBaseTileSize();
     bool scrollingDown() { return m_scrollingDown; }
     SkIRect* expandedTileBounds() { return &m_expandedTileBounds; }
 
 private:
-    void updateTileState(const SkIRect& tileBounds);
     void prepareRow(bool goingLeft, int tilesInRow, int firstTileX, int y, const SkIRect& tileBounds);
-    void updateTileUsedLevel(const SkIRect& tileBounds, BaseTile& tile);
 
     BaseTile* getBaseTile(int x, int y) const;
 
index 1aac44d..c1fb4d1 100644 (file)
@@ -68,7 +68,6 @@ 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);
     }
@@ -130,19 +129,16 @@ void TiledTexture::prepareTile(bool repaint, int x, int y)
         tile = new BaseTile(true);
         m_tiles.append(tile);
     }
-    tile->reserveTexture();
-    if (!tile->texture())
-        return;
 
     tile->setContents(this, x, y, m_surface->scale());
-    tile->setUsedLevel(0);
 
-    bool schedule = false;
-    if (tile->isDirty())
-        schedule = true;
+    // TODO: move below (which is largely the same for layers / tiled page) into
+    // prepare() function
 
+    if (tile->isDirty() || !tile->frontTexture())
+        tile->reserveTexture();
     LayerAndroid* layer = m_surface->layer();
-    if (schedule && layer && !tile->isRepaintPending()) {
+    if (tile->backTexture() && tile->isDirty() && !tile->isRepaintPending() && layer) {
         PaintTileOperation *operation = new PaintTileOperation(tile, m_surface);
         TilesManager::instance()->scheduleOperation(operation);
     }
@@ -187,11 +183,13 @@ 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] dirty: %d", i, this, tile->painter(), tile, tile->x(), tile->y(), tile->scale(), tile->isTileReady(), tile->isDirty());
+            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->swapTexturesIfNeeded();
             tile->draw(m_surface->opacity(), rect, m_surface->scale());
 #ifdef DEBUG
-            TilesManager::instance()->getTilesTracker()->track(tile->isTileReady(), tile->texture());
+            TilesManager::instance()->getTilesTracker()->track(tile->isTileReady(), tile->backTexture());
 #endif
         }
     }
@@ -241,7 +239,9 @@ bool TiledTexture::owns(BaseTileTexture* texture)
 {
     for (unsigned int i = 0; i < m_tiles.size(); i++) {
         BaseTile* tile = m_tiles[i];
-        if (tile->texture() == texture)
+        if (tile->frontTexture() == texture)
+            return true;
+        if (tile->backTexture() == texture)
             return true;
     }
     return false;
index 57c38cf..2c263e3 100644 (file)
@@ -100,7 +100,7 @@ TilesManager::TilesManager()
     , m_showVisualIndicator(false)
     , m_invertedScreen(false)
     , m_invertedScreenSwitch(false)
-    , m_drawRegistrationCount(0)
+    , m_drawGLCount(0)
 {
     XLOG("TilesManager ctor");
     m_textures.reserveCapacity(MAX_TEXTURE_ALLOCATION);
@@ -164,27 +164,14 @@ void TilesManager::printTextures()
             x = o->x();
             y = o->y();
         }
-        XLOG("[%d] texture %x usedLevel: %d busy: %d owner: %x (%d, %d) page: %x scale: %.2f",
-               i, texture, texture->usedLevel(),
+        XLOG("[%d] texture %x  busy: %d owner: %x (%d, %d) page: %x scale: %.2f",
+               i, texture,
                texture->busy(), o, x, y, o ? o->page() : 0, o ? o->scale() : 0);
     }
     XLOG("------");
 #endif // DEBUG
 }
 
-void TilesManager::resetTextureUsage(TiledPage* page)
-{
-    android::Mutex::Autolock lock(m_texturesLock);
-    for (unsigned int i = 0; i < m_textures.size(); i++) {
-        BaseTileTexture* texture = m_textures[i];
-        TextureOwner* owner = texture->owner();
-        if (owner) {
-            if (owner->page() == page)
-                texture->setUsedLevel(-1);
-        }
-    }
-}
-
 void TilesManager::swapLayersTextures(LayerAndroid* oldTree, LayerAndroid* newTree)
 {
     if (oldTree)
@@ -227,81 +214,69 @@ BaseTileTexture* TilesManager::getAvailableTexture(BaseTile* owner)
     android::Mutex::Autolock lock(m_texturesLock);
 
     // Sanity check that the tile does not already own a texture
-    if (owner->texture() && owner->texture()->owner() == owner) {
-        owner->texture()->setUsedLevel(0);
-        XLOG("same owner (%d, %d), getAvailableTexture(%x) => texture %x",
-             owner->x(), owner->y(), owner, owner->texture());
+    if (owner->backTexture() && owner->backTexture()->owner() == owner) {
+        XLOG("same owner (%d, %d), getAvailableBackTexture(%x) => texture %x",
+             owner->x(), owner->y(), owner, owner->backTexture());
         if (owner->isLayerTile())
-            m_availableTilesTextures.remove(m_availableTilesTextures.find(owner->texture()));
+            m_availableTilesTextures.remove(m_availableTilesTextures.find(owner->backTexture()));
         else
-            m_availableTextures.remove(m_availableTextures.find(owner->texture()));
-        return owner->texture();
+            m_availableTextures.remove(m_availableTextures.find(owner->backTexture()));
+        return owner->backTexture();
     }
 
+    WTF::Vector<BaseTileTexture*>* availableTexturePool;
     if (owner->isLayerTile()) {
-        BaseTileTexture* layerTexture = 0;
-        unsigned int max = m_availableTilesTextures.size();
-        for (unsigned int i = 0; i < max; i++) {
-            BaseTileTexture* texture = m_availableTilesTextures[i];
-            if (texture->owner() && texture->owner()->isRepaintPending())
-                continue;
-            if (!texture->owner() && texture->acquire(owner)) {
-                layerTexture = texture;
-                break;
-            }
-            if (texture->usedLevel() != 0 && texture->acquire(owner)) {
-                layerTexture = texture;
-                break;
-            }
-            if (texture->scale() != owner->scale() && texture->acquire(owner)) {
-                layerTexture = texture;
-                break;
-            }
-        }
-        if (layerTexture)
-            m_availableTilesTextures.remove(m_availableTilesTextures.find(layerTexture));
-        return layerTexture;
+        availableTexturePool = &m_availableTilesTextures;
+    } else {
+        availableTexturePool = &m_availableTextures;
     }
 
     // The heuristic for selecting a texture is as follows:
-    //  1. If usedLevel == -1, break with that one
-    //  2. Otherwise, select the highest usedLevel available
-    //  3. Break ties with the lowest LRU(RecentLevel) valued GLWebViewState
+    //  1. If a tile isn't owned, break with that one
+    //  2. If we find a tile in the same page with a different scale,
+    //         it's old and not visible. Break with that one
+    //  3. Otherwise, use the least recently prepared tile
 
     BaseTileTexture* farthestTexture = 0;
-    int farthestTextureLevel = 0;
-    unsigned int lowestDrawCount = ~0; //maximum uint
-    const unsigned int max = m_availableTextures.size();
+    unsigned long long oldestDrawCount = ~0; //maximum u64
+    const unsigned int max = availableTexturePool->size();
     for (unsigned int i = 0; i < max; i++) {
-        BaseTileTexture* texture = m_availableTextures[i];
-
-        if (texture->usedLevel() == -1) { // found an unused texture, grab it
+        BaseTileTexture* texture = (*availableTexturePool)[i];
+        TextureOwner* currentOwner = texture->owner();
+        if (!currentOwner) {
             farthestTexture = texture;
             break;
         }
 
-        int textureLevel = texture->usedLevel();
-        unsigned int textureDrawCount = getGLWebViewStateDrawCount(texture->owner()->state());
+        if (currentOwner->page() == owner->page() && texture->scale() != owner->scale()) {
+            // if we render the back page with one scale, then another while
+            // still zooming, we recycle the tiles with the old scale instead of
+            // taking ones from the front page
+            farthestTexture = texture;
+            break;
+        }
 
-        // if (higher distance or equal distance but less recently rendered)
-        if (farthestTextureLevel < textureLevel
-            || ((farthestTextureLevel == textureLevel) && (lowestDrawCount > textureDrawCount))) {
+        unsigned long long textureDrawCount = currentOwner->drawCount();
+        if (oldestDrawCount > textureDrawCount) {
             farthestTexture = texture;
-            farthestTextureLevel = textureLevel;
-            lowestDrawCount = textureDrawCount;
+            oldestDrawCount = textureDrawCount;
         }
     }
 
+    TextureOwner* previousOwner = farthestTexture->owner();
     if (farthestTexture && farthestTexture->acquire(owner)) {
-        XLOG("farthest texture, getAvailableTexture(%x) => texture %x (level %d, drawCount %d)",
-             owner, farthestTexture, farthestTextureLevel, lowestDrawCount);
-        farthestTexture->setUsedLevel(0);
-        m_availableTextures.remove(m_availableTextures.find(farthestTexture));
+        if (previousOwner) {
+            XLOG("%s texture %p stolen from tile %d, %d, drawCount was %llu",
+                 owner->isLayerTile() ? "LAYER" : "BASE",
+                 farthestTexture, owner->x(), owner->y(), oldestDrawCount);
+        }
+
+        availableTexturePool->remove(availableTexturePool->find(farthestTexture));
         return farthestTexture;
     }
 
-    XLOG("Couldn't find an available texture for BaseTile %x (%d, %d) !!!",
-         owner, owner->x(), owner->y());
+    XLOG("Couldn't find an available texture for tile %x (%d, %d) out of %d available!!!",
+          owner, owner->x(), owner->y(), max);
 #ifdef DEBUG
     printTextures();
 #endif // DEBUG
@@ -362,27 +337,11 @@ float TilesManager::layerTileHeight()
     return LAYER_TILE_HEIGHT;
 }
 
-void TilesManager::registerGLWebViewState(GLWebViewState* state)
-{
-    m_glWebViewStateMap.set(state, m_drawRegistrationCount);
-    m_drawRegistrationCount++;
-    XLOG("now state %p, total of %d states", state, m_glWebViewStateMap.size());
-}
-
 void TilesManager::unregisterGLWebViewState(GLWebViewState* state)
 {
     // Discard the whole queue b/c we lost GL context already.
     // Note the real updateTexImage will still wait for the next draw.
     transferQueue()->discardQueue();
-
-    m_glWebViewStateMap.remove(state);
-    XLOG("state %p now removed, total of %d states", state, m_glWebViewStateMap.size());
-}
-
-unsigned int TilesManager::getGLWebViewStateDrawCount(GLWebViewState* state)
-{
-    XLOG("looking up state %p, contains=%s", state, m_glWebViewStateMap.contains(state) ? "TRUE" : "FALSE");
-    return m_glWebViewStateMap.find(state)->second;
 }
 
 TilesManager* TilesManager::instance()
index a383a2e..513494c 100644 (file)
@@ -108,7 +108,6 @@ public:
     static float tileHeight();
     static float layerTileWidth();
     static float layerTileHeight();
-    void registerGLWebViewState(GLWebViewState* state);
     void unregisterGLWebViewState(GLWebViewState* state);
 
     void allocateTiles();
@@ -165,6 +164,16 @@ public:
         m_shader.setContrast(contrast);
     }
 
+    void incDrawGLCount()
+    {
+        m_drawGLCount++;
+    }
+
+    unsigned long long getDrawGLCount()
+    {
+        return m_drawGLCount;
+    }
+
 private:
     TilesManager();
 
@@ -206,13 +215,9 @@ private:
 
     VideoLayerManager m_videoLayerManager;
 
-    HashMap<GLWebViewState*, unsigned int> m_glWebViewStateMap;
-    unsigned int m_drawRegistrationCount;
-
-    unsigned int getGLWebViewStateDrawCount(GLWebViewState* state);
-
     TilesProfiler m_profiler;
     TilesTracker m_tilesTracker;
+    unsigned long long m_drawGLCount;
 };
 
 } // namespace WebCore
index 653d525..0271ee3 100644 (file)
@@ -122,7 +122,7 @@ void TilesProfiler::nextTile(BaseTile& tile, float scale, bool inView)
     }
     m_records.last().append(TileProfileRecord(
                                 left, top, right, bottom,
-                                scale, isReady, tile.usedLevel()));
+                                scale, isReady, (int)tile.drawCount()));
     XLOG("adding tile %d %d %d %d, scale %f", left, top, right, bottom, scale);
 }
 
index 851d02c..b73f388 100644 (file)
@@ -113,7 +113,7 @@ bool TransferQueue::checkObsolete(int index)
         return true;
     }
 
-    BaseTileTexture* baseTileTexture = baseTilePtr->texture();
+    BaseTileTexture* baseTileTexture = baseTilePtr->backTexture();
     if (!baseTileTexture) {
         XLOG("Invalid baseTileTexture , such that the tile is obsolete");
         return true;
@@ -248,7 +248,7 @@ void TransferQueue::updateDirtyBaseTiles()
             // the queue. Then either move on to next item or copy the content.
             BaseTileTexture* destTexture = 0;
             if (!obsoleteBaseTile)
-                destTexture = m_transferQueue[index].savedBaseTilePtr->texture();
+                destTexture = m_transferQueue[index].savedBaseTilePtr->backTexture();
 
             m_sharedSurfaceTexture->updateTexImage();
 
@@ -271,9 +271,10 @@ void TransferQueue::updateDirtyBaseTiles()
             // texturesTileInfo.
             destTexture->setOwnTextureTileInfoFromQueue(&m_transferQueue[index].tileInfo);
 
-            XLOG("Blit tile x, y %d %d to destTexture->m_ownTextureId %d",
+            XLOG("Blit tile x, y %d %d with dest texture %p to destTexture->m_ownTextureId %d",
                  m_transferQueue[index].tileInfo.m_x,
                  m_transferQueue[index].tileInfo.m_y,
+                 destTexture,
                  destTexture->m_ownTextureId);
         }
         index = (index + 1) % ST_BUFFER_NUMBER;
index 3c62205..839a887 100644 (file)
@@ -155,6 +155,11 @@ void PictureSet::add(const SkRegion& area, SkPicture* picture,
 
 Bucket* PictureSet::getBucket(int x, int y)
 {
+    // only create buckets for valid, positive coordinates, ignore and return
+    // NULL otherwise
+    if (x < 0 || y < 0)
+        return 0;
+
     BucketPosition position(x+1, y+1);
     if (!mBuckets.contains(position)) {
         Bucket* bucket = new Bucket();
@@ -277,6 +282,10 @@ void PictureSet::gatherBucketsForArea(WTF::Vector<Bucket*>& list, const SkIRect&
 {
     int maxSize = BUCKET_SIZE;
 
+    XLOG("\n--- gatherBucketsForArea for rect %d, %d, %d, %d (%d x %d)",
+          rect.fLeft, rect.fTop, rect.fRight, rect.fBottom,
+          rect.width(), rect.height());
+
     int x = rect.fLeft;
     int y = rect.fTop;
     int firstTileX = rect.fLeft / maxSize;
@@ -288,7 +297,8 @@ void PictureSet::gatherBucketsForArea(WTF::Vector<Bucket*>& list, const SkIRect&
         for (int j = firstTileY; j <= lastTileY; j++) {
             Bucket* bucket = getBucket(i, j);
             XLOG("gather bucket %x for %d, %d", bucket, i+1, j+1);
-            list.append(bucket);
+            if (bucket)
+                list.append(bucket);
         }
     }
 }
@@ -319,6 +329,9 @@ void PictureSet::splitAdd(const SkIRect& rect)
     for (int i = firstTileX; i <= lastTileX; i++) {
         for (int j = firstTileY; j <= lastTileY; j++) {
             Bucket* bucket = getBucket(i, j);
+            if (!bucket)
+                continue;
+
             SkIRect newRect;
             int deltaX = i * maxSize;
             int deltaY = j * maxSize;
@@ -442,8 +455,10 @@ void PictureSet::add(const SkRegion& area, SkPicture* picture,
     Pictures pictureAndBounds = {collect, 0, collect.getBounds(),
         elapsed, split, false, false, empty};
 
+#ifdef FAST_PICTURESET
     if (mPictures.size() == 0)
         checkForNewBases = true;
+#endif
 
     mPictures.append(pictureAndBounds);
     mAdditionalArea += totalArea.width() * totalArea.height();