OSDN Git Service

Merge "Scroll position now passed to all layers" 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::gatherTexturesNumbers(int* nbTextures, int* nbAllocatedTextures,
193                                         int* nbLayerTextures, int* nbAllocatedLayerTextures)
194 {
195     *nbTextures = m_textures.size();
196     for (unsigned int i = 0; i < m_textures.size(); i++) {
197         BaseTileTexture* texture = m_textures[i];
198         if (texture->m_ownTextureId)
199             *nbAllocatedTextures += 1;
200     }
201     *nbLayerTextures = m_tilesTextures.size();
202     for (unsigned int i = 0; i < m_tilesTextures.size(); i++) {
203         BaseTileTexture* texture = m_tilesTextures[i];
204         if (texture->m_ownTextureId)
205             *nbAllocatedLayerTextures += 1;
206     }
207 }
208
209 void TilesManager::printTextures()
210 {
211 #ifdef DEBUG
212     XLOG("++++++");
213     for (unsigned int i = 0; i < m_textures.size(); i++) {
214         BaseTileTexture* texture = m_textures[i];
215         BaseTile* o = 0;
216         if (texture->owner())
217             o = (BaseTile*) texture->owner();
218         int x = -1;
219         int y = -1;
220         if (o) {
221             x = o->x();
222             y = o->y();
223         }
224         XLOG("[%d] texture %x  busy: %d owner: %x (%d, %d) page: %x scale: %.2f",
225                i, texture,
226                texture->busy(), o, x, y, o ? o->page() : 0, o ? o->scale() : 0);
227     }
228     XLOG("------");
229 #endif // DEBUG
230 }
231
232 void TilesManager::addPaintedSurface(PaintedSurface* surface)
233 {
234     m_paintedSurfaces.append(surface);
235 }
236
237 void TilesManager::gatherTextures()
238 {
239     android::Mutex::Autolock lock(m_texturesLock);
240     m_availableTextures = m_textures;
241 }
242
243 void TilesManager::gatherLayerTextures()
244 {
245     android::Mutex::Autolock lock(m_texturesLock);
246     m_availableTilesTextures = m_tilesTextures;
247     m_layerTexturesRemain = true;
248 }
249
250 BaseTileTexture* TilesManager::getAvailableTexture(BaseTile* owner)
251 {
252     android::Mutex::Autolock lock(m_texturesLock);
253
254     // Sanity check that the tile does not already own a texture
255     if (owner->backTexture() && owner->backTexture()->owner() == owner) {
256         XLOG("same owner (%d, %d), getAvailableBackTexture(%x) => texture %x",
257              owner->x(), owner->y(), owner, owner->backTexture());
258         if (owner->isLayerTile())
259             m_availableTilesTextures.remove(m_availableTilesTextures.find(owner->backTexture()));
260         else
261             m_availableTextures.remove(m_availableTextures.find(owner->backTexture()));
262         return owner->backTexture();
263     }
264
265     WTF::Vector<BaseTileTexture*>* availableTexturePool;
266     if (owner->isLayerTile()) {
267         availableTexturePool = &m_availableTilesTextures;
268     } else {
269         availableTexturePool = &m_availableTextures;
270     }
271
272     // The heuristic for selecting a texture is as follows:
273     //  1. Skip textures currently being painted, they can't be painted while
274     //         busy anyway
275     //  2. If a tile isn't owned, break with that one
276     //  3. Don't let tiles acquire their front textures
277     //  4. If we find a tile in the same page with a different scale,
278     //         it's old and not visible. Break with that one
279     //  5. Otherwise, use the least recently prepared tile, but ignoring tiles
280     //         drawn in the last frame to avoid flickering
281
282     BaseTileTexture* farthestTexture = 0;
283     unsigned long long oldestDrawCount = getDrawGLCount() - 1;
284     const unsigned int max = availableTexturePool->size();
285     for (unsigned int i = 0; i < max; i++) {
286         BaseTileTexture* texture = (*availableTexturePool)[i];
287         BaseTile* currentOwner = static_cast<BaseTile*>(texture->owner());
288
289         if (texture->busy()) {
290             // don't bother, since the acquire() will likely fail
291             continue;
292         }
293
294         if (!currentOwner) {
295             // unused texture! take it!
296             farthestTexture = texture;
297             break;
298         }
299
300         if (currentOwner == owner) {
301             // Don't let a tile acquire its own front texture, as the
302             // acquisition logic doesn't handle that
303             continue;
304         }
305
306         if (currentOwner->painter() == owner->painter() && texture->scale() != owner->scale()) {
307             // if we render the back page with one scale, then another while
308             // still zooming, we recycle the tiles with the old scale instead of
309             // taking ones from the front page
310             farthestTexture = texture;
311             break;
312         }
313
314         unsigned long long textureDrawCount = currentOwner->drawCount();
315         if (oldestDrawCount > textureDrawCount) {
316             farthestTexture = texture;
317             oldestDrawCount = textureDrawCount;
318         }
319     }
320
321     if (farthestTexture) {
322         BaseTile* previousOwner = static_cast<BaseTile*>(farthestTexture->owner());
323         if (farthestTexture->acquire(owner)) {
324             if (previousOwner) {
325                 previousOwner->removeTexture(farthestTexture);
326
327                 XLOG("%s texture %p stolen from tile %d, %d for %d, %d, drawCount was %llu (now %llu)",
328                      owner->isLayerTile() ? "LAYER" : "BASE",
329                      farthestTexture, previousOwner->x(), previousOwner->y(),
330                      owner->x(), owner->y(),
331                      oldestDrawCount, getDrawGLCount());
332             }
333
334             availableTexturePool->remove(availableTexturePool->find(farthestTexture));
335             return farthestTexture;
336         }
337     } else {
338         if (owner->isLayerTile()) {
339             // couldn't find a tile for a layer, layers shouldn't request redraw
340             // TODO: once we do layer prefetching, don't set this for those
341             // tiles
342             m_layerTexturesRemain = false;
343         }
344     }
345
346     XLOG("Couldn't find an available texture for %s tile %x (%d, %d) out of %d available",
347           owner->isLayerTile() ? "LAYER" : "BASE",
348           owner, owner->x(), owner->y(), max);
349 #ifdef DEBUG
350     printTextures();
351 #endif // DEBUG
352     return 0;
353 }
354
355 int TilesManager::maxTextureCount()
356 {
357     android::Mutex::Autolock lock(m_texturesLock);
358     return m_maxTextureCount;
359 }
360
361 int TilesManager::maxLayerTextureCount()
362 {
363     android::Mutex::Autolock lock(m_texturesLock);
364     return m_maxLayerTextureCount;
365 }
366
367 void TilesManager::setMaxTextureCount(int max)
368 {
369     XLOG("setMaxTextureCount: %d (current: %d, total:%d)",
370          max, m_maxTextureCount, MAX_TEXTURE_ALLOCATION);
371     if (m_maxTextureCount == MAX_TEXTURE_ALLOCATION ||
372          max <= m_maxTextureCount)
373         return;
374
375     android::Mutex::Autolock lock(m_texturesLock);
376
377     if (max < MAX_TEXTURE_ALLOCATION)
378         m_maxTextureCount = max;
379     else
380         m_maxTextureCount = MAX_TEXTURE_ALLOCATION;
381
382     allocateTiles();
383 }
384
385 void TilesManager::setMaxLayerTextureCount(int max)
386 {
387     XLOG("setMaxLayerTextureCount: %d (current: %d, total:%d)",
388          max, m_maxLayerTextureCount, MAX_TEXTURE_ALLOCATION);
389     if (!max && m_hasLayerTextures) {
390         double secondsSinceLayersUsed = WTF::currentTime() - m_lastTimeLayersUsed;
391         if (secondsSinceLayersUsed > LAYER_TEXTURES_DESTROY_TIMEOUT) {
392             unsigned long long sparedDrawCount = ~0; // by default, spare no textures
393             deallocateTexturesVector(sparedDrawCount, m_tilesTextures);
394             m_hasLayerTextures = false;
395         }
396         return;
397     }
398     m_lastTimeLayersUsed = WTF::currentTime();
399     if (m_maxLayerTextureCount == MAX_TEXTURE_ALLOCATION ||
400          max <= m_maxLayerTextureCount)
401         return;
402
403     android::Mutex::Autolock lock(m_texturesLock);
404
405     if (max < MAX_TEXTURE_ALLOCATION)
406         m_maxLayerTextureCount = max;
407     else
408         m_maxLayerTextureCount = MAX_TEXTURE_ALLOCATION;
409
410     allocateTiles();
411     m_hasLayerTextures = true;
412 }
413
414
415 float TilesManager::tileWidth()
416 {
417     return TILE_WIDTH;
418 }
419
420 float TilesManager::tileHeight()
421 {
422     return TILE_HEIGHT;
423 }
424
425 float TilesManager::layerTileWidth()
426 {
427     return LAYER_TILE_WIDTH;
428 }
429
430 float TilesManager::layerTileHeight()
431 {
432     return LAYER_TILE_HEIGHT;
433 }
434
435 void TilesManager::paintedSurfacesCleanup(GLWebViewState* state)
436 {
437     // PaintedSurfaces are created by LayerAndroid with a refcount of 1,
438     // and just transferred to new (corresponding) layers when a new layer tree
439     // is received.
440     // PaintedSurface also keep a reference on the Layer it currently has, so
441     // when we unref the tree of layer, those layers with a PaintedSurface will
442     // still be around if we do nothing.
443     // Here, if the surface does not have any associated layer, it means that we
444     // received a new layer tree without a corresponding layer (i.e. a layer
445     // using a texture has been removed by webkit).
446     // In that case, we remove the PaintedSurface from our list, and unref it.
447     // If the surface does have a layer, but the GLWebViewState associated to
448     // that layer is different from the one passed in parameter, it means we can
449     // also remove the surface (and we also remove/unref any layer that surface
450     // has). We do this when we deallocate GLWebViewState (i.e. the webview has
451     // been destroyed) and also when we switch to a page without
452     // composited layers.
453
454     WTF::Vector<PaintedSurface*> collect;
455     for (unsigned int i = 0; i < m_paintedSurfaces.size(); i++) {
456         PaintedSurface* surface = m_paintedSurfaces[i];
457
458         Layer* drawing = surface->drawingLayer();
459         Layer* painting = surface->paintingLayer();
460
461         XLOG("considering PS %p, drawing %p, painting %p", surface, drawing, painting);
462
463         bool drawingMatchesState = state && drawing && (drawing->state() == state);
464         bool paintingMatchesState = state && painting && (painting->state() == state);
465
466         if ((!painting && !drawing) || drawingMatchesState || paintingMatchesState) {
467             XLOG("trying to remove PS %p, painting %p, drawing %p, DMS %d, PMS %d",
468                  surface, painting, drawing, drawingMatchesState, paintingMatchesState);
469             collect.append(surface);
470         }
471     }
472     for (unsigned int i = 0; i < collect.size(); i++) {
473         PaintedSurface* surface = collect[i];
474         m_paintedSurfaces.remove(m_paintedSurfaces.find(surface));
475         SkSafeUnref(surface);
476     }
477 }
478
479 void TilesManager::unregisterGLWebViewState(GLWebViewState* state)
480 {
481     // Discard the whole queue b/c we lost GL context already.
482     // Note the real updateTexImage will still wait for the next draw.
483     transferQueue()->discardQueue();
484 }
485
486 TilesManager* TilesManager::instance()
487 {
488     if (!gInstance) {
489         gInstance = new TilesManager();
490         XLOG("instance(), new gInstance is %x", gInstance);
491         XLOG("Waiting for the generator...");
492         gInstance->waitForGenerator();
493         XLOG("Generator ready!");
494     }
495     return gInstance;
496 }
497
498 TilesManager* TilesManager::gInstance = 0;
499
500 } // namespace WebCore
501
502 #endif // USE(ACCELERATED_COMPOSITING)