Beispiel #1
0
// Note: this need to be called within the lock and on the UI thread.
// Only called by updateDirtyTiles() and emptyQueue() for now
void TransferQueue::cleanupPendingDiscard()
{
    int index = getNextTransferQueueIndex();

    for (int i = 0 ; i < m_transferQueueSize; 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)
                    ALOGE("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
            Tile* tile = m_transferQueue[index].savedTilePtr;
            TileTexture* texture = m_transferQueue[index].savedTileTexturePtr;
            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();
                ALOGV("transfer queue discarded tile %p, removed texture", tile);
            }
            clearItemInTranferQueue(index);
        }
        index = (index + 1) % m_transferQueueSize;
    }
}
Beispiel #2
0
void TransferQueue::updatePureColorTiles()
{
    for (unsigned int i = 0 ; i < m_pureColorTileQueue.size(); i++) {
        TileTransferData* data = &m_pureColorTileQueue[i];
        if (data->status == pendingBlit) {
            TileTexture* destTexture = 0;
            bool obsoleteTile = checkObsolete(data);
            if (!obsoleteTile) {
                destTexture = data->savedTilePtr->backTexture();
                destTexture->setPureColor(data->pureColor);
                destTexture->transferComplete();
            }
        } else if (data->status == emptyItem || data->status == pendingDiscard) {
            // The queue should be clear instead of setting to different status.
            ALOGV("Warning: Don't expect an emptyItem here.");
        }
    }
    clearPureColorQueue();
}
Beispiel #3
0
bool Tile::isTileReady()
{
    // Return true if the tile's most recently drawn texture is up to date
    android::AutoMutex lock(m_atomicSync);
    TileTexture * texture = (m_state == ReadyToSwap) ? m_backTexture : m_frontTexture;

    if (!texture)
        return false;

    if (texture->owner() != this)
        return false;

    if (m_dirty)
        return false;

    if (m_state != ReadyToSwap && m_state != UpToDate)
        return false;

    return true;
}
void TilesManager::printTextures()
{
#ifdef DEBUG
    ALOGV("++++++");
    for (unsigned int i = 0; i < m_textures.size(); i++) {
        TileTexture* texture = m_textures[i];
        Tile* o = 0;
        if (texture->owner())
            o = (Tile*) texture->owner();
        int x = -1;
        int y = -1;
        if (o) {
            x = o->x();
            y = o->y();
        }
        ALOGV("[%d] texture %x owner: %x (%d, %d) scale: %.2f",
              i, texture, o, x, y, o ? o->scale() : 0);
    }
    ALOGV("------");
#endif // DEBUG
}
Beispiel #5
0
// Call on UI thread to copy from the shared Surface Texture to the Tile's texture.
void TransferQueue::updateDirtyTiles()
{
    android::Mutex::Autolock lock(m_transferQueueItemLocks);

    cleanupPendingDiscard();
    if (!getHasGLContext())
        setHasGLContext(true);

    // Check the pure color tile first, since it is simpler.
    updatePureColorTiles();

    // Start from the oldest item, we call the updateTexImage to retrive
    // the texture and blit that into each Tile's texture.
    const int nextItemIndex = getNextTransferQueueIndex();
    int index = nextItemIndex;
    bool usedFboForUpload = false;
    for (int k = 0; k < m_transferQueueSize ; k++) {
        if (m_transferQueue[index].status == pendingBlit) {
            bool obsoleteTile = checkObsolete(&m_transferQueue[index]);
            // Save the needed info, update the Surf Tex, clean up the item in
            // the queue. Then either move on to next item or copy the content.
            TileTexture* destTexture = 0;
            if (!obsoleteTile)
                destTexture = m_transferQueue[index].savedTilePtr->backTexture();

            if (m_transferQueue[index].uploadType == GpuUpload) {
                status_t result = m_sharedSurfaceTexture->updateTexImage();
                if (result != OK)
                    ALOGE("unexpected error: updateTexImage return %d", result);
            }

            if (obsoleteTile) {
                ALOGV("Warning: the texture is obsolete for this baseTile");
                clearItemInTranferQueue(index);
                index = (index + 1) % m_transferQueueSize;
                continue;
            }

            // guarantee that we have a texture to blit into
            destTexture->requireGLTexture();
            GLUtils::checkGlError("before blitTileFromQueue");
            if (m_transferQueue[index].uploadType == CpuUpload) {
                // Here we just need to upload the bitmap content to the GL Texture
                GLUtils::updateTextureWithBitmap(destTexture->m_ownTextureId,
                                                 *m_transferQueue[index].bitmap);
            } else {
                if (!usedFboForUpload) {
                    saveGLState();
                    usedFboForUpload = true;
                }
                blitTileFromQueue(m_fboID, destTexture, m_sharedSurfaceTextureId,
                                  m_sharedSurfaceTexture->getCurrentTextureTarget(),
                                  index);
            }

            destTexture->setPure(false);
            destTexture->transferComplete();
            clearItemInTranferQueue(index);
            ALOGV("Blit tile x, y %d %d with dest texture %p to destTexture->m_ownTextureId %d",
                  m_transferQueue[index].savedTilePtr,
                  destTexture,
                  destTexture->m_ownTextureId);
        }
        index = (index + 1) % m_transferQueueSize;
    }

    // Clean up FBO setup. Doing this for both CPU/GPU upload can make the
    // dynamic switch possible. Moving this out from the loop can save some
    // milli-seconds.
    if (usedFboForUpload) {
        restoreGLState();
        GLUtils::checkGlError("updateDirtyTiles");
    }

    m_emptyItemCount = m_transferQueueSize;
    m_transferQueueItemCond.signal();
}
TileTexture* TilesManager::getAvailableTexture(Tile* owner)
{
    android::Mutex::Autolock lock(m_texturesLock);

    WTF::Vector<TileTexture*>* availableTexturePool;
    if (owner->isLayerTile())
        availableTexturePool = &m_availableTilesTextures;
    else
        availableTexturePool = &m_availableTextures;

    // Sanity check that the tile does not already own a texture
    if (owner->backTexture() && owner->backTexture()->owner() == owner) {
        int removeIndex = availableTexturePool->find(owner->backTexture());

        // TODO: investigate why texture isn't found
        if (removeIndex >= 0)
            availableTexturePool->remove(removeIndex);
        return owner->backTexture();
    }

    // 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. Otherwise, use the least recently prepared tile, but ignoring tiles
    //         drawn in the last frame to avoid flickering

    TileTexture* farthestTexture = 0;
    unsigned long long oldestDrawCount = getDrawGLCount() - 1;
    const unsigned int max = availableTexturePool->size();
    for (unsigned int i = 0; i < max; i++) {
        TileTexture* texture = (*availableTexturePool)[i];
        Tile* currentOwner = static_cast<Tile*>(texture->owner());
        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;
        }

        unsigned long long textureDrawCount = currentOwner->drawCount();
        if (oldestDrawCount > textureDrawCount) {
            farthestTexture = texture;
            oldestDrawCount = textureDrawCount;
        }
    }

    if (farthestTexture) {
        Tile* previousOwner = static_cast<Tile*>(farthestTexture->owner());
        if (farthestTexture->acquire(owner)) {
            if (previousOwner) {
                previousOwner->removeTexture(farthestTexture);

                ALOGV("%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;
        }
    }

    ALOGV("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;
}
Beispiel #7
0
// This is called from the texture generation thread
void Tile::paintBitmap(TilePainter* painter, BaseRenderer* renderer)
{
    // We acquire the values below atomically. This ensures that we are reading
    // values correctly across cores. Further, once we have these values they
    // can be updated by other threads without consequence.
    m_atomicSync.lock();
    bool dirty = m_dirty;
    TileTexture* texture = m_backTexture;
    SkRegion dirtyArea = m_dirtyArea;
    float scale = m_scale;
    const int x = m_x;
    const int y = m_y;

    if (!dirty || !texture) {
        m_atomicSync.unlock();
        return;
    }
    if (m_state != Unpainted) {
        ALOGV("Warning: started painting tile %p, but was at state %d, ft %p bt %p",
              this, m_state, m_frontTexture, m_backTexture);
    }
    m_state = PaintingStarted;
    TextureInfo* textureInfo = texture->getTextureInfo();
    m_atomicSync.unlock();

    // at this point we can safely check the ownership (if the texture got
    // transferred to another Tile under us)
    if (texture->owner() != this) {
        return;
    }

    // setup the common renderInfo fields;
    TileRenderInfo renderInfo;
    renderInfo.x = x;
    renderInfo.y = y;
    renderInfo.scale = scale;
    renderInfo.tileSize = texture->getSize();
    renderInfo.tilePainter = painter;
    renderInfo.baseTile = this;
    renderInfo.textureInfo = textureInfo;

    const float tileWidth = renderInfo.tileSize.width();
    const float tileHeight = renderInfo.tileSize.height();

    renderer->renderTiledContent(renderInfo);

    m_atomicSync.lock();

    if (texture == m_backTexture) {
        // set the fullrepaint flags
        m_fullRepaint = false;

        // The various checks to see if we are still dirty...

        m_dirty = false;

        if (m_scale != scale)
            m_dirty = true;

        m_dirtyArea.setEmpty();

        ALOGV("painted tile %p (%d, %d), texture %p, dirty=%d", this, x, y, texture, m_dirty);

        validatePaint();
    } else {
        ALOGV("tile %p no longer owns texture %p, m_state %d. ft %p bt %p",
              this, texture, m_state, m_frontTexture, m_backTexture);
    }

    m_atomicSync.unlock();
}