OSDN Git Service

Fix low-res tiles rendering too early
[android-x86/external-webkit.git] / Source / WebCore / platform / graphics / android / BaseLayerAndroid.cpp
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 1
61 #define PREFETCH_Y_DIST 2
62
63 namespace WebCore {
64
65 using namespace android;
66
67 BaseLayerAndroid::BaseLayerAndroid()
68 #if USE(ACCELERATED_COMPOSITING)
69     : m_glWebViewState(0)
70     , m_color(Color::white)
71     , m_scrollState(NotScrolling)
72 #endif
73 {
74 #ifdef DEBUG_COUNT
75     ClassTracker::instance()->increment("BaseLayerAndroid");
76 #endif
77 }
78
79 BaseLayerAndroid::~BaseLayerAndroid()
80 {
81     m_content.clear();
82 #ifdef DEBUG_COUNT
83     ClassTracker::instance()->decrement("BaseLayerAndroid");
84 #endif
85 }
86
87 void BaseLayerAndroid::setContent(const PictureSet& src)
88 {
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);
96 #endif
97     m_content.set(src);
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());
102 }
103
104 void BaseLayerAndroid::setExtra(SkPicture& src)
105 {
106 #if USE(ACCELERATED_COMPOSITING)
107     android::Mutex::Autolock lock(m_drawLock);
108 #endif
109     m_extra.swap(src);
110 }
111
112 void BaseLayerAndroid::drawCanvas(SkCanvas* canvas)
113 {
114 #if USE(ACCELERATED_COMPOSITING)
115     android::Mutex::Autolock lock(m_drawLock);
116 #endif
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);
122 }
123
124 #if USE(ACCELERATED_COMPOSITING)
125
126 void BaseLayerAndroid::prefetchBasePicture(SkRect& viewport, float currentScale,
127                                            TiledPage* prefetchTiledPage)
128 {
129     SkIRect bounds;
130     float prefetchScale = currentScale * PREFETCH_SCALE_MODIFIER;
131
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();
138
139
140     XLOG("fetch rect %f %f %f %f, scale %f",
141          viewport.fLeft,
142          viewport.fTop,
143          viewport.fRight,
144          viewport.fBottom,
145          scale);
146
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;
151
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,
156          prefetchTiledPage);
157
158     prefetchTiledPage->setScale(prefetchScale);
159     prefetchTiledPage->updateTileDirtiness(bounds);
160     prefetchTiledPage->prepare(goingDown, goingLeft, bounds,
161                                TiledPage::ExpandedBounds);
162     prefetchTiledPage->swapBuffersIfReady(bounds,
163                                           prefetchScale,
164                                           TiledPage::SwapWhateverIsReady);
165     prefetchTiledPage->draw(PREFETCH_OPACITY, bounds);
166 }
167
168 bool BaseLayerAndroid::drawBasePictureInGL(SkRect& viewport, float scale,
169                                            double currentTime, bool* buffersSwappedPtr)
170 {
171     ZoomManager* zoomManager = m_glWebViewState->zoomManager();
172
173     bool goingDown = m_glWebViewState->goingDown();
174     bool goingLeft = m_glWebViewState->goingLeft();
175
176     const SkIRect& viewportTileBounds = m_glWebViewState->viewportTileBounds();
177     XLOG("drawBasePicture, TX: %d, TY: %d scale %.2f", viewportTileBounds.fLeft,
178             viewportTileBounds.fTop, scale);
179
180     // Query the resulting state from the zoom manager
181     bool prepareNextTiledPage = zoomManager->needPrepareNextTiledPage();
182
183     // Display the current page
184     TiledPage* tiledPage = m_glWebViewState->frontPage();
185     TiledPage* nextTiledPage = m_glWebViewState->backPage();
186     tiledPage->setScale(zoomManager->currentScale());
187
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();
193
194         // ignore dirtiness return value since while zooming we repaint regardless
195         nextTiledPage->updateTileDirtiness(viewportTileBounds);
196
197         nextTiledPage->prepare(goingDown, goingLeft, viewportTileBounds,
198                                TiledPage::VisibleBounds);
199         // Cancel pending paints for the foreground page
200         TilesManager::instance()->removePaintOperationsForPage(tiledPage, false);
201     }
202
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
209     }
210
211     float transparency = 1;
212     bool doZoomPageSwap = false;
213
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);
221     }
222
223     const SkIRect& preZoomBounds = m_glWebViewState->preZoomBounds();
224
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;
231
232     bool scrolling = m_scrollState != NotScrolling;
233     bool zooming = ZoomManager::kNoScaleRequest != zoomManager->scaleRequestState();
234
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;
239     if (!zooming) {
240         TiledPage::SwapMethod swapMethod;
241         if (scrolling)
242             swapMethod = TiledPage::SwapWhateverIsReady;
243         else
244             swapMethod = TiledPage::SwapWholePage;
245
246         buffersSwapped = tiledPage->swapBuffersIfReady(preZoomBounds,
247                                                        zoomManager->currentScale(),
248                                                        swapMethod);
249
250         if (buffersSwappedPtr && buffersSwapped)
251             *buffersSwappedPtr = true;
252         if (buffersSwapped) {
253             if (m_scrollState == ScrollingFinishPaint) {
254                 m_scrollState = NotScrolling;
255                 scrolling = false;
256             }
257         }
258     }
259
260     if (doZoomPageSwap) {
261         zoomManager->setCurrentScale(scale);
262         m_glWebViewState->swapPages();
263         if (buffersSwappedPtr)
264             *buffersSwappedPtr = true;
265     }
266
267
268     bool needsRedraw = scrolling || zooming || !buffersSwapped;
269
270     // if we don't expect to redraw, unlock the invals
271     if (!needsRedraw)
272         m_glWebViewState->unlockBaseLayerUpdate();
273
274     // if applied invals mark tiles dirty, need to redraw
275     needsRedraw |= tiledPage->updateTileDirtiness(preZoomBounds);
276
277     if (needsRedraw) {
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();
281         if (!zooming)
282             tiledPage->prepare(goingDown, goingLeft, preZoomBounds,
283                                TiledPage::ExpandedBounds);
284     }
285
286     XLOG("scrolling %d, zooming %d, buffersSwapped %d, needsRedraw %d",
287          scrolling, zooming, buffersSwapped, needsRedraw);
288
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);
293     if (usePrefetchPage)
294         prefetchBasePicture(viewport, scale, nextTiledPage);
295
296     tiledPage->draw(transparency, preZoomBounds);
297
298     return needsRedraw;
299 }
300 #endif // USE(ACCELERATED_COMPOSITING)
301
302 bool BaseLayerAndroid::drawGL(double currentTime, LayerAndroid* compositedRoot,
303                               IntRect& viewRect, SkRect& visibleRect, float scale,
304                               bool* buffersSwappedPtr)
305 {
306     bool needsRedraw = false;
307 #if USE(ACCELERATED_COMPOSITING)
308
309     needsRedraw = drawBasePictureInGL(visibleRect, scale, currentTime,
310                                       buffersSwappedPtr);
311
312     if (!needsRedraw)
313         m_glWebViewState->resetFrameworkInval();
314
315     if (compositedRoot) {
316         TransformationMatrix ident;
317
318         bool animsRunning = compositedRoot->evaluateAnimations();
319         if (animsRunning)
320             needsRedraw = true;
321
322         compositedRoot->updateFixedLayersPositions(visibleRect);
323         FloatRect clip(0, 0, viewRect.width(), viewRect.height());
324         compositedRoot->updateGLPositionsAndScale(
325             ident, clip, 1, m_glWebViewState->zoomManager()->layersScale());
326         SkMatrix matrix;
327         matrix.setTranslate(viewRect.x(), viewRect.y());
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         // Clean up GL textures for video layer.
337         TilesManager::instance()->videoLayerManager()->deleteUnusedTextures();
338
339         compositedRoot->prepare(m_glWebViewState);
340         if (compositedRoot->drawGL(m_glWebViewState, matrix))
341             needsRedraw = true;
342         else if (!animsRunning)
343             m_glWebViewState->resetLayersDirtyArea();
344
345     }
346
347     m_previousVisible = visibleRect;
348
349 #endif // USE(ACCELERATED_COMPOSITING)
350 #ifdef DEBUG
351     ClassTracker::instance()->show();
352 #endif
353     return needsRedraw;
354 }
355
356 } // namespace WebCore