OSDN Git Service

Merge "Fix extras clipping" into ics-mr1
[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()
73     : m_zoomManager(this)
74     , m_paintingBaseLayer(0)
75     , m_currentBaseLayer(0)
76     , m_currentBaseLayerRoot(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_baseLayerUpdate(true)
82     , m_backgroundColor(SK_ColorWHITE)
83     , m_isScrolling(false)
84     , m_goingDown(true)
85     , m_goingLeft(false)
86     , m_expandedTileBoundsX(0)
87     , m_expandedTileBoundsY(0)
88     , m_scale(1)
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_currentBaseLayerRoot)
112         TilesManager::instance()->swapLayersTextures(m_currentBaseLayerRoot, 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_paintingBaseLayer 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_paintingBaseLayer);
126     SkSafeUnref(m_currentBaseLayer);
127     SkSafeUnref(m_currentBaseLayerRoot);
128     m_paintingBaseLayer = 0;
129     m_currentBaseLayer = 0;
130     m_currentBaseLayerRoot = 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
150     SkSafeRef(layer);
151     SkSafeUnref(m_currentBaseLayer);
152     m_currentBaseLayer = layer;
153
154
155     // copy content from old composited root to new
156     LayerAndroid* oldRoot = m_currentBaseLayerRoot;
157     if (layer) {
158         layer->setGLWebViewState(this);
159         m_currentBaseLayerRoot = static_cast<LayerAndroid*>(layer->getChild(0));
160         SkSafeRef(m_currentBaseLayerRoot);
161     } else {
162         m_currentBaseLayerRoot = 0;
163     }
164     if (oldRoot != m_currentBaseLayerRoot)
165         TilesManager::instance()->swapLayersTextures(oldRoot, m_currentBaseLayerRoot);
166     SkSafeUnref(oldRoot);
167
168     // We only update the base layer if we are not currently
169     // waiting for a tiledPage to be painted
170     if (m_baseLayerUpdate) {
171         SkSafeRef(layer);
172         SkSafeUnref(m_paintingBaseLayer);
173         m_paintingBaseLayer = layer;
174     }
175     m_glExtras.setDrawExtra(0);
176     invalRegion(inval);
177
178 #ifdef MEASURES_PERF
179     if (m_measurePerfs && !showVisualIndicator)
180         dumpMeasures();
181     m_measurePerfs = showVisualIndicator;
182 #endif
183
184     TilesManager::instance()->setShowVisualIndicator(showVisualIndicator);
185 }
186
187 void GLWebViewState::invalRegion(const SkRegion& region)
188 {
189     SkRegion::Iterator iterator(region);
190     while (!iterator.done()) {
191         SkIRect r = iterator.rect();
192         IntRect ir(r.fLeft, r.fTop, r.width(), r.height());
193         inval(ir);
194         iterator.next();
195     }
196 }
197
198 void GLWebViewState::unlockBaseLayerUpdate() {
199     if (m_baseLayerUpdate)
200         return;
201
202     m_baseLayerUpdate = true;
203     android::Mutex::Autolock lock(m_baseLayerLock);
204     SkSafeRef(m_currentBaseLayer);
205     SkSafeUnref(m_paintingBaseLayer);
206     m_paintingBaseLayer = m_currentBaseLayer;
207
208     invalRegion(m_invalidateRegion);
209     m_invalidateRegion.setEmpty();
210 }
211
212 void GLWebViewState::inval(const IntRect& rect)
213 {
214     if (m_baseLayerUpdate) {
215         // base layer isn't locked, so go ahead and issue the inval to both tiled pages
216         m_currentPictureCounter++;
217         if (!rect.isEmpty()) {
218             // find which tiles fall within the invalRect and mark them as dirty
219             m_tiledPageA->invalidateRect(rect, m_currentPictureCounter);
220             m_tiledPageB->invalidateRect(rect, m_currentPictureCounter);
221             if (m_frameworkInval.isEmpty())
222                 m_frameworkInval = rect;
223             else
224                 m_frameworkInval.unite(rect);
225             XLOG("intermediate invalRect(%d, %d, %d, %d) after unite with rect %d %d %d %d", m_frameworkInval.x(),
226                  m_frameworkInval.y(), m_frameworkInval.width(), m_frameworkInval.height(),
227                  rect.x(), rect.y(), rect.width(), rect.height());
228         }
229     } else {
230         // base layer is locked, so defer invalidation until unlockBaseLayerUpdate()
231         m_invalidateRegion.op(rect.x(), rect.y(), rect.maxX(), rect.maxY(), SkRegion::kUnion_Op);
232     }
233     TilesManager::instance()->getProfiler()->nextInval(rect, zoomManager()->currentScale());
234 }
235
236 unsigned int GLWebViewState::paintBaseLayerContent(SkCanvas* canvas)
237 {
238     m_baseLayerLock.lock();
239     BaseLayerAndroid* base = m_paintingBaseLayer;
240     SkSafeRef(base);
241     m_baseLayerLock.unlock();
242     if (base) {
243         base->drawCanvas(canvas);
244     }
245     SkSafeUnref(base);
246     return m_currentPictureCounter;
247 }
248
249 TiledPage* GLWebViewState::sibling(TiledPage* page)
250 {
251     return (page == m_tiledPageA) ? m_tiledPageB : m_tiledPageA;
252 }
253
254 TiledPage* GLWebViewState::frontPage()
255 {
256     android::Mutex::Autolock lock(m_tiledPageLock);
257     return m_usePageA ? m_tiledPageA : m_tiledPageB;
258 }
259
260 TiledPage* GLWebViewState::backPage()
261 {
262     android::Mutex::Autolock lock(m_tiledPageLock);
263     return m_usePageA ? m_tiledPageB : m_tiledPageA;
264 }
265
266 void GLWebViewState::swapPages()
267 {
268     android::Mutex::Autolock lock(m_tiledPageLock);
269     m_usePageA ^= true;
270     TiledPage* oldPage = m_usePageA ? m_tiledPageB : m_tiledPageA;
271     zoomManager()->swapPages();
272     oldPage->discardTextures();
273 }
274
275 int GLWebViewState::baseContentWidth()
276 {
277     return m_paintingBaseLayer ? m_paintingBaseLayer->content()->width() : 0;
278 }
279 int GLWebViewState::baseContentHeight()
280 {
281     return m_paintingBaseLayer ? m_paintingBaseLayer->content()->height() : 0;
282 }
283
284 void GLWebViewState::setViewport(SkRect& viewport, float scale)
285 {
286     if ((m_viewport == viewport) &&
287         (zoomManager()->futureScale() == scale))
288         return;
289
290     m_goingDown = m_viewport.fTop - viewport.fTop <= 0;
291     m_goingLeft = m_viewport.fLeft - viewport.fLeft >= 0;
292     m_viewport = viewport;
293
294     XLOG("New VIEWPORT %.2f - %.2f %.2f - %.2f (w: %2.f h: %.2f scale: %.2f currentScale: %.2f futureScale: %.2f)",
295          m_viewport.fLeft, m_viewport.fTop, m_viewport.fRight, m_viewport.fBottom,
296          m_viewport.width(), m_viewport.height(), scale,
297          zoomManager()->currentScale(), zoomManager()->futureScale());
298
299     const float invTileContentWidth = scale / TilesManager::tileWidth();
300     const float invTileContentHeight = scale / TilesManager::tileHeight();
301
302     m_viewportTileBounds.set(
303             static_cast<int>(floorf(viewport.fLeft * invTileContentWidth)),
304             static_cast<int>(floorf(viewport.fTop * invTileContentHeight)),
305             static_cast<int>(ceilf(viewport.fRight * invTileContentWidth)),
306             static_cast<int>(ceilf(viewport.fBottom * invTileContentHeight)));
307
308     // allocate max possible number of tiles visible with this viewport
309     int viewMaxTileX = static_cast<int>(ceilf((viewport.width()-1) * invTileContentWidth)) + 1;
310     int viewMaxTileY = static_cast<int>(ceilf((viewport.height()-1) * invTileContentHeight)) + 1;
311
312     int maxTextureCount = (viewMaxTileX + m_expandedTileBoundsX * 2) *
313         (viewMaxTileY + m_expandedTileBoundsY * 2) * 2;
314
315     TilesManager::instance()->setMaxTextureCount(maxTextureCount);
316     m_tiledPageA->updateBaseTileSize();
317     m_tiledPageB->updateBaseTileSize();
318 }
319
320 #ifdef MEASURES_PERF
321 void GLWebViewState::dumpMeasures()
322 {
323     for (int i = 0; i < m_timeCounter; i++) {
324         XLOGC("%d delay: %d ms", m_totalTimeCounter + i,
325              static_cast<int>(m_delayTimes[i]*1000));
326         m_delayTimes[i] = 0;
327     }
328     m_totalTimeCounter += m_timeCounter;
329     m_timeCounter = 0;
330 }
331 #endif // MEASURES_PERF
332
333 void GLWebViewState::resetFrameworkInval()
334 {
335     m_frameworkInval.setX(0);
336     m_frameworkInval.setY(0);
337     m_frameworkInval.setWidth(0);
338     m_frameworkInval.setHeight(0);
339 }
340
341 void GLWebViewState::addDirtyArea(const IntRect& rect)
342 {
343     if (rect.isEmpty())
344         return;
345
346     IntRect inflatedRect = rect;
347     inflatedRect.inflate(8);
348     if (m_frameworkLayersInval.isEmpty())
349         m_frameworkLayersInval = inflatedRect;
350     else
351         m_frameworkLayersInval.unite(inflatedRect);
352 }
353
354 void GLWebViewState::resetLayersDirtyArea()
355 {
356     m_frameworkLayersInval.setX(0);
357     m_frameworkLayersInval.setY(0);
358     m_frameworkLayersInval.setWidth(0);
359     m_frameworkLayersInval.setHeight(0);
360 }
361
362 double GLWebViewState::setupDrawing(IntRect& viewRect, SkRect& visibleRect,
363                                   IntRect& webViewRect, int titleBarHeight,
364                                   IntRect& screenClip, float scale)
365 {
366     int left = viewRect.x();
367     int top = viewRect.y();
368     int width = viewRect.width();
369     int height = viewRect.height();
370
371     if (TilesManager::instance()->invertedScreen()) {
372         float color = 1.0 - ((((float) m_backgroundColor.red() / 255.0) +
373                       ((float) m_backgroundColor.green() / 255.0) +
374                       ((float) m_backgroundColor.blue() / 255.0)) / 3.0);
375         glClearColor(color, color, color, 1);
376     } else {
377         glClearColor((float)m_backgroundColor.red() / 255.0,
378                      (float)m_backgroundColor.green() / 255.0,
379                      (float)m_backgroundColor.blue() / 255.0, 1);
380     }
381     glClear(GL_COLOR_BUFFER_BIT);
382
383     glViewport(left, top, width, height);
384
385     ShaderProgram* shader = TilesManager::instance()->shader();
386     if (shader->program() == -1) {
387         XLOG("Reinit shader");
388         shader->init();
389     }
390     shader->setViewRect(viewRect);
391     shader->setViewport(visibleRect);
392     shader->setWebViewRect(webViewRect);
393     shader->setTitleBarHeight(titleBarHeight);
394     shader->setScreenClip(screenClip);
395     shader->resetBlending();
396
397     double currentTime = WTF::currentTime();
398
399     setViewport(visibleRect, scale);
400     m_zoomManager.processNewScale(currentTime, scale);
401
402     return currentTime;
403 }
404
405 bool GLWebViewState::drawGL(IntRect& rect, SkRect& viewport, IntRect* invalRect,
406                             IntRect& webViewRect, int titleBarHeight,
407                             IntRect& clip, float scale, bool* buffersSwappedPtr)
408 {
409     m_scale = scale;
410     TilesManager::instance()->getProfiler()->nextFrame(viewport.fLeft,
411                                                        viewport.fTop,
412                                                        viewport.fRight,
413                                                        viewport.fBottom,
414                                                        scale);
415     TilesManager::instance()->incDrawGLCount();
416
417 #ifdef DEBUG
418     TilesManager::instance()->getTilesTracker()->clear();
419 #endif
420
421     m_baseLayerLock.lock();
422     BaseLayerAndroid* baseLayer = m_paintingBaseLayer;
423     SkSafeRef(baseLayer);
424     m_baseLayerLock.unlock();
425     if (!baseLayer)
426          return false;
427
428     float viewWidth = (viewport.fRight - viewport.fLeft) * TILE_PREFETCH_RATIO;
429     float viewHeight = (viewport.fBottom - viewport.fTop) * TILE_PREFETCH_RATIO;
430     bool useMinimalMemory = TilesManager::instance()->useMinimalMemory();
431     bool useHorzPrefetch = useMinimalMemory ? 0 : viewWidth < baseContentWidth();
432     bool useVertPrefetch = useMinimalMemory ? 0 : viewHeight < baseContentHeight();
433     m_expandedTileBoundsX = (useHorzPrefetch) ? TILE_PREFETCH_DISTANCE : 0;
434     m_expandedTileBoundsY = (useVertPrefetch) ? TILE_PREFETCH_DISTANCE : 0;
435
436     XLOG("drawGL, rect(%d, %d, %d, %d), viewport(%.2f, %.2f, %.2f, %.2f)",
437          rect.x(), rect.y(), rect.width(), rect.height(),
438          viewport.fLeft, viewport.fTop, viewport.fRight, viewport.fBottom);
439
440     resetLayersDirtyArea();
441
442     LayerAndroid* compositedRoot = m_currentBaseLayerRoot;
443     LayerAndroid* paintingBaseLayerRoot = 0;
444     if (baseLayer && baseLayer->countChildren() >= 1)
445         paintingBaseLayerRoot = static_cast<LayerAndroid*>(baseLayer->getChild(0));
446
447     // when adding or removing layers, use the the paintingBaseLayer's tree so
448     // that content that moves to the base layer from a layer is synchronized
449     bool paintingHasLayers = (paintingBaseLayerRoot == 0);
450     bool currentHasLayers = (m_currentBaseLayerRoot == 0);
451     if (paintingHasLayers != currentHasLayers)
452         compositedRoot = paintingBaseLayerRoot;
453
454     if (scale < MIN_SCALE_WARNING || scale > MAX_SCALE_WARNING)
455         XLOGC("WARNING, scale seems corrupted before update: %e", scale);
456
457     // Here before we draw, update the BaseTile which has updated content.
458     // Inside this function, just do GPU blits from the transfer queue into
459     // the BaseTiles' texture.
460     TilesManager::instance()->transferQueue()->updateDirtyBaseTiles();
461
462     // Upload any pending ImageTexture
463     // Return true if we still have some images to upload.
464     // TODO: upload as many textures as possible within a certain time limit
465     bool ret = ImagesManager::instance()->uploadTextures();
466
467     if (scale < MIN_SCALE_WARNING || scale > MAX_SCALE_WARNING) {
468         XLOGC("WARNING, scale seems corrupted after update: %e", scale);
469         CRASH();
470     }
471
472     // gather the textures we can use
473     TilesManager::instance()->gatherLayerTextures();
474
475     // set up zoom manager, shaders, etc.
476     m_backgroundColor = baseLayer->getBackgroundColor();
477     double currentTime = setupDrawing(rect, viewport, webViewRect, titleBarHeight, clip, scale);
478     ret |= baseLayer->drawGL(currentTime, compositedRoot, rect,
479                                  viewport, scale, buffersSwappedPtr);
480     FloatRect extrasclip(0, 0, rect.width(), rect.height());
481     TilesManager::instance()->shader()->clip(extrasclip);
482     m_glExtras.drawGL(webViewRect, viewport, titleBarHeight);
483
484     glBindBuffer(GL_ARRAY_BUFFER, 0);
485
486     ret |= TilesManager::instance()->invertedScreenSwitch();
487
488     if (ret) {
489         // ret==true && empty inval region means we've inval'd everything,
490         // but don't have new content. Keep redrawing full view (0,0,0,0)
491         // until tile generation catches up and we swap pages.
492         bool fullScreenInval = m_frameworkInval.isEmpty();
493
494         if (TilesManager::instance()->invertedScreenSwitch()) {
495             fullScreenInval = true;
496             TilesManager::instance()->setInvertedScreenSwitch(false);
497         }
498
499         if (!fullScreenInval) {
500             FloatRect frameworkInval = TilesManager::instance()->shader()->rectInInvScreenCoord(
501                     m_frameworkInval);
502             // Inflate the invalidate rect to avoid precision lost.
503             frameworkInval.inflate(1);
504             IntRect inval(frameworkInval.x(), frameworkInval.y(),
505                     frameworkInval.width(), frameworkInval.height());
506
507             inval.unite(m_frameworkLayersInval);
508
509             invalRect->setX(inval.x());
510             invalRect->setY(inval.y());
511             invalRect->setWidth(inval.width());
512             invalRect->setHeight(inval.height());
513
514             XLOG("invalRect(%d, %d, %d, %d)", inval.x(),
515                     inval.y(), inval.width(), inval.height());
516
517             if (!invalRect->intersects(rect)) {
518                 // invalidate is occurring offscreen, do full inval to guarantee redraw
519                 fullScreenInval = true;
520             }
521         }
522
523         if (fullScreenInval) {
524             invalRect->setX(0);
525             invalRect->setY(0);
526             invalRect->setWidth(0);
527             invalRect->setHeight(0);
528         }
529     } else {
530         resetFrameworkInval();
531     }
532
533 #ifdef MEASURES_PERF
534     if (m_measurePerfs) {
535         m_delayTimes[m_timeCounter++] = delta;
536         if (m_timeCounter >= MAX_MEASURES_PERF)
537             dumpMeasures();
538     }
539 #endif
540
541     SkSafeUnref(baseLayer);
542 #ifdef DEBUG
543     TilesManager::instance()->getTilesTracker()->showTrackTextures();
544     ImagesManager::instance()->showImages();
545 #endif
546     return ret;
547 }
548
549 } // namespace WebCore
550
551 #endif // USE(ACCELERATED_COMPOSITING)