• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #define LOG_TAG "GLWebViewState"
27 #define LOG_NDEBUG 1
28 
29 #include "config.h"
30 #include "GLWebViewState.h"
31 
32 #if USE(ACCELERATED_COMPOSITING)
33 
34 #include "AndroidLog.h"
35 #include "BaseLayerAndroid.h"
36 #include "ClassTracker.h"
37 #include "GLUtils.h"
38 #include "ImagesManager.h"
39 #include "LayerAndroid.h"
40 #include "private/hwui/DrawGlInfo.h"
41 #include "ScrollableLayerAndroid.h"
42 #include "SkPath.h"
43 #include "TilesManager.h"
44 #include "TransferQueue.h"
45 #include "SurfaceCollection.h"
46 #include "SurfaceCollectionManager.h"
47 #include <pthread.h>
48 #include <wtf/CurrentTime.h>
49 
50 // log warnings if scale goes outside this range
51 #define MIN_SCALE_WARNING 0.1
52 #define MAX_SCALE_WARNING 10
53 
54 // fps indicator is FPS_INDICATOR_HEIGHT pixels high.
55 // The max width is equal to MAX_FPS_VALUE fps.
56 #define FPS_INDICATOR_HEIGHT 10
57 #define MAX_FPS_VALUE 60
58 
59 #define COLLECTION_SWAPPED_COUNTER_MODULE 10
60 
61 namespace WebCore {
62 
63 using namespace android::uirenderer;
64 
GLWebViewState()65 GLWebViewState::GLWebViewState()
66     : m_frameworkLayersInval(0, 0, 0, 0)
67     , m_doFrameworkFullInval(false)
68     , m_isScrolling(false)
69     , m_isVisibleContentRectScrolling(false)
70     , m_goingDown(true)
71     , m_goingLeft(false)
72     , m_scale(1)
73     , m_layersRenderingMode(kAllTextures)
74     , m_surfaceCollectionManager()
75 {
76     m_visibleContentRect.setEmpty();
77 
78 #ifdef DEBUG_COUNT
79     ClassTracker::instance()->increment("GLWebViewState");
80 #endif
81 #ifdef MEASURES_PERF
82     m_timeCounter = 0;
83     m_totalTimeCounter = 0;
84     m_measurePerfs = false;
85 #endif
86 }
87 
~GLWebViewState()88 GLWebViewState::~GLWebViewState()
89 {
90 #ifdef DEBUG_COUNT
91     ClassTracker::instance()->decrement("GLWebViewState");
92 #endif
93 
94 }
95 
setBaseLayer(BaseLayerAndroid * layer,bool showVisualIndicator,bool isPictureAfterFirstLayout)96 bool GLWebViewState::setBaseLayer(BaseLayerAndroid* layer, bool showVisualIndicator,
97                                   bool isPictureAfterFirstLayout)
98 {
99     if (!layer || isPictureAfterFirstLayout)
100         m_layersRenderingMode = kAllTextures;
101 
102     SurfaceCollection* collection = 0;
103     if (layer) {
104         ALOGV("layer tree %p, with child %p", layer, layer->getChild(0));
105         layer->setState(this);
106         collection = new SurfaceCollection(layer);
107     }
108     bool queueFull = m_surfaceCollectionManager.updateWithSurfaceCollection(
109         collection, isPictureAfterFirstLayout);
110     m_glExtras.setDrawExtra(0);
111 
112 #ifdef MEASURES_PERF
113     if (m_measurePerfs && !showVisualIndicator)
114         dumpMeasures();
115     m_measurePerfs = showVisualIndicator;
116 #endif
117 
118     TilesManager::instance()->setShowVisualIndicator(showVisualIndicator);
119     return queueFull;
120 }
121 
scrollLayer(int layerId,int x,int y)122 void GLWebViewState::scrollLayer(int layerId, int x, int y)
123 {
124     m_surfaceCollectionManager.updateScrollableLayer(layerId, x, y);
125 }
126 
setVisibleContentRect(const SkRect & visibleContentRect,float scale)127 void GLWebViewState::setVisibleContentRect(const SkRect& visibleContentRect, float scale)
128 {
129     // allocate max possible number of tiles visible with this visibleContentRect / expandedTileBounds
130     const float invTileContentWidth = scale / TilesManager::tileWidth();
131     const float invTileContentHeight = scale / TilesManager::tileHeight();
132 
133     int viewMaxTileX =
134         static_cast<int>(ceilf((visibleContentRect.width()-1) * invTileContentWidth)) + 1;
135     int viewMaxTileY =
136         static_cast<int>(ceilf((visibleContentRect.height()-1) * invTileContentHeight)) + 1;
137 
138     TilesManager* tilesManager = TilesManager::instance();
139     int maxTextureCount = viewMaxTileX * viewMaxTileY * (tilesManager->highEndGfx() ? 4 : 2);
140 
141     tilesManager->setCurrentTextureCount(maxTextureCount);
142 
143     // TODO: investigate whether we can move this return earlier.
144     if ((m_visibleContentRect == visibleContentRect)
145         && (m_scale == scale)) {
146         // everything below will stay the same, early return.
147         m_isVisibleContentRectScrolling = false;
148         return;
149     }
150     m_scale = scale;
151 
152     m_goingDown = m_visibleContentRect.fTop - visibleContentRect.fTop <= 0;
153     m_goingLeft = m_visibleContentRect.fLeft - visibleContentRect.fLeft >= 0;
154 
155     // detect visibleContentRect scrolling from short programmatic scrolls/jumps
156     m_isVisibleContentRectScrolling = m_visibleContentRect != visibleContentRect
157         && SkRect::Intersects(m_visibleContentRect, visibleContentRect);
158     m_visibleContentRect = visibleContentRect;
159 
160     ALOGV("New visibleContentRect %.2f - %.2f %.2f - %.2f (w: %2.f h: %.2f scale: %.2f )",
161           m_visibleContentRect.fLeft, m_visibleContentRect.fTop,
162           m_visibleContentRect.fRight, m_visibleContentRect.fBottom,
163           m_visibleContentRect.width(), m_visibleContentRect.height(), scale);
164 }
165 
166 #ifdef MEASURES_PERF
dumpMeasures()167 void GLWebViewState::dumpMeasures()
168 {
169     for (int i = 0; i < m_timeCounter; i++) {
170         ALOGD("%d delay: %d ms", m_totalTimeCounter + i,
171              static_cast<int>(m_delayTimes[i]*1000));
172         m_delayTimes[i] = 0;
173     }
174     m_totalTimeCounter += m_timeCounter;
175     m_timeCounter = 0;
176 }
177 #endif // MEASURES_PERF
178 
addDirtyArea(const IntRect & rect)179 void GLWebViewState::addDirtyArea(const IntRect& rect)
180 {
181     if (rect.isEmpty())
182         return;
183 
184     IntRect inflatedRect = rect;
185     inflatedRect.inflate(8);
186     if (m_frameworkLayersInval.isEmpty())
187         m_frameworkLayersInval = inflatedRect;
188     else
189         m_frameworkLayersInval.unite(inflatedRect);
190 }
191 
resetLayersDirtyArea()192 void GLWebViewState::resetLayersDirtyArea()
193 {
194     m_frameworkLayersInval.setX(0);
195     m_frameworkLayersInval.setY(0);
196     m_frameworkLayersInval.setWidth(0);
197     m_frameworkLayersInval.setHeight(0);
198     m_doFrameworkFullInval = false;
199 }
200 
doFrameworkFullInval()201 void GLWebViewState::doFrameworkFullInval()
202 {
203     m_doFrameworkFullInval = true;
204 }
205 
setupDrawing(const IntRect & invScreenRect,const SkRect & visibleContentRect,const IntRect & screenRect,int titleBarHeight,const IntRect & screenClip,float scale)206 double GLWebViewState::setupDrawing(const IntRect& invScreenRect,
207                                     const SkRect& visibleContentRect,
208                                     const IntRect& screenRect, int titleBarHeight,
209                                     const IntRect& screenClip, float scale)
210 {
211     TilesManager* tilesManager = TilesManager::instance();
212 
213     // Make sure GL resources are created on the UI thread.
214     // They are created either for the first time, or after EGL context
215     // recreation caused by onTrimMemory in the framework.
216     ShaderProgram* shader = tilesManager->shader();
217     if (shader->needsInit()) {
218         ALOGD("Reinit shader");
219         shader->initGLResources();
220     }
221     TransferQueue* transferQueue = tilesManager->transferQueue();
222     if (transferQueue->needsInit()) {
223         ALOGD("Reinit transferQueue");
224         transferQueue->initGLResources(TilesManager::tileWidth(),
225                                        TilesManager::tileHeight());
226     }
227     shader->setupDrawing(invScreenRect, visibleContentRect, screenRect,
228                          titleBarHeight, screenClip, scale);
229 
230     double currentTime = WTF::currentTime();
231 
232     setVisibleContentRect(visibleContentRect, scale);
233 
234     return currentTime;
235 }
236 
setLayersRenderingMode(TexturesResult & nbTexturesNeeded)237 bool GLWebViewState::setLayersRenderingMode(TexturesResult& nbTexturesNeeded)
238 {
239     bool invalBase = false;
240 
241     if (!nbTexturesNeeded.full)
242         TilesManager::instance()->setCurrentLayerTextureCount(0);
243     else
244         TilesManager::instance()->setCurrentLayerTextureCount((2 * nbTexturesNeeded.full) + 1);
245 
246     int maxTextures = TilesManager::instance()->currentLayerTextureCount();
247     LayersRenderingMode layersRenderingMode = m_layersRenderingMode;
248 
249     if (m_layersRenderingMode == kSingleSurfaceRendering) {
250         // only switch out of SingleSurface mode, if we have 2x needed textures
251         // to avoid changing too often
252         maxTextures /= 2;
253     }
254 
255     m_layersRenderingMode = kSingleSurfaceRendering;
256     if (nbTexturesNeeded.fixed < maxTextures)
257         m_layersRenderingMode = kFixedLayers;
258     if (nbTexturesNeeded.scrollable < maxTextures)
259         m_layersRenderingMode = kScrollableAndFixedLayers;
260     if (nbTexturesNeeded.clipped < maxTextures)
261         m_layersRenderingMode = kClippedTextures;
262     if (nbTexturesNeeded.full < maxTextures)
263         m_layersRenderingMode = kAllTextures;
264 
265     if (!maxTextures && !nbTexturesNeeded.full)
266         m_layersRenderingMode = kAllTextures;
267 
268     if (m_layersRenderingMode < layersRenderingMode
269         && m_layersRenderingMode != kAllTextures)
270         invalBase = true;
271 
272     if (m_layersRenderingMode > layersRenderingMode
273         && m_layersRenderingMode != kClippedTextures)
274         invalBase = true;
275 
276 #ifdef DEBUG
277     if (m_layersRenderingMode != layersRenderingMode) {
278         char* mode[] = { "kAllTextures", "kClippedTextures",
279             "kScrollableAndFixedLayers", "kFixedLayers", "kSingleSurfaceRendering" };
280         ALOGD("Change from mode %s to %s -- We need textures: fixed: %d,"
281               " scrollable: %d, clipped: %d, full: %d, max textures: %d",
282               static_cast<char*>(mode[layersRenderingMode]),
283               static_cast<char*>(mode[m_layersRenderingMode]),
284               nbTexturesNeeded.fixed,
285               nbTexturesNeeded.scrollable,
286               nbTexturesNeeded.clipped,
287               nbTexturesNeeded.full, maxTextures);
288     }
289 #endif
290 
291     // For now, anything below kClippedTextures is equivalent
292     // to kSingleSurfaceRendering
293     // TODO: implement the other rendering modes
294     if (m_layersRenderingMode > kClippedTextures)
295         m_layersRenderingMode = kSingleSurfaceRendering;
296 
297     // update the base surface if needed
298     // TODO: inval base layergroup when going into single surface mode
299     return (m_layersRenderingMode != layersRenderingMode && invalBase);
300 }
301 
302 // -invScreenRect is the webView's rect with inverted Y screen coordinate.
303 // -visibleContentRect is the visible area in content coordinate.
304 // They are both based on  webView's rect and calculated in Java side.
305 //
306 // -screenClip is in screen coordinate, so we need to invert the Y axis before
307 // passing into GL functions. Clip can be smaller than the webView's rect.
308 //
309 // TODO: Try to decrease the number of parameters as some info is redundant.
drawGL(IntRect & invScreenRect,SkRect & visibleContentRect,IntRect * invalRect,IntRect & screenRect,int titleBarHeight,IntRect & screenClip,float scale,bool * collectionsSwappedPtr,bool * newCollectionHasAnimPtr,bool shouldDraw)310 int GLWebViewState::drawGL(IntRect& invScreenRect, SkRect& visibleContentRect,
311                            IntRect* invalRect, IntRect& screenRect, int titleBarHeight,
312                            IntRect& screenClip, float scale,
313                            bool* collectionsSwappedPtr, bool* newCollectionHasAnimPtr,
314                            bool shouldDraw)
315 {
316     TilesManager* tilesManager = TilesManager::instance();
317     if (shouldDraw)
318         tilesManager->getProfiler()->nextFrame(visibleContentRect.fLeft,
319                                                visibleContentRect.fTop,
320                                                visibleContentRect.fRight,
321                                                visibleContentRect.fBottom,
322                                                scale);
323     tilesManager->incDrawGLCount();
324 
325     ALOGV("drawGL, invScreenRect(%d, %d, %d, %d), visibleContentRect(%.2f, %.2f, %.2f, %.2f)",
326           invScreenRect.x(), invScreenRect.y(), invScreenRect.width(), invScreenRect.height(),
327           visibleContentRect.fLeft, visibleContentRect.fTop,
328           visibleContentRect.fRight, visibleContentRect.fBottom);
329 
330     ALOGV("drawGL, invalRect(%d, %d, %d, %d), screenRect(%d, %d, %d, %d)"
331           "screenClip (%d, %d, %d, %d), scale %f titleBarHeight %d",
332           invalRect->x(), invalRect->y(), invalRect->width(), invalRect->height(),
333           screenRect.x(), screenRect.y(), screenRect.width(), screenRect.height(),
334           screenClip.x(), screenClip.y(), screenClip.width(), screenClip.height(), scale, titleBarHeight);
335 
336     m_inUnclippedDraw = shouldDraw && (screenRect == screenClip);
337 
338     resetLayersDirtyArea();
339 
340     if (scale < MIN_SCALE_WARNING || scale > MAX_SCALE_WARNING)
341         ALOGW("WARNING, scale seems corrupted before update: %e", scale);
342 
343     tilesManager->updateTilesIfContextVerified();
344 
345     // gather the textures we can use, make sure this happens before any
346     // texture preparation work.
347     tilesManager->gatherTextures();
348 
349     // Upload any pending ImageTexture
350     // Return true if we still have some images to upload.
351     // TODO: upload as many textures as possible within a certain time limit
352     int returnFlags = 0;
353     if (ImagesManager::instance()->prepareTextures(this))
354         returnFlags |= DrawGlInfo::kStatusDraw;
355 
356     if (scale < MIN_SCALE_WARNING || scale > MAX_SCALE_WARNING) {
357         ALOGW("WARNING, scale seems corrupted after update: %e", scale);
358         scale = 1.0f; // WORKAROUND for corrupted scale: use 1.0
359     }
360 
361     double currentTime = setupDrawing(invScreenRect, visibleContentRect, screenRect,
362                                       titleBarHeight, screenClip, scale);
363 
364     TexturesResult nbTexturesNeeded;
365     bool scrolling = isScrolling();
366     bool singleSurfaceMode = m_layersRenderingMode == kSingleSurfaceRendering;
367     m_glExtras.setVisibleContentRect(visibleContentRect);
368 
369     returnFlags |= m_surfaceCollectionManager.drawGL(currentTime, invScreenRect,
370                                                      visibleContentRect,
371                                                      scale, scrolling,
372                                                      singleSurfaceMode,
373                                                      collectionsSwappedPtr,
374                                                      newCollectionHasAnimPtr,
375                                                      &nbTexturesNeeded, shouldDraw);
376 
377     int nbTexturesForImages = ImagesManager::instance()->nbTextures();
378     ALOGV("*** We have %d textures for images, %d full, %d clipped, total %d / %d",
379           nbTexturesForImages, nbTexturesNeeded.full, nbTexturesNeeded.clipped,
380           nbTexturesNeeded.full + nbTexturesForImages,
381           nbTexturesNeeded.clipped + nbTexturesForImages);
382     nbTexturesNeeded.full += nbTexturesForImages;
383     nbTexturesNeeded.clipped += nbTexturesForImages;
384 
385     if (setLayersRenderingMode(nbTexturesNeeded)) {
386         TilesManager::instance()->dirtyAllTiles();
387         returnFlags |= DrawGlInfo::kStatusDraw | DrawGlInfo::kStatusInvoke;
388     }
389 
390     glBindBuffer(GL_ARRAY_BUFFER, 0);
391 
392     if (returnFlags & DrawGlInfo::kStatusDraw) {
393         // returnFlags & kStatusDraw && empty inval region means we've inval'd everything,
394         // but don't have new content. Keep redrawing full view (0,0,0,0)
395         // until tile generation catches up and we swap pages.
396         bool fullScreenInval = m_frameworkLayersInval.isEmpty() || m_doFrameworkFullInval;
397 
398         if (!fullScreenInval) {
399             m_frameworkLayersInval.inflate(1);
400 
401             invalRect->setX(m_frameworkLayersInval.x());
402             invalRect->setY(m_frameworkLayersInval.y());
403             invalRect->setWidth(m_frameworkLayersInval.width());
404             invalRect->setHeight(m_frameworkLayersInval.height());
405 
406             ALOGV("invalRect(%d, %d, %d, %d)", invalRect->x(),
407                   invalRect->y(), invalRect->width(), invalRect->height());
408 
409             if (!invalRect->intersects(invScreenRect)) {
410                 // invalidate is occurring offscreen, do full inval to guarantee redraw
411                 fullScreenInval = true;
412             }
413         }
414 
415         if (fullScreenInval) {
416             invalRect->setX(0);
417             invalRect->setY(0);
418             invalRect->setWidth(0);
419             invalRect->setHeight(0);
420         }
421     }
422 
423     if (shouldDraw)
424         showFrameInfo(invScreenRect, *collectionsSwappedPtr);
425 
426     return returnFlags;
427 }
428 
showFrameInfo(const IntRect & rect,bool collectionsSwapped)429 void GLWebViewState::showFrameInfo(const IntRect& rect, bool collectionsSwapped)
430 {
431     bool showVisualIndicator = TilesManager::instance()->getShowVisualIndicator();
432 
433     bool drawOrDumpFrameInfo = showVisualIndicator;
434 #ifdef MEASURES_PERF
435     drawOrDumpFrameInfo |= m_measurePerfs;
436 #endif
437     if (!drawOrDumpFrameInfo)
438         return;
439 
440     double currentDrawTime = WTF::currentTime();
441     double delta = currentDrawTime - m_prevDrawTime;
442     m_prevDrawTime = currentDrawTime;
443 
444 #ifdef MEASURES_PERF
445     if (m_measurePerfs) {
446         m_delayTimes[m_timeCounter++] = delta;
447         if (m_timeCounter >= MAX_MEASURES_PERF)
448             dumpMeasures();
449     }
450 #endif
451 
452     IntRect frameInfoRect = rect;
453     frameInfoRect.setHeight(FPS_INDICATOR_HEIGHT);
454     double ratio = (1.0 / delta) / MAX_FPS_VALUE;
455 
456     clearRectWithColor(frameInfoRect, 1, 1, 1, 1);
457     frameInfoRect.setWidth(frameInfoRect.width() * ratio);
458     clearRectWithColor(frameInfoRect, 1, 0, 0, 1);
459 
460     // Draw the collection swap counter as a circling progress bar.
461     // This will basically show how fast we are updating the collection.
462     static int swappedCounter = 0;
463     if (collectionsSwapped)
464         swappedCounter = (swappedCounter + 1) % COLLECTION_SWAPPED_COUNTER_MODULE;
465 
466     frameInfoRect = rect;
467     frameInfoRect.setHeight(FPS_INDICATOR_HEIGHT);
468     frameInfoRect.move(0, FPS_INDICATOR_HEIGHT);
469 
470     clearRectWithColor(frameInfoRect, 1, 1, 1, 1);
471     ratio = (swappedCounter + 1.0) / COLLECTION_SWAPPED_COUNTER_MODULE;
472 
473     frameInfoRect.setWidth(frameInfoRect.width() * ratio);
474     clearRectWithColor(frameInfoRect, 0, 1, 0, 1);
475 }
476 
clearRectWithColor(const IntRect & rect,float r,float g,float b,float a)477 void GLWebViewState::clearRectWithColor(const IntRect& rect, float r, float g,
478                                       float b, float a)
479 {
480     glScissor(rect.x(), rect.y(), rect.width(), rect.height());
481     glClearColor(r, g, b, a);
482     glClear(GL_COLOR_BUFFER_BIT);
483 }
484 
485 } // namespace WebCore
486 
487 #endif // USE(ACCELERATED_COMPOSITING)
488