OSDN Git Service

Finalize the sync part.
authorTeng-Hui Zhu <ztenghui@google.com>
Wed, 3 Aug 2011 22:31:41 +0000 (15:31 -0700)
committerTeng-Hui Zhu <ztenghui@google.com>
Thu, 4 Aug 2011 00:01:59 +0000 (17:01 -0700)
Improve the sync part for the Shared Surface Texture.
Clean up the interface as much as possible.

bug:5044597
Change-Id: I123cc520fb447aeb6e72e90149d1658a657740f7

Source/WebCore/platform/graphics/android/BaseTile.cpp
Source/WebCore/platform/graphics/android/GLUtils.cpp
Source/WebCore/platform/graphics/android/TilesManager.cpp
Source/WebCore/platform/graphics/android/TransferQueue.cpp
Source/WebCore/platform/graphics/android/TransferQueue.h

index 8bc560e..60c1ebb 100644 (file)
@@ -92,17 +92,6 @@ BaseTile::BaseTile(bool isLayerTile)
 
 BaseTile::~BaseTile()
 {
-    TransferQueue* tileQueue = TilesManager::instance()->transferQueue();
-    if (tileQueue->getHasGLContext()) {
-        tileQueue->m_transferQueueLock.lock();
-        for (int i = 0 ; i < tileQueue->size(); i ++) {
-            TileTransferData* data = &(tileQueue->m_transferQueue[i]);
-            if (data->savedBaseTilePtr == this)
-                data->status = pendingDiscard;
-        }
-        tileQueue->m_transferQueueLock.unlock();
-    }
-
     setUsedLevel(-1);
     if (m_texture)
         m_texture->release(this);
index 5a6a158..d1fe51a 100644 (file)
@@ -488,69 +488,8 @@ void GLUtils::updateSharedSurfaceTextureWithBitmap(const TileRenderInfo* renderI
         || !renderInfo->textureInfo
         || !renderInfo->baseTile)
         return;
-    TransferQueue* tileQueue = TilesManager::instance()->transferQueue();
-    // Only changed in the Tex Gen thread.
-    const int index = tileQueue->getNextTransferQueueIndex();
 
-    bool ready = tileQueue->lockForUpdate(index, renderInfo);
-    if (!ready)
-        return;
-
-    // Dequeue the Surface Texture.
-    sp<ANativeWindow> ANW = tileQueue->m_ANW;
-    if (!ANW.get()) {
-        XLOG("ERROR: ANW is null");
-        return;
-    }
-    ANativeWindowBuffer* anb;
-
-    // We bound the Surface Texture update and transfer queue update together.
-    tileQueue->m_transferQueueLock.lock();
-
-    int status = ANW->dequeueBuffer(ANW.get(), &anb);
-    checkSurfaceTextureError("dequeueBuffer", status);
-    // a) Update surface texture
-    sp<android::GraphicBuffer> buf(new android::GraphicBuffer(anb, false));
-    status |= ANW->lockBuffer(ANW.get(), buf->getNativeBuffer()); // Mutex Lock
-    checkSurfaceTextureError("lockBuffer", status);
-
-    // Fill the buffer with the content of the bitmap
-    uint8_t* img = 0;
-    status |= buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
-    checkSurfaceTextureError("lock", status);
-
-    if (status == NO_ERROR) {
-        int row, col;
-        int bpp = 4; // Now we only deal with RGBA8888 format.
-        int width = TilesManager::instance()->tileWidth();
-        int height = TilesManager::instance()->tileHeight();
-        if (x == 0 && y == 0 && bitmap.width() == width && bitmap.height() == height) {
-            bitmap.lockPixels();
-            uint8_t* bitmapOrigin = static_cast<uint8_t*>(bitmap.getPixels());
-            // Copied line by line since we need to handle the offsets and stride.
-            for (row = 0 ; row < bitmap.height(); row ++) {
-                uint8_t* dst = &(img[(buf->getStride() * (row + x) + y) * bpp]);
-                uint8_t* src = &(bitmapOrigin[bitmap.width() * row * bpp]);
-                memcpy(dst, src, bpp * bitmap.width());
-            }
-            bitmap.unlockPixels();
-        }
-        else{
-            // TODO: implement the partial invalidate here!
-            XLOG("ERROR: don't expect to get here yet before we support partial inval");
-        }
-    }
-    buf->unlock();
-
-    status = ANW->queueBuffer(ANW.get(), buf->getNativeBuffer());
-    checkSurfaceTextureError("queueBuffer", status);
-
-    // b) After update the Surface Texture, now udpate the transfer queue info.
-    tileQueue->addItemInTransferQueue(renderInfo, index);
-    XLOG("Bitmap updated x, y %d %d, baseTile %p",
-         renderInfo->x, renderInfo->y, renderInfo->baseTile);
-
-    tileQueue->m_transferQueueLock.unlock();
+    TilesManager::instance()->transferQueue()->updateQueueWithBitmap(renderInfo, x, y, bitmap);
 }
 
 void GLUtils::createTextureWithBitmap(GLuint texture, const SkBitmap& bitmap, GLint filter)
index 7b1581b..9a18758 100644 (file)
@@ -204,9 +204,7 @@ void TilesManager::cleanupTilesTextures()
         m_paintedSurfaces.remove(m_paintedSurfaces.find(collect[i]));
         TilePainter* painter = collect[i]->texture();
         // Mark the current painter to destroy!!
-        transferQueue()->m_currentRemovingPaint = painter;
         m_pixmapsGenerationThread->removeOperationsForPainter(painter, true);
-        transferQueue()->m_currentRemovingPaint = 0;
         XLOG("destroy %x (%x)", collect[i], painter);
         delete collect[i];
     }
index 878affb..0d48175 100644 (file)
 namespace WebCore {
 
 TransferQueue::TransferQueue()
-    : m_currentRemovingPaint(0)
-    , m_transferQueueIndex(0)
+    : m_transferQueueIndex(0)
     , m_fboID(0)
     , m_sharedSurfaceTextureId(0)
     , m_hasGLContext(true)
 {
     memset(&m_GLStateBeforeBlit, 0, sizeof(m_GLStateBeforeBlit));
 
-    m_transferQueueItemLocks = new android::Mutex[ST_BUFFER_NUMBER];
+    m_emptyItemCount = ST_BUFFER_NUMBER;
 
     m_transferQueue = new TileTransferData[ST_BUFFER_NUMBER];
     for (int i = 0; i < ST_BUFFER_NUMBER; i++) {
@@ -77,15 +76,9 @@ TransferQueue::~TransferQueue()
     glDeleteTextures(1, &m_sharedSurfaceTextureId);
     m_sharedSurfaceTextureId = 0;
 
-    delete[] m_transferQueueItemLocks;
     delete[] m_transferQueue;
 }
 
-int TransferQueue::size()
-{
-    return ST_BUFFER_NUMBER;
-}
-
 void TransferQueue::initSharedSurfaceTextures(int width, int height)
 {
     if (!m_sharedSurfaceTextureId) {
@@ -170,77 +163,55 @@ void TransferQueue::blitTileFromQueue(GLuint fboID, BaseTileTexture* destTex, GL
     GLUtils::checkGlError("copy the surface texture into the normal one");
 }
 
-bool TransferQueue::currentOpWaitingRemoval(const TileRenderInfo* renderInfo)
+bool TransferQueue::readyForUpdate()
 {
-    if (m_currentRemovingPaint
-        && m_currentRemovingPaint == renderInfo->tilePainter)
-        return true;
-    return false;
-}
-
-bool TransferQueue::lockForUpdate(int index, const TileRenderInfo* renderInfo)
-{
-    // Before dequeuing the buffer from Surface Texture, make sure this item
-    // has been consumed. We can't simply rely on dequeueBuffer, due to the
-    // UI thread may want to remove the current operation, so we have to add
-    // our own locking mechanism.
-    // For blocking case, the item's status should not be emptyItem.
-    while (m_transferQueueItemLocks[index].tryLock()) {
-        // If the current operation is on an resource which is going to be
-        // removed from UI thread, then early return.
-        if (currentOpWaitingRemoval(renderInfo)) {
-            XLOG("Quit bitmap update: operation is removed from UI thread!"
-                 " x y %d %d",
-                 renderInfo->x, renderInfo->y);
-            return false;
-        }
-    }
+    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)
+        m_transferQueueItemCond.wait(m_transferQueueItemLocks);
 
-    // And if we have lost GL Context, then we can just early return here.
-    if (!getHasGLContext()) {
-        m_transferQueue[index].status = pendingDiscard;
-        m_transferQueueItemLocks[index].unlock();
-        XLOG("Quit bitmap update: No GL Context! x y %d %d",
-             renderInfo->x, renderInfo->y);
+    if (!getHasGLContext())
         return false;
-    }
 
     return true;
 }
 
+// Both getHasGLContext and setHasGLContext should be called within the lock.
 bool TransferQueue::getHasGLContext()
 {
-    android::Mutex::Autolock lock(m_hasGLContextLock);
-    bool hasContext = m_hasGLContext;
-    return hasContext;
+    return m_hasGLContext;
 }
 
 void TransferQueue::setHasGLContext(bool hasContext)
 {
-    android::Mutex::Autolock lock(m_hasGLContextLock);
     m_hasGLContext = hasContext;
 }
 
+// Only called when WebView is destroyed.
 void TransferQueue::discardQueue()
 {
+    android::Mutex::Autolock lock(m_transferQueueItemLocks);
+
+    for (int i = 0 ; i < ST_BUFFER_NUMBER; i++)
+        m_transferQueue[i].status = pendingDiscard;
+
+    bool GLContextExisted = getHasGLContext();
     // Unblock the Tex Gen thread first before Tile Page deletion.
     // Otherwise, there will be a deadlock while removing operations.
     setHasGLContext(false);
 
-    for (int i = 0 ; i < ST_BUFFER_NUMBER; i++) {
-        m_transferQueue[i].status = pendingDiscard;
-        m_transferQueueItemLocks[i].unlock();
-    }
+    // Only signal once when GL context lost.
+    if (GLContextExisted)
+        m_transferQueueItemCond.signal();
 }
 
 // Call on UI thread to copy from the shared Surface Texture to the BaseTile's texture.
 void TransferQueue::updateDirtyBaseTiles()
 {
-    bool unlockFlag[ST_BUFFER_NUMBER];
-    memset(unlockFlag, 0, sizeof(unlockFlag));
-
     saveGLState();
-    m_transferQueueLock.lock();
+    android::Mutex::Autolock lock(m_transferQueueItemLocks);
 
     cleanupTransportQueue();
     if (!getHasGLContext())
@@ -261,11 +232,11 @@ void TransferQueue::updateDirtyBaseTiles()
 
             m_sharedSurfaceTexture->updateTexImage();
 
-            unlockFlag[index] = true;
             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;
             }
 
@@ -290,24 +261,80 @@ void TransferQueue::updateDirtyBaseTiles()
 
     restoreGLState();
 
-    int unlockIndex = nextItemIndex;
-    for (int k = 0; k < ST_BUFFER_NUMBER; k++) {
-        // Check the same order as the updateTexImage.
-        if (unlockFlag[unlockIndex])
-            m_transferQueueItemLocks[unlockIndex].unlock();
-        unlockIndex = (unlockIndex + 1) % ST_BUFFER_NUMBER;
+    m_emptyItemCount = ST_BUFFER_NUMBER;
+    m_transferQueueItemCond.signal();
+}
+
+void TransferQueue::updateQueueWithBitmap(const TileRenderInfo* renderInfo,
+                                          int x, int y, const SkBitmap& bitmap)
+{
+    android::Mutex::Autolock lock(m_transferQueueItemLocks);
+
+    bool ready = readyForUpdate();
+
+    if (!ready) {
+        XLOG("Quit bitmap update: not ready! for tile x y %d %d",
+             renderInfo->x, renderInfo->y);
+        return;
     }
+    // Dequeue the Surface Texture.
+    sp<ANativeWindow> ANW = m_ANW;
+    if (!ANW.get()) {
+        XLOG("ERROR: ANW is null");
+        return;
+    }
+    ANativeWindowBuffer* anb;
+
+    int status = ANW->dequeueBuffer(ANW.get(), &anb);
+    GLUtils::checkSurfaceTextureError("dequeueBuffer", status);
+    // a) Update surface texture
+    sp<android::GraphicBuffer> buf(new android::GraphicBuffer(anb, false));
+    status |= ANW->lockBuffer(ANW.get(), buf->getNativeBuffer()); // Mutex Lock
+    GLUtils::checkSurfaceTextureError("lockBuffer", status);
+
+    // Fill the buffer with the content of the bitmap
+    uint8_t* img = 0;
+    status |= buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
+    GLUtils::checkSurfaceTextureError("lock", status);
+
+    if (status == NO_ERROR) {
+        int row, col;
+        int bpp = 4; // Now we only deal with RGBA8888 format.
+        int width = TilesManager::instance()->tileWidth();
+        int height = TilesManager::instance()->tileHeight();
+        if (!x && !y && bitmap.width() == width && bitmap.height() == height) {
+            bitmap.lockPixels();
+            uint8_t* bitmapOrigin = static_cast<uint8_t*>(bitmap.getPixels());
+            // Copied line by line since we need to handle the offsets and stride.
+            for (row = 0 ; row < bitmap.height(); row ++) {
+                uint8_t* dst = &(img[(buf->getStride() * (row + x) + y) * bpp]);
+                uint8_t* src = &(bitmapOrigin[bitmap.width() * row * bpp]);
+                memcpy(dst, src, bpp * bitmap.width());
+            }
+            bitmap.unlockPixels();
+        } else {
+            // TODO: implement the partial invalidate here!
+            XLOG("ERROR: don't expect to get here yet before we support partial inval");
+        }
+    }
+    buf->unlock();
+
+    status = ANW->queueBuffer(ANW.get(), buf->getNativeBuffer());
+    GLUtils::checkSurfaceTextureError("queueBuffer", status);
 
-    m_transferQueueLock.unlock();
+    // b) After update the Surface Texture, now udpate the transfer queue info.
+    addItemInTransferQueue(renderInfo);
+    XLOG("Bitmap updated x, y %d %d, baseTile %p",
+         renderInfo->x, renderInfo->y, renderInfo->baseTile);
 }
 
 // Note that there should be lock/unlock around this function call.
 // Currently only called by GLUtils::updateSharedSurfaceTextureWithBitmap.
-void TransferQueue::addItemInTransferQueue(const TileRenderInfo* renderInfo,
-                                          int index)
+void TransferQueue::addItemInTransferQueue(const TileRenderInfo* renderInfo)
 {
-    m_transferQueueIndex = index;
+    m_transferQueueIndex = (m_transferQueueIndex + 1) % ST_BUFFER_NUMBER;
 
+    int index = m_transferQueueIndex;
     if (m_transferQueue[index].savedBaseTilePtr
         || m_transferQueue[index].status != emptyItem) {
         XLOG("ERROR update a tile which is dirty already @ index %d", index);
@@ -325,34 +352,25 @@ void TransferQueue::addItemInTransferQueue(const TileRenderInfo* renderInfo,
     textureInfo->m_painter = renderInfo->tilePainter;
 
     textureInfo->m_picture = renderInfo->textureInfo->m_pictureCount;
+
+    m_emptyItemCount--;
 }
 
-// Note: this need to be called within th m_transferQueueLock.
+// Note: this need to be called within th lock.
+// Only called by updateDirtyBaseTiles() for now
 void TransferQueue::cleanupTransportQueue()
 {
-    // We should call updateTexImage to the items first,
-    // then unlock. And we should start from the next item.
-    const int nextItemIndex = getNextTransferQueueIndex();
-    bool needUnlock[ST_BUFFER_NUMBER];
-    int index = nextItemIndex;
+    int index = getNextTransferQueueIndex();
 
     for (int i = 0 ; i < ST_BUFFER_NUMBER; i++) {
-        needUnlock[index] = false;
         if (m_transferQueue[index].status == pendingDiscard) {
             m_sharedSurfaceTexture->updateTexImage();
 
             m_transferQueue[index].savedBaseTilePtr = 0;
-            m_transferQueue[index].status == emptyItem;
-            needUnlock[index] = true;
+            m_transferQueue[index].status = emptyItem;
         }
         index = (index + 1) % ST_BUFFER_NUMBER;
     }
-    index = nextItemIndex;
-    for (int i = 0 ; i < ST_BUFFER_NUMBER; i++) {
-        if (needUnlock[index])
-            m_transferQueueItemLocks[index].unlock();
-        index = (index + 1) % ST_BUFFER_NUMBER;
-    }
 }
 
 void TransferQueue::saveGLState()
index e0046c3..8d9df68 100644 (file)
@@ -49,52 +49,46 @@ public:
 
     void updateDirtyBaseTiles();
 
-    // This queue can be accessed from UI and TexGen thread, therefore, we need
-    // a lock to protect its access
-    TileTransferData* m_transferQueue;
-    android::Mutex m_transferQueueLock;
-
     void initSharedSurfaceTextures(int width, int height);
-    sp<ANativeWindow> m_ANW;
 
-    bool getHasGLContext();
-    void setHasGLContext(bool hasContext);
+    void updateQueueWithBitmap(const TileRenderInfo* renderInfo, int x, int y,
+                               const SkBitmap& bitmap);
 
-    int getNextTransferQueueIndex();
+    void discardQueue();
 
-    void addItemInTransferQueue(const TileRenderInfo* info, int index);
+    void addItemInTransferQueue(const TileRenderInfo* info);
 
     // Check if the item @ index is ready for update.
     // The lock will be done when returning true.
-    bool lockForUpdate(int index, const TileRenderInfo* renderInfo);
+    bool readyForUpdate();
 
-    void discardQueue();
+    // This queue can be accessed from UI and TexGen thread, therefore, we need
+    // a lock to protect its access
+    TileTransferData* m_transferQueue;
 
-    // Store info for currentOpWaitingRemoval() to tell which operation
-    // will be removed.
-    TilePainter* m_currentRemovingPaint;
+    // We are using wait/signal to handle our own queue sync.
+    // First of all, if we don't have our own lock, then while WebView is
+    // destroyed, the UI thread will wait for the Tex Gen to get out from
+    // dequeue operation, which will not succeed. B/c at this moment, we
+    // already lost the GL Context.
+    // Now we maintain a counter, which is m_emptyItemCount. When this reach
+    // 0, then we need the Tex Gen thread to wait. UI thread can signal this
+    // wait after calling updateTexImage at the draw call , or after WebView
+    // is destroyed.
+    android::Mutex m_transferQueueItemLocks;
 
-    // Return the buffer number.
-    int size();
+    sp<ANativeWindow> m_ANW;
 
 private:
-    // Note that the m_transferQueueIndex only changed in the TexGen thread
-    // where we are going to move on to update the next item in the queue.
-    int m_transferQueueIndex;
-
-    GLuint m_fboID; // The FBO used for copy the SurfTex to each tile
-
-    GLuint m_sharedSurfaceTextureId;
+    bool getHasGLContext();
+    void setHasGLContext(bool hasContext);
 
-    // GLContext can be lost when WebView destroyed.
-    bool m_hasGLContext;
-    android::Mutex m_hasGLContextLock;
+    int getNextTransferQueueIndex();
 
     // Save and restore the GL State while switching from/to FBO.
     void saveGLState();
     void setGLStateForCopy(int width, int height);
     void restoreGLState();
-    GLState m_GLStateBeforeBlit;
 
     // Check the current transfer queue item is obsolete or not.
     bool checkObsolete(int index);
@@ -103,21 +97,25 @@ private:
     // pendingDiscard items.
     void cleanupTransportQueue();
 
-    // This function can tell Tex Gen thread whether or not the current
-    // operation need to be removed now.
-    bool currentOpWaitingRemoval(const TileRenderInfo* renderInfo);
+    void blitTileFromQueue(GLuint fboID, BaseTileTexture* destTex,
+                           GLuint srcTexId, GLenum srcTexTarget);
 
-    void blitTileFromQueue(GLuint fboID, BaseTileTexture* destTex, GLuint srcTexId, GLenum srcTexTarget);
+    // Note that the m_transferQueueIndex only changed in the TexGen thread
+    // where we are going to move on to update the next item in the queue.
+    int m_transferQueueIndex;
 
-    // Each element in the queue has its own lock, basically lock before update
-    // and unlock at drawGL time.
-    // This is similar to the internal lock from SurfaceTexture, but we can't
-    // naively rely on them since when tearing down, UI thread need to clean up
-    // the pending jobs in that Tex Gen thread, if the Tex Gen is waiting for
-    // Surface Texture, then we are stuck.
-    android::Mutex* m_transferQueueItemLocks;
+    GLuint m_fboID; // The FBO used for copy the SurfTex to each tile
 
+    GLuint m_sharedSurfaceTextureId;
+
+    // GLContext can be lost when WebView destroyed.
+    bool m_hasGLContext;
+
+    GLState m_GLStateBeforeBlit;
     sp<android::SurfaceTexture> m_sharedSurfaceTexture;
+
+    android::Condition m_transferQueueItemCond;
+    int m_emptyItemCount;
 };
 
 } // namespace WebCore