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