OSDN Git Service

Mark tiles discarded by TransferQueue as dirty
[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 // It turns out the viewport dependent value m_maxTextureCount is a reasonable
69 // number to cap the layer tile texturs, it worked on both phones and tablets.
70 // TODO: after merge the pool of base tiles and layer tiles, we should revisit
71 // the logic of allocation management.
72 #define MAX_TEXTURE_ALLOCATION ((6+TILE_PREFETCH_DISTANCE*2)*(5+TILE_PREFETCH_DISTANCE*2)*2)
73 #define TILE_WIDTH 256
74 #define TILE_HEIGHT 256
75 #define LAYER_TILE_WIDTH 256
76 #define LAYER_TILE_HEIGHT 256
77
78 #define BYTES_PER_PIXEL 4 // 8888 config
79
80 namespace WebCore {
81
82 GLint TilesManager::getMaxTextureSize()
83 {
84     static GLint maxTextureSize = 0;
85     if (!maxTextureSize)
86         glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
87     return maxTextureSize;
88 }
89
90 int TilesManager::getMaxTextureAllocation()
91 {
92     return MAX_TEXTURE_ALLOCATION;
93 }
94
95 TilesManager::TilesManager()
96     : m_layersMemoryUsage(0)
97     , m_maxTextureCount(0)
98     , m_generatorReady(false)
99     , m_showVisualIndicator(false)
100     , m_invertedScreen(false)
101     , m_invertedScreenSwitch(false)
102     , m_drawGLCount(1)
103 {
104     XLOG("TilesManager ctor");
105     m_textures.reserveCapacity(MAX_TEXTURE_ALLOCATION);
106     m_availableTextures.reserveCapacity(MAX_TEXTURE_ALLOCATION);
107     m_tilesTextures.reserveCapacity(MAX_TEXTURE_ALLOCATION);
108     m_availableTilesTextures.reserveCapacity(MAX_TEXTURE_ALLOCATION);
109     m_pixmapsGenerationThread = new TexturesGenerator();
110     m_pixmapsGenerationThread->run("TexturesGenerator");
111 }
112
113 void TilesManager::allocateTiles()
114 {
115     int nbTexturesToAllocate = m_maxTextureCount - m_textures.size();
116     XLOG("%d tiles to allocate (%d textures planned)", nbTexturesToAllocate, m_maxTextureCount);
117     int nbTexturesAllocated = 0;
118     for (int i = 0; i < nbTexturesToAllocate; i++) {
119         BaseTileTexture* texture = new BaseTileTexture(
120             tileWidth(), tileHeight());
121         // the atomic load ensures that the texture has been fully initialized
122         // before we pass a pointer for other threads to operate on
123         BaseTileTexture* loadedTexture =
124             reinterpret_cast<BaseTileTexture*>(
125             android_atomic_acquire_load(reinterpret_cast<int32_t*>(&texture)));
126         m_textures.append(loadedTexture);
127         nbTexturesAllocated++;
128     }
129
130     int nbLayersTexturesToAllocate = m_maxTextureCount - m_tilesTextures.size();
131     XLOG("%d layers tiles to allocate (%d textures planned)",
132          nbLayersTexturesToAllocate, m_maxTextureCount);
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::deallocateTextures(bool allTextures)
153 {
154     const unsigned int max = m_textures.size();
155     const unsigned int maxLayer = m_tilesTextures.size();
156
157     unsigned long long sparedDrawCount = ~0; // by default, spare no textures
158     if (!allTextures) {
159         // if we're not deallocating all textures, spare those with max drawcount
160         sparedDrawCount = 0;
161         for (unsigned int i = 0; i < max; i++) {
162             TextureOwner* owner = m_textures[i]->owner();
163             if (owner)
164                 sparedDrawCount = std::max(sparedDrawCount, owner->drawCount());
165         }
166     }
167
168     int dealloc = 0;
169     for (unsigned int i = 0; i < max; i++) {
170         TextureOwner* owner = m_textures[i]->owner();
171         if (!owner || owner->drawCount() < sparedDrawCount) {
172             m_textures[i]->discardGLTexture();
173             dealloc++;
174         }
175     }
176     for (unsigned int i = 0; i < maxLayer; i++) {
177         TextureOwner* owner = m_tilesTextures[i]->owner();
178         if (!owner || owner->drawCount() < sparedDrawCount) {
179             m_tilesTextures[i]->discardGLTexture();
180             dealloc++;
181         }
182     }
183     XLOG("Deallocated %d gl textures (out of %d base tiles and %d layer tiles)",
184          dealloc, max, maxLayer);
185 }
186
187 void TilesManager::printTextures()
188 {
189 #ifdef DEBUG
190     XLOG("++++++");
191     for (unsigned int i = 0; i < m_textures.size(); i++) {
192         BaseTileTexture* texture = m_textures[i];
193         BaseTile* o = 0;
194         if (texture->owner())
195             o = (BaseTile*) texture->owner();
196         int x = -1;
197         int y = -1;
198         if (o) {
199             x = o->x();
200             y = o->y();
201         }
202         XLOG("[%d] texture %x  busy: %d owner: %x (%d, %d) page: %x scale: %.2f",
203                i, texture,
204                texture->busy(), o, x, y, o ? o->page() : 0, o ? o->scale() : 0);
205     }
206     XLOG("------");
207 #endif // DEBUG
208 }
209
210 void TilesManager::swapLayersTextures(LayerAndroid* oldTree, LayerAndroid* newTree)
211 {
212     if (oldTree)
213         oldTree->assignTextureTo(newTree);
214
215     if (newTree)
216         newTree->createTexture();
217
218     GLWebViewState* oldState = 0;
219     if (oldTree && !newTree)
220         oldState = oldTree->state();
221
222     paintedSurfacesCleanup(oldState);
223 }
224
225 void TilesManager::addPaintedSurface(PaintedSurface* surface)
226 {
227     m_paintedSurfaces.append(surface);
228 }
229
230 void TilesManager::gatherTextures()
231 {
232     android::Mutex::Autolock lock(m_texturesLock);
233     m_availableTextures = m_textures;
234 }
235
236 void TilesManager::gatherLayerTextures()
237 {
238     android::Mutex::Autolock lock(m_texturesLock);
239     m_availableTilesTextures = m_tilesTextures;
240 }
241
242 BaseTileTexture* TilesManager::getAvailableTexture(BaseTile* owner)
243 {
244     android::Mutex::Autolock lock(m_texturesLock);
245
246     // Sanity check that the tile does not already own a texture
247     if (owner->backTexture() && owner->backTexture()->owner() == owner) {
248         XLOG("same owner (%d, %d), getAvailableBackTexture(%x) => texture %x",
249              owner->x(), owner->y(), owner, owner->backTexture());
250         if (owner->isLayerTile())
251             m_availableTilesTextures.remove(m_availableTilesTextures.find(owner->backTexture()));
252         else
253             m_availableTextures.remove(m_availableTextures.find(owner->backTexture()));
254         return owner->backTexture();
255     }
256
257     WTF::Vector<BaseTileTexture*>* availableTexturePool;
258     if (owner->isLayerTile()) {
259         availableTexturePool = &m_availableTilesTextures;
260     } else {
261         availableTexturePool = &m_availableTextures;
262     }
263
264     // The heuristic for selecting a texture is as follows:
265     //  1. Skip textures currently being painted, they can't be painted while
266     //         busy anyway
267     //  2. If a tile isn't owned, break with that one
268     //  3. Don't let tiles acquire their front textures
269     //  4. If we find a tile in the same page with a different scale,
270     //         it's old and not visible. Break with that one
271     //  5. Otherwise, use the least recently prepared tile, but ignoring tiles
272     //         drawn in the last frame to avoid flickering
273
274     BaseTileTexture* farthestTexture = 0;
275     unsigned long long oldestDrawCount = getDrawGLCount() - 1;
276     const unsigned int max = availableTexturePool->size();
277     for (unsigned int i = 0; i < max; i++) {
278         BaseTileTexture* texture = (*availableTexturePool)[i];
279         TextureOwner* currentOwner = texture->owner();
280
281         if (texture->busy()) {
282             // don't bother, since the acquire() will likely fail
283             continue;
284         }
285
286         if (!currentOwner) {
287             // unused texture! take it!
288             farthestTexture = texture;
289             break;
290         }
291
292         if (currentOwner == owner) {
293             // Don't let a tile acquire its own front texture, as the
294             // acquisition logic doesn't handle that
295             continue;
296         }
297
298         if (currentOwner->page() == owner->page() && texture->scale() != owner->scale()) {
299             // if we render the back page with one scale, then another while
300             // still zooming, we recycle the tiles with the old scale instead of
301             // taking ones from the front page
302             farthestTexture = texture;
303             break;
304         }
305
306         unsigned long long textureDrawCount = currentOwner->drawCount();
307         if (oldestDrawCount > textureDrawCount) {
308             farthestTexture = texture;
309             oldestDrawCount = textureDrawCount;
310         }
311     }
312
313     if (farthestTexture) {
314         BaseTile* previousOwner = static_cast<BaseTile*>(farthestTexture->owner());
315         if (farthestTexture->acquire(owner)) {
316             if (previousOwner) {
317                 previousOwner->removeTexture(farthestTexture);
318
319                 XLOG("%s texture %p stolen from tile %d, %d for %d, %d, drawCount was %llu (now %llu)",
320                      owner->isLayerTile() ? "LAYER" : "BASE",
321                      farthestTexture, previousOwner->x(), previousOwner->y(),
322                      owner->x(), owner->y(),
323                      oldestDrawCount, getDrawGLCount());
324             }
325
326             availableTexturePool->remove(availableTexturePool->find(farthestTexture));
327             return farthestTexture;
328         }
329     }
330
331     XLOG("Couldn't find an available texture for %s tile %x (%d, %d) out of %d available",
332           owner->isLayerTile() ? "LAYER" : "BASE",
333           owner, owner->x(), owner->y(), max);
334 #ifdef DEBUG
335     printTextures();
336 #endif // DEBUG
337     return 0;
338 }
339
340 int TilesManager::maxTextureCount()
341 {
342     android::Mutex::Autolock lock(m_texturesLock);
343     return m_maxTextureCount;
344 }
345
346 void TilesManager::setMaxTextureCount(int max)
347 {
348     XLOG("setMaxTextureCount: %d (current: %d, total:%d)",
349          max, m_maxTextureCount, MAX_TEXTURE_ALLOCATION);
350     if (m_maxTextureCount == MAX_TEXTURE_ALLOCATION ||
351          max <= m_maxTextureCount)
352         return;
353
354     android::Mutex::Autolock lock(m_texturesLock);
355
356     if (max < MAX_TEXTURE_ALLOCATION)
357         m_maxTextureCount = max;
358     else
359         m_maxTextureCount = MAX_TEXTURE_ALLOCATION;
360
361     allocateTiles();
362 }
363
364 float TilesManager::tileWidth()
365 {
366     return TILE_WIDTH;
367 }
368
369 float TilesManager::tileHeight()
370 {
371     return TILE_HEIGHT;
372 }
373
374 float TilesManager::layerTileWidth()
375 {
376     return LAYER_TILE_WIDTH;
377 }
378
379 float TilesManager::layerTileHeight()
380 {
381     return LAYER_TILE_HEIGHT;
382 }
383
384 void TilesManager::paintedSurfacesCleanup(GLWebViewState* state)
385 {
386     // PaintedSurfaces are created by LayerAndroid with a refcount of 1,
387     // and just transferred to new (corresponding) layers when a new layer tree
388     // is received.
389     // PaintedSurface also keep a reference on the Layer it currently has, so
390     // when we unref the tree of layer, those layers with a PaintedSurface will
391     // still be around if we do nothing.
392     // Here, if the surface does not have any associated layer, it means that we
393     // received a new layer tree without a corresponding layer (i.e. a layer
394     // using a texture has been removed by webkit).
395     // In that case, we remove the PaintedSurface from our list, and unref it.
396     // If the surface does have a layer, but the GLWebViewState associated to
397     // that layer is different from the one passed in parameter, it means we can
398     // also remove the surface (and we also remove/unref any layer that surface
399     // has). We do this when we deallocate GLWebViewState (i.e. the webview has
400     // been destroyed) and also when we switch to a page without
401     // composited layers.
402
403     WTF::Vector<PaintedSurface*> collect;
404     for (unsigned int i = 0; i < m_paintedSurfaces.size(); i++) {
405         PaintedSurface* surface = m_paintedSurfaces[i];
406         if (!surface->layer() || (state && surface->layer()->state() == state))
407             collect.append(surface);
408     }
409     for (unsigned int i = 0; i < collect.size(); i++) {
410         PaintedSurface* surface = collect[i];
411         m_paintedSurfaces.remove(m_paintedSurfaces.find(surface));
412         surface->removeLayer();
413         SkSafeUnref(surface);
414     }
415 }
416
417 void TilesManager::unregisterGLWebViewState(GLWebViewState* state)
418 {
419     // Discard the whole queue b/c we lost GL context already.
420     // Note the real updateTexImage will still wait for the next draw.
421     transferQueue()->discardQueue();
422 }
423
424 void TilesManager::addImage(SkBitmapRef* imgRef)
425 {
426     if (!imgRef)
427         return;
428
429     android::Mutex::Autolock lock(m_imagesLock);
430     if (!m_images.contains(imgRef))
431         m_images.set(imgRef, new ImageTexture(imgRef));
432 }
433
434 void TilesManager::removeImage(SkBitmapRef* imgRef)
435 {
436     android::Mutex::Autolock lock(m_imagesLock);
437     if (!m_images.contains(imgRef))
438         return;
439
440     ImageTexture* image = m_images.get(imgRef);
441     image->release();
442
443     if (!image->refCount()) {
444         m_images.remove(imgRef);
445         delete image;
446     }
447 }
448
449 void TilesManager::showImages()
450 {
451     XLOGC("We have %d images", m_images.size());
452     HashMap<SkBitmapRef*, ImageTexture*>::iterator end = m_images.end();
453     int i = 0;
454     for (HashMap<SkBitmapRef*, ImageTexture*>::iterator it = m_images.begin(); it != end; ++it) {
455         XLOGC("Image %x (%d/%d) has %d references", it->first, i,
456               m_images.size(), it->second->refCount());
457         i++;
458     }
459 }
460
461 ImageTexture* TilesManager::getTextureForImage(SkBitmapRef* img, bool retain)
462 {
463     android::Mutex::Autolock lock(m_imagesLock);
464     ImageTexture* image = m_images.get(img);
465     if (retain && image)
466         image->retain();
467     return image;
468 }
469
470 TilesManager* TilesManager::instance()
471 {
472     if (!gInstance) {
473         gInstance = new TilesManager();
474         XLOG("instance(), new gInstance is %x", gInstance);
475         XLOG("Waiting for the generator...");
476         gInstance->waitForGenerator();
477         XLOG("Generator ready!");
478     }
479     return gInstance;
480 }
481
482 TilesManager* TilesManager::gInstance = 0;
483
484 } // namespace WebCore
485
486 #endif // USE(ACCELERATED_COMPOSITING)