Home | History | Annotate | Download | only in rendering
      1 /*
      2  * Copyright 2011, 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 #define LOG_TAG "TransferQueue"
     27 #define LOG_NDEBUG 1
     28 
     29 #include "config.h"
     30 #include "TransferQueue.h"
     31 
     32 #if USE(ACCELERATED_COMPOSITING)
     33 
     34 #include "AndroidLog.h"
     35 #include "BaseRenderer.h"
     36 #include "DrawQuadData.h"
     37 #include "GLUtils.h"
     38 #include "Tile.h"
     39 #include "TileTexture.h"
     40 #include "TilesManager.h"
     41 #include <android/native_window.h>
     42 #include <gui/GLConsumer.h>
     43 #include <gui/Surface.h>
     44 
     45 // For simple webView usage, MINIMAL_SIZE is recommended for memory saving.
     46 // In browser case, EFFICIENT_SIZE is preferred.
     47 #define MINIMAL_SIZE 1
     48 #define EFFICIENT_SIZE 6
     49 
     50 // Set this to 1 if we would like to take the new GpuUpload approach which
     51 // relied on the glCopyTexSubImage2D instead of a glDraw call
     52 #define GPU_UPLOAD_WITHOUT_DRAW 1
     53 
     54 namespace WebCore {
     55 
     56 TransferQueue::TransferQueue(bool useMinimalMem)
     57     : m_eglSurface(EGL_NO_SURFACE)
     58     , m_transferQueueIndex(0)
     59     , m_fboID(0)
     60     , m_sharedSurfaceTextureId(0)
     61     , m_hasGLContext(true)
     62     , m_currentDisplay(EGL_NO_DISPLAY)
     63     , m_currentUploadType(DEFAULT_UPLOAD_TYPE)
     64 {
     65     memset(&m_GLStateBeforeBlit, 0, sizeof(m_GLStateBeforeBlit));
     66     m_transferQueueSize = useMinimalMem ? MINIMAL_SIZE : EFFICIENT_SIZE;
     67     m_emptyItemCount = m_transferQueueSize;
     68     m_transferQueue = new TileTransferData[m_transferQueueSize];
     69 }
     70 
     71 TransferQueue::~TransferQueue()
     72 {
     73     android::Mutex::Autolock lock(m_transferQueueItemLocks);
     74     cleanupGLResources();
     75     delete[] m_transferQueue;
     76 }
     77 
     78 // Set the queue to be totally empty, abandon the Surface Texture. This should
     79 // be called only when we hit a wrong EGL Context in an error situation.
     80 void TransferQueue::resetQueue()
     81 {
     82     android::Mutex::Autolock lock(m_transferQueueItemLocks);
     83     emptyAndAbandonQueue();
     84     m_sharedSurfaceTextureId = 0;
     85 }
     86 
     87 // This should be called within the m_transferQueueItemLocks.
     88 // Now only called by emptyQueue() and destructor.
     89 void TransferQueue::cleanupGLResources()
     90 {
     91     if (m_fboID) {
     92         glDeleteFramebuffers(1, &m_fboID);
     93         m_fboID = 0;
     94     }
     95     if (m_sharedSurfaceTextureId) {
     96         glDeleteTextures(1, &m_sharedSurfaceTextureId);
     97         m_sharedSurfaceTextureId = 0;
     98     }
     99 }
    100 
    101 void TransferQueue::initGLResources(int width, int height)
    102 {
    103     android::Mutex::Autolock lock(m_transferQueueItemLocks);
    104     if (!m_sharedSurfaceTextureId) {
    105         glGenTextures(1, &m_sharedSurfaceTextureId);
    106         sp<BufferQueue> bufferQueue(new BufferQueue(true));
    107         m_sharedSurfaceTexture =
    108 #if GPU_UPLOAD_WITHOUT_DRAW
    109             new android::GLConsumer(m_sharedSurfaceTextureId, true,
    110                                         GL_TEXTURE_2D, true, bufferQueue);
    111 #else
    112             new android::GLConsumer(m_sharedSurfaceTextureId, true,
    113                                         GL_TEXTURE_EXTERNAL_OES, true,
    114                                         bufferQueue);
    115 #endif
    116         m_ANW = new android::Surface(bufferQueue);
    117         m_sharedSurfaceTexture->setSynchronousMode(true);
    118 
    119         int extraBuffersNeeded = 0;
    120         m_ANW->query(m_ANW.get(), NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
    121                      &extraBuffersNeeded);
    122         bufferQueue->setBufferCount(m_transferQueueSize + extraBuffersNeeded);
    123 
    124         int result = native_window_set_buffers_geometry(m_ANW.get(),
    125                 width, height, HAL_PIXEL_FORMAT_RGBA_8888);
    126         GLUtils::checkSurfaceTextureError("native_window_set_buffers_geometry", result);
    127         result = native_window_set_usage(m_ANW.get(),
    128                 GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);
    129         GLUtils::checkSurfaceTextureError("native_window_set_usage", result);
    130     }
    131 
    132     if (!m_fboID)
    133         glGenFramebuffers(1, &m_fboID);
    134 }
    135 
    136 // When bliting, if the item from the transfer queue is mismatching b/t the
    137 // Tile and the content, then the item is considered as obsolete, and
    138 // the content is discarded.
    139 bool TransferQueue::checkObsolete(const TileTransferData* data)
    140 {
    141     Tile* baseTilePtr = data->savedTilePtr;
    142     if (!baseTilePtr) {
    143         ALOGV("Invalid savedTilePtr , such that the tile is obsolete");
    144         return true;
    145     }
    146 
    147     TileTexture* baseTileTexture = baseTilePtr->backTexture();
    148     if (!baseTileTexture || baseTileTexture != data->savedTileTexturePtr) {
    149         ALOGV("Invalid baseTileTexture %p (vs expected %p), such that the tile is obsolete",
    150               baseTileTexture, data->savedTileTexturePtr);
    151         return true;
    152     }
    153 
    154     return false;
    155 }
    156 
    157 void TransferQueue::blitTileFromQueue(GLuint fboID, TileTexture* destTex,
    158                                       GLuint srcTexId, GLenum srcTexTarget,
    159                                       int index)
    160 {
    161 #if GPU_UPLOAD_WITHOUT_DRAW
    162     glBindFramebuffer(GL_FRAMEBUFFER, fboID);
    163     glBindTexture(GL_TEXTURE_2D, destTex->m_ownTextureId);
    164 
    165     int textureWidth = destTex->getSize().width();
    166     int textureHeight = destTex->getSize().height();
    167 
    168     glFramebufferTexture2D(GL_FRAMEBUFFER,
    169                            GL_COLOR_ATTACHMENT0,
    170                            GL_TEXTURE_2D,
    171                            srcTexId,
    172                            0);
    173 
    174     glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0,
    175                         textureWidth, textureHeight);
    176     if (GLUtils::checkGlError("At the end of blitTileFromQueue()")) {
    177 #ifndef DEBUG
    178         if (GLUtils::allowGLLog())
    179 #endif
    180         ALOGE("blitTileFromQueue ERROR: fboId %d, destTexId %d, srcTexId %d,"
    181               " textureWidth %d, textureHeight %d", fboID, destTex->m_ownTextureId,
    182               srcTexId, textureWidth, textureHeight);
    183     }
    184 #else
    185     // Then set up the FBO and copy the SurfTex content in.
    186     glBindFramebuffer(GL_FRAMEBUFFER, fboID);
    187     glFramebufferTexture2D(GL_FRAMEBUFFER,
    188                            GL_COLOR_ATTACHMENT0,
    189                            GL_TEXTURE_2D,
    190                            destTex->m_ownTextureId,
    191                            0);
    192     setGLStateForCopy(destTex->getSize().width(),
    193                       destTex->getSize().height());
    194     GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
    195     if (status != GL_FRAMEBUFFER_COMPLETE) {
    196         ALOGV("Error: glCheckFramebufferStatus failed");
    197         return;
    198     }
    199 
    200     // Use empty rect to set up the special matrix to draw.
    201     SkRect rect  = SkRect::MakeEmpty();
    202 
    203     TextureQuadData data(srcTexId, GL_NEAREST, srcTexTarget, Blit, 0, 0, 1.0, false);
    204     TilesManager::instance()->shader()->drawQuad(&data);
    205 #endif
    206 }
    207 
    208 // This function must be called inside the m_transferQueueItemLocks, for the
    209 // wait and getHasGLContext().
    210 // Only called by updateQueueWithBitmap() for now.
    211 bool TransferQueue::readyForUpdate()
    212 {
    213     if (!getHasGLContext())
    214         return false;
    215     // Don't use a while loop since when the WebView tear down, the emptyCount
    216     // will still be 0, and we bailed out b/c of GL context lost.
    217     if (!m_emptyItemCount)
    218         m_transferQueueItemCond.wait(m_transferQueueItemLocks);
    219 
    220     if (!getHasGLContext())
    221         return false;
    222 
    223     return true;
    224 }
    225 
    226 // Both getHasGLContext and setHasGLContext should be called within the lock.
    227 bool TransferQueue::getHasGLContext()
    228 {
    229     return m_hasGLContext;
    230 }
    231 
    232 void TransferQueue::setHasGLContext(bool hasContext)
    233 {
    234     m_hasGLContext = hasContext;
    235 }
    236 
    237 // Call within a m_transferQueueItemLocks, now called by resetQueue() and
    238 // cleanupGLResoucesAndQueue()
    239 void TransferQueue::emptyAndAbandonQueue()
    240 {
    241     for (int i = 0 ; i < m_transferQueueSize; i++)
    242         clearItemInTranferQueue(i);
    243     m_emptyItemCount = m_transferQueueSize;
    244     clearPureColorQueue();
    245 
    246     if (m_sharedSurfaceTexture.get()) {
    247         m_sharedSurfaceTexture->abandon();
    248         m_sharedSurfaceTexture.clear();
    249     }
    250     // This can prevent the tex gen thread to produce, until next incoming draw.
    251     setHasGLContext(false);
    252 }
    253 
    254 void TransferQueue::cleanupGLResourcesAndQueue()
    255 {
    256     android::Mutex::Autolock lock(m_transferQueueItemLocks);
    257     emptyAndAbandonQueue();
    258     cleanupGLResources();
    259 }
    260 
    261 // Set all the content in the queue to pendingDiscard, after this, there will
    262 // be nothing added to the queue, and this can be called in any thread.
    263 // However, in order to discard the content in the Surface Texture using
    264 // updateTexImage, cleanupPendingDiscard need to be called on the UI thread.
    265 // Must be called within a m_transferQueueItemLocks.
    266 void TransferQueue::setPendingDiscard()
    267 {
    268     for (int i = 0 ; i < m_transferQueueSize; i++)
    269         if (m_transferQueue[i].status == pendingBlit)
    270             m_transferQueue[i].status = pendingDiscard;
    271 
    272     clearPureColorQueue();
    273 
    274     bool GLContextExisted = getHasGLContext();
    275     // Unblock the Tex Gen thread first before Tile Page deletion.
    276     // Otherwise, there will be a deadlock while removing operations.
    277     setHasGLContext(false);
    278 
    279     // Only signal once when GL context lost.
    280     if (GLContextExisted)
    281         m_transferQueueItemCond.signal();
    282 }
    283 
    284 void TransferQueue::clearPureColorQueue()
    285 {
    286     for (unsigned int i = 0 ; i < m_pureColorTileQueue.size(); i++) {
    287         SkSafeUnref(m_pureColorTileQueue[i].savedTilePainter);
    288         m_pureColorTileQueue[i].savedTilePainter = 0;
    289     }
    290     m_pureColorTileQueue.clear();
    291 }
    292 
    293 void TransferQueue::updatePureColorTiles()
    294 {
    295     for (unsigned int i = 0 ; i < m_pureColorTileQueue.size(); i++) {
    296         TileTransferData* data = &m_pureColorTileQueue[i];
    297         if (data->status == pendingBlit) {
    298             TileTexture* destTexture = 0;
    299             bool obsoleteTile = checkObsolete(data);
    300             if (!obsoleteTile) {
    301                 destTexture = data->savedTilePtr->backTexture();
    302                 destTexture->setPureColor(data->pureColor);
    303                 destTexture->transferComplete();
    304             }
    305         } else if (data->status == emptyItem || data->status == pendingDiscard) {
    306             // The queue should be clear instead of setting to different status.
    307             ALOGV("Warning: Don't expect an emptyItem here.");
    308         }
    309     }
    310     clearPureColorQueue();
    311 }
    312 
    313 // Call on UI thread to copy from the shared Surface Texture to the Tile's texture.
    314 void TransferQueue::updateDirtyTiles()
    315 {
    316     android::Mutex::Autolock lock(m_transferQueueItemLocks);
    317 
    318     cleanupPendingDiscard();
    319     if (!getHasGLContext())
    320         setHasGLContext(true);
    321 
    322     // Check the pure color tile first, since it is simpler.
    323     updatePureColorTiles();
    324 
    325     // Start from the oldest item, we call the updateTexImage to retrive
    326     // the texture and blit that into each Tile's texture.
    327     const int nextItemIndex = getNextTransferQueueIndex();
    328     int index = nextItemIndex;
    329     bool usedFboForUpload = false;
    330     for (int k = 0; k < m_transferQueueSize ; k++) {
    331         if (m_transferQueue[index].status == pendingBlit) {
    332             bool obsoleteTile = checkObsolete(&m_transferQueue[index]);
    333             // Save the needed info, update the Surf Tex, clean up the item in
    334             // the queue. Then either move on to next item or copy the content.
    335             TileTexture* destTexture = 0;
    336             if (!obsoleteTile)
    337                 destTexture = m_transferQueue[index].savedTilePtr->backTexture();
    338 
    339             if (m_transferQueue[index].uploadType == GpuUpload) {
    340                 status_t result = m_sharedSurfaceTexture->updateTexImage();
    341                 if (result != OK)
    342                     ALOGE("unexpected error: updateTexImage return %d", result);
    343             }
    344 
    345             if (obsoleteTile) {
    346                 ALOGV("Warning: the texture is obsolete for this baseTile");
    347                 clearItemInTranferQueue(index);
    348                 index = (index + 1) % m_transferQueueSize;
    349                 continue;
    350             }
    351 
    352             // guarantee that we have a texture to blit into
    353             destTexture->requireGLTexture();
    354             GLUtils::checkGlError("before blitTileFromQueue");
    355             if (m_transferQueue[index].uploadType == CpuUpload) {
    356                 // Here we just need to upload the bitmap content to the GL Texture
    357                 GLUtils::updateTextureWithBitmap(destTexture->m_ownTextureId,
    358                                                  *m_transferQueue[index].bitmap);
    359             } else {
    360                 if (!usedFboForUpload) {
    361                     saveGLState();
    362                     usedFboForUpload = true;
    363                 }
    364                 blitTileFromQueue(m_fboID, destTexture, m_sharedSurfaceTextureId,
    365                                   m_sharedSurfaceTexture->getCurrentTextureTarget(),
    366                                   index);
    367             }
    368 
    369             destTexture->setPure(false);
    370             destTexture->transferComplete();
    371             clearItemInTranferQueue(index);
    372             ALOGV("Blit tile x, y %d %d with dest texture %p to destTexture->m_ownTextureId %d",
    373                   m_transferQueue[index].savedTilePtr,
    374                   destTexture,
    375                   destTexture->m_ownTextureId);
    376         }
    377         index = (index + 1) % m_transferQueueSize;
    378     }
    379 
    380     // Clean up FBO setup. Doing this for both CPU/GPU upload can make the
    381     // dynamic switch possible. Moving this out from the loop can save some
    382     // milli-seconds.
    383     if (usedFboForUpload) {
    384         restoreGLState();
    385         GLUtils::checkGlError("updateDirtyTiles");
    386     }
    387 
    388     m_emptyItemCount = m_transferQueueSize;
    389     m_transferQueueItemCond.signal();
    390 }
    391 
    392 void TransferQueue::updateQueueWithBitmap(const TileRenderInfo* renderInfo,
    393                                           SkBitmap& bitmap)
    394 {
    395     TRACE_METHOD();
    396     if (!tryUpdateQueueWithBitmap(renderInfo, bitmap)) {
    397         // failed placing bitmap in queue, discard tile's texture so it will be
    398         // re-enqueued (and repainted)
    399         Tile* tile = renderInfo->baseTile;
    400         if (tile)
    401             tile->backTextureTransferFail();
    402     }
    403 }
    404 
    405 bool TransferQueue::tryUpdateQueueWithBitmap(const TileRenderInfo* renderInfo,
    406                                              SkBitmap& bitmap)
    407 {
    408     // This lock need to cover the full update since it is possible that queue
    409     // will be cleaned up in the middle of this update without the lock.
    410     // The Surface Texture will not block us since the readyForUpdate will check
    411     // availability of the slots in the queue first.
    412     android::Mutex::Autolock lock(m_transferQueueItemLocks);
    413     bool ready = readyForUpdate();
    414     TextureUploadType currentUploadType = m_currentUploadType;
    415     if (!ready) {
    416         ALOGV("Quit bitmap update: not ready! for tile x y %d %d",
    417               renderInfo->x, renderInfo->y);
    418         return false;
    419     }
    420     if (currentUploadType == GpuUpload) {
    421         // a) Dequeue the Surface Texture and write into the buffer
    422         if (!m_ANW.get()) {
    423             ALOGV("ERROR: ANW is null");
    424             return false;
    425         }
    426 
    427         if (!GLUtils::updateSharedSurfaceTextureWithBitmap(m_ANW.get(), bitmap))
    428             return false;
    429     }
    430 
    431     // b) After update the Surface Texture, now udpate the transfer queue info.
    432     addItemInTransferQueue(renderInfo, currentUploadType, bitmap);
    433 
    434     ALOGV("Bitmap updated x, y %d %d, baseTile %p",
    435           renderInfo->x, renderInfo->y, renderInfo->baseTile);
    436     return true;
    437 }
    438 
    439 void TransferQueue::addItemInPureColorQueue(const TileRenderInfo* renderInfo)
    440 {
    441     // The pure color tiles' queue will be read from UI thread and written in
    442     // Tex Gen thread, thus we need to have a lock here.
    443     android::Mutex::Autolock lock(m_transferQueueItemLocks);
    444     TileTransferData data;
    445     addItemCommon(renderInfo, GpuUpload, &data);
    446     data.pureColor = renderInfo->pureColor;
    447     m_pureColorTileQueue.append(data);
    448 }
    449 
    450 void TransferQueue::clearItemInTranferQueue(int index)
    451 {
    452     m_transferQueue[index].savedTilePtr = 0;
    453     SkSafeUnref(m_transferQueue[index].savedTilePainter);
    454     m_transferQueue[index].savedTilePainter = 0;
    455     m_transferQueue[index].status = emptyItem;
    456 }
    457 
    458 // Translates the info from TileRenderInfo and others to TileTransferData.
    459 // This is used by pure color tiles and normal tiles.
    460 void TransferQueue::addItemCommon(const TileRenderInfo* renderInfo,
    461                                   TextureUploadType type,
    462                                   TileTransferData* data)
    463 {
    464     data->savedTileTexturePtr = renderInfo->baseTile->backTexture();
    465     data->savedTilePainter = renderInfo->tilePainter;
    466     SkSafeRef(data->savedTilePainter);
    467     data->savedTilePtr = renderInfo->baseTile;
    468     data->status = pendingBlit;
    469     data->uploadType = type;
    470 
    471     IntRect inval(0, 0, 0, 0);
    472 }
    473 
    474 // Note that there should be lock/unlock around this function call.
    475 // Currently only called by GLUtils::updateSharedSurfaceTextureWithBitmap.
    476 void TransferQueue::addItemInTransferQueue(const TileRenderInfo* renderInfo,
    477                                            TextureUploadType type,
    478                                            SkBitmap& bitmap)
    479 {
    480     m_transferQueueIndex = (m_transferQueueIndex + 1) % m_transferQueueSize;
    481 
    482     int index = m_transferQueueIndex;
    483     if (m_transferQueue[index].savedTilePtr
    484         || m_transferQueue[index].status != emptyItem) {
    485         ALOGV("ERROR update a tile which is dirty already @ index %d", index);
    486     }
    487 
    488     TileTransferData* data = &m_transferQueue[index];
    489     addItemCommon(renderInfo, type, data);
    490     if (type == CpuUpload) {
    491         // Lazily create the bitmap
    492         if (!m_transferQueue[index].bitmap) {
    493             m_transferQueue[index].bitmap = new SkBitmap();
    494             int w = bitmap.width();
    495             int h = bitmap.height();
    496             m_transferQueue[index].bitmap->setConfig(bitmap.config(), w, h);
    497             m_transferQueue[index].bitmap->allocPixels();
    498         }
    499         SkBitmap temp = (*m_transferQueue[index].bitmap);
    500         (*m_transferQueue[index].bitmap) = bitmap;
    501         bitmap = temp;
    502     }
    503 
    504     m_emptyItemCount--;
    505 }
    506 
    507 void TransferQueue::setTextureUploadType(TextureUploadType type)
    508 {
    509     android::Mutex::Autolock lock(m_transferQueueItemLocks);
    510     if (m_currentUploadType == type)
    511         return;
    512 
    513     setPendingDiscard();
    514 
    515     m_currentUploadType = type;
    516     ALOGD("Now we set the upload to %s", m_currentUploadType == GpuUpload ? "GpuUpload" : "CpuUpload");
    517 }
    518 
    519 // Note: this need to be called within the lock and on the UI thread.
    520 // Only called by updateDirtyTiles() and emptyQueue() for now
    521 void TransferQueue::cleanupPendingDiscard()
    522 {
    523     int index = getNextTransferQueueIndex();
    524 
    525     for (int i = 0 ; i < m_transferQueueSize; i++) {
    526         if (m_transferQueue[index].status == pendingDiscard) {
    527             // No matter what the current upload type is, as long as there has
    528             // been a Surf Tex enqueue operation, this updateTexImage need to
    529             // be called to keep things in sync.
    530             if (m_transferQueue[index].uploadType == GpuUpload) {
    531                 status_t result = m_sharedSurfaceTexture->updateTexImage();
    532                 if (result != OK)
    533                     ALOGE("unexpected error: updateTexImage return %d", result);
    534             }
    535 
    536             // since tiles in the queue may be from another webview, remove
    537             // their textures so that they will be repainted / retransferred
    538             Tile* tile = m_transferQueue[index].savedTilePtr;
    539             TileTexture* texture = m_transferQueue[index].savedTileTexturePtr;
    540             if (tile && texture && texture->owner() == tile) {
    541                 // since tile destruction removes textures on the UI thread, the
    542                 // texture->owner ptr guarantees the tile is valid
    543                 tile->discardBackTexture();
    544                 ALOGV("transfer queue discarded tile %p, removed texture", tile);
    545             }
    546             clearItemInTranferQueue(index);
    547         }
    548         index = (index + 1) % m_transferQueueSize;
    549     }
    550 }
    551 
    552 void TransferQueue::saveGLState()
    553 {
    554     glGetIntegerv(GL_FRAMEBUFFER_BINDING, m_GLStateBeforeBlit.bufferId);
    555     glGetIntegerv(GL_VIEWPORT, m_GLStateBeforeBlit.viewport);
    556     glGetBooleanv(GL_SCISSOR_TEST, m_GLStateBeforeBlit.scissor);
    557     glGetBooleanv(GL_DEPTH_TEST, m_GLStateBeforeBlit.depth);
    558 #ifdef DEBUG
    559     glGetFloatv(GL_COLOR_CLEAR_VALUE, m_GLStateBeforeBlit.clearColor);
    560 #endif
    561 }
    562 
    563 void TransferQueue::setGLStateForCopy(int width, int height)
    564 {
    565     // Need to match the texture size.
    566     glViewport(0, 0, width, height);
    567     glDisable(GL_SCISSOR_TEST);
    568     glDisable(GL_DEPTH_TEST);
    569     // Clear the content is only for debug purpose.
    570 #ifdef DEBUG
    571     glClearColor(0, 0, 0, 0);
    572     glClear(GL_COLOR_BUFFER_BIT);
    573 #endif
    574 }
    575 
    576 void TransferQueue::restoreGLState()
    577 {
    578     glBindFramebuffer(GL_FRAMEBUFFER, m_GLStateBeforeBlit.bufferId[0]);
    579     glViewport(m_GLStateBeforeBlit.viewport[0],
    580                m_GLStateBeforeBlit.viewport[1],
    581                m_GLStateBeforeBlit.viewport[2],
    582                m_GLStateBeforeBlit.viewport[3]);
    583 
    584     if (m_GLStateBeforeBlit.scissor[0])
    585         glEnable(GL_SCISSOR_TEST);
    586 
    587     if (m_GLStateBeforeBlit.depth[0])
    588         glEnable(GL_DEPTH_TEST);
    589 #ifdef DEBUG
    590     glClearColor(m_GLStateBeforeBlit.clearColor[0],
    591                  m_GLStateBeforeBlit.clearColor[1],
    592                  m_GLStateBeforeBlit.clearColor[2],
    593                  m_GLStateBeforeBlit.clearColor[3]);
    594 #endif
    595 }
    596 
    597 int TransferQueue::getNextTransferQueueIndex()
    598 {
    599     return (m_transferQueueIndex + 1) % m_transferQueueSize;
    600 }
    601 
    602 } // namespace WebCore
    603 
    604 #endif // USE(ACCELERATED_COMPOSITING
    605