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