// Note: this need to be called within th lock. // Only called by updateDirtyBaseTiles() for now void TransferQueue::cleanupTransportQueue() { int index = getNextTransferQueueIndex(); for (int i = 0 ; i < ST_BUFFER_NUMBER; i++) { if (m_transferQueue[index].status == pendingDiscard) { // No matter what the current upload type is, as long as there has // been a Surf Tex enqueue operation, this updateTexImage need to // be called to keep things in sync. if (m_transferQueue[index].uploadType == GpuUpload) { status_t result = m_sharedSurfaceTexture->updateTexImage(); if (result != OK) XLOGC("unexpected error: updateTexImage return %d", result); } // since tiles in the queue may be from another webview, remove // their textures so that they will be repainted / retransferred BaseTile* tile = m_transferQueue[index].savedBaseTilePtr; BaseTileTexture* texture = m_transferQueue[index].savedBaseTileTexturePtr; if (tile && texture && texture->owner() == tile) { // since tile destruction removes textures on the UI thread, the // texture->owner ptr guarantees the tile is valid tile->discardBackTexture(); XLOG("transfer queue discarded tile %p, removed texture", tile); } m_transferQueue[index].savedBaseTilePtr = 0; m_transferQueue[index].savedBaseTileTexturePtr = 0; m_transferQueue[index].status = emptyItem; } index = (index + 1) % ST_BUFFER_NUMBER; } }
void TilesManager::printTextures() { #ifdef DEBUG XLOG("++++++"); for (unsigned int i = 0; i < m_textures.size(); i++) { BaseTileTexture* texture = m_textures[i]; BaseTile* o = 0; if (texture->owner()) o = (BaseTile*) texture->owner(); int x = -1; int y = -1; if (o) { x = o->x(); y = o->y(); } XLOG("[%d] texture %x busy: %d owner: %x (%d, %d) page: %x scale: %.2f", i, texture, texture->busy(), o, x, y, o ? o->page() : 0, o ? o->scale() : 0); } XLOG("------"); #endif // DEBUG }
BaseTileTexture* TilesManager::getAvailableTexture(BaseTile* owner) { android::Mutex::Autolock lock(m_texturesLock); // Sanity check that the tile does not already own a texture if (owner->backTexture() && owner->backTexture()->owner() == owner) { XLOG("same owner (%d, %d), getAvailableBackTexture(%x) => texture %x", owner->x(), owner->y(), owner, owner->backTexture()); if (owner->isLayerTile()) m_availableTilesTextures.remove(m_availableTilesTextures.find(owner->backTexture())); else m_availableTextures.remove(m_availableTextures.find(owner->backTexture())); return owner->backTexture(); } WTF::Vector<BaseTileTexture*>* availableTexturePool; if (owner->isLayerTile()) { availableTexturePool = &m_availableTilesTextures; } else { availableTexturePool = &m_availableTextures; } // The heuristic for selecting a texture is as follows: // 1. Skip textures currently being painted, they can't be painted while // busy anyway // 2. If a tile isn't owned, break with that one // 3. Don't let tiles acquire their front textures // 4. If we find a tile in the same page with a different scale, // it's old and not visible. Break with that one // 5. Otherwise, use the least recently prepared tile, but ignoring tiles // drawn in the last frame to avoid flickering BaseTileTexture* farthestTexture = 0; unsigned long long oldestDrawCount = getDrawGLCount() - 1; const unsigned int max = availableTexturePool->size(); for (unsigned int i = 0; i < max; i++) { BaseTileTexture* texture = (*availableTexturePool)[i]; BaseTile* currentOwner = static_cast<BaseTile*>(texture->owner()); if (texture->busy()) { // don't bother, since the acquire() will likely fail continue; } if (!currentOwner) { // unused texture! take it! farthestTexture = texture; break; } if (currentOwner == owner) { // Don't let a tile acquire its own front texture, as the // acquisition logic doesn't handle that continue; } if (currentOwner->painter() == owner->painter() && texture->scale() != owner->scale()) { // if we render the back page with one scale, then another while // still zooming, we recycle the tiles with the old scale instead of // taking ones from the front page farthestTexture = texture; break; } unsigned long long textureDrawCount = currentOwner->drawCount(); if (oldestDrawCount > textureDrawCount) { farthestTexture = texture; oldestDrawCount = textureDrawCount; } } if (farthestTexture) { BaseTile* previousOwner = static_cast<BaseTile*>(farthestTexture->owner()); if (farthestTexture->acquire(owner)) { if (previousOwner) { previousOwner->removeTexture(farthestTexture); XLOG("%s texture %p stolen from tile %d, %d for %d, %d, drawCount was %llu (now %llu)", owner->isLayerTile() ? "LAYER" : "BASE", farthestTexture, previousOwner->x(), previousOwner->y(), owner->x(), owner->y(), oldestDrawCount, getDrawGLCount()); } availableTexturePool->remove(availableTexturePool->find(farthestTexture)); return farthestTexture; } } else { if (owner->isLayerTile()) { // couldn't find a tile for a layer, layers shouldn't request redraw // TODO: once we do layer prefetching, don't set this for those // tiles m_layerTexturesRemain = false; } } XLOG("Couldn't find an available texture for %s tile %x (%d, %d) out of %d available", owner->isLayerTile() ? "LAYER" : "BASE", owner, owner->x(), owner->y(), max); #ifdef DEBUG printTextures(); #endif // DEBUG return 0; }