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 #define MAX_TEXTURE_ALLOCATION ((6+TILE_PREFETCH_DISTANCE*2)*(5+TILE_PREFETCH_DISTANCE*2)*2)
69 #define TILE_WIDTH 256
70 #define TILE_HEIGHT 256
71 #define LAYER_TILE_WIDTH 256
72 #define LAYER_TILE_HEIGHT 256
73 #define LAYER_TILES 50
75 // Define a maximum amount of ram used by layers
76 #define MAX_LAYERS_ALLOCATION 33554432 // 32Mb
77 // Define a maximum amount of ram used by one layer
78 #define MAX_LAYER_ALLOCATION 8388608 // 8Mb
79 #define BYTES_PER_PIXEL 4 // 8888 config
83 GLint TilesManager::getMaxTextureSize()
85 static GLint maxTextureSize = 0;
87 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
88 return maxTextureSize;
91 int TilesManager::getMaxTextureAllocation()
93 return MAX_TEXTURE_ALLOCATION;
96 TilesManager::TilesManager()
97 : m_layersMemoryUsage(0)
98 , m_maxTextureCount(0)
99 , m_generatorReady(false)
100 , m_showVisualIndicator(false)
101 , m_invertedScreen(false)
102 , m_invertedScreenSwitch(false)
105 XLOG("TilesManager ctor");
106 m_textures.reserveCapacity(MAX_TEXTURE_ALLOCATION);
107 m_availableTextures.reserveCapacity(MAX_TEXTURE_ALLOCATION);
108 m_tilesTextures.reserveCapacity(LAYER_TILES);
109 m_availableTilesTextures.reserveCapacity(LAYER_TILES);
110 m_pixmapsGenerationThread = new TexturesGenerator();
111 m_pixmapsGenerationThread->run("TexturesGenerator");
114 void TilesManager::allocateTiles()
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++;
131 int nbLayersTexturesToAllocate = LAYER_TILES - m_tilesTextures.size();
132 XLOG("%d layers tiles to allocate (%d textures planned)", nbLayersTexturesToAllocate, LAYER_TILES);
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++;
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);
152 void TilesManager::printTextures()
156 for (unsigned int i = 0; i < m_textures.size(); i++) {
157 BaseTileTexture* texture = m_textures[i];
159 if (texture->owner())
160 o = (BaseTile*) texture->owner();
167 XLOG("[%d] texture %x busy: %d owner: %x (%d, %d) page: %x scale: %.2f",
169 texture->busy(), o, x, y, o ? o->page() : 0, o ? o->scale() : 0);
175 void TilesManager::swapLayersTextures(LayerAndroid* oldTree, LayerAndroid* newTree)
178 oldTree->assignTextureTo(newTree);
181 newTree->createTexture();
183 WTF::Vector<PaintedSurface*> collect;
184 for (unsigned int i = 0; i < m_paintedSurfaces.size(); i++) {
185 PaintedSurface* surface = m_paintedSurfaces[i];
186 if (!surface->layer())
187 collect.append(surface);
189 for (unsigned int i = 0; i < collect.size(); i++) {
190 m_paintedSurfaces.remove(m_paintedSurfaces.find(collect[i]));
191 SkSafeUnref(collect[i]);
195 void TilesManager::addPaintedSurface(PaintedSurface* surface)
197 m_paintedSurfaces.append(surface);
200 void TilesManager::gatherTextures()
202 android::Mutex::Autolock lock(m_texturesLock);
203 m_availableTextures = m_textures;
206 void TilesManager::gatherLayerTextures()
208 android::Mutex::Autolock lock(m_texturesLock);
209 m_availableTilesTextures = m_tilesTextures;
212 BaseTileTexture* TilesManager::getAvailableTexture(BaseTile* owner)
214 android::Mutex::Autolock lock(m_texturesLock);
216 // Sanity check that the tile does not already own a texture
217 if (owner->backTexture() && owner->backTexture()->owner() == owner) {
218 XLOG("same owner (%d, %d), getAvailableBackTexture(%x) => texture %x",
219 owner->x(), owner->y(), owner, owner->backTexture());
220 if (owner->isLayerTile())
221 m_availableTilesTextures.remove(m_availableTilesTextures.find(owner->backTexture()));
223 m_availableTextures.remove(m_availableTextures.find(owner->backTexture()));
224 return owner->backTexture();
227 WTF::Vector<BaseTileTexture*>* availableTexturePool;
228 if (owner->isLayerTile()) {
229 availableTexturePool = &m_availableTilesTextures;
231 availableTexturePool = &m_availableTextures;
234 // The heuristic for selecting a texture is as follows:
235 // 1. If a tile isn't owned, break with that one
236 // 2. If we find a tile in the same page with a different scale,
237 // it's old and not visible. Break with that one
238 // 3. Otherwise, use the least recently prepared tile, but ignoring tiles
239 // drawn in the last frame to avoid flickering
241 BaseTileTexture* farthestTexture = 0;
242 unsigned long long oldestDrawCount = getDrawGLCount() - 1;
243 const unsigned int max = availableTexturePool->size();
244 for (unsigned int i = 0; i < max; i++) {
245 BaseTileTexture* texture = (*availableTexturePool)[i];
246 TextureOwner* currentOwner = texture->owner();
248 farthestTexture = texture;
252 if (currentOwner->page() == owner->page() && texture->scale() != owner->scale()) {
253 // if we render the back page with one scale, then another while
254 // still zooming, we recycle the tiles with the old scale instead of
255 // taking ones from the front page
256 farthestTexture = texture;
260 unsigned long long textureDrawCount = currentOwner->drawCount();
261 if (oldestDrawCount > textureDrawCount) {
262 farthestTexture = texture;
263 oldestDrawCount = textureDrawCount;
267 if (farthestTexture) {
268 TextureOwner* previousOwner = farthestTexture->owner();
269 if (farthestTexture->acquire(owner)) {
271 XLOG("%s texture %p stolen from tile %d, %d, drawCount was %llu",
272 owner->isLayerTile() ? "LAYER" : "BASE",
273 farthestTexture, owner->x(), owner->y(), oldestDrawCount);
276 availableTexturePool->remove(availableTexturePool->find(farthestTexture));
277 return farthestTexture;
281 XLOG("Couldn't find an available texture for tile %x (%d, %d) out of %d available!!!",
282 owner, owner->x(), owner->y(), max);
289 int TilesManager::maxLayersAllocation()
291 return MAX_LAYERS_ALLOCATION;
294 int TilesManager::maxLayerAllocation()
296 return MAX_LAYER_ALLOCATION;
299 int TilesManager::maxTextureCount()
301 android::Mutex::Autolock lock(m_texturesLock);
302 return m_maxTextureCount;
305 void TilesManager::setMaxTextureCount(int max)
307 XLOG("setMaxTextureCount: %d (current: %d, total:%d)",
308 max, m_maxTextureCount, MAX_TEXTURE_ALLOCATION);
309 if (m_maxTextureCount == MAX_TEXTURE_ALLOCATION ||
310 max <= m_maxTextureCount)
313 android::Mutex::Autolock lock(m_texturesLock);
315 if (max < MAX_TEXTURE_ALLOCATION)
316 m_maxTextureCount = max;
318 m_maxTextureCount = MAX_TEXTURE_ALLOCATION;
323 float TilesManager::tileWidth()
328 float TilesManager::tileHeight()
333 float TilesManager::layerTileWidth()
335 return LAYER_TILE_WIDTH;
338 float TilesManager::layerTileHeight()
340 return LAYER_TILE_HEIGHT;
343 void TilesManager::unregisterGLWebViewState(GLWebViewState* state)
345 // Discard the whole queue b/c we lost GL context already.
346 // Note the real updateTexImage will still wait for the next draw.
347 transferQueue()->discardQueue();
350 TilesManager* TilesManager::instance()
353 gInstance = new TilesManager();
354 XLOG("instance(), new gInstance is %x", gInstance);
355 XLOG("Waiting for the generator...");
356 gInstance->waitForGenerator();
357 XLOG("Generator ready!");
362 TilesManager* TilesManager::gInstance = 0;
364 } // namespace WebCore
366 #endif // USE(ACCELERATED_COMPOSITING)