OSDN Git Service

Scroll position now passed to all layers
[android-x86/external-webkit.git] / Source / WebCore / platform / graphics / android / GLWebViewState.cpp
index bf39257..900d0fd 100644 (file)
 #include "GLUtils.h"
 #include "ImagesManager.h"
 #include "LayerAndroid.h"
+#include "ScrollableLayerAndroid.h"
 #include "SkPath.h"
 #include "TilesManager.h"
 #include "TilesTracker.h"
+#include "TreeManager.h"
 #include <wtf/CurrentTime.h>
 
+#include <pthread.h>
+
 #include <cutils/log.h>
 #include <wtf/text/CString.h>
 
@@ -69,23 +73,20 @@ namespace WebCore {
 
 using namespace android;
 
-GLWebViewState::GLWebViewState(android::Mutex* buttonMutex)
+GLWebViewState::GLWebViewState()
     : m_zoomManager(this)
-    , m_baseLayer(0)
-    , m_currentBaseLayer(0)
-    , m_previouslyUsedRoot(0)
     , m_currentPictureCounter(0)
     , m_usePageA(true)
     , m_frameworkInval(0, 0, 0, 0)
     , m_frameworkLayersInval(0, 0, 0, 0)
-    , m_globalButtonMutex(buttonMutex)
-    , m_baseLayerUpdate(true)
-    , m_backgroundColor(SK_ColorWHITE)
     , m_isScrolling(false)
     , m_goingDown(true)
     , m_goingLeft(false)
     , m_expandedTileBoundsX(0)
     , m_expandedTileBoundsY(0)
+    , m_highEndGfx(false)
+    , m_scale(1)
+    , m_layersRenderingMode(kAllTextures)
 {
     m_viewport.setEmpty();
     m_futureViewportTileBounds.setEmpty();
@@ -107,27 +108,17 @@ GLWebViewState::GLWebViewState(android::Mutex* buttonMutex)
 
 GLWebViewState::~GLWebViewState()
 {
-    // Unref the existing tree/PaintedSurfaces
-    if (m_previouslyUsedRoot)
-        TilesManager::instance()->swapLayersTextures(m_previouslyUsedRoot, 0);
-
     // Take care of the transfer queue such that Tex Gen thread will not stuck
     TilesManager::instance()->unregisterGLWebViewState(this);
 
     // We have to destroy the two tiled pages first as their destructor
     // may depend on the existence of this GLWebViewState and some of its
     // instance variables in order to complete.
-    // Explicitely, currently we need to have the m_currentBaseLayer around
+    // Explicitely, currently we need to have the m_paintingBaseLayer around
     // in order to complete any pending paint operations (the tiled pages
     // will remove any pending operations, and wait if one is underway).
     delete m_tiledPageA;
     delete m_tiledPageB;
-    SkSafeUnref(m_previouslyUsedRoot);
-    SkSafeUnref(m_currentBaseLayer);
-    SkSafeUnref(m_baseLayer);
-    m_previouslyUsedRoot = 0;
-    m_baseLayer = 0;
-    m_currentBaseLayer = 0;
 #ifdef DEBUG_COUNT
     ClassTracker::instance()->decrement("GLWebViewState");
 #endif
@@ -137,33 +128,18 @@ GLWebViewState::~GLWebViewState()
 void GLWebViewState::setBaseLayer(BaseLayerAndroid* layer, const SkRegion& inval,
                                   bool showVisualIndicator, bool isPictureAfterFirstLayout)
 {
-    android::Mutex::Autolock lock(m_baseLayerLock);
     if (!layer || isPictureAfterFirstLayout) {
+        // TODO: move this into TreeManager
         m_tiledPageA->discardTextures();
         m_tiledPageB->discardTextures();
     }
-    if (isPictureAfterFirstLayout) {
-        m_baseLayerUpdate = true;
-        m_invalidateRegion.setEmpty();
-    }
-    if (m_baseLayer && layer)
-        m_baseLayer->swapExtra(layer);
-
-    SkSafeRef(layer);
-    SkSafeUnref(m_baseLayer);
-    m_baseLayer = layer;
-    if (m_baseLayer)
-        m_baseLayer->setGLWebViewState(this);
-
-    // We only update the layers if we are not currently
-    // waiting for a tiledPage to be painted
-    if (m_baseLayerUpdate) {
-        SkSafeRef(layer);
-        SkSafeUnref(m_currentBaseLayer);
-        m_currentBaseLayer = layer;
+    if (layer) {
+        XLOG("new base layer %p, (inval region empty %d) with child %p", layer, inval.isEmpty(), layer->getChild(0));
+        layer->setState(this);
+        layer->markAsDirty(inval); // TODO: set in webview.cpp
     }
+    m_treeManager.updateWithTree(layer, isPictureAfterFirstLayout);
     m_glExtras.setDrawExtra(0);
-    invalRegion(inval);
 
 #ifdef MEASURES_PERF
     if (m_measurePerfs && !showVisualIndicator)
@@ -174,8 +150,24 @@ void GLWebViewState::setBaseLayer(BaseLayerAndroid* layer, const SkRegion& inval
     TilesManager::instance()->setShowVisualIndicator(showVisualIndicator);
 }
 
+void GLWebViewState::scrollLayer(int layerId, int x, int y)
+{
+    m_treeManager.updateScrollableLayer(layerId, x, y);
+
+    // TODO: only inval the area of the scrolled layer instead of
+    // doing a fullInval()
+    if (m_layersRenderingMode == kSingleSurfaceRendering)
+        fullInval();
+}
+
 void GLWebViewState::invalRegion(const SkRegion& region)
 {
+    if (m_layersRenderingMode == kSingleSurfaceRendering) {
+        // TODO: do the union of both layers tree to compute
+        //the minimum inval instead of doing a fullInval()
+        fullInval();
+        return;
+    }
     SkRegion::Iterator iterator(region);
     while (!iterator.done()) {
         SkIRect r = iterator.rect();
@@ -185,52 +177,27 @@ void GLWebViewState::invalRegion(const SkRegion& region)
     }
 }
 
-void GLWebViewState::unlockBaseLayerUpdate() {
-    if (m_baseLayerUpdate)
-        return;
-
-    m_baseLayerUpdate = true;
-    android::Mutex::Autolock lock(m_baseLayerLock);
-    SkSafeRef(m_baseLayer);
-    SkSafeUnref(m_currentBaseLayer);
-    m_currentBaseLayer = m_baseLayer;
-
-    invalRegion(m_invalidateRegion);
-    m_invalidateRegion.setEmpty();
-}
-
 void GLWebViewState::inval(const IntRect& rect)
 {
-    if (m_baseLayerUpdate) {
-        // base layer isn't locked, so go ahead and issue the inval to both tiled pages
-        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);
-            if (m_frameworkInval.isEmpty())
-                m_frameworkInval = rect;
-            else
-                m_frameworkInval.unite(rect);
-            XLOG("intermediate invalRect(%d, %d, %d, %d) after unite with rect %d %d %d %d", m_frameworkInval.x(),
-                 m_frameworkInval.y(), m_frameworkInval.width(), m_frameworkInval.height(),
-                 rect.x(), rect.y(), rect.width(), rect.height());
-        }
-    } else {
-        // base layer is locked, so defer invalidation until unlockBaseLayerUpdate()
-        m_invalidateRegion.op(rect.x(), rect.y(), rect.maxX(), rect.maxY(), SkRegion::kUnion_Op);
+    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);
+        if (m_frameworkInval.isEmpty())
+            m_frameworkInval = rect;
+        else
+            m_frameworkInval.unite(rect);
+        XLOG("intermediate invalRect(%d, %d, %d, %d) after unite with rect %d %d %d %d", m_frameworkInval.x(),
+             m_frameworkInval.y(), m_frameworkInval.width(), m_frameworkInval.height(),
+             rect.x(), rect.y(), rect.width(), rect.height());
     }
     TilesManager::instance()->getProfiler()->nextInval(rect, zoomManager()->currentScale());
 }
 
 unsigned int GLWebViewState::paintBaseLayerContent(SkCanvas* canvas)
 {
-    android::Mutex::Autolock lock(m_baseLayerLock);
-    if (m_currentBaseLayer) {
-        m_globalButtonMutex->lock();
-        m_currentBaseLayer->drawCanvas(canvas);
-        m_globalButtonMutex->unlock();
-    }
+    m_treeManager.drawCanvas(canvas, m_layersRenderingMode == kSingleSurfaceRendering);
     return m_currentPictureCounter;
 }
 
@@ -262,11 +229,11 @@ void GLWebViewState::swapPages()
 
 int GLWebViewState::baseContentWidth()
 {
-    return m_currentBaseLayer ? m_currentBaseLayer->content()->width() : 0;
+    return m_treeManager.baseContentWidth();
 }
 int GLWebViewState::baseContentHeight()
 {
-    return m_currentBaseLayer ? m_currentBaseLayer->content()->height() : 0;
+    return m_treeManager.baseContentHeight();
 }
 
 void GLWebViewState::setViewport(SkRect& viewport, float scale)
@@ -296,8 +263,10 @@ void GLWebViewState::setViewport(SkRect& viewport, float scale)
     // allocate max possible number of tiles visible with this viewport
     int viewMaxTileX = static_cast<int>(ceilf((viewport.width()-1) * invTileContentWidth)) + 1;
     int viewMaxTileY = static_cast<int>(ceilf((viewport.height()-1) * invTileContentHeight)) + 1;
-    int maxTextureCount = (viewMaxTileX + TILE_PREFETCH_DISTANCE * 2) *
-        (viewMaxTileY + TILE_PREFETCH_DISTANCE * 2) * 2;
+
+    int maxTextureCount = (viewMaxTileX + m_expandedTileBoundsX * 2) *
+        (viewMaxTileY + m_expandedTileBoundsY * 2) * (m_highEndGfx ? 4 : 2);
+
     TilesManager::instance()->setMaxTextureCount(maxTextureCount);
     m_tiledPageA->updateBaseTileSize();
     m_tiledPageB->updateBaseTileSize();
@@ -345,28 +314,29 @@ void GLWebViewState::resetLayersDirtyArea()
     m_frameworkLayersInval.setHeight(0);
 }
 
-double GLWebViewState::setupDrawing(IntRect& viewRect, SkRect& visibleRect,
-                                  IntRect& webViewRect, int titleBarHeight,
-                                  IntRect& screenClip, float scale)
+void GLWebViewState::drawBackground(Color& backgroundColor)
 {
-    int left = viewRect.x();
-    int top = viewRect.y();
-    int width = viewRect.width();
-    int height = viewRect.height();
-
     if (TilesManager::instance()->invertedScreen()) {
-        float color = 1.0 - ((((float) m_backgroundColor.red() / 255.0) +
-                      ((float) m_backgroundColor.green() / 255.0) +
-                      ((float) m_backgroundColor.blue() / 255.0)) / 3.0);
+        float color = 1.0 - ((((float) backgroundColor.red() / 255.0) +
+                      ((float) backgroundColor.green() / 255.0) +
+                      ((float) backgroundColor.blue() / 255.0)) / 3.0);
         glClearColor(color, color, color, 1);
     } else {
-        glClearColor((float)m_backgroundColor.red() / 255.0,
-                     (float)m_backgroundColor.green() / 255.0,
-                     (float)m_backgroundColor.blue() / 255.0, 1);
+        glClearColor((float)backgroundColor.red() / 255.0,
+                     (float)backgroundColor.green() / 255.0,
+                     (float)backgroundColor.blue() / 255.0, 1);
     }
     glClear(GL_COLOR_BUFFER_BIT);
+}
 
-    glViewport(left, top, width, height);
+double GLWebViewState::setupDrawing(IntRect& viewRect, SkRect& visibleRect,
+                                    IntRect& webViewRect, int titleBarHeight,
+                                    IntRect& screenClip, float scale)
+{
+    int left = viewRect.x();
+    int top = viewRect.y();
+    int width = viewRect.width();
+    int height = viewRect.height();
 
     ShaderProgram* shader = TilesManager::instance()->shader();
     if (shader->program() == -1) {
@@ -374,12 +344,18 @@ double GLWebViewState::setupDrawing(IntRect& viewRect, SkRect& visibleRect,
         shader->init();
     }
     shader->setViewRect(viewRect);
-    shader->setViewport(visibleRect);
+    shader->setViewport(visibleRect, scale);
     shader->setWebViewRect(webViewRect);
     shader->setTitleBarHeight(titleBarHeight);
     shader->setScreenClip(screenClip);
     shader->resetBlending();
 
+    shader->calculateAnimationDelta();
+
+    glViewport(left + shader->getAnimationDeltaX(),
+               top - shader->getAnimationDeltaY(),
+               width, height);
+
     double currentTime = WTF::currentTime();
 
     setViewport(visibleRect, scale);
@@ -388,10 +364,84 @@ double GLWebViewState::setupDrawing(IntRect& viewRect, SkRect& visibleRect,
     return currentTime;
 }
 
+bool GLWebViewState::setLayersRenderingMode(TexturesResult& nbTexturesNeeded)
+{
+    bool invalBase = false;
+
+    if (!nbTexturesNeeded.full)
+        TilesManager::instance()->setMaxLayerTextureCount(0);
+    else
+        TilesManager::instance()->setMaxLayerTextureCount((2*nbTexturesNeeded.full)+1);
+
+    int maxTextures = TilesManager::instance()->maxLayerTextureCount();
+    LayersRenderingMode layersRenderingMode = m_layersRenderingMode;
+
+    m_layersRenderingMode = kSingleSurfaceRendering;
+    if (nbTexturesNeeded.fixed < maxTextures)
+        m_layersRenderingMode = kFixedLayers;
+    if (nbTexturesNeeded.scrollable < maxTextures)
+        m_layersRenderingMode = kScrollableAndFixedLayers;
+    if (nbTexturesNeeded.clipped < maxTextures)
+        m_layersRenderingMode = kClippedTextures;
+    if (nbTexturesNeeded.full < maxTextures)
+        m_layersRenderingMode = kAllTextures;
+
+    if (!maxTextures && !nbTexturesNeeded.full)
+        m_layersRenderingMode = kAllTextures;
+
+    if (m_layersRenderingMode < layersRenderingMode
+        && m_layersRenderingMode != kAllTextures)
+        invalBase = true;
+
+    if (m_layersRenderingMode > layersRenderingMode
+        && m_layersRenderingMode != kClippedTextures)
+        invalBase = true;
+
+#ifdef DEBUG
+    if (m_layersRenderingMode != layersRenderingMode) {
+        char* mode[] = { "kAllTextures", "kClippedTextures",
+            "kScrollableAndFixedLayers", "kFixedLayers", "kSingleSurfaceRendering" };
+        XLOGC("Change from mode %s to %s -- We need textures: fixed: %d,"
+              " scrollable: %d, clipped: %d, full: %d, max textures: %d",
+              static_cast<char*>(mode[layersRenderingMode]),
+              static_cast<char*>(mode[m_layersRenderingMode]),
+              nbTexturesNeeded.fixed,
+              nbTexturesNeeded.scrollable,
+              nbTexturesNeeded.clipped,
+              nbTexturesNeeded.full, maxTextures);
+    }
+#endif
+
+    // For now, anything below kClippedTextures is equivalent
+    // to kSingleSurfaceRendering
+    // TODO: implement the other rendering modes
+    if (m_layersRenderingMode > kClippedTextures)
+        m_layersRenderingMode = kSingleSurfaceRendering;
+
+    // update the base surface if needed
+    if (m_layersRenderingMode != layersRenderingMode
+        && invalBase) {
+        m_tiledPageA->discardTextures();
+        m_tiledPageB->discardTextures();
+        fullInval();
+        return true;
+    }
+    return false;
+}
+
+void GLWebViewState::fullInval()
+{
+    // TODO -- use base layer's size.
+    IntRect ir(0, 0, 1E6, 1E6);
+    inval(ir);
+}
+
 bool GLWebViewState::drawGL(IntRect& rect, SkRect& viewport, IntRect* invalRect,
                             IntRect& webViewRect, int titleBarHeight,
-                            IntRect& clip, float scale, bool* buffersSwappedPtr)
+                            IntRect& clip, float scale,
+                            bool* treesSwappedPtr, bool* newTreeHasAnimPtr)
 {
+    m_scale = scale;
     TilesManager::instance()->getProfiler()->nextFrame(viewport.fLeft,
                                                        viewport.fTop,
                                                        viewport.fRight,
@@ -403,21 +453,11 @@ bool GLWebViewState::drawGL(IntRect& rect, SkRect& viewport, IntRect* invalRect,
     TilesManager::instance()->getTilesTracker()->clear();
 #endif
 
-    m_baseLayerLock.lock();
-    BaseLayerAndroid* baseLayer = m_currentBaseLayer;
-    SkSafeRef(baseLayer);
-    BaseLayerAndroid* baseForComposited = m_baseLayer;
-    SkSafeRef(baseForComposited);
-    m_baseLayerLock.unlock();
-    if (!baseLayer) {
-        SkSafeUnref(baseForComposited);
-        return false;
-    }
-
     float viewWidth = (viewport.fRight - viewport.fLeft) * TILE_PREFETCH_RATIO;
     float viewHeight = (viewport.fBottom - viewport.fTop) * TILE_PREFETCH_RATIO;
-    bool useHorzPrefetch = viewWidth < baseContentWidth();
-    bool useVertPrefetch = viewHeight < baseContentHeight();
+    bool useMinimalMemory = TilesManager::instance()->useMinimalMemory();
+    bool useHorzPrefetch = useMinimalMemory ? 0 : viewWidth < baseContentWidth();
+    bool useVertPrefetch = useMinimalMemory ? 0 : viewHeight < baseContentHeight();
     m_expandedTileBoundsX = (useHorzPrefetch) ? TILE_PREFETCH_DISTANCE : 0;
     m_expandedTileBoundsY = (useVertPrefetch) ? TILE_PREFETCH_DISTANCE : 0;
 
@@ -427,16 +467,8 @@ bool GLWebViewState::drawGL(IntRect& rect, SkRect& viewport, IntRect* invalRect,
 
     resetLayersDirtyArea();
 
-    if (!baseForComposited ||
-        (baseForComposited && !baseForComposited->countChildren())) {
-        SkSafeRef(baseLayer);
-        SkSafeUnref(baseForComposited);
-        baseForComposited = baseLayer;
-    }
-
-    LayerAndroid* compositedRoot = 0;
-    if (baseForComposited && baseForComposited->countChildren() >= 1)
-        compositedRoot = static_cast<LayerAndroid*>(baseForComposited->getChild(0));
+    // when adding or removing layers, use the the paintingBaseLayer's tree so
+    // that content that moves to the base layer from a layer is synchronized
 
     if (scale < MIN_SCALE_WARNING || scale > MAX_SCALE_WARNING)
         XLOGC("WARNING, scale seems corrupted before update: %e", scale);
@@ -451,30 +483,35 @@ bool GLWebViewState::drawGL(IntRect& rect, SkRect& viewport, IntRect* invalRect,
     // TODO: upload as many textures as possible within a certain time limit
     bool ret = ImagesManager::instance()->uploadTextures();
 
-    if (scale < MIN_SCALE_WARNING || scale > MAX_SCALE_WARNING) {
+    if (scale < MIN_SCALE_WARNING || scale > MAX_SCALE_WARNING)
         XLOGC("WARNING, scale seems corrupted after update: %e", scale);
-        CRASH();
-    }
 
     // gather the textures we can use
     TilesManager::instance()->gatherLayerTextures();
 
-    if (compositedRoot != m_previouslyUsedRoot)
-        TilesManager::instance()->swapLayersTextures(m_previouslyUsedRoot, compositedRoot);
-
-    // set up zoom manager, shaders, etc.
-    m_backgroundColor = baseLayer->getBackgroundColor();
     double currentTime = setupDrawing(rect, viewport, webViewRect, titleBarHeight, clip, scale);
-    ret |= baseLayer->drawGL(currentTime, compositedRoot, rect,
-                                 viewport, scale, buffersSwappedPtr);
+
+
+    TexturesResult nbTexturesNeeded;
+    bool fastSwap = isScrolling() || m_layersRenderingMode == kSingleSurfaceRendering;
+    ret |= m_treeManager.drawGL(currentTime, rect, viewport,
+                                scale, fastSwap,
+                                treesSwappedPtr, newTreeHasAnimPtr,
+                                &nbTexturesNeeded);
+    if (!ret)
+        resetFrameworkInval();
+
+    ret |= setLayersRenderingMode(nbTexturesNeeded);
+
+    FloatRect extrasclip(0, 0, rect.width(), rect.height());
+    TilesManager::instance()->shader()->clip(extrasclip);
+
     m_glExtras.drawGL(webViewRect, viewport, titleBarHeight);
 
     glBindBuffer(GL_ARRAY_BUFFER, 0);
 
-    SkSafeRef(compositedRoot);
-    SkSafeUnref(m_previouslyUsedRoot);
-    m_previouslyUsedRoot = compositedRoot;
-
+    // Clean up GL textures for video layer.
+    TilesManager::instance()->videoLayerManager()->deleteUnusedTextures();
     ret |= TilesManager::instance()->invertedScreenSwitch();
 
     if (ret) {
@@ -530,12 +567,11 @@ bool GLWebViewState::drawGL(IntRect& rect, SkRect& viewport, IntRect* invalRect,
     }
 #endif
 
-    SkSafeUnref(baseForComposited);
-    SkSafeUnref(baseLayer);
 #ifdef DEBUG
     TilesManager::instance()->getTilesTracker()->showTrackTextures();
     ImagesManager::instance()->showImages();
 #endif
+
     return ret;
 }