OSDN Git Service

Reconcile with ics-mr0-release
[android-x86/external-webkit.git] / Source / WebCore / platform / graphics / android / GLWebViewState.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 "GLWebViewState.h"
28
29 #if USE(ACCELERATED_COMPOSITING)
30
31 #include "BaseLayerAndroid.h"
32 #include "ClassTracker.h"
33 #include "GLUtils.h"
34 #include "ImagesManager.h"
35 #include "LayerAndroid.h"
36 #include "SkPath.h"
37 #include "TilesManager.h"
38 #include "TilesTracker.h"
39 #include <wtf/CurrentTime.h>
40
41 #include <cutils/log.h>
42 #include <wtf/text/CString.h>
43
44 #undef XLOGC
45 #define XLOGC(...) android_printLog(ANDROID_LOG_DEBUG, "GLWebViewState", __VA_ARGS__)
46
47 #ifdef DEBUG
48
49 #undef XLOG
50 #define XLOG(...) android_printLog(ANDROID_LOG_DEBUG, "GLWebViewState", __VA_ARGS__)
51
52 #else
53
54 #undef XLOG
55 #define XLOG(...)
56
57 #endif // DEBUG
58
59 #define FIRST_TILED_PAGE_ID 1
60 #define SECOND_TILED_PAGE_ID 2
61
62 #define FRAMERATE_CAP 0.01666 // We cap at 60 fps
63
64 // log warnings if scale goes outside this range
65 #define MIN_SCALE_WARNING 0.1
66 #define MAX_SCALE_WARNING 10
67
68 namespace WebCore {
69
70 using namespace android;
71
72 GLWebViewState::GLWebViewState(android::Mutex* buttonMutex)
73     : m_zoomManager(this)
74     , m_baseLayer(0)
75     , m_currentBaseLayer(0)
76     , m_previouslyUsedRoot(0)
77     , m_currentPictureCounter(0)
78     , m_usePageA(true)
79     , m_frameworkInval(0, 0, 0, 0)
80     , m_frameworkLayersInval(0, 0, 0, 0)
81     , m_globalButtonMutex(buttonMutex)
82     , m_baseLayerUpdate(true)
83     , m_backgroundColor(SK_ColorWHITE)
84     , m_isScrolling(false)
85     , m_goingDown(true)
86     , m_goingLeft(false)
87     , m_expandedTileBoundsX(0)
88     , m_expandedTileBoundsY(0)
89 {
90     m_viewport.setEmpty();
91     m_futureViewportTileBounds.setEmpty();
92     m_viewportTileBounds.setEmpty();
93     m_preZoomBounds.setEmpty();
94
95     m_tiledPageA = new TiledPage(FIRST_TILED_PAGE_ID, this);
96     m_tiledPageB = new TiledPage(SECOND_TILED_PAGE_ID, this);
97
98 #ifdef DEBUG_COUNT
99     ClassTracker::instance()->increment("GLWebViewState");
100 #endif
101 #ifdef MEASURES_PERF
102     m_timeCounter = 0;
103     m_totalTimeCounter = 0;
104     m_measurePerfs = false;
105 #endif
106 }
107
108 GLWebViewState::~GLWebViewState()
109 {
110     // Unref the existing tree/PaintedSurfaces
111     if (m_previouslyUsedRoot)
112         TilesManager::instance()->swapLayersTextures(m_previouslyUsedRoot, 0);
113
114     // Take care of the transfer queue such that Tex Gen thread will not stuck
115     TilesManager::instance()->unregisterGLWebViewState(this);
116
117     // We have to destroy the two tiled pages first as their destructor
118     // may depend on the existence of this GLWebViewState and some of its
119     // instance variables in order to complete.
120     // Explicitely, currently we need to have the m_currentBaseLayer around
121     // in order to complete any pending paint operations (the tiled pages
122     // will remove any pending operations, and wait if one is underway).
123     delete m_tiledPageA;
124     delete m_tiledPageB;
125     SkSafeUnref(m_previouslyUsedRoot);
126     SkSafeUnref(m_currentBaseLayer);
127     SkSafeUnref(m_baseLayer);
128     m_previouslyUsedRoot = 0;
129     m_baseLayer = 0;
130     m_currentBaseLayer = 0;
131 #ifdef DEBUG_COUNT
132     ClassTracker::instance()->decrement("GLWebViewState");
133 #endif
134
135 }
136
137 void GLWebViewState::setBaseLayer(BaseLayerAndroid* layer, const SkRegion& inval,
138                                   bool showVisualIndicator, bool isPictureAfterFirstLayout)
139 {
140     android::Mutex::Autolock lock(m_baseLayerLock);
141     if (!layer || isPictureAfterFirstLayout) {
142         m_tiledPageA->discardTextures();
143         m_tiledPageB->discardTextures();
144     }
145     if (isPictureAfterFirstLayout) {
146         m_baseLayerUpdate = true;
147         m_invalidateRegion.setEmpty();
148     }
149     if (m_baseLayer && layer)
150         m_baseLayer->swapExtra(layer);
151
152     SkSafeRef(layer);
153     SkSafeUnref(m_baseLayer);
154     m_baseLayer = layer;
155     if (m_baseLayer)
156         m_baseLayer->setGLWebViewState(this);
157
158     // We only update the layers if we are not currently
159     // waiting for a tiledPage to be painted
160     if (m_baseLayerUpdate) {
161         SkSafeRef(layer);
162         SkSafeUnref(m_currentBaseLayer);
163         m_currentBaseLayer = layer;
164     }
165     m_glExtras.setDrawExtra(0);
166     invalRegion(inval);
167
168 #ifdef MEASURES_PERF
169     if (m_measurePerfs && !showVisualIndicator)
170         dumpMeasures();
171     m_measurePerfs = showVisualIndicator;
172 #endif
173
174     TilesManager::instance()->setShowVisualIndicator(showVisualIndicator);
175 }
176
177 void GLWebViewState::invalRegion(const SkRegion& region)
178 {
179     SkRegion::Iterator iterator(region);
180     while (!iterator.done()) {
181         SkIRect r = iterator.rect();
182         IntRect ir(r.fLeft, r.fTop, r.width(), r.height());
183         inval(ir);
184         iterator.next();
185     }
186 }
187
188 void GLWebViewState::unlockBaseLayerUpdate() {
189     if (m_baseLayerUpdate)
190         return;
191
192     m_baseLayerUpdate = true;
193     android::Mutex::Autolock lock(m_baseLayerLock);
194     SkSafeRef(m_baseLayer);
195     SkSafeUnref(m_currentBaseLayer);
196     m_currentBaseLayer = m_baseLayer;
197
198     invalRegion(m_invalidateRegion);
199     m_invalidateRegion.setEmpty();
200 }
201
202 void GLWebViewState::inval(const IntRect& rect)
203 {
204     if (m_baseLayerUpdate) {
205         // base layer isn't locked, so go ahead and issue the inval to both tiled pages
206         m_currentPictureCounter++;
207         if (!rect.isEmpty()) {
208             // find which tiles fall within the invalRect and mark them as dirty
209             m_tiledPageA->invalidateRect(rect, m_currentPictureCounter);
210             m_tiledPageB->invalidateRect(rect, m_currentPictureCounter);
211             if (m_frameworkInval.isEmpty())
212                 m_frameworkInval = rect;
213             else
214                 m_frameworkInval.unite(rect);
215             XLOG("intermediate invalRect(%d, %d, %d, %d) after unite with rect %d %d %d %d", m_frameworkInval.x(),
216                  m_frameworkInval.y(), m_frameworkInval.width(), m_frameworkInval.height(),
217                  rect.x(), rect.y(), rect.width(), rect.height());
218         }
219     } else {
220         // base layer is locked, so defer invalidation until unlockBaseLayerUpdate()
221         m_invalidateRegion.op(rect.x(), rect.y(), rect.maxX(), rect.maxY(), SkRegion::kUnion_Op);
222     }
223     TilesManager::instance()->getProfiler()->nextInval(rect, zoomManager()->currentScale());
224 }
225
226 unsigned int GLWebViewState::paintBaseLayerContent(SkCanvas* canvas)
227 {
228     android::Mutex::Autolock lock(m_baseLayerLock);
229     if (m_currentBaseLayer) {
230         m_globalButtonMutex->lock();
231         m_currentBaseLayer->drawCanvas(canvas);
232         m_globalButtonMutex->unlock();
233     }
234     return m_currentPictureCounter;
235 }
236
237 TiledPage* GLWebViewState::sibling(TiledPage* page)
238 {
239     return (page == m_tiledPageA) ? m_tiledPageB : m_tiledPageA;
240 }
241
242 TiledPage* GLWebViewState::frontPage()
243 {
244     android::Mutex::Autolock lock(m_tiledPageLock);
245     return m_usePageA ? m_tiledPageA : m_tiledPageB;
246 }
247
248 TiledPage* GLWebViewState::backPage()
249 {
250     android::Mutex::Autolock lock(m_tiledPageLock);
251     return m_usePageA ? m_tiledPageB : m_tiledPageA;
252 }
253
254 void GLWebViewState::swapPages()
255 {
256     android::Mutex::Autolock lock(m_tiledPageLock);
257     m_usePageA ^= true;
258     TiledPage* oldPage = m_usePageA ? m_tiledPageB : m_tiledPageA;
259     zoomManager()->swapPages();
260     oldPage->discardTextures();
261 }
262
263 int GLWebViewState::baseContentWidth()
264 {
265     return m_currentBaseLayer ? m_currentBaseLayer->content()->width() : 0;
266 }
267 int GLWebViewState::baseContentHeight()
268 {
269     return m_currentBaseLayer ? m_currentBaseLayer->content()->height() : 0;
270 }
271
272 void GLWebViewState::setViewport(SkRect& viewport, float scale)
273 {
274     if ((m_viewport == viewport) &&
275         (zoomManager()->futureScale() == scale))
276         return;
277
278     m_goingDown = m_viewport.fTop - viewport.fTop <= 0;
279     m_goingLeft = m_viewport.fLeft - viewport.fLeft >= 0;
280     m_viewport = viewport;
281
282     XLOG("New VIEWPORT %.2f - %.2f %.2f - %.2f (w: %2.f h: %.2f scale: %.2f currentScale: %.2f futureScale: %.2f)",
283          m_viewport.fLeft, m_viewport.fTop, m_viewport.fRight, m_viewport.fBottom,
284          m_viewport.width(), m_viewport.height(), scale,
285          zoomManager()->currentScale(), zoomManager()->futureScale());
286
287     const float invTileContentWidth = scale / TilesManager::tileWidth();
288     const float invTileContentHeight = scale / TilesManager::tileHeight();
289
290     m_viewportTileBounds.set(
291             static_cast<int>(floorf(viewport.fLeft * invTileContentWidth)),
292             static_cast<int>(floorf(viewport.fTop * invTileContentHeight)),
293             static_cast<int>(ceilf(viewport.fRight * invTileContentWidth)),
294             static_cast<int>(ceilf(viewport.fBottom * invTileContentHeight)));
295
296     // allocate max possible number of tiles visible with this viewport
297     int viewMaxTileX = static_cast<int>(ceilf((viewport.width()-1) * invTileContentWidth)) + 1;
298     int viewMaxTileY = static_cast<int>(ceilf((viewport.height()-1) * invTileContentHeight)) + 1;
299     int maxTextureCount = (viewMaxTileX + TILE_PREFETCH_DISTANCE * 2) *
300         (viewMaxTileY + TILE_PREFETCH_DISTANCE * 2) * 2;
301     TilesManager::instance()->setMaxTextureCount(maxTextureCount);
302     m_tiledPageA->updateBaseTileSize();
303     m_tiledPageB->updateBaseTileSize();
304 }
305
306 #ifdef MEASURES_PERF
307 void GLWebViewState::dumpMeasures()
308 {
309     for (int i = 0; i < m_timeCounter; i++) {
310         XLOGC("%d delay: %d ms", m_totalTimeCounter + i,
311              static_cast<int>(m_delayTimes[i]*1000));
312         m_delayTimes[i] = 0;
313     }
314     m_totalTimeCounter += m_timeCounter;
315     m_timeCounter = 0;
316 }
317 #endif // MEASURES_PERF
318
319 void GLWebViewState::resetFrameworkInval()
320 {
321     m_frameworkInval.setX(0);
322     m_frameworkInval.setY(0);
323     m_frameworkInval.setWidth(0);
324     m_frameworkInval.setHeight(0);
325 }
326
327 void GLWebViewState::addDirtyArea(const IntRect& rect)
328 {
329     if (rect.isEmpty())
330         return;
331
332     IntRect inflatedRect = rect;
333     inflatedRect.inflate(8);
334     if (m_frameworkLayersInval.isEmpty())
335         m_frameworkLayersInval = inflatedRect;
336     else
337         m_frameworkLayersInval.unite(inflatedRect);
338 }
339
340 void GLWebViewState::resetLayersDirtyArea()
341 {
342     m_frameworkLayersInval.setX(0);
343     m_frameworkLayersInval.setY(0);
344     m_frameworkLayersInval.setWidth(0);
345     m_frameworkLayersInval.setHeight(0);
346 }
347
348 double GLWebViewState::setupDrawing(IntRect& viewRect, SkRect& visibleRect,
349                                   IntRect& webViewRect, int titleBarHeight,
350                                   IntRect& screenClip, float scale)
351 {
352     int left = viewRect.x();
353     int top = viewRect.y();
354     int width = viewRect.width();
355     int height = viewRect.height();
356
357     if (TilesManager::instance()->invertedScreen()) {
358         float color = 1.0 - ((((float) m_backgroundColor.red() / 255.0) +
359                       ((float) m_backgroundColor.green() / 255.0) +
360                       ((float) m_backgroundColor.blue() / 255.0)) / 3.0);
361         glClearColor(color, color, color, 1);
362     } else {
363         glClearColor((float)m_backgroundColor.red() / 255.0,
364                      (float)m_backgroundColor.green() / 255.0,
365                      (float)m_backgroundColor.blue() / 255.0, 1);
366     }
367     glClear(GL_COLOR_BUFFER_BIT);
368
369     glViewport(left, top, width, height);
370
371     ShaderProgram* shader = TilesManager::instance()->shader();
372     if (shader->program() == -1) {
373         XLOG("Reinit shader");
374         shader->init();
375     }
376     shader->setViewRect(viewRect);
377     shader->setViewport(visibleRect);
378     shader->setWebViewRect(webViewRect);
379     shader->setTitleBarHeight(titleBarHeight);
380     shader->setScreenClip(screenClip);
381     shader->resetBlending();
382
383     double currentTime = WTF::currentTime();
384
385     setViewport(visibleRect, scale);
386     m_zoomManager.processNewScale(currentTime, scale);
387
388     return currentTime;
389 }
390
391 bool GLWebViewState::drawGL(IntRect& rect, SkRect& viewport, IntRect* invalRect,
392                             IntRect& webViewRect, int titleBarHeight,
393                             IntRect& clip, float scale, bool* buffersSwappedPtr)
394 {
395     TilesManager::instance()->getProfiler()->nextFrame(viewport.fLeft,
396                                                        viewport.fTop,
397                                                        viewport.fRight,
398                                                        viewport.fBottom,
399                                                        scale);
400     TilesManager::instance()->incDrawGLCount();
401
402 #ifdef DEBUG
403     TilesManager::instance()->getTilesTracker()->clear();
404 #endif
405
406     m_baseLayerLock.lock();
407     BaseLayerAndroid* baseLayer = m_currentBaseLayer;
408     SkSafeRef(baseLayer);
409     BaseLayerAndroid* baseForComposited = m_baseLayer;
410     SkSafeRef(baseForComposited);
411     m_baseLayerLock.unlock();
412     if (!baseLayer) {
413         SkSafeUnref(baseForComposited);
414         return false;
415     }
416
417     float viewWidth = (viewport.fRight - viewport.fLeft) * TILE_PREFETCH_RATIO;
418     float viewHeight = (viewport.fBottom - viewport.fTop) * TILE_PREFETCH_RATIO;
419     bool useHorzPrefetch = viewWidth < baseContentWidth();
420     bool useVertPrefetch = viewHeight < baseContentHeight();
421     m_expandedTileBoundsX = (useHorzPrefetch) ? TILE_PREFETCH_DISTANCE : 0;
422     m_expandedTileBoundsY = (useVertPrefetch) ? TILE_PREFETCH_DISTANCE : 0;
423
424     XLOG("drawGL, rect(%d, %d, %d, %d), viewport(%.2f, %.2f, %.2f, %.2f)",
425          rect.x(), rect.y(), rect.width(), rect.height(),
426          viewport.fLeft, viewport.fTop, viewport.fRight, viewport.fBottom);
427
428     resetLayersDirtyArea();
429
430     if (!baseForComposited ||
431         (baseForComposited && !baseForComposited->countChildren())) {
432         SkSafeRef(baseLayer);
433         SkSafeUnref(baseForComposited);
434         baseForComposited = baseLayer;
435     }
436
437     LayerAndroid* compositedRoot = 0;
438     if (baseForComposited && baseForComposited->countChildren() >= 1)
439         compositedRoot = static_cast<LayerAndroid*>(baseForComposited->getChild(0));
440
441     if (scale < MIN_SCALE_WARNING || scale > MAX_SCALE_WARNING)
442         XLOGC("WARNING, scale seems corrupted before update: %e", scale);
443
444     // Here before we draw, update the BaseTile which has updated content.
445     // Inside this function, just do GPU blits from the transfer queue into
446     // the BaseTiles' texture.
447     TilesManager::instance()->transferQueue()->updateDirtyBaseTiles();
448
449     // Upload any pending ImageTexture
450     // Return true if we still have some images to upload.
451     // TODO: upload as many textures as possible within a certain time limit
452     bool ret = ImagesManager::instance()->uploadTextures();
453
454     if (scale < MIN_SCALE_WARNING || scale > MAX_SCALE_WARNING) {
455         XLOGC("WARNING, scale seems corrupted after update: %e", scale);
456         CRASH();
457     }
458
459     // gather the textures we can use
460     TilesManager::instance()->gatherLayerTextures();
461
462     if (compositedRoot != m_previouslyUsedRoot)
463         TilesManager::instance()->swapLayersTextures(m_previouslyUsedRoot, compositedRoot);
464
465     // set up zoom manager, shaders, etc.
466     m_backgroundColor = baseLayer->getBackgroundColor();
467     double currentTime = setupDrawing(rect, viewport, webViewRect, titleBarHeight, clip, scale);
468     ret |= baseLayer->drawGL(currentTime, compositedRoot, rect,
469                                  viewport, scale, buffersSwappedPtr);
470     m_glExtras.drawGL(webViewRect, viewport, titleBarHeight);
471
472     glBindBuffer(GL_ARRAY_BUFFER, 0);
473
474     SkSafeRef(compositedRoot);
475     SkSafeUnref(m_previouslyUsedRoot);
476     m_previouslyUsedRoot = compositedRoot;
477
478     ret |= TilesManager::instance()->invertedScreenSwitch();
479
480     if (ret) {
481         // ret==true && empty inval region means we've inval'd everything,
482         // but don't have new content. Keep redrawing full view (0,0,0,0)
483         // until tile generation catches up and we swap pages.
484         bool fullScreenInval = m_frameworkInval.isEmpty();
485
486         if (TilesManager::instance()->invertedScreenSwitch()) {
487             fullScreenInval = true;
488             TilesManager::instance()->setInvertedScreenSwitch(false);
489         }
490
491         if (!fullScreenInval) {
492             FloatRect frameworkInval = TilesManager::instance()->shader()->rectInInvScreenCoord(
493                     m_frameworkInval);
494             // Inflate the invalidate rect to avoid precision lost.
495             frameworkInval.inflate(1);
496             IntRect inval(frameworkInval.x(), frameworkInval.y(),
497                     frameworkInval.width(), frameworkInval.height());
498
499             inval.unite(m_frameworkLayersInval);
500
501             invalRect->setX(inval.x());
502             invalRect->setY(inval.y());
503             invalRect->setWidth(inval.width());
504             invalRect->setHeight(inval.height());
505
506             XLOG("invalRect(%d, %d, %d, %d)", inval.x(),
507                     inval.y(), inval.width(), inval.height());
508
509             if (!invalRect->intersects(rect)) {
510                 // invalidate is occurring offscreen, do full inval to guarantee redraw
511                 fullScreenInval = true;
512             }
513         }
514
515         if (fullScreenInval) {
516             invalRect->setX(0);
517             invalRect->setY(0);
518             invalRect->setWidth(0);
519             invalRect->setHeight(0);
520         }
521     } else {
522         resetFrameworkInval();
523     }
524
525 #ifdef MEASURES_PERF
526     if (m_measurePerfs) {
527         m_delayTimes[m_timeCounter++] = delta;
528         if (m_timeCounter >= MAX_MEASURES_PERF)
529             dumpMeasures();
530     }
531 #endif
532
533     SkSafeUnref(baseForComposited);
534     SkSafeUnref(baseLayer);
535 #ifdef DEBUG
536     TilesManager::instance()->getTilesTracker()->showTrackTextures();
537     ImagesManager::instance()->showImages();
538 #endif
539     return ret;
540 }
541
542 } // namespace WebCore
543
544 #endif // USE(ACCELERATED_COMPOSITING)