OSDN Git Service

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