OSDN Git Service

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