2 * Copyright 2010, The Android Open Source Project
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
27 #include "BaseLayerAndroid.h"
29 #if USE(ACCELERATED_COMPOSITING)
30 #include "ClassTracker.h"
32 #include "ShaderProgram.h"
34 #include "TilesManager.h"
35 #include <GLES2/gl2.h>
36 #include <wtf/CurrentTime.h>
37 #endif // USE(ACCELERATED_COMPOSITING)
39 #include <cutils/log.h>
40 #include <wtf/text/CString.h>
43 #define XLOGC(...) android_printLog(ANDROID_LOG_DEBUG, "BaseLayerAndroid", __VA_ARGS__)
48 #define XLOG(...) android_printLog(ANDROID_LOG_DEBUG, "BaseLayerAndroid", __VA_ARGS__)
57 // TODO: dynamically determine based on DPI
58 #define PREFETCH_SCALE_MODIFIER 0.3
59 #define PREFETCH_OPACITY 1
60 #define PREFETCH_X_DIST 1
61 #define PREFETCH_Y_DIST 2
65 using namespace android;
67 BaseLayerAndroid::BaseLayerAndroid()
68 #if USE(ACCELERATED_COMPOSITING)
70 , m_color(Color::white)
71 , m_scrollState(NotScrolling)
75 ClassTracker::instance()->increment("BaseLayerAndroid");
79 BaseLayerAndroid::~BaseLayerAndroid()
83 ClassTracker::instance()->decrement("BaseLayerAndroid");
87 void BaseLayerAndroid::setContent(const PictureSet& src)
89 #if USE(ACCELERATED_COMPOSITING)
90 // FIXME: We lock here because we do not want
91 // to paint and change the m_content concurrently.
92 // We should instead refactor PictureSet to use
93 // an atomic refcounting scheme and use atomic operations
94 // to swap PictureSets.
95 android::Mutex::Autolock lock(m_drawLock);
98 // FIXME: We cannot set the size of the base layer because it will screw up
99 // the matrix used. We need to fix matrix computation for the base layer
100 // and then we can set the size.
101 // setSize(src.width(), src.height());
104 void BaseLayerAndroid::setExtra(SkPicture& src)
106 #if USE(ACCELERATED_COMPOSITING)
107 android::Mutex::Autolock lock(m_drawLock);
112 void BaseLayerAndroid::drawCanvas(SkCanvas* canvas)
114 #if USE(ACCELERATED_COMPOSITING)
115 android::Mutex::Autolock lock(m_drawLock);
117 if (!m_content.isEmpty())
118 m_content.draw(canvas);
119 // TODO : replace with !m_extra.isEmpty() once such a call exists
120 if (m_extra.width() > 0)
121 m_extra.draw(canvas);
124 #if USE(ACCELERATED_COMPOSITING)
126 void BaseLayerAndroid::prefetchBasePicture(SkRect& viewport, float currentScale,
127 TiledPage* prefetchTiledPage)
130 float prefetchScale = currentScale * PREFETCH_SCALE_MODIFIER;
132 float invTileWidth = (prefetchScale)
133 / TilesManager::instance()->tileWidth();
134 float invTileHeight = (prefetchScale)
135 / TilesManager::instance()->tileHeight();
136 bool goingDown = m_glWebViewState->goingDown();
137 bool goingLeft = m_glWebViewState->goingLeft();
140 XLOG("fetch rect %f %f %f %f, scale %f",
147 bounds.fLeft = static_cast<int>(floorf(viewport.fLeft * invTileWidth)) - PREFETCH_X_DIST;
148 bounds.fTop = static_cast<int>(floorf(viewport.fTop * invTileHeight)) - PREFETCH_Y_DIST;
149 bounds.fRight = static_cast<int>(ceilf(viewport.fRight * invTileWidth)) + PREFETCH_X_DIST;
150 bounds.fBottom = static_cast<int>(ceilf(viewport.fBottom * invTileHeight)) + PREFETCH_Y_DIST;
152 XLOG("prefetch rect %d %d %d %d, scale %f, preparing page %p",
153 bounds.fLeft, bounds.fTop,
154 bounds.fRight, bounds.fBottom,
155 scale * PREFETCH_SCALE,
158 prefetchTiledPage->setScale(prefetchScale);
159 prefetchTiledPage->updateTileDirtiness(bounds);
160 prefetchTiledPage->prepare(goingDown, goingLeft, bounds,
161 TiledPage::ExpandedBounds);
162 prefetchTiledPage->swapBuffersIfReady(bounds,
164 TiledPage::SwapWhateverIsReady);
165 prefetchTiledPage->draw(PREFETCH_OPACITY, bounds);
168 bool BaseLayerAndroid::drawBasePictureInGL(SkRect& viewport, float scale,
169 double currentTime, bool* buffersSwappedPtr)
171 ZoomManager* zoomManager = m_glWebViewState->zoomManager();
173 bool goingDown = m_glWebViewState->goingDown();
174 bool goingLeft = m_glWebViewState->goingLeft();
176 const SkIRect& viewportTileBounds = m_glWebViewState->viewportTileBounds();
177 XLOG("drawBasePicture, TX: %d, TY: %d scale %.2f", viewportTileBounds.fLeft,
178 viewportTileBounds.fTop, scale);
180 // Query the resulting state from the zoom manager
181 bool prepareNextTiledPage = zoomManager->needPrepareNextTiledPage();
183 // Display the current page
184 TiledPage* tiledPage = m_glWebViewState->frontPage();
185 TiledPage* nextTiledPage = m_glWebViewState->backPage();
186 tiledPage->setScale(zoomManager->currentScale());
188 // Let's prepare the page if needed so that it will start painting
189 if (prepareNextTiledPage) {
190 nextTiledPage->setScale(scale);
191 m_glWebViewState->setFutureViewport(viewportTileBounds);
192 m_glWebViewState->lockBaseLayerUpdate();
194 // ignore dirtiness return value since while zooming we repaint regardless
195 nextTiledPage->updateTileDirtiness(viewportTileBounds);
197 nextTiledPage->prepare(goingDown, goingLeft, viewportTileBounds,
198 TiledPage::VisibleBounds);
199 // Cancel pending paints for the foreground page
200 TilesManager::instance()->removePaintOperationsForPage(tiledPage, false);
203 // If we fired a request, let's check if it's ready to use
204 if (zoomManager->didFireRequest()) {
205 if (nextTiledPage->swapBuffersIfReady(viewportTileBounds,
206 zoomManager->futureScale(),
207 TiledPage::SwapWholePage))
208 zoomManager->setReceivedRequest(); // transition to received request state
211 float transparency = 1;
212 bool doZoomPageSwap = false;
214 // If the page is ready, display it. We do a short transition between
215 // the two pages (current one and future one with the new scale factor)
216 if (zoomManager->didReceivedRequest()) {
217 float nextTiledPageTransparency = 1;
218 zoomManager->processTransition(currentTime, scale, &doZoomPageSwap,
219 &nextTiledPageTransparency, &transparency);
220 nextTiledPage->draw(nextTiledPageTransparency, viewportTileBounds);
223 const SkIRect& preZoomBounds = m_glWebViewState->preZoomBounds();
225 // update scrolling state machine by querying glwebviewstate - note that the
226 // NotScrolling state is only set below
227 if (m_glWebViewState->isScrolling())
228 m_scrollState = Scrolling;
229 else if (m_scrollState == Scrolling)
230 m_scrollState = ScrollingFinishPaint;
232 bool scrolling = m_scrollState != NotScrolling;
233 bool zooming = ZoomManager::kNoScaleRequest != zoomManager->scaleRequestState();
235 // When we aren't zooming, we should TRY and swap tile buffers if they're
236 // ready. When scrolling, we swap whatever's ready. Otherwise, buffer until
237 // the entire page is ready and then swap.
238 bool buffersSwapped = false;
240 TiledPage::SwapMethod swapMethod;
242 swapMethod = TiledPage::SwapWhateverIsReady;
244 swapMethod = TiledPage::SwapWholePage;
246 buffersSwapped = tiledPage->swapBuffersIfReady(preZoomBounds,
247 zoomManager->currentScale(),
250 if (buffersSwappedPtr && buffersSwapped)
251 *buffersSwappedPtr = true;
252 if (buffersSwapped) {
253 if (m_scrollState == ScrollingFinishPaint) {
254 m_scrollState = NotScrolling;
260 if (doZoomPageSwap) {
261 zoomManager->setCurrentScale(scale);
262 m_glWebViewState->swapPages();
263 if (buffersSwappedPtr)
264 *buffersSwappedPtr = true;
268 bool needsRedraw = scrolling || zooming || !buffersSwapped;
270 // if we don't expect to redraw, unlock the invals
272 m_glWebViewState->unlockBaseLayerUpdate();
274 // if applied invals mark tiles dirty, need to redraw
275 needsRedraw |= tiledPage->updateTileDirtiness(preZoomBounds);
278 // lock and paint what's needed unless we're zooming, since the new
279 // tiles won't be relevant soon anyway
280 m_glWebViewState->lockBaseLayerUpdate();
282 tiledPage->prepare(goingDown, goingLeft, preZoomBounds,
283 TiledPage::ExpandedBounds);
286 XLOG("scrolling %d, zooming %d, buffersSwapped %d, needsRedraw %d",
287 scrolling, zooming, buffersSwapped, needsRedraw);
289 // prefetch in the nextTiledPage if unused by zooming (even if not scrolling
290 // since we want the tiles to be ready before they're needed)
291 bool usePrefetchPage = !zooming;
292 nextTiledPage->setIsPrefetchPage(usePrefetchPage);
294 prefetchBasePicture(viewport, scale, nextTiledPage);
296 tiledPage->draw(transparency, preZoomBounds);
300 #endif // USE(ACCELERATED_COMPOSITING)
302 bool BaseLayerAndroid::drawGL(double currentTime, LayerAndroid* compositedRoot,
303 IntRect& viewRect, SkRect& visibleRect, float scale,
304 bool* buffersSwappedPtr)
306 bool needsRedraw = false;
307 #if USE(ACCELERATED_COMPOSITING)
309 needsRedraw = drawBasePictureInGL(visibleRect, scale, currentTime,
313 m_glWebViewState->resetFrameworkInval();
315 if (compositedRoot) {
316 TransformationMatrix ident;
318 bool animsRunning = compositedRoot->evaluateAnimations();
322 compositedRoot->updateFixedLayersPositions(visibleRect);
323 FloatRect clip(0, 0, viewRect.width(), viewRect.height());
324 compositedRoot->updateGLPositionsAndScale(
325 ident, clip, 1, m_glWebViewState->zoomManager()->layersScale());
327 matrix.setTranslate(viewRect.x(), viewRect.y());
330 compositedRoot->showLayer(0);
331 XLOG("We have %d layers, %d textured",
332 compositedRoot->nbLayers(),
333 compositedRoot->nbTexturedLayers());
336 // Clean up GL textures for video layer.
337 TilesManager::instance()->videoLayerManager()->deleteUnusedTextures();
339 compositedRoot->prepare(m_glWebViewState);
340 if (compositedRoot->drawGL(m_glWebViewState, matrix))
342 else if (!animsRunning)
343 m_glWebViewState->resetLayersDirtyArea();
347 m_previousVisible = visibleRect;
349 #endif // USE(ACCELERATED_COMPOSITING)
351 ClassTracker::instance()->show();
356 } // namespace WebCore