Home | History | Annotate | Download | only in android
      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 #include "config.h"
     27 #include "TransferQueue.h"
     28 
     29 #if USE(ACCELERATED_COMPOSITING)
     30 
     31 #include "BaseTile.h"
     32 #include "PaintedSurface.h"
     33 #include <android/native_window.h>
     34 #include <gui/SurfaceTexture.h>
     35 #include <gui/SurfaceTextureClient.h>
     36 
     37 #include <cutils/log.h>
     38 #include <wtf/text/CString.h>
     39 #define XLOGC(...) android_printLog(ANDROID_LOG_DEBUG, "TransferQueue", __VA_ARGS__)
     40 
     41 #ifdef DEBUG
     42 
     43 #undef XLOG
     44 #define XLOG(...) android_printLog(ANDROID_LOG_DEBUG, "TransferQueue", __VA_ARGS__)
     45 
     46 #else
     47 
     48 #undef XLOG
     49 #define XLOG(...)
     50 
     51 #endif // DEBUG
     52 
     53 #define ST_BUFFER_NUMBER 6
     54 
     55 // Set this to 1 if we would like to take the new GpuUpload approach which
     56 // relied on the glCopyTexSubImage2D instead of a glDraw call
     57 #define GPU_UPLOAD_WITHOUT_DRAW 1
     58 
     59 namespace WebCore {
     60 
     61 TransferQueue::TransferQueue()
     62     : m_eglSurface(EGL_NO_SURFACE)
     63     , m_transferQueueIndex(0)
     64     , m_fboID(0)
     65     , m_sharedSurfaceTextureId(0)
     66     , m_hasGLContext(true)
     67     , m_interruptedByRemovingOp(false)
     68     , m_currentDisplay(EGL_NO_DISPLAY)
     69     , m_currentUploadType(DEFAULT_UPLOAD_TYPE)
     70 {
     71     memset(&m_GLStateBeforeBlit, 0, sizeof(m_GLStateBeforeBlit));
     72 
     73     m_emptyItemCount = ST_BUFFER_NUMBER;
     74 
     75     m_transferQueue = new TileTransferData[ST_BUFFER_NUMBER];
     76 }
     77 
     78 TransferQueue::~TransferQueue()
     79 {
     80     glDeleteFramebuffers(1, &m_fboID);
     81     m_fboID = 0;
     82     glDeleteTextures(1, &m_sharedSurfaceTextureId);
     83     m_sharedSurfaceTextureId = 0;
     84 
     85     delete[] m_transferQueue;
     86 }
     87 
     88 void TransferQueue::initSharedSurfaceTextures(int width, int height)
     89 {
     90     if (!m_sharedSurfaceTextureId) {
     91         glGenTextures(1, &m_sharedSurfaceTextureId);
     92         m_sharedSurfaceTexture =
     93 #if GPU_UPLOAD_WITHOUT_DRAW
     94             new android::SurfaceTexture(m_sharedSurfaceTextureId, true, GL_TEXTURE_2D);
     95 #else
     96             new android::SurfaceTexture(m_sharedSurfaceTextureId);
     97 #endif
     98         m_ANW = new android::SurfaceTextureClient(m_sharedSurfaceTexture);
     99         m_sharedSurfaceTexture->setSynchronousMode(true);
    100         m_sharedSurfaceTexture->setBufferCount(ST_BUFFER_NUMBER+1);
    101 
    102         int result = native_window_set_buffers_geometry(m_ANW.get(),
    103                 width, height, HAL_PIXEL_FORMAT_RGBA_8888);
    104         GLUtils::checkSurfaceTextureError("native_window_set_buffers_geometry", result);
    105         result = native_window_set_usage(m_ANW.get(),
    106                 GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);
    107         GLUtils::checkSurfaceTextureError("native_window_set_usage", result);
    108     }
    109 
    110     if (!m_fboID)
    111         glGenFramebuffers(1, &m_fboID);
    112 }
    113 
    114 // When bliting, if the item from the transfer queue is mismatching b/t the
    115 // BaseTile and the content, then the item is considered as obsolete, and
    116 // the content is discarded.
    117 bool TransferQueue::checkObsolete(int index)
    118 {
    119     BaseTile* baseTilePtr = m_transferQueue[index].savedBaseTilePtr;
    120     if (!baseTilePtr) {
    121         XLOG("Invalid savedBaseTilePtr , such that the tile is obsolete");
    122         return true;
    123     }
    124 
    125     BaseTileTexture* baseTileTexture = baseTilePtr->backTexture();
    126     if (!baseTileTexture) {
    127         XLOG("Invalid baseTileTexture , such that the tile is obsolete");
    128         return true;
    129     }
    130 
    131     const TextureTileInfo* tileInfo = &m_transferQueue[index].tileInfo;
    132 
    133     if (tileInfo->m_x != baseTilePtr->x()
    134         || tileInfo->m_y != baseTilePtr->y()
    135         || tileInfo->m_scale != baseTilePtr->scale()
    136         || tileInfo->m_painter != baseTilePtr->painter()) {
    137         XLOG("Mismatching x, y, scale or painter , such that the tile is obsolete");
    138         return true;
    139     }
    140 
    141     return false;
    142 }
    143 
    144 void TransferQueue::blitTileFromQueue(GLuint fboID, BaseTileTexture* destTex,
    145                                       GLuint srcTexId, GLenum srcTexTarget,
    146                                       int index)
    147 {
    148 #if GPU_UPLOAD_WITHOUT_DRAW
    149     glBindFramebuffer(GL_FRAMEBUFFER, fboID);
    150     glFramebufferTexture2D(GL_FRAMEBUFFER,
    151                            GL_COLOR_ATTACHMENT0,
    152                            GL_TEXTURE_2D,
    153                            srcTexId,
    154                            0);
    155     glBindTexture(GL_TEXTURE_2D, destTex->m_ownTextureId);
    156     glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0,
    157                         destTex->getSize().width(),
    158                         destTex->getSize().height());
    159 #else
    160     // Then set up the FBO and copy the SurfTex content in.
    161     glBindFramebuffer(GL_FRAMEBUFFER, fboID);
    162     glFramebufferTexture2D(GL_FRAMEBUFFER,
    163                            GL_COLOR_ATTACHMENT0,
    164                            GL_TEXTURE_2D,
    165                            destTex->m_ownTextureId,
    166                            0);
    167     setGLStateForCopy(destTex->getSize().width(),
    168                       destTex->getSize().height());
    169     GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
    170     if (status != GL_FRAMEBUFFER_COMPLETE) {
    171         XLOG("Error: glCheckFramebufferStatus failed");
    172         glBindFramebuffer(GL_FRAMEBUFFER, 0);
    173         return;
    174     }
    175 
    176     // Use empty rect to set up the special matrix to draw.
    177     SkRect rect  = SkRect::MakeEmpty();
    178     TilesManager::instance()->shader()->drawQuad(rect, srcTexId, 1.0,
    179                        srcTexTarget, GL_NEAREST);
    180 
    181     // To workaround a sync issue on some platforms, we should insert the sync
    182     // here while in the current FBO.
    183     // This will essentially kick off the GPU command buffer, and the Tex Gen
    184     // thread will then have to wait for this buffer to finish before writing
    185     // into the same memory.
    186     EGLDisplay dpy = eglGetCurrentDisplay();
    187     if (m_currentDisplay != dpy)
    188         m_currentDisplay = dpy;
    189     if (m_currentDisplay != EGL_NO_DISPLAY) {
    190         if (m_transferQueue[index].m_syncKHR != EGL_NO_SYNC_KHR)
    191             eglDestroySyncKHR(m_currentDisplay, m_transferQueue[index].m_syncKHR);
    192         m_transferQueue[index].m_syncKHR = eglCreateSyncKHR(m_currentDisplay,
    193                                                             EGL_SYNC_FENCE_KHR,
    194                                                             0);
    195     }
    196     GLUtils::checkEglError("CreateSyncKHR");
    197 #endif
    198 }
    199 
    200 void TransferQueue::interruptTransferQueue(bool interrupt)
    201 {
    202     m_transferQueueItemLocks.lock();
    203     m_interruptedByRemovingOp = interrupt;
    204     if (m_interruptedByRemovingOp)
    205         m_transferQueueItemCond.signal();
    206     m_transferQueueItemLocks.unlock();
    207 }
    208 
    209 // This function must be called inside the m_transferQueueItemLocks, for the
    210 // wait, m_interruptedByRemovingOp and getHasGLContext().
    211 // Only called by updateQueueWithBitmap() for now.
    212 bool TransferQueue::readyForUpdate()
    213 {
    214     if (!getHasGLContext())
    215         return false;
    216     // Don't use a while loop since when the WebView tear down, the emptyCount
    217     // will still be 0, and we bailed out b/c of GL context lost.
    218     if (!m_emptyItemCount) {
    219         if (m_interruptedByRemovingOp)
    220             return false;
    221         m_transferQueueItemCond.wait(m_transferQueueItemLocks);
    222         if (m_interruptedByRemovingOp)
    223             return false;
    224     }
    225 
    226     if (!getHasGLContext())
    227         return false;
    228 
    229     // Disable this wait until we figure out why this didn't work on some
    230     // drivers b/5332112.
    231 #if 0
    232     if (m_currentUploadType == GpuUpload
    233         && m_currentDisplay != EGL_NO_DISPLAY) {
    234         // Check the GPU fence
    235         EGLSyncKHR syncKHR = m_transferQueue[getNextTransferQueueIndex()].m_syncKHR;
    236         if (syncKHR != EGL_NO_SYNC_KHR)
    237             eglClientWaitSyncKHR(m_currentDisplay,
    238                                  syncKHR,
    239                                  EGL_SYNC_FLUSH_COMMANDS_BIT_KHR,
    240                                  EGL_FOREVER_KHR);
    241     }
    242     GLUtils::checkEglError("WaitSyncKHR");
    243 #endif
    244 
    245     return true;
    246 }
    247 
    248 // Both getHasGLContext and setHasGLContext should be called within the lock.
    249 bool TransferQueue::getHasGLContext()
    250 {
    251     return m_hasGLContext;
    252 }
    253 
    254 void TransferQueue::setHasGLContext(bool hasContext)
    255 {
    256     m_hasGLContext = hasContext;
    257 }
    258 
    259 // Only called when WebView is destroyed or switching the uploadType.
    260 void TransferQueue::discardQueue()
    261 {
    262     android::Mutex::Autolock lock(m_transferQueueItemLocks);
    263 
    264     for (int i = 0 ; i < ST_BUFFER_NUMBER; i++)
    265         if (m_transferQueue[i].status == pendingBlit)
    266             m_transferQueue[i].status = pendingDiscard;
    267 
    268     bool GLContextExisted = getHasGLContext();
    269     // Unblock the Tex Gen thread first before Tile Page deletion.
    270     // Otherwise, there will be a deadlock while removing operations.
    271     setHasGLContext(false);
    272 
    273     // Only signal once when GL context lost.
    274     if (GLContextExisted)
    275         m_transferQueueItemCond.signal();
    276 }
    277 
    278 // Call on UI thread to copy from the shared Surface Texture to the BaseTile's texture.
    279 void TransferQueue::updateDirtyBaseTiles()
    280 {
    281     android::Mutex::Autolock lock(m_transferQueueItemLocks);
    282 
    283     cleanupTransportQueue();
    284     if (!getHasGLContext())
    285         setHasGLContext(true);
    286 
    287     // Start from the oldest item, we call the updateTexImage to retrive
    288     // the texture and blit that into each BaseTile's texture.
    289     const int nextItemIndex = getNextTransferQueueIndex();
    290     int index = nextItemIndex;
    291     bool usedFboForUpload = false;
    292     for (int k = 0; k < ST_BUFFER_NUMBER ; k++) {
    293         if (m_transferQueue[index].status == pendingBlit) {
    294             bool obsoleteBaseTile = checkObsolete(index);
    295             // Save the needed info, update the Surf Tex, clean up the item in
    296             // the queue. Then either move on to next item or copy the content.
    297             BaseTileTexture* destTexture = 0;
    298             if (!obsoleteBaseTile)
    299                 destTexture = m_transferQueue[index].savedBaseTilePtr->backTexture();
    300             if (m_transferQueue[index].uploadType == GpuUpload) {
    301                 status_t result = m_sharedSurfaceTexture->updateTexImage();
    302                 if (result != OK)
    303                     XLOGC("unexpected error: updateTexImage return %d", result);
    304             }
    305             m_transferQueue[index].savedBaseTilePtr = 0;
    306             m_transferQueue[index].status = emptyItem;
    307             if (obsoleteBaseTile) {
    308                 XLOG("Warning: the texture is obsolete for this baseTile");
    309                 index = (index + 1) % ST_BUFFER_NUMBER;
    310                 continue;
    311             }
    312 
    313             // guarantee that we have a texture to blit into
    314             destTexture->requireGLTexture();
    315 
    316             if (m_transferQueue[index].uploadType == CpuUpload) {
    317                 // Here we just need to upload the bitmap content to the GL Texture
    318                 GLUtils::updateTextureWithBitmap(destTexture->m_ownTextureId, 0, 0,
    319                                                  *m_transferQueue[index].bitmap);
    320             } else {
    321                 if (!usedFboForUpload) {
    322                     saveGLState();
    323                     usedFboForUpload = true;
    324                 }
    325                 blitTileFromQueue(m_fboID, destTexture,
    326                                   m_sharedSurfaceTextureId,
    327                                   m_sharedSurfaceTexture->getCurrentTextureTarget(),
    328                                   index);
    329             }
    330 
    331             // After the base tile copied into the GL texture, we need to
    332             // update the texture's info such that at draw time, readyFor
    333             // will find the latest texture's info
    334             // We don't need a map any more, each texture contains its own
    335             // texturesTileInfo.
    336             destTexture->setOwnTextureTileInfoFromQueue(&m_transferQueue[index].tileInfo);
    337 
    338             XLOG("Blit tile x, y %d %d with dest texture %p to destTexture->m_ownTextureId %d",
    339                  m_transferQueue[index].tileInfo.m_x,
    340                  m_transferQueue[index].tileInfo.m_y,
    341                  destTexture,
    342                  destTexture->m_ownTextureId);
    343         }
    344         index = (index + 1) % ST_BUFFER_NUMBER;
    345     }
    346 
    347     // Clean up FBO setup. Doing this for both CPU/GPU upload can make the
    348     // dynamic switch possible. Moving this out from the loop can save some
    349     // milli-seconds.
    350     if (usedFboForUpload) {
    351         glBindFramebuffer(GL_FRAMEBUFFER, 0); // rebind the standard FBO
    352         restoreGLState();
    353         GLUtils::checkGlError("updateDirtyBaseTiles");
    354     }
    355 
    356     m_emptyItemCount = ST_BUFFER_NUMBER;
    357     m_transferQueueItemCond.signal();
    358 }
    359 
    360 void TransferQueue::updateQueueWithBitmap(const TileRenderInfo* renderInfo,
    361                                           int x, int y, const SkBitmap& bitmap)
    362 {
    363     if (!tryUpdateQueueWithBitmap(renderInfo, x, y, bitmap)) {
    364         // failed placing bitmap in queue, discard tile's texture so it will be
    365         // re-enqueued (and repainted)
    366         BaseTile* tile = renderInfo->baseTile;
    367         if (tile)
    368             tile->backTextureTransferFail();
    369     }
    370 }
    371 
    372 bool TransferQueue::tryUpdateQueueWithBitmap(const TileRenderInfo* renderInfo,
    373                                           int x, int y, const SkBitmap& bitmap)
    374 {
    375     m_transferQueueItemLocks.lock();
    376     bool ready = readyForUpdate();
    377     TextureUploadType currentUploadType = m_currentUploadType;
    378     m_transferQueueItemLocks.unlock();
    379     if (!ready) {
    380         XLOG("Quit bitmap update: not ready! for tile x y %d %d",
    381              renderInfo->x, renderInfo->y);
    382         return false;
    383     }
    384     if (currentUploadType == GpuUpload) {
    385         // a) Dequeue the Surface Texture and write into the buffer
    386         if (!m_ANW.get()) {
    387             XLOG("ERROR: ANW is null");
    388             return false;
    389         }
    390 
    391         ANativeWindow_Buffer buffer;
    392         if (ANativeWindow_lock(m_ANW.get(), &buffer, 0))
    393             return false;
    394 
    395         uint8_t* img = (uint8_t*)buffer.bits;
    396         int row, col;
    397         int bpp = 4; // Now we only deal with RGBA8888 format.
    398         int width = TilesManager::instance()->tileWidth();
    399         int height = TilesManager::instance()->tileHeight();
    400         if (!x && !y && bitmap.width() == width && bitmap.height() == height) {
    401             bitmap.lockPixels();
    402             uint8_t* bitmapOrigin = static_cast<uint8_t*>(bitmap.getPixels());
    403             if (buffer.stride != bitmap.width())
    404                 // Copied line by line since we need to handle the offsets and stride.
    405                 for (row = 0 ; row < bitmap.height(); row ++) {
    406                     uint8_t* dst = &(img[buffer.stride * row * bpp]);
    407                     uint8_t* src = &(bitmapOrigin[bitmap.width() * row * bpp]);
    408                     memcpy(dst, src, bpp * bitmap.width());
    409                 }
    410             else
    411                 memcpy(img, bitmapOrigin, bpp * bitmap.width() * bitmap.height());
    412 
    413             bitmap.unlockPixels();
    414         } else {
    415             // TODO: implement the partial invalidate here!
    416             XLOG("ERROR: don't expect to get here yet before we support partial inval");
    417         }
    418 
    419         ANativeWindow_unlockAndPost(m_ANW.get());
    420     }
    421 
    422     m_transferQueueItemLocks.lock();
    423     // b) After update the Surface Texture, now udpate the transfer queue info.
    424     addItemInTransferQueue(renderInfo, currentUploadType, &bitmap);
    425 
    426     m_transferQueueItemLocks.unlock();
    427     XLOG("Bitmap updated x, y %d %d, baseTile %p",
    428          renderInfo->x, renderInfo->y, renderInfo->baseTile);
    429     return true;
    430 }
    431 
    432 // Note that there should be lock/unlock around this function call.
    433 // Currently only called by GLUtils::updateSharedSurfaceTextureWithBitmap.
    434 void TransferQueue::addItemInTransferQueue(const TileRenderInfo* renderInfo,
    435                                            TextureUploadType type,
    436                                            const SkBitmap* bitmap)
    437 {
    438     m_transferQueueIndex = (m_transferQueueIndex + 1) % ST_BUFFER_NUMBER;
    439 
    440     int index = m_transferQueueIndex;
    441     if (m_transferQueue[index].savedBaseTilePtr
    442         || m_transferQueue[index].status != emptyItem) {
    443         XLOG("ERROR update a tile which is dirty already @ index %d", index);
    444     }
    445 
    446     m_transferQueue[index].savedBaseTileTexturePtr = renderInfo->baseTile->backTexture();
    447     m_transferQueue[index].savedBaseTilePtr = renderInfo->baseTile;
    448     m_transferQueue[index].status = pendingBlit;
    449     m_transferQueue[index].uploadType = type;
    450     if (type == CpuUpload && bitmap) {
    451         // Lazily create the bitmap
    452         if (!m_transferQueue[index].bitmap) {
    453             m_transferQueue[index].bitmap = new SkBitmap();
    454             int w = bitmap->width();
    455             int h = bitmap->height();
    456             m_transferQueue[index].bitmap->setConfig(bitmap->config(), w, h);
    457         }
    458         bitmap->copyTo(m_transferQueue[index].bitmap, bitmap->config());
    459     }
    460 
    461     // Now fill the tileInfo.
    462     TextureTileInfo* textureInfo = &m_transferQueue[index].tileInfo;
    463 
    464     textureInfo->m_x = renderInfo->x;
    465     textureInfo->m_y = renderInfo->y;
    466     textureInfo->m_scale = renderInfo->scale;
    467     textureInfo->m_painter = renderInfo->tilePainter;
    468 
    469     textureInfo->m_picture = renderInfo->textureInfo->m_pictureCount;
    470 
    471     m_emptyItemCount--;
    472 }
    473 
    474 void TransferQueue::setTextureUploadType(TextureUploadType type)
    475 {
    476     if (m_currentUploadType == type)
    477         return;
    478 
    479     discardQueue();
    480 
    481     android::Mutex::Autolock lock(m_transferQueueItemLocks);
    482     m_currentUploadType = type;
    483     XLOGC("Now we set the upload to %s", m_currentUploadType == GpuUpload ? "GpuUpload" : "CpuUpload");
    484 }
    485 
    486 // Note: this need to be called within th lock.
    487 // Only called by updateDirtyBaseTiles() for now
    488 void TransferQueue::cleanupTransportQueue()
    489 {
    490     int index = getNextTransferQueueIndex();
    491 
    492     for (int i = 0 ; i < ST_BUFFER_NUMBER; i++) {
    493         if (m_transferQueue[index].status == pendingDiscard) {
    494             // No matter what the current upload type is, as long as there has
    495             // been a Surf Tex enqueue operation, this updateTexImage need to
    496             // be called to keep things in sync.
    497             if (m_transferQueue[index].uploadType == GpuUpload) {
    498                 status_t result = m_sharedSurfaceTexture->updateTexImage();
    499                 if (result != OK)
    500                     XLOGC("unexpected error: updateTexImage return %d", result);
    501             }
    502 
    503             // since tiles in the queue may be from another webview, remove
    504             // their textures so that they will be repainted / retransferred
    505             BaseTile* tile = m_transferQueue[index].savedBaseTilePtr;
    506             BaseTileTexture* texture = m_transferQueue[index].savedBaseTileTexturePtr;
    507             if (tile && texture && texture->owner() == tile) {
    508                 // since tile destruction removes textures on the UI thread, the
    509                 // texture->owner ptr guarantees the tile is valid
    510                 tile->discardBackTexture();
    511                 XLOG("transfer queue discarded tile %p, removed texture", tile);
    512             }
    513 
    514             m_transferQueue[index].savedBaseTilePtr = 0;
    515             m_transferQueue[index].savedBaseTileTexturePtr = 0;
    516             m_transferQueue[index].status = emptyItem;
    517         }
    518         index = (index + 1) % ST_BUFFER_NUMBER;
    519     }
    520 }
    521 
    522 void TransferQueue::saveGLState()
    523 {
    524     glGetIntegerv(GL_VIEWPORT, m_GLStateBeforeBlit.viewport);
    525     glGetBooleanv(GL_SCISSOR_TEST, m_GLStateBeforeBlit.scissor);
    526     glGetBooleanv(GL_DEPTH_TEST, m_GLStateBeforeBlit.depth);
    527 #if DEBUG
    528     glGetFloatv(GL_COLOR_CLEAR_VALUE, m_GLStateBeforeBlit.clearColor);
    529 #endif
    530 }
    531 
    532 void TransferQueue::setGLStateForCopy(int width, int height)
    533 {
    534     // Need to match the texture size.
    535     glViewport(0, 0, width, height);
    536     glDisable(GL_SCISSOR_TEST);
    537     glDisable(GL_DEPTH_TEST);
    538     // Clear the content is only for debug purpose.
    539 #if DEBUG
    540     glClearColor(0, 0, 0, 0);
    541     glClear(GL_COLOR_BUFFER_BIT);
    542 #endif
    543 }
    544 
    545 void TransferQueue::restoreGLState()
    546 {
    547     glViewport(m_GLStateBeforeBlit.viewport[0],
    548                m_GLStateBeforeBlit.viewport[1],
    549                m_GLStateBeforeBlit.viewport[2],
    550                m_GLStateBeforeBlit.viewport[3]);
    551 
    552     if (m_GLStateBeforeBlit.scissor[0])
    553         glEnable(GL_SCISSOR_TEST);
    554 
    555     if (m_GLStateBeforeBlit.depth[0])
    556         glEnable(GL_DEPTH_TEST);
    557 #if DEBUG
    558     glClearColor(m_GLStateBeforeBlit.clearColor[0],
    559                  m_GLStateBeforeBlit.clearColor[1],
    560                  m_GLStateBeforeBlit.clearColor[2],
    561                  m_GLStateBeforeBlit.clearColor[3]);
    562 #endif
    563 }
    564 
    565 int TransferQueue::getNextTransferQueueIndex()
    566 {
    567     return (m_transferQueueIndex + 1) % ST_BUFFER_NUMBER;
    568 }
    569 
    570 } // namespace WebCore
    571 
    572 #endif // USE(ACCELERATED_COMPOSITING
    573