2 * Copyright 2010, The Android Open Source Project
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
27 #include "TilesManager.h"
29 #if USE(ACCELERATED_COMPOSITING)
32 #include "PaintedSurface.h"
36 #include <android/native_window.h>
37 #include <cutils/atomic.h>
38 #include <gui/SurfaceTexture.h>
39 #include <gui/SurfaceTextureClient.h>
42 #include <cutils/log.h>
43 #include <wtf/CurrentTime.h>
44 #include <wtf/text/CString.h>
47 #define XLOGC(...) android_printLog(ANDROID_LOG_DEBUG, "TilesManager", __VA_ARGS__)
52 #define XLOG(...) android_printLog(ANDROID_LOG_DEBUG, "TilesManager", __VA_ARGS__)
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
78 #define BYTES_PER_PIXEL 4 // 8888 config
80 #define LAYER_TEXTURES_DESTROY_TIMEOUT 60 // If we do not need layers for 60 seconds, free the textures
84 GLint TilesManager::getMaxTextureSize()
86 static GLint maxTextureSize = 0;
88 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
89 return maxTextureSize;
92 int TilesManager::getMaxTextureAllocation()
94 return MAX_TEXTURE_ALLOCATION;
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)
107 , m_lastTimeLayersUsed(0)
108 , m_hasLayerTextures(false)
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);
119 void TilesManager::allocateTiles()
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++;
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++;
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);
158 void TilesManager::deallocateTextures(bool allTextures)
160 const unsigned int max = m_textures.size();
162 unsigned long long sparedDrawCount = ~0; // by default, spare no textures
164 // if we're not deallocating all textures, spare those with max drawcount
166 for (unsigned int i = 0; i < max; i++) {
167 TextureOwner* owner = m_textures[i]->owner();
169 sparedDrawCount = std::max(sparedDrawCount, owner->drawCount());
172 deallocateTexturesVector(sparedDrawCount, m_textures);
173 deallocateTexturesVector(sparedDrawCount, m_tilesTextures);
176 void TilesManager::deallocateTexturesVector(unsigned long long sparedDrawCount,
177 WTF::Vector<BaseTileTexture*>& textures)
179 const unsigned int max = textures.size();
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();
188 XLOG("Deallocated %d gl textures (out of %d base tiles and %d layer tiles)",
189 dealloc, max, maxLayer);
192 void TilesManager::gatherTexturesNumbers(int* nbTextures, int* nbAllocatedTextures,
193 int* nbLayerTextures, int* nbAllocatedLayerTextures)
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;
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;
209 void TilesManager::printTextures()
213 for (unsigned int i = 0; i < m_textures.size(); i++) {
214 BaseTileTexture* texture = m_textures[i];
216 if (texture->owner())
217 o = (BaseTile*) texture->owner();
224 XLOG("[%d] texture %x busy: %d owner: %x (%d, %d) page: %x scale: %.2f",
226 texture->busy(), o, x, y, o ? o->page() : 0, o ? o->scale() : 0);
232 void TilesManager::addPaintedSurface(PaintedSurface* surface)
234 m_paintedSurfaces.append(surface);
237 void TilesManager::gatherTextures()
239 android::Mutex::Autolock lock(m_texturesLock);
240 m_availableTextures = m_textures;
243 void TilesManager::gatherLayerTextures()
245 android::Mutex::Autolock lock(m_texturesLock);
246 m_availableTilesTextures = m_tilesTextures;
247 m_layerTexturesRemain = true;
250 BaseTileTexture* TilesManager::getAvailableTexture(BaseTile* owner)
252 android::Mutex::Autolock lock(m_texturesLock);
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()));
261 m_availableTextures.remove(m_availableTextures.find(owner->backTexture()));
262 return owner->backTexture();
265 WTF::Vector<BaseTileTexture*>* availableTexturePool;
266 if (owner->isLayerTile()) {
267 availableTexturePool = &m_availableTilesTextures;
269 availableTexturePool = &m_availableTextures;
272 // The heuristic for selecting a texture is as follows:
273 // 1. Skip textures currently being painted, they can't be painted while
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
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());
289 if (texture->busy()) {
290 // don't bother, since the acquire() will likely fail
295 // unused texture! take it!
296 farthestTexture = texture;
300 if (currentOwner == owner) {
301 // Don't let a tile acquire its own front texture, as the
302 // acquisition logic doesn't handle that
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;
314 unsigned long long textureDrawCount = currentOwner->drawCount();
315 if (oldestDrawCount > textureDrawCount) {
316 farthestTexture = texture;
317 oldestDrawCount = textureDrawCount;
321 if (farthestTexture) {
322 BaseTile* previousOwner = static_cast<BaseTile*>(farthestTexture->owner());
323 if (farthestTexture->acquire(owner)) {
325 previousOwner->removeTexture(farthestTexture);
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());
334 availableTexturePool->remove(availableTexturePool->find(farthestTexture));
335 return farthestTexture;
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
342 m_layerTexturesRemain = false;
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);
355 int TilesManager::maxTextureCount()
357 android::Mutex::Autolock lock(m_texturesLock);
358 return m_maxTextureCount;
361 int TilesManager::maxLayerTextureCount()
363 android::Mutex::Autolock lock(m_texturesLock);
364 return m_maxLayerTextureCount;
367 void TilesManager::setMaxTextureCount(int max)
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)
375 android::Mutex::Autolock lock(m_texturesLock);
377 if (max < MAX_TEXTURE_ALLOCATION)
378 m_maxTextureCount = max;
380 m_maxTextureCount = MAX_TEXTURE_ALLOCATION;
385 void TilesManager::setMaxLayerTextureCount(int max)
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;
398 m_lastTimeLayersUsed = WTF::currentTime();
399 if (m_maxLayerTextureCount == MAX_TEXTURE_ALLOCATION ||
400 max <= m_maxLayerTextureCount)
403 android::Mutex::Autolock lock(m_texturesLock);
405 if (max < MAX_TEXTURE_ALLOCATION)
406 m_maxLayerTextureCount = max;
408 m_maxLayerTextureCount = MAX_TEXTURE_ALLOCATION;
411 m_hasLayerTextures = true;
415 float TilesManager::tileWidth()
420 float TilesManager::tileHeight()
425 float TilesManager::layerTileWidth()
427 return LAYER_TILE_WIDTH;
430 float TilesManager::layerTileHeight()
432 return LAYER_TILE_HEIGHT;
435 void TilesManager::paintedSurfacesCleanup(GLWebViewState* state)
437 // PaintedSurfaces are created by LayerAndroid with a refcount of 1,
438 // and just transferred to new (corresponding) layers when a new layer tree
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.
454 WTF::Vector<PaintedSurface*> collect;
455 for (unsigned int i = 0; i < m_paintedSurfaces.size(); i++) {
456 PaintedSurface* surface = m_paintedSurfaces[i];
458 Layer* drawing = surface->drawingLayer();
459 Layer* painting = surface->paintingLayer();
461 XLOG("considering PS %p, drawing %p, painting %p", surface, drawing, painting);
463 bool drawingMatchesState = state && drawing && (drawing->state() == state);
464 bool paintingMatchesState = state && painting && (painting->state() == state);
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);
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);
479 void TilesManager::unregisterGLWebViewState(GLWebViewState* state)
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();
486 TilesManager* TilesManager::instance()
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!");
498 TilesManager* TilesManager::gInstance = 0;
500 } // namespace WebCore
502 #endif // USE(ACCELERATED_COMPOSITING)