Home | History | Annotate | Download | only in android
      1 /*
      2  * Copyright 2010, The Android Open Source Project
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  *  * Redistributions of source code must retain the above copyright
      8  *    notice, this list of conditions and the following disclaimer.
      9  *  * Redistributions in binary form must reproduce the above copyright
     10  *    notice, this list of conditions and the following disclaimer in the
     11  *    documentation and/or other materials provided with the distribution.
     12  *
     13  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
     14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
     17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     24  */
     25 
     26 #include "config.h"
     27 #include "BaseLayerAndroid.h"
     28 
     29 #if USE(ACCELERATED_COMPOSITING)
     30 #include "ClassTracker.h"
     31 #include "GLUtils.h"
     32 #include "ShaderProgram.h"
     33 #include "SkCanvas.h"
     34 #include "TilesManager.h"
     35 #include <GLES2/gl2.h>
     36 #include <wtf/CurrentTime.h>
     37 #endif // USE(ACCELERATED_COMPOSITING)
     38 
     39 #include <cutils/log.h>
     40 #include <wtf/text/CString.h>
     41 
     42 #undef XLOGC
     43 #define XLOGC(...) android_printLog(ANDROID_LOG_DEBUG, "BaseLayerAndroid", __VA_ARGS__)
     44 
     45 #ifdef DEBUG
     46 
     47 #undef XLOG
     48 #define XLOG(...) android_printLog(ANDROID_LOG_DEBUG, "BaseLayerAndroid", __VA_ARGS__)
     49 
     50 #else
     51 
     52 #undef XLOG
     53 #define XLOG(...)
     54 
     55 #endif // DEBUG
     56 
     57 // TODO: dynamically determine based on DPI
     58 #define PREFETCH_SCALE_MODIFIER 0.3
     59 #define PREFETCH_OPACITY 1
     60 #define PREFETCH_X_DIST 0
     61 #define PREFETCH_Y_DIST 1
     62 
     63 namespace WebCore {
     64 
     65 using namespace android;
     66 
     67 BaseLayerAndroid::BaseLayerAndroid()
     68 #if USE(ACCELERATED_COMPOSITING)
     69     : m_color(Color::white)
     70     , m_scrollState(NotScrolling)
     71 #endif
     72 {
     73 #ifdef DEBUG_COUNT
     74     ClassTracker::instance()->increment("BaseLayerAndroid");
     75 #endif
     76 }
     77 
     78 BaseLayerAndroid::~BaseLayerAndroid()
     79 {
     80     m_content.clear();
     81 #ifdef DEBUG_COUNT
     82     ClassTracker::instance()->decrement("BaseLayerAndroid");
     83 #endif
     84 }
     85 
     86 void BaseLayerAndroid::setContent(const PictureSet& src)
     87 {
     88 #if USE(ACCELERATED_COMPOSITING)
     89     // FIXME: We lock here because we do not want
     90     // to paint and change the m_content concurrently.
     91     // We should instead refactor PictureSet to use
     92     // an atomic refcounting scheme and use atomic operations
     93     // to swap PictureSets.
     94     android::Mutex::Autolock lock(m_drawLock);
     95 #endif
     96     m_content.set(src);
     97     // FIXME: We cannot set the size of the base layer because it will screw up
     98     // the matrix used.  We need to fix matrix computation for the base layer
     99     // and then we can set the size.
    100     // setSize(src.width(), src.height());
    101 }
    102 
    103 bool BaseLayerAndroid::drawCanvas(SkCanvas* canvas)
    104 {
    105 #if USE(ACCELERATED_COMPOSITING)
    106     android::Mutex::Autolock lock(m_drawLock);
    107 #endif
    108     if (!m_content.isEmpty())
    109         m_content.draw(canvas);
    110     return true;
    111 }
    112 
    113 #if USE(ACCELERATED_COMPOSITING)
    114 
    115 void BaseLayerAndroid::prefetchBasePicture(SkRect& viewport, float currentScale,
    116                                            TiledPage* prefetchTiledPage, bool draw)
    117 {
    118     SkIRect bounds;
    119     float prefetchScale = currentScale * PREFETCH_SCALE_MODIFIER;
    120 
    121     float invTileWidth = (prefetchScale)
    122         / TilesManager::instance()->tileWidth();
    123     float invTileHeight = (prefetchScale)
    124         / TilesManager::instance()->tileHeight();
    125     bool goingDown = m_state->goingDown();
    126     bool goingLeft = m_state->goingLeft();
    127 
    128 
    129     XLOG("fetch rect %f %f %f %f, scale %f",
    130          viewport.fLeft,
    131          viewport.fTop,
    132          viewport.fRight,
    133          viewport.fBottom,
    134          scale);
    135 
    136     bounds.fLeft = static_cast<int>(floorf(viewport.fLeft * invTileWidth)) - PREFETCH_X_DIST;
    137     bounds.fTop = static_cast<int>(floorf(viewport.fTop * invTileHeight)) - PREFETCH_Y_DIST;
    138     bounds.fRight = static_cast<int>(ceilf(viewport.fRight * invTileWidth)) + PREFETCH_X_DIST;
    139     bounds.fBottom = static_cast<int>(ceilf(viewport.fBottom * invTileHeight)) + PREFETCH_Y_DIST;
    140 
    141     XLOG("prefetch rect %d %d %d %d, scale %f, preparing page %p",
    142          bounds.fLeft, bounds.fTop,
    143          bounds.fRight, bounds.fBottom,
    144          scale * PREFETCH_SCALE,
    145          prefetchTiledPage);
    146 
    147     prefetchTiledPage->setScale(prefetchScale);
    148     prefetchTiledPage->updateTileDirtiness(bounds);
    149     prefetchTiledPage->prepare(goingDown, goingLeft, bounds,
    150                                TiledPage::ExpandedBounds);
    151     prefetchTiledPage->swapBuffersIfReady(bounds,
    152                                           prefetchScale);
    153     if (draw)
    154         prefetchTiledPage->prepareForDrawGL(PREFETCH_OPACITY, bounds);
    155 }
    156 
    157 bool BaseLayerAndroid::isReady()
    158 {
    159     ZoomManager* zoomManager = m_state->zoomManager();
    160     if (ZoomManager::kNoScaleRequest != zoomManager->scaleRequestState()) {
    161         XLOG("base layer not ready, still zooming");
    162         return false; // still zooming
    163     }
    164 
    165     if (!m_state->frontPage()->isReady(m_state->preZoomBounds())) {
    166         XLOG("base layer not ready, front page not done painting");
    167         return false;
    168     }
    169 
    170     LayerAndroid* compositedRoot = static_cast<LayerAndroid*>(getChild(0));
    171     if (compositedRoot) {
    172         XLOG("base layer is ready, how about children?");
    173         return compositedRoot->isReady();
    174     }
    175 
    176     return true;
    177 }
    178 
    179 void BaseLayerAndroid::swapTiles()
    180 {
    181     if (countChildren())
    182         getChild(0)->swapTiles(); // TODO: move to parent impl
    183 
    184     m_state->frontPage()->swapBuffersIfReady(m_state->preZoomBounds(),
    185                                              m_state->zoomManager()->currentScale());
    186 
    187     m_state->backPage()->swapBuffersIfReady(m_state->preZoomBounds(),
    188                                             m_state->zoomManager()->currentScale());
    189 }
    190 
    191 void BaseLayerAndroid::setIsDrawing(bool isDrawing)
    192 {
    193     if (countChildren())
    194         getChild(0)->setIsDrawing(isDrawing); // TODO: move to parent impl
    195 }
    196 
    197 void BaseLayerAndroid::setIsPainting(Layer* drawingTree)
    198 {
    199     XLOG("BLA %p painting, dirty %d", this, isDirty());
    200     if (drawingTree)
    201         drawingTree = drawingTree->getChild(0);
    202 
    203     if (countChildren())
    204         getChild(0)->setIsPainting(drawingTree); // TODO: move to parent impl
    205 
    206     m_state->invalRegion(m_dirtyRegion);
    207     m_dirtyRegion.setEmpty();
    208 }
    209 
    210 void BaseLayerAndroid::mergeInvalsInto(Layer* replacementTree)
    211 {
    212     XLOG("merging invals (empty=%d) from BLA %p to %p", m_dirtyRegion.isEmpty(), this, replacementTree);
    213     if (countChildren() && replacementTree->countChildren())
    214         getChild(0)->mergeInvalsInto(replacementTree->getChild(0));
    215 
    216     replacementTree->markAsDirty(m_dirtyRegion);
    217 }
    218 
    219 bool BaseLayerAndroid::prepareBasePictureInGL(SkRect& viewport, float scale,
    220                                               double currentTime)
    221 {
    222     ZoomManager* zoomManager = m_state->zoomManager();
    223 
    224     bool goingDown = m_state->goingDown();
    225     bool goingLeft = m_state->goingLeft();
    226 
    227     const SkIRect& viewportTileBounds = m_state->viewportTileBounds();
    228     XLOG("drawBasePicture, TX: %d, TY: %d scale %.2f", viewportTileBounds.fLeft,
    229             viewportTileBounds.fTop, scale);
    230 
    231     // Query the resulting state from the zoom manager
    232     bool prepareNextTiledPage = zoomManager->needPrepareNextTiledPage();
    233 
    234     // Display the current page
    235     TiledPage* tiledPage = m_state->frontPage();
    236     TiledPage* nextTiledPage = m_state->backPage();
    237     tiledPage->setScale(zoomManager->currentScale());
    238 
    239     // Let's prepare the page if needed so that it will start painting
    240     if (prepareNextTiledPage) {
    241         nextTiledPage->setScale(scale);
    242         m_state->setFutureViewport(viewportTileBounds);
    243 
    244         // ignore dirtiness return value since while zooming we repaint regardless
    245         nextTiledPage->updateTileDirtiness(viewportTileBounds);
    246 
    247         nextTiledPage->prepare(goingDown, goingLeft, viewportTileBounds,
    248                                TiledPage::VisibleBounds);
    249         // Cancel pending paints for the foreground page
    250         TilesManager::instance()->removePaintOperationsForPage(tiledPage, false);
    251     }
    252 
    253     // If we fired a request, let's check if it's ready to use
    254     if (zoomManager->didFireRequest()) {
    255         if (nextTiledPage->swapBuffersIfReady(viewportTileBounds,
    256                                               zoomManager->futureScale()))
    257             zoomManager->setReceivedRequest(); // transition to received request state
    258     }
    259 
    260     float transparency = 1;
    261     bool doZoomPageSwap = false;
    262 
    263     // If the page is ready, display it. We do a short transition between
    264     // the two pages (current one and future one with the new scale factor)
    265     if (zoomManager->didReceivedRequest()) {
    266         float nextTiledPageTransparency = 1;
    267         m_state->resetFrameworkInval();
    268         zoomManager->processTransition(currentTime, scale, &doZoomPageSwap,
    269                                        &nextTiledPageTransparency, &transparency);
    270         nextTiledPage->prepareForDrawGL(nextTiledPageTransparency, viewportTileBounds);
    271     }
    272 
    273     const SkIRect& preZoomBounds = m_state->preZoomBounds();
    274 
    275     bool zooming = ZoomManager::kNoScaleRequest != zoomManager->scaleRequestState();
    276 
    277     if (doZoomPageSwap) {
    278         zoomManager->setCurrentScale(scale);
    279         m_state->swapPages();
    280     }
    281 
    282     bool needsRedraw = zooming;
    283 
    284     // if applied invals mark tiles dirty, need to redraw
    285     needsRedraw |= tiledPage->updateTileDirtiness(preZoomBounds);
    286 
    287     // paint what's needed unless we're zooming, since the new tiles won't
    288     // be relevant soon anyway
    289     if (!zooming)
    290         tiledPage->prepare(goingDown, goingLeft, preZoomBounds,
    291                            TiledPage::ExpandedBounds);
    292 
    293     XLOG("scrolling %d, zooming %d, needsRedraw %d",
    294          scrolling, zooming, needsRedraw);
    295 
    296     // prefetch in the nextTiledPage if unused by zooming (even if not scrolling
    297     // since we want the tiles to be ready before they're needed)
    298     bool usePrefetchPage = !zooming;
    299     nextTiledPage->setIsPrefetchPage(usePrefetchPage);
    300     if (usePrefetchPage) {
    301         // if the non-prefetch page isn't missing tiles, don't bother drawing
    302         // prefetch page
    303         bool drawPrefetchPage = tiledPage->hasMissingContent(preZoomBounds);
    304         prefetchBasePicture(viewport, scale, nextTiledPage, drawPrefetchPage);
    305     }
    306 
    307     tiledPage->prepareForDrawGL(transparency, preZoomBounds);
    308 
    309     return needsRedraw;
    310 }
    311 
    312 void BaseLayerAndroid::drawBasePictureInGL()
    313 {
    314     m_state->backPage()->drawGL();
    315     m_state->frontPage()->drawGL();
    316 }
    317 
    318 #endif // USE(ACCELERATED_COMPOSITING)
    319 
    320 void BaseLayerAndroid::updateLayerPositions(SkRect& visibleRect)
    321 {
    322     LayerAndroid* compositedRoot = static_cast<LayerAndroid*>(getChild(0));
    323     TransformationMatrix ident;
    324     compositedRoot->updateFixedLayersPositions(visibleRect);
    325     FloatRect clip(0, 0, content()->width(), content()->height());
    326     compositedRoot->updateGLPositionsAndScale(
    327         ident, clip, 1, m_state->zoomManager()->layersScale());
    328 
    329 #ifdef DEBUG
    330     compositedRoot->showLayer(0);
    331     XLOG("We have %d layers, %d textured",
    332          compositedRoot->nbLayers(),
    333          compositedRoot->nbTexturedLayers());
    334 #endif
    335 }
    336 
    337 bool BaseLayerAndroid::prepare(double currentTime, IntRect& viewRect,
    338                                SkRect& visibleRect, float scale)
    339 {
    340     XLOG("preparing BLA %p", this);
    341 
    342     // base layer is simply drawn in prepare, since there is always a base layer it doesn't matter
    343     bool needsRedraw = prepareBasePictureInGL(visibleRect, scale, currentTime);
    344 
    345     LayerAndroid* compositedRoot = static_cast<LayerAndroid*>(getChild(0));
    346     if (compositedRoot) {
    347         updateLayerPositions(visibleRect);
    348 
    349         XLOG("preparing BLA %p, root %p", this, compositedRoot);
    350         compositedRoot->prepare();
    351     }
    352 
    353     return needsRedraw;
    354 }
    355 
    356 bool BaseLayerAndroid::drawGL(IntRect& viewRect, SkRect& visibleRect,
    357                               float scale)
    358 {
    359     XLOG("drawing BLA %p", this);
    360 
    361     // TODO: consider moving drawBackground outside of prepare (into tree manager)
    362     m_state->drawBackground(m_color);
    363     drawBasePictureInGL();
    364 
    365     bool needsRedraw = false;
    366 
    367 #if USE(ACCELERATED_COMPOSITING)
    368 
    369     LayerAndroid* compositedRoot = static_cast<LayerAndroid*>(getChild(0));
    370     if (compositedRoot) {
    371         updateLayerPositions(visibleRect);
    372         // For now, we render layers only if the rendering mode
    373         // is kAllTextures or kClippedTextures
    374         if (compositedRoot->drawGL()) {
    375             if (TilesManager::instance()->layerTexturesRemain()) {
    376                 // only try redrawing for layers if layer textures remain,
    377                 // otherwise we'll repaint without getting anything done
    378                 needsRedraw = true;
    379             }
    380         }
    381     }
    382 
    383 #endif // USE(ACCELERATED_COMPOSITING)
    384 #ifdef DEBUG
    385     ClassTracker::instance()->show();
    386 #endif
    387     return needsRedraw;
    388 }
    389 
    390 } // namespace WebCore
    391