OSDN Git Service

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