OSDN Git Service

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