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