OSDN Git Service

Implement dual textures for layers to handle zooming correctly.
authorNicolas Roard <nicolasroard@google.com>
Thu, 20 Oct 2011 22:55:34 +0000 (15:55 -0700)
committerNicolas Roard <nicolasroard@google.com>
Thu, 20 Oct 2011 23:47:41 +0000 (16:47 -0700)
We add a new class, DualTiledTexture, that encapsulate two TiledTextures
and manage them according to the current scale factor.

bug:5492874

Change-Id: I4ba3ff539f9242ae5102189e9623e1535e9cc28f

Source/WebCore/platform/graphics/android/GLWebViewState.cpp
Source/WebCore/platform/graphics/android/GLWebViewState.h
Source/WebCore/platform/graphics/android/PaintTileOperation.h
Source/WebCore/platform/graphics/android/PaintedSurface.cpp
Source/WebCore/platform/graphics/android/PaintedSurface.h
Source/WebCore/platform/graphics/android/TiledTexture.cpp
Source/WebCore/platform/graphics/android/TiledTexture.h
Source/WebCore/platform/graphics/android/TilesManager.cpp

index 2d7b177..300573c 100644 (file)
@@ -86,6 +86,7 @@ GLWebViewState::GLWebViewState(android::Mutex* buttonMutex)
     , m_goingLeft(false)
     , m_expandedTileBoundsX(0)
     , m_expandedTileBoundsY(0)
+    , m_scale(1)
 {
     m_viewport.setEmpty();
     m_futureViewportTileBounds.setEmpty();
@@ -394,6 +395,7 @@ bool GLWebViewState::drawGL(IntRect& rect, SkRect& viewport, IntRect* invalRect,
                             IntRect& webViewRect, int titleBarHeight,
                             IntRect& clip, float scale, bool* buffersSwappedPtr)
 {
+    m_scale = scale;
     TilesManager::instance()->getProfiler()->nextFrame(viewport.fLeft,
                                                        viewport.fTop,
                                                        viewport.fRight,
index 23d7de2..0bc1209 100644 (file)
@@ -231,6 +231,8 @@ public:
     int expandedTileBoundsX() { return m_expandedTileBoundsX; }
     int expandedTileBoundsY() { return m_expandedTileBoundsY; }
 
+    float scale() { return m_scale; }
+
 private:
     void inval(const IntRect& rect); // caller must hold m_baseLayerLock
     void invalRegion(const SkRegion& region);
@@ -274,6 +276,8 @@ private:
 
     int m_expandedTileBoundsX;
     int m_expandedTileBoundsY;
+
+    float m_scale;
 };
 
 } // namespace WebCore
index 57bbd8b..65d20f2 100644 (file)
@@ -52,17 +52,20 @@ private:
 
 class ScaleFilter : public OperationFilter {
 public:
-    ScaleFilter(float scale) : m_scale(scale) {}
+    ScaleFilter(TilePainter* painter, float scale)
+        : m_painter(painter)
+        , m_scale(scale) {}
     virtual bool check(QueuedOperation* operation)
     {
         if (operation->type() == QueuedOperation::PaintTile) {
             PaintTileOperation* op = static_cast<PaintTileOperation*>(operation);
-            if (op->scale() != m_scale)
+            if ((op->painter() == m_painter) && (op->scale() != m_scale))
                 return true;
         }
         return false;
     }
 private:
+    TilePainter* m_painter;
     float m_scale;
 };
 
index c5ed38c..0957c0c 100644 (file)
@@ -68,7 +68,7 @@ PaintedSurface::PaintedSurface(LayerAndroid* layer)
 #ifdef DEBUG_COUNT
     ClassTracker::instance()->increment("PaintedSurface");
 #endif
-    m_tiledTexture = new TiledTexture(this);
+    m_tiledTexture = new DualTiledTexture(this);
     if (layer && layer->picture())
         m_updateManager.updatePicture(layer->picture());
 }
@@ -142,7 +142,6 @@ void PaintedSurface::prepare(GLWebViewState* state)
          m_layer->uniqueId(), m_layer,
          m_layer->getScale());
 
-    float scale = m_layer->getScale();
     int w = m_layer->getSize().width();
     int h = m_layer->getSize().height();
 
@@ -154,13 +153,13 @@ void PaintedSurface::prepare(GLWebViewState* state)
 
     computeVisibleArea();
 
-    if (scale != m_scale)
-        m_scale = scale;
+    m_scale = state->scale();
 
-    XLOG("layer %d %x prepared at size (%d, %d) @ scale %.2f", m_layer->uniqueId(),
-         m_layer, w, h, scale);
+    XLOGC("%x layer %d %x prepared at size (%d, %d) @ scale %.2f", this, m_layer->uniqueId(),
+         m_layer, w, h, m_scale);
 
-    m_tiledTexture->prepare(state, m_pictureUsed != m_layer->pictureUsed(), startFastSwap);
+    m_tiledTexture->prepare(state, m_scale, m_pictureUsed != m_layer->pictureUsed(),
+                            startFastSwap, m_visibleArea);
 }
 
 bool PaintedSurface::draw()
index 5df76db..761be74 100644 (file)
@@ -75,13 +75,12 @@ public:
     float scale() { return m_scale; }
     float opacity();
     unsigned int pictureUsed() { return m_pictureUsed; }
-    TiledTexture* texture() { return m_tiledTexture; }
 
 private:
     UpdateManager m_updateManager;
 
     LayerAndroid* m_layer;
-    TiledTexture* m_tiledTexture;
+    DualTiledTexture* m_tiledTexture;
 
     IntRect m_area;
     IntRect m_visibleArea;
index ce4dc7f..87996ab 100644 (file)
 
 namespace WebCore {
 
-void TiledTexture::prepare(GLWebViewState* state, bool repaint, bool startFastSwap)
+bool TiledTexture::ready() {
+    bool tilesAllReady = true;
+    bool tilesVisible = false;
+    for (unsigned int i = 0; i < m_tiles.size(); i++) {
+        BaseTile* tile = m_tiles[i];
+        if (tile->isTileVisible(m_area) && !tile->isTileReady()) {
+            tilesAllReady = false;
+            break;
+        }
+        if (tile->isTileVisible(m_area))
+            tilesVisible = true;
+    }
+    // For now, if no textures are available, consider ourselves as ready
+    // in order to unblock the zooming process.
+    // FIXME: have a better system -- maybe keeping the last scale factor
+    // able to fully render everything
+    return !TilesManager::instance()->layerTexturesRemain()
+           || (tilesAllReady && tilesVisible);
+}
+
+void TiledTexture::prepare(GLWebViewState* state, float scale, bool repaint,
+                           bool startFastSwap, IntRect& visibleArea)
 {
     if (!m_surface)
         return;
@@ -63,11 +84,10 @@ void TiledTexture::prepare(GLWebViewState* state, bool repaint, bool startFastSw
         return;
 
     // first, how many tiles do we need
-    IntRect visibleArea = m_surface->visibleArea();
-    IntRect area(visibleArea.x() * m_surface->scale(),
-                 visibleArea.y() * m_surface->scale(),
-                 ceilf(visibleArea.width() * m_surface->scale()),
-                 ceilf(visibleArea.height() * m_surface->scale()));
+    IntRect area(visibleArea.x() * scale,
+                 visibleArea.y() * scale,
+                 ceilf(visibleArea.width() * scale),
+                 ceilf(visibleArea.height() * scale));
 
     if (area.width() == 0 && area.height() == 0) {
         m_area.setWidth(0);
@@ -85,8 +105,8 @@ void TiledTexture::prepare(GLWebViewState* state, bool repaint, bool startFastSw
     m_area.setWidth(ceilf(right) - m_area.x());
     m_area.setHeight(ceilf(bottom) - m_area.y());
 
-    XLOG("for TiledTexture %p, we have a visible area of %d, %d - %d x %d, corresponding to %d, %d x - %d x %d tiles",
-         this,
+    XLOG("for TiledTexture %p, we prepare with scale %.2f, have a visible area of %d, %d - %d x %d, corresponding to %d, %d x - %d x %d tiles",
+         this, scale,
          visibleArea.x(), visibleArea.y(),
          visibleArea.width(), visibleArea.height(),
          m_area.x(), m_area.y(),
@@ -95,20 +115,13 @@ void TiledTexture::prepare(GLWebViewState* state, bool repaint, bool startFastSw
     bool goingDown = m_prevTileY < m_area.y();
     m_prevTileY = m_area.y();
 
-    if (m_surface->scale() != m_prevScale)
-        TilesManager::instance()->removeOperationsForFilter(new ScaleFilter(m_surface->scale()));
+    if (scale != m_scale)
+        TilesManager::instance()->removeOperationsForFilter(new ScaleFilter(this, scale));
 
-    m_prevScale = m_surface->scale();
+    m_scale = scale;
 
     // unlock if tiles all ready
-    bool tilesAllReady = true;
-    for (unsigned int i = 0; i < m_tiles.size(); i++) {
-        BaseTile* tile = m_tiles[i];
-        if (tile->isTileVisible(m_area) && !tile->isTileReady()) {
-            tilesAllReady = false;
-            break;
-        }
-    }
+    bool tilesAllReady = ready();
 
     // startFastSwap=true will swap all ready tiles each
     // frame until all visible tiles are up to date
@@ -173,7 +186,7 @@ void TiledTexture::prepareTile(bool repaint, int x, int y)
     }
 
     XLOG("preparing tile %p, painter is this %p", tile, this);
-    tile->setContents(this, x, y, m_surface->scale());
+    tile->setContents(this, x, y, m_scale);
 
     // TODO: move below (which is largely the same for layers / tiled page) into
     // prepare() function
@@ -210,10 +223,9 @@ bool TiledTexture::draw()
     TilesManager::instance()->getTilesTracker()->trackVisibleLayer();
 #endif
 
-    float m_invScale = 1 / m_surface->scale();
+    float m_invScale = 1 / m_scale;
     const float tileWidth = TilesManager::layerTileWidth() * m_invScale;
     const float tileHeight = TilesManager::layerTileHeight() * m_invScale;
-    XLOG("draw tile %x, tiles %d", this, m_tiles.size());
 
     bool askRedraw = false;
     for (unsigned int i = 0; i < m_tiles.size(); i++) {
@@ -226,10 +238,10 @@ 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",
+            XLOG(" - [%d], { painter %x vs %x }, tile %x %d,%d at scale %.2f vs %.2f [ready: %d] dirty: %d",
                  i, this, tile->painter(), tile, tile->x(), tile->y(),
-                 tile->scale(), tile->isTileReady(), tile->isDirty());
-            tile->draw(m_surface->opacity(), rect, m_surface->scale());
+                 tile->scale(), m_scale, tile->isTileReady(), tile->isDirty());
+            tile->draw(m_surface->opacity(), rect, m_scale);
 #ifdef DEBUG
             TilesManager::instance()->getTilesTracker()->track(tile->isTileReady(), tile->backTexture());
 #endif
@@ -260,6 +272,13 @@ void TiledTexture::removeTiles()
     for (unsigned int i = 0; i < m_tiles.size(); i++) {
         delete m_tiles[i];
     }
+    m_tiles.clear();
+}
+
+void TiledTexture::discardTextures()
+{
+    for (unsigned int i = 0; i < m_tiles.size(); i++)
+        m_tiles[i]->discardTextures();
 }
 
 bool TiledTexture::owns(BaseTileTexture* texture)
@@ -274,4 +293,80 @@ bool TiledTexture::owns(BaseTileTexture* texture)
     return false;
 }
 
+DualTiledTexture::DualTiledTexture(PaintedSurface* surface)
+{
+    m_textureA = new TiledTexture(surface);
+    m_textureB = new TiledTexture(surface);
+    m_frontTexture = m_textureA;
+    m_backTexture = m_textureB;
+    m_scale = -1;
+    m_futureScale = -1;
+    m_zooming = false;
+}
+
+DualTiledTexture::~DualTiledTexture()
+{
+    delete m_textureA;
+    delete m_textureB;
+}
+
+void DualTiledTexture::prepare(GLWebViewState* state, float scale, bool repaint,
+                               bool startFastSwap, IntRect& visibleArea)
+{
+    // If we are zooming, we will use the previously used area, to prevent the
+    // frontTexture to try to allocate more tiles than what it has already
+    if (!m_zooming)
+        m_preZoomVisibleArea = visibleArea;
+
+    if (m_futureScale != scale) {
+        m_futureScale = scale;
+        m_zoomUpdateTime = WTF::currentTime() + DualTiledTexture::s_zoomUpdateDelay;
+        m_zooming = true;
+    }
+
+    XLOG("\n*** %x Drawing with scale %.2f, futureScale: %.2f, zooming: %d",
+          this, scale, m_futureScale, m_zooming);
+
+    if (m_scale > 0)
+        m_frontTexture->prepare(state, m_scale, repaint, startFastSwap, m_preZoomVisibleArea);
+
+    // If we had a scheduled update
+    if (m_zooming && m_zoomUpdateTime < WTF::currentTime()) {
+        m_backTexture->prepare(state, m_futureScale, repaint, startFastSwap, visibleArea);
+        if (m_backTexture->ready()) {
+            swap();
+            m_zooming = false;
+        }
+    }
+}
+
+void DualTiledTexture::swap()
+{
+    m_frontTexture = m_frontTexture == m_textureA ? m_textureB : m_textureA;
+    m_backTexture = m_backTexture == m_textureA ? m_textureB : m_textureA;
+    m_scale = m_futureScale;
+    m_backTexture->discardTextures();
+}
+
+bool DualTiledTexture::draw()
+{
+    bool needsRepaint = m_frontTexture->draw();
+    needsRepaint |= m_zooming;
+    needsRepaint |= (m_scale <= 0);
+    return needsRepaint;
+}
+
+void DualTiledTexture::update(const SkRegion& dirtyArea, SkPicture* picture)
+{
+    m_backTexture->update(dirtyArea, picture);
+    m_frontTexture->update(dirtyArea, picture);
+}
+
+bool DualTiledTexture::owns(BaseTileTexture* texture)
+{
+    bool owns = m_textureA->owns(texture);
+    owns |= m_textureB->owns(texture);
+    return owns;
+}
+
 } // namespace WebCore
index aa82e36..206961b 100644 (file)
@@ -49,7 +49,7 @@ public:
         : m_surface(surface)
         , m_prevTileX(0)
         , m_prevTileY(0)
-        , m_prevScale(1)
+        , m_scale(1)
         , m_swapWhateverIsReady(false)
     {
         m_dirtyRegion.setEmpty();
@@ -65,7 +65,8 @@ public:
         removeTiles();
     };
 
-    void prepare(GLWebViewState* state, bool repaint, bool startFastSwap);
+    void prepare(GLWebViewState* state, float scale, bool repaint,
+                 bool startFastSwap, IntRect& visibleArea);
     bool draw();
 
     void prepareTile(bool repaint, int x, int y);
@@ -74,6 +75,7 @@ public:
     BaseTile* getTile(int x, int y);
 
     void removeTiles();
+    void discardTextures();
     bool owns(BaseTileTexture* texture);
 
     // TilePainter methods
@@ -81,6 +83,11 @@ public:
     virtual void paintExtra(SkCanvas*);
     virtual const TransformationMatrix* transform();
 
+    float scale() { return m_scale; }
+    bool ready();
+
+    PaintedSurface* surface() { return m_surface; }
+
 private:
     bool tileIsVisible(BaseTile* tile);
 
@@ -96,11 +103,36 @@ private:
 
     int m_prevTileX;
     int m_prevTileY;
-    float m_prevScale;
+    float m_scale;
 
     bool m_swapWhateverIsReady;
 };
 
+class DualTiledTexture {
+public:
+    DualTiledTexture(PaintedSurface* surface);
+    ~DualTiledTexture();
+    void prepare(GLWebViewState* state, float scale, bool repaint,
+                 bool startFastSwap, IntRect& area);
+    void swap();
+    bool draw();
+    void update(const SkRegion& dirtyArea, SkPicture* picture);
+    bool owns(BaseTileTexture* texture);
+private:
+    // Delay before we schedule a new tile at the new scale factor
+    static const double s_zoomUpdateDelay = 0.2; // 200 ms
+
+    TiledTexture* m_frontTexture;
+    TiledTexture* m_backTexture;
+    TiledTexture* m_textureA;
+    TiledTexture* m_textureB;
+    float m_scale;
+    float m_futureScale;
+    double m_zoomUpdateTime;
+    bool m_zooming;
+    IntRect m_preZoomVisibleArea;
+};
+
 } // namespace WebCore
 
 #endif // TiledTexture_h
index 7edc4b8..f56c443 100644 (file)
@@ -277,7 +277,7 @@ BaseTileTexture* TilesManager::getAvailableTexture(BaseTile* owner)
     const unsigned int max = availableTexturePool->size();
     for (unsigned int i = 0; i < max; i++) {
         BaseTileTexture* texture = (*availableTexturePool)[i];
-        TextureOwner* currentOwner = texture->owner();
+        BaseTile* currentOwner = static_cast<BaseTile*>(texture->owner());
 
         if (texture->busy()) {
             // don't bother, since the acquire() will likely fail
@@ -296,7 +296,7 @@ BaseTileTexture* TilesManager::getAvailableTexture(BaseTile* owner)
             continue;
         }
 
-        if (currentOwner->page() == owner->page() && texture->scale() != owner->scale()) {
+        if (currentOwner->painter() == owner->painter() && 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