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 #ifndef GLWebViewState_h 27 #define GLWebViewState_h 28 29 #if USE(ACCELERATED_COMPOSITING) 30 31 #include "Color.h" 32 #include "DrawExtra.h" 33 #include "GLExtras.h" 34 #include "IntRect.h" 35 #include "SkCanvas.h" 36 #include "SkRect.h" 37 #include "SkRegion.h" 38 #include "TiledPage.h" 39 #include "ZoomManager.h" 40 #include <utils/threads.h> 41 42 // Performance measurements probe 43 // To use it, enable the visual indicators in debug mode. 44 // turning off the visual indicators will flush the measures. 45 // #define MEASURES_PERF 46 #define MAX_MEASURES_PERF 2000 47 48 // Prefetch and render 1 tiles ahead of the scroll 49 // TODO: We should either dynamically change the outer bound by detecting the 50 // HW limit or save further in the GPU memory consumption. 51 #define TILE_PREFETCH_DISTANCE 1 52 53 // ratio of content to view required for prefetching to enable 54 #define TILE_PREFETCH_RATIO 1.2 55 56 namespace WebCore { 57 58 class BaseLayerAndroid; 59 class LayerAndroid; 60 61 ///////////////////////////////////////////////////////////////////////////////// 62 // GL Architecture 63 ///////////////////////////////////////////////////////////////////////////////// 64 // 65 // To draw things, WebView use a tree of layers. The root of that tree is a 66 // BaseLayerAndroid, which may have numerous LayerAndroid over it. The content 67 // of those layers are SkPicture, the content of the BaseLayer is an PictureSet. 68 // 69 // When drawing, we therefore have one large "surface" that is the BaseLayer, 70 // and (possibly) additional surfaces (usually smaller), which are the 71 // LayerAndroids. The BaseLayer usually corresponds to the normal web page 72 // content, the Layers are used for some parts such as specific divs (e.g. fixed 73 // position divs, or elements using CSS3D transforms, or containing video, 74 // plugins, etc.). 75 // 76 // *** NOTE: The GL drawing architecture only paints the BaseLayer for now. 77 // 78 // The rendering model is to use tiles to display the BaseLayer (as obviously a 79 // BaseLayer's area can be arbitrarly large). The idea is to compute a set of 80 // tiles covering the viewport's area, paint those tiles using the webview's 81 // content (i.e. the BaseLayer's PictureSet), then display those tiles. 82 // We check which tile we should use at every frame. 83 // 84 // Overview 85 // --------- 86 // 87 // The tiles are grouped into a TiledPage -- basically a map of tiles covering 88 // the BaseLayer's surface. When drawing, we ask the TiledPage to prepare() 89 // itself then draw itself on screen. The prepare() function is the one 90 // that schedules tiles to be painted -- i.e. the subset of tiles that intersect 91 // with the current viewport. When they are ready, we can display 92 // the TiledPage. 93 // 94 // Note that BaseLayerAndroid::drawGL() will return true to the java side if 95 // there is a need to be called again (i.e. if we do not have up to date 96 // textures or a transition is going on). 97 // 98 // Tiles are implemented as a BaseTile. It knows how to paint itself with the 99 // PictureSet, and to display itself. A GL texture is usually associated to it. 100 // 101 // We also works with two TiledPages -- one to display the page at the 102 // current scale factor, and another we use to paint the page at a different 103 // scale factor. I.e. when we zoom, we use TiledPage A, with its tiles scaled 104 // accordingly (and therefore possible loss of quality): this is fast as it's 105 // purely a hardware operation. When the user is done zooming, we ask for 106 // TiledPage B to be painted at the new scale factor, covering the 107 // viewport's area. When B is ready, we swap it with A. 108 // 109 // Texture allocation 110 // ------------------ 111 // 112 // Obviously we cannot have every BaseTile having a GL texture -- we need to 113 // get the GL textures from an existing pool, and reuse them. 114 // 115 // The way we do it is that when we call TiledPage::prepare(), we group the 116 // tiles we need (i.e. in the viewport and dirty) into a TilesSet and call 117 // BaseTile::reserveTexture() for each tile (which ensures there is a specific 118 // GL textures backing the BaseTiles). 119 // 120 // reserveTexture() will ask the TilesManager for a texture. The allocation 121 // mechanism goal is to (in order): 122 // - prefers to allocate the same texture as the previous time 123 // - prefers to allocate textures that are as far from the viewport as possible 124 // - prefers to allocate textures that are used by different TiledPages 125 // 126 // Note that to compute the distance of each tile from the viewport, each time 127 // we prepare() a TiledPage. Also during each prepare() we compute which tiles 128 // are dirty based on the info we have received from webkit. 129 // 130 // BaseTile Invalidation 131 // ------------------ 132 // 133 // We do not want to redraw a tile if the tile is up-to-date. A tile is 134 // considered to be dirty an in need of redrawing in the following cases 135 // - the tile has acquires a new texture 136 // - webkit invalidates all or part of the tiles contents 137 // 138 // To handle the case of webkit invalidation we store two ids (counters) of the 139 // pictureSets in the tile. The first id (A) represents the pictureSet used to 140 // paint the tile and the second id (B) represents the pictureSet in which the 141 // tile was invalidated by webkit. Thus, if A < B then tile is dirty. 142 // 143 // Since invalidates can occur faster than a full tiled page update, the tiled 144 // page is protected by a 'lock' (m_baseLayerUpdate) that is set to true to 145 // defer updates to the background layer, giving the foreground time to render 146 // content instead of constantly flushing with invalidates. See 147 // lockBaseLayerUpdate() & unlockBaseLayerUpdate(). 148 // 149 // Painting scheduling 150 // ------------------- 151 // 152 // The next operation is to schedule this TilesSet to be painted 153 // (TilesManager::schedulePaintForTilesSet()). TexturesGenerator 154 // will get the TilesSet and ask the BaseTiles in it to be painted. 155 // 156 // BaseTile::paintBitmap() will paint the texture using the BaseLayer's 157 // PictureSet (calling TiledPage::paintBaseLayerContent() which in turns 158 // calls GLWebViewState::paintBaseLayerContent()). 159 // 160 // Note that TexturesGenerator is running in a separate thread, the textures 161 // are shared using EGLImages (this is necessary to not slow down the rendering 162 // speed -- updating GL textures in the main GL thread would slow things down). 163 // 164 ///////////////////////////////////////////////////////////////////////////////// 165 166 class GLWebViewState { 167 public: 168 GLWebViewState(android::Mutex* globalButtonMutex); 169 ~GLWebViewState(); 170 zoomManager()171 ZoomManager* zoomManager() { return &m_zoomManager; } futureViewport()172 const SkIRect& futureViewport() const { return m_futureViewportTileBounds; } setFutureViewport(const SkIRect & viewport)173 void setFutureViewport(const SkIRect& viewport) { m_futureViewportTileBounds = viewport; } 174 175 unsigned int paintBaseLayerContent(SkCanvas* canvas); 176 void setBaseLayer(BaseLayerAndroid* layer, const SkRegion& inval, bool showVisualIndicator, 177 bool isPictureAfterFirstLayout); 178 void paintExtras(); 179 glExtras()180 GLExtras* glExtras() { return &m_glExtras; } 181 182 TiledPage* sibling(TiledPage* page); 183 TiledPage* frontPage(); 184 TiledPage* backPage(); 185 void swapPages(); 186 187 // dimensions of the current base layer 188 int baseContentWidth(); 189 int baseContentHeight(); 190 191 void setViewport(SkRect& viewport, float scale); 192 193 // a rect containing the coordinates of all tiles in the current viewport viewportTileBounds()194 const SkIRect& viewportTileBounds() const { return m_viewportTileBounds; } 195 // a rect containing the viewportTileBounds before there was a scale change preZoomBounds()196 const SkIRect& preZoomBounds() const { return m_preZoomBounds; } setPreZoomBounds(const SkIRect & bounds)197 void setPreZoomBounds(const SkIRect& bounds) { m_preZoomBounds = bounds; } 198 currentPictureCounter()199 unsigned int currentPictureCounter() const { return m_currentPictureCounter; } 200 lockBaseLayerUpdate()201 void lockBaseLayerUpdate() { m_baseLayerUpdate = false; } 202 void unlockBaseLayerUpdate(); 203 setIsScrolling(bool isScrolling)204 void setIsScrolling(bool isScrolling) { m_isScrolling = isScrolling; } isScrolling()205 bool isScrolling() { return m_isScrolling; } 206 207 double setupDrawing(IntRect& rect, SkRect& viewport, IntRect& webViewRect, 208 int titleBarHeight, IntRect& screenClip, 209 float scale); 210 211 bool drawGL(IntRect& rect, SkRect& viewport, IntRect* invalRect, 212 IntRect& webViewRect, int titleBarHeight, 213 IntRect& clip, float scale, bool* buffersSwappedPtr); 214 215 #ifdef MEASURES_PERF 216 void dumpMeasures(); 217 #endif 218 219 void resetFrameworkInval(); 220 void addDirtyArea(const IntRect& rect); 221 void resetLayersDirtyArea(); 222 goingDown()223 bool goingDown() { return m_goingDown; } goingLeft()224 bool goingLeft() { return m_goingLeft; } setDirection(bool goingDown,bool goingLeft)225 void setDirection(bool goingDown, bool goingLeft) { 226 m_goingDown = goingDown; 227 m_goingLeft = goingLeft; 228 } 229 expandedTileBoundsX()230 int expandedTileBoundsX() { return m_expandedTileBoundsX; } expandedTileBoundsY()231 int expandedTileBoundsY() { return m_expandedTileBoundsY; } 232 scale()233 float scale() { return m_scale; } 234 235 private: 236 void inval(const IntRect& rect); // caller must hold m_baseLayerLock 237 void invalRegion(const SkRegion& region); 238 239 ZoomManager m_zoomManager; 240 android::Mutex m_tiledPageLock; 241 SkRect m_viewport; 242 SkIRect m_viewportTileBounds; 243 SkIRect m_futureViewportTileBounds; 244 SkIRect m_preZoomBounds; 245 android::Mutex m_baseLayerLock; 246 BaseLayerAndroid* m_paintingBaseLayer; 247 BaseLayerAndroid* m_currentBaseLayer; 248 LayerAndroid* m_currentBaseLayerRoot; 249 250 unsigned int m_currentPictureCounter; 251 bool m_usePageA; 252 TiledPage* m_tiledPageA; 253 TiledPage* m_tiledPageB; 254 IntRect m_lastInval; 255 IntRect m_frameworkInval; 256 IntRect m_frameworkLayersInval; 257 android::Mutex* m_globalButtonMutex; 258 259 bool m_baseLayerUpdate; 260 SkRegion m_invalidateRegion; 261 262 Color m_backgroundColor; 263 264 #ifdef MEASURES_PERF 265 unsigned int m_totalTimeCounter; 266 int m_timeCounter; 267 double m_delayTimes[MAX_MEASURES_PERF]; 268 bool m_measurePerfs; 269 #endif 270 GLExtras m_glExtras; 271 272 bool m_isScrolling; 273 bool m_goingDown; 274 bool m_goingLeft; 275 276 int m_expandedTileBoundsX; 277 int m_expandedTileBoundsY; 278 279 float m_scale; 280 }; 281 282 } // namespace WebCore 283 284 #endif // USE(ACCELERATED_COMPOSITING) 285 #endif // GLWebViewState_h 286