OSDN Git Service

Stop layer tile flickering
[android-x86/external-webkit.git] / Source / WebCore / platform / graphics / android / TilesManager.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 "TilesManager.h"
28
29 #if USE(ACCELERATED_COMPOSITING)
30
31 #include "BaseTile.h"
32 #include "PaintedSurface.h"
33 #include "SkCanvas.h"
34 #include "SkDevice.h"
35 #include "SkPaint.h"
36 #include <android/native_window.h>
37 #include <cutils/atomic.h>
38 #include <gui/SurfaceTexture.h>
39 #include <gui/SurfaceTextureClient.h>
40
41
42 #include <cutils/log.h>
43 #include <wtf/CurrentTime.h>
44 #include <wtf/text/CString.h>
45
46 #undef XLOGC
47 #define XLOGC(...) android_printLog(ANDROID_LOG_DEBUG, "TilesManager", __VA_ARGS__)
48
49 #ifdef DEBUG
50
51 #undef XLOG
52 #define XLOG(...) android_printLog(ANDROID_LOG_DEBUG, "TilesManager", __VA_ARGS__)
53
54 #else
55
56 #undef XLOG
57 #define XLOG(...)
58
59 #endif // DEBUG
60
61 // Important: We need at least twice as many textures as is needed to cover
62 // one viewport, otherwise the allocation may stall.
63 // We need n textures for one TiledPage, and another n textures for the
64 // second page used when scaling.
65 // In our case, we use 256*256 textures. On the tablet, this equates to
66 // at least 60 textures, or 112 with expanded tile boundaries.
67 // 112(tiles)*256*256*4(bpp)*2(pages) = 56MB
68 #define MAX_TEXTURE_ALLOCATION ((6+TILE_PREFETCH_DISTANCE*2)*(5+TILE_PREFETCH_DISTANCE*2)*2)
69 #define TILE_WIDTH 256
70 #define TILE_HEIGHT 256
71 #define LAYER_TILE_WIDTH 256
72 #define LAYER_TILE_HEIGHT 256
73 #define LAYER_TILES 50
74
75 // Define a maximum amount of ram used by layers
76 #define MAX_LAYERS_ALLOCATION 33554432 // 32Mb
77 // Define a maximum amount of ram used by one layer
78 #define MAX_LAYER_ALLOCATION 8388608 // 8Mb
79 #define BYTES_PER_PIXEL 4 // 8888 config
80
81 namespace WebCore {
82
83 GLint TilesManager::getMaxTextureSize()
84 {
85     static GLint maxTextureSize = 0;
86     if (!maxTextureSize)
87         glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
88     return maxTextureSize;
89 }
90
91 int TilesManager::getMaxTextureAllocation()
92 {
93     return MAX_TEXTURE_ALLOCATION;
94 }
95
96 TilesManager::TilesManager()
97     : m_layersMemoryUsage(0)
98     , m_maxTextureCount(0)
99     , m_generatorReady(false)
100     , m_showVisualIndicator(false)
101     , m_invertedScreen(false)
102     , m_invertedScreenSwitch(false)
103     , m_drawGLCount(0)
104 {
105     XLOG("TilesManager ctor");
106     m_textures.reserveCapacity(MAX_TEXTURE_ALLOCATION);
107     m_availableTextures.reserveCapacity(MAX_TEXTURE_ALLOCATION);
108     m_tilesTextures.reserveCapacity(LAYER_TILES);
109     m_availableTilesTextures.reserveCapacity(LAYER_TILES);
110     m_pixmapsGenerationThread = new TexturesGenerator();
111     m_pixmapsGenerationThread->run("TexturesGenerator");
112 }
113
114 void TilesManager::allocateTiles()
115 {
116     int nbTexturesToAllocate = m_maxTextureCount - m_textures.size();
117     XLOG("%d tiles to allocate (%d textures planned)", nbTexturesToAllocate, m_maxTextureCount);
118     int nbTexturesAllocated = 0;
119     for (int i = 0; i < nbTexturesToAllocate; i++) {
120         BaseTileTexture* texture = new BaseTileTexture(
121             tileWidth(), tileHeight());
122         // the atomic load ensures that the texture has been fully initialized
123         // before we pass a pointer for other threads to operate on
124         BaseTileTexture* loadedTexture =
125             reinterpret_cast<BaseTileTexture*>(
126             android_atomic_acquire_load(reinterpret_cast<int32_t*>(&texture)));
127         m_textures.append(loadedTexture);
128         nbTexturesAllocated++;
129     }
130
131     int nbLayersTexturesToAllocate = LAYER_TILES - m_tilesTextures.size();
132     XLOG("%d layers tiles to allocate (%d textures planned)", nbLayersTexturesToAllocate, LAYER_TILES);
133     int nbLayersTexturesAllocated = 0;
134     for (int i = 0; i < nbLayersTexturesToAllocate; i++) {
135         BaseTileTexture* texture = new BaseTileTexture(
136             layerTileWidth(), layerTileHeight());
137         // the atomic load ensures that the texture has been fully initialized
138         // before we pass a pointer for other threads to operate on
139         BaseTileTexture* loadedTexture =
140             reinterpret_cast<BaseTileTexture*>(
141             android_atomic_acquire_load(reinterpret_cast<int32_t*>(&texture)));
142         m_tilesTextures.append(loadedTexture);
143         nbLayersTexturesAllocated++;
144     }
145     XLOG("allocated %d textures for base (total: %d, %d Mb), %d textures for layers (total: %d, %d Mb)",
146          nbTexturesAllocated, m_textures.size(),
147          m_textures.size() * TILE_WIDTH * TILE_HEIGHT * 4 / 1024 / 1024,
148          nbLayersTexturesAllocated, m_tilesTextures.size(),
149          m_tilesTextures.size() * LAYER_TILE_WIDTH * LAYER_TILE_HEIGHT * 4 / 1024 / 1024);
150 }
151
152 void TilesManager::printTextures()
153 {
154 #ifdef DEBUG
155     XLOG("++++++");
156     for (unsigned int i = 0; i < m_textures.size(); i++) {
157         BaseTileTexture* texture = m_textures[i];
158         BaseTile* o = 0;
159         if (texture->owner())
160             o = (BaseTile*) texture->owner();
161         int x = -1;
162         int y = -1;
163         if (o) {
164             x = o->x();
165             y = o->y();
166         }
167         XLOG("[%d] texture %x  busy: %d owner: %x (%d, %d) page: %x scale: %.2f",
168                i, texture,
169                texture->busy(), o, x, y, o ? o->page() : 0, o ? o->scale() : 0);
170     }
171     XLOG("------");
172 #endif // DEBUG
173 }
174
175 void TilesManager::swapLayersTextures(LayerAndroid* oldTree, LayerAndroid* newTree)
176 {
177     if (oldTree)
178         oldTree->assignTextureTo(newTree);
179
180     if (newTree)
181         newTree->createTexture();
182
183     WTF::Vector<PaintedSurface*> collect;
184     for (unsigned int i = 0; i < m_paintedSurfaces.size(); i++) {
185         PaintedSurface* surface = m_paintedSurfaces[i];
186         if (!surface->layer())
187             collect.append(surface);
188     }
189     for (unsigned int i = 0; i < collect.size(); i++) {
190         m_paintedSurfaces.remove(m_paintedSurfaces.find(collect[i]));
191         SkSafeUnref(collect[i]);
192     }
193 }
194
195 void TilesManager::addPaintedSurface(PaintedSurface* surface)
196 {
197     m_paintedSurfaces.append(surface);
198 }
199
200 void TilesManager::gatherTextures()
201 {
202     android::Mutex::Autolock lock(m_texturesLock);
203     m_availableTextures = m_textures;
204 }
205
206 void TilesManager::gatherLayerTextures()
207 {
208     android::Mutex::Autolock lock(m_texturesLock);
209     m_availableTilesTextures = m_tilesTextures;
210 }
211
212 BaseTileTexture* TilesManager::getAvailableTexture(BaseTile* owner)
213 {
214     android::Mutex::Autolock lock(m_texturesLock);
215
216     // Sanity check that the tile does not already own a texture
217     if (owner->backTexture() && owner->backTexture()->owner() == owner) {
218         XLOG("same owner (%d, %d), getAvailableBackTexture(%x) => texture %x",
219              owner->x(), owner->y(), owner, owner->backTexture());
220         if (owner->isLayerTile())
221             m_availableTilesTextures.remove(m_availableTilesTextures.find(owner->backTexture()));
222         else
223             m_availableTextures.remove(m_availableTextures.find(owner->backTexture()));
224         return owner->backTexture();
225     }
226
227     WTF::Vector<BaseTileTexture*>* availableTexturePool;
228     if (owner->isLayerTile()) {
229         availableTexturePool = &m_availableTilesTextures;
230     } else {
231         availableTexturePool = &m_availableTextures;
232     }
233
234     // The heuristic for selecting a texture is as follows:
235     //  1. If a tile isn't owned, break with that one
236     //  2. If we find a tile in the same page with a different scale,
237     //         it's old and not visible. Break with that one
238     //  3. Otherwise, use the least recently prepared tile, but ignoring tiles
239     //         drawn in the last frame to avoid flickering
240
241     BaseTileTexture* farthestTexture = 0;
242     unsigned long long oldestDrawCount = getDrawGLCount() - 1;
243     const unsigned int max = availableTexturePool->size();
244     for (unsigned int i = 0; i < max; i++) {
245         BaseTileTexture* texture = (*availableTexturePool)[i];
246         TextureOwner* currentOwner = texture->owner();
247         if (!currentOwner) {
248             farthestTexture = texture;
249             break;
250         }
251
252         if (currentOwner->page() == owner->page() && texture->scale() != owner->scale()) {
253             // if we render the back page with one scale, then another while
254             // still zooming, we recycle the tiles with the old scale instead of
255             // taking ones from the front page
256             farthestTexture = texture;
257             break;
258         }
259
260         unsigned long long textureDrawCount = currentOwner->drawCount();
261         if (oldestDrawCount > textureDrawCount) {
262             farthestTexture = texture;
263             oldestDrawCount = textureDrawCount;
264         }
265     }
266
267     if (farthestTexture) {
268         TextureOwner* previousOwner = farthestTexture->owner();
269         if (farthestTexture->acquire(owner)) {
270             if (previousOwner) {
271                 XLOG("%s texture %p stolen from tile %d, %d, drawCount was %llu",
272                      owner->isLayerTile() ? "LAYER" : "BASE",
273                      farthestTexture, owner->x(), owner->y(), oldestDrawCount);
274             }
275
276             availableTexturePool->remove(availableTexturePool->find(farthestTexture));
277             return farthestTexture;
278         }
279     }
280
281     XLOG("Couldn't find an available texture for tile %x (%d, %d) out of %d available!!!",
282           owner, owner->x(), owner->y(), max);
283 #ifdef DEBUG
284     printTextures();
285 #endif // DEBUG
286     return 0;
287 }
288
289 int TilesManager::maxLayersAllocation()
290 {
291     return MAX_LAYERS_ALLOCATION;
292 }
293
294 int TilesManager::maxLayerAllocation()
295 {
296     return MAX_LAYER_ALLOCATION;
297 }
298
299 int TilesManager::maxTextureCount()
300 {
301     android::Mutex::Autolock lock(m_texturesLock);
302     return m_maxTextureCount;
303 }
304
305 void TilesManager::setMaxTextureCount(int max)
306 {
307     XLOG("setMaxTextureCount: %d (current: %d, total:%d)",
308          max, m_maxTextureCount, MAX_TEXTURE_ALLOCATION);
309     if (m_maxTextureCount == MAX_TEXTURE_ALLOCATION ||
310          max <= m_maxTextureCount)
311         return;
312
313     android::Mutex::Autolock lock(m_texturesLock);
314
315     if (max < MAX_TEXTURE_ALLOCATION)
316         m_maxTextureCount = max;
317     else
318         m_maxTextureCount = MAX_TEXTURE_ALLOCATION;
319
320     allocateTiles();
321 }
322
323 float TilesManager::tileWidth()
324 {
325     return TILE_WIDTH;
326 }
327
328 float TilesManager::tileHeight()
329 {
330     return TILE_HEIGHT;
331 }
332
333 float TilesManager::layerTileWidth()
334 {
335     return LAYER_TILE_WIDTH;
336 }
337
338 float TilesManager::layerTileHeight()
339 {
340     return LAYER_TILE_HEIGHT;
341 }
342
343 void TilesManager::unregisterGLWebViewState(GLWebViewState* state)
344 {
345     // Discard the whole queue b/c we lost GL context already.
346     // Note the real updateTexImage will still wait for the next draw.
347     transferQueue()->discardQueue();
348 }
349
350 TilesManager* TilesManager::instance()
351 {
352     if (!gInstance) {
353         gInstance = new TilesManager();
354         XLOG("instance(), new gInstance is %x", gInstance);
355         XLOG("Waiting for the generator...");
356         gInstance->waitForGenerator();
357         XLOG("Generator ready!");
358     }
359     return gInstance;
360 }
361
362 TilesManager* TilesManager::gInstance = 0;
363
364 } // namespace WebCore
365
366 #endif // USE(ACCELERATED_COMPOSITING)