// 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; } }
// This function must be called inside the m_transferQueueItemLocks, for the // wait, m_interruptedByRemovingOp and getHasGLContext(). // Only called by updateQueueWithBitmap() for now. bool TransferQueue::readyForUpdate() { if (!getHasGLContext()) return false; // Don't use a while loop since when the WebView tear down, the emptyCount // will still be 0, and we bailed out b/c of GL context lost. if (!m_emptyItemCount) { if (m_interruptedByRemovingOp) return false; m_transferQueueItemCond.wait(m_transferQueueItemLocks); if (m_interruptedByRemovingOp) return false; } if (!getHasGLContext()) return false; // Disable this wait until we figure out why this didn't work on some // drivers b/5332112. #if 0 if (m_currentUploadType == GpuUpload && m_currentDisplay != EGL_NO_DISPLAY) { // Check the GPU fence EGLSyncKHR syncKHR = m_transferQueue[getNextTransferQueueIndex()].m_syncKHR; if (syncKHR != EGL_NO_SYNC_KHR) eglClientWaitSyncKHR(m_currentDisplay, syncKHR, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, EGL_FOREVER_KHR); } GLUtils::checkEglError("WaitSyncKHR"); #endif return true; }
// 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(); }
// Call on UI thread to copy from the shared Surface Texture to the BaseTile's texture. void TransferQueue::updateDirtyBaseTiles() { android::Mutex::Autolock lock(m_transferQueueItemLocks); cleanupTransportQueue(); if (!getHasGLContext()) setHasGLContext(true); // Start from the oldest item, we call the updateTexImage to retrive // the texture and blit that into each BaseTile's texture. const int nextItemIndex = getNextTransferQueueIndex(); int index = nextItemIndex; bool usedFboForUpload = false; for (int k = 0; k < ST_BUFFER_NUMBER ; k++) { if (m_transferQueue[index].status == pendingBlit) { bool obsoleteBaseTile = checkObsolete(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. BaseTileTexture* destTexture = 0; if (!obsoleteBaseTile) destTexture = m_transferQueue[index].savedBaseTilePtr->backTexture(); if (m_transferQueue[index].uploadType == GpuUpload) { status_t result = m_sharedSurfaceTexture->updateTexImage(); if (result != OK) XLOGC("unexpected error: updateTexImage return %d", result); } m_transferQueue[index].savedBaseTilePtr = 0; m_transferQueue[index].status = emptyItem; if (obsoleteBaseTile) { XLOG("Warning: the texture is obsolete for this baseTile"); index = (index + 1) % ST_BUFFER_NUMBER; continue; } // guarantee that we have a texture to blit into destTexture->requireGLTexture(); if (m_transferQueue[index].uploadType == CpuUpload) { // Here we just need to upload the bitmap content to the GL Texture GLUtils::updateTextureWithBitmap(destTexture->m_ownTextureId, 0, 0, *m_transferQueue[index].bitmap); } else { if (!usedFboForUpload) { saveGLState(); usedFboForUpload = true; } blitTileFromQueue(m_fboID, destTexture, m_sharedSurfaceTextureId, m_sharedSurfaceTexture->getCurrentTextureTarget(), index); } // After the base tile copied into the GL texture, we need to // update the texture's info such that at draw time, readyFor // will find the latest texture's info // We don't need a map any more, each texture contains its own // texturesTileInfo. destTexture->setOwnTextureTileInfoFromQueue(&m_transferQueue[index].tileInfo); XLOG("Blit tile x, y %d %d with dest texture %p to destTexture->m_ownTextureId %d", m_transferQueue[index].tileInfo.m_x, m_transferQueue[index].tileInfo.m_y, destTexture, destTexture->m_ownTextureId); } index = (index + 1) % ST_BUFFER_NUMBER; } // 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) { glBindFramebuffer(GL_FRAMEBUFFER, 0); // rebind the standard FBO restoreGLState(); GLUtils::checkGlError("updateDirtyBaseTiles"); } m_emptyItemCount = ST_BUFFER_NUMBER; m_transferQueueItemCond.signal(); }