• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 4
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 
TransferQueue()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 
~TransferQueue()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 
initSharedSurfaceTextures(int width,int height)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.
checkObsolete(int index)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 
blitTileFromQueue(GLuint fboID,BaseTileTexture * destTex,GLuint srcTexId,GLenum srcTexTarget,int index)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 
interruptTransferQueue(bool interrupt)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.
readyForUpdate()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.
getHasGLContext()249 bool TransferQueue::getHasGLContext()
250 {
251     return m_hasGLContext;
252 }
253 
setHasGLContext(bool hasContext)254 void TransferQueue::setHasGLContext(bool hasContext)
255 {
256     m_hasGLContext = hasContext;
257 }
258 
259 // Only called when WebView is destroyed or switching the uploadType.
discardQueue()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.
updateDirtyBaseTiles()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                 m_sharedSurfaceTexture->updateTexImage();
302             m_transferQueue[index].savedBaseTilePtr = 0;
303             m_transferQueue[index].status = emptyItem;
304             if (obsoleteBaseTile) {
305                 XLOG("Warning: the texture is obsolete for this baseTile");
306                 index = (index + 1) % ST_BUFFER_NUMBER;
307                 continue;
308             }
309 
310             // guarantee that we have a texture to blit into
311             destTexture->requireGLTexture();
312 
313             if (m_transferQueue[index].uploadType == CpuUpload) {
314                 // Here we just need to upload the bitmap content to the GL Texture
315                 GLUtils::updateTextureWithBitmap(destTexture->m_ownTextureId, 0, 0,
316                                                  *m_transferQueue[index].bitmap);
317             } else {
318                 if (!usedFboForUpload) {
319                     saveGLState();
320                     usedFboForUpload = true;
321                 }
322                 blitTileFromQueue(m_fboID, destTexture,
323                                   m_sharedSurfaceTextureId,
324                                   m_sharedSurfaceTexture->getCurrentTextureTarget(),
325                                   index);
326             }
327 
328             // After the base tile copied into the GL texture, we need to
329             // update the texture's info such that at draw time, readyFor
330             // will find the latest texture's info
331             // We don't need a map any more, each texture contains its own
332             // texturesTileInfo.
333             destTexture->setOwnTextureTileInfoFromQueue(&m_transferQueue[index].tileInfo);
334 
335             XLOG("Blit tile x, y %d %d with dest texture %p to destTexture->m_ownTextureId %d",
336                  m_transferQueue[index].tileInfo.m_x,
337                  m_transferQueue[index].tileInfo.m_y,
338                  destTexture,
339                  destTexture->m_ownTextureId);
340         }
341         index = (index + 1) % ST_BUFFER_NUMBER;
342     }
343 
344     // Clean up FBO setup. Doing this for both CPU/GPU upload can make the
345     // dynamic switch possible. Moving this out from the loop can save some
346     // milli-seconds.
347     if (usedFboForUpload) {
348         glBindFramebuffer(GL_FRAMEBUFFER, 0); // rebind the standard FBO
349         restoreGLState();
350         GLUtils::checkGlError("updateDirtyBaseTiles");
351     }
352 
353     m_emptyItemCount = ST_BUFFER_NUMBER;
354     m_transferQueueItemCond.signal();
355 }
356 
updateQueueWithBitmap(const TileRenderInfo * renderInfo,int x,int y,const SkBitmap & bitmap)357 void TransferQueue::updateQueueWithBitmap(const TileRenderInfo* renderInfo,
358                                           int x, int y, const SkBitmap& bitmap)
359 {
360     if (!tryUpdateQueueWithBitmap(renderInfo, x, y, bitmap)) {
361         // failed placing bitmap in queue, discard tile's texture so it will be
362         // re-enqueued (and repainted)
363         BaseTile* tile = renderInfo->baseTile;
364         if (tile)
365             tile->backTextureTransferFail();
366     }
367 }
368 
tryUpdateQueueWithBitmap(const TileRenderInfo * renderInfo,int x,int y,const SkBitmap & bitmap)369 bool TransferQueue::tryUpdateQueueWithBitmap(const TileRenderInfo* renderInfo,
370                                           int x, int y, const SkBitmap& bitmap)
371 {
372     m_transferQueueItemLocks.lock();
373     bool ready = readyForUpdate();
374     TextureUploadType currentUploadType = m_currentUploadType;
375     m_transferQueueItemLocks.unlock();
376     if (!ready) {
377         XLOG("Quit bitmap update: not ready! for tile x y %d %d",
378              renderInfo->x, renderInfo->y);
379         return false;
380     }
381     if (currentUploadType == GpuUpload) {
382         // a) Dequeue the Surface Texture and write into the buffer
383         if (!m_ANW.get()) {
384             XLOG("ERROR: ANW is null");
385             return false;
386         }
387 
388         ANativeWindow_Buffer buffer;
389         if (ANativeWindow_lock(m_ANW.get(), &buffer, 0))
390             return false;
391 
392         uint8_t* img = (uint8_t*)buffer.bits;
393         int row, col;
394         int bpp = 4; // Now we only deal with RGBA8888 format.
395         int width = TilesManager::instance()->tileWidth();
396         int height = TilesManager::instance()->tileHeight();
397         if (!x && !y && bitmap.width() == width && bitmap.height() == height) {
398             bitmap.lockPixels();
399             uint8_t* bitmapOrigin = static_cast<uint8_t*>(bitmap.getPixels());
400             if (buffer.stride != bitmap.width())
401                 // Copied line by line since we need to handle the offsets and stride.
402                 for (row = 0 ; row < bitmap.height(); row ++) {
403                     uint8_t* dst = &(img[buffer.stride * row * bpp]);
404                     uint8_t* src = &(bitmapOrigin[bitmap.width() * row * bpp]);
405                     memcpy(dst, src, bpp * bitmap.width());
406                 }
407             else
408                 memcpy(img, bitmapOrigin, bpp * bitmap.width() * bitmap.height());
409 
410             bitmap.unlockPixels();
411         } else {
412             // TODO: implement the partial invalidate here!
413             XLOG("ERROR: don't expect to get here yet before we support partial inval");
414         }
415 
416         ANativeWindow_unlockAndPost(m_ANW.get());
417     }
418 
419     m_transferQueueItemLocks.lock();
420     // b) After update the Surface Texture, now udpate the transfer queue info.
421     addItemInTransferQueue(renderInfo, currentUploadType, &bitmap);
422 
423     m_transferQueueItemLocks.unlock();
424     XLOG("Bitmap updated x, y %d %d, baseTile %p",
425          renderInfo->x, renderInfo->y, renderInfo->baseTile);
426     return true;
427 }
428 
429 // Note that there should be lock/unlock around this function call.
430 // Currently only called by GLUtils::updateSharedSurfaceTextureWithBitmap.
addItemInTransferQueue(const TileRenderInfo * renderInfo,TextureUploadType type,const SkBitmap * bitmap)431 void TransferQueue::addItemInTransferQueue(const TileRenderInfo* renderInfo,
432                                            TextureUploadType type,
433                                            const SkBitmap* bitmap)
434 {
435     m_transferQueueIndex = (m_transferQueueIndex + 1) % ST_BUFFER_NUMBER;
436 
437     int index = m_transferQueueIndex;
438     if (m_transferQueue[index].savedBaseTilePtr
439         || m_transferQueue[index].status != emptyItem) {
440         XLOG("ERROR update a tile which is dirty already @ index %d", index);
441     }
442 
443     m_transferQueue[index].savedBaseTileTexturePtr = renderInfo->baseTile->backTexture();
444     m_transferQueue[index].savedBaseTilePtr = renderInfo->baseTile;
445     m_transferQueue[index].status = pendingBlit;
446     m_transferQueue[index].uploadType = type;
447     if (type == CpuUpload && bitmap) {
448         // Lazily create the bitmap
449         if (!m_transferQueue[index].bitmap) {
450             m_transferQueue[index].bitmap = new SkBitmap();
451             int w = bitmap->width();
452             int h = bitmap->height();
453             m_transferQueue[index].bitmap->setConfig(bitmap->config(), w, h);
454         }
455         bitmap->copyTo(m_transferQueue[index].bitmap, bitmap->config());
456     }
457 
458     // Now fill the tileInfo.
459     TextureTileInfo* textureInfo = &m_transferQueue[index].tileInfo;
460 
461     textureInfo->m_x = renderInfo->x;
462     textureInfo->m_y = renderInfo->y;
463     textureInfo->m_scale = renderInfo->scale;
464     textureInfo->m_painter = renderInfo->tilePainter;
465 
466     textureInfo->m_picture = renderInfo->textureInfo->m_pictureCount;
467 
468     m_emptyItemCount--;
469 }
470 
setTextureUploadType(TextureUploadType type)471 void TransferQueue::setTextureUploadType(TextureUploadType type)
472 {
473     discardQueue();
474 
475     android::Mutex::Autolock lock(m_transferQueueItemLocks);
476     m_currentUploadType = type;
477     XLOGC("Now we set the upload to %s", m_currentUploadType == GpuUpload ? "GpuUpload" : "CpuUpload");
478 }
479 
480 // Note: this need to be called within th lock.
481 // Only called by updateDirtyBaseTiles() for now
cleanupTransportQueue()482 void TransferQueue::cleanupTransportQueue()
483 {
484     int index = getNextTransferQueueIndex();
485 
486     for (int i = 0 ; i < ST_BUFFER_NUMBER; i++) {
487         if (m_transferQueue[index].status == pendingDiscard) {
488             // No matter what the current upload type is, as long as there has
489             // been a Surf Tex enqueue operation, this updateTexImage need to
490             // be called to keep things in sync.
491             if (m_transferQueue[index].uploadType == GpuUpload)
492                 m_sharedSurfaceTexture->updateTexImage();
493 
494             // since tiles in the queue may be from another webview, remove
495             // their textures so that they will be repainted / retransferred
496             BaseTile* tile = m_transferQueue[index].savedBaseTilePtr;
497             BaseTileTexture* texture = m_transferQueue[index].savedBaseTileTexturePtr;
498             if (tile && texture && texture->owner() == tile) {
499                 // since tile destruction removes textures on the UI thread, the
500                 // texture->owner ptr guarantees the tile is valid
501                 tile->discardBackTexture();
502                 XLOG("transfer queue discarded tile %p, removed texture", tile);
503             }
504 
505             m_transferQueue[index].savedBaseTilePtr = 0;
506             m_transferQueue[index].savedBaseTileTexturePtr = 0;
507             m_transferQueue[index].status = emptyItem;
508         }
509         index = (index + 1) % ST_BUFFER_NUMBER;
510     }
511 }
512 
saveGLState()513 void TransferQueue::saveGLState()
514 {
515     glGetIntegerv(GL_VIEWPORT, m_GLStateBeforeBlit.viewport);
516     glGetBooleanv(GL_SCISSOR_TEST, m_GLStateBeforeBlit.scissor);
517     glGetBooleanv(GL_DEPTH_TEST, m_GLStateBeforeBlit.depth);
518 #if DEBUG
519     glGetFloatv(GL_COLOR_CLEAR_VALUE, m_GLStateBeforeBlit.clearColor);
520 #endif
521 }
522 
setGLStateForCopy(int width,int height)523 void TransferQueue::setGLStateForCopy(int width, int height)
524 {
525     // Need to match the texture size.
526     glViewport(0, 0, width, height);
527     glDisable(GL_SCISSOR_TEST);
528     glDisable(GL_DEPTH_TEST);
529     // Clear the content is only for debug purpose.
530 #if DEBUG
531     glClearColor(0, 0, 0, 0);
532     glClear(GL_COLOR_BUFFER_BIT);
533 #endif
534 }
535 
restoreGLState()536 void TransferQueue::restoreGLState()
537 {
538     glViewport(m_GLStateBeforeBlit.viewport[0],
539                m_GLStateBeforeBlit.viewport[1],
540                m_GLStateBeforeBlit.viewport[2],
541                m_GLStateBeforeBlit.viewport[3]);
542 
543     if (m_GLStateBeforeBlit.scissor[0])
544         glEnable(GL_SCISSOR_TEST);
545 
546     if (m_GLStateBeforeBlit.depth[0])
547         glEnable(GL_DEPTH_TEST);
548 #if DEBUG
549     glClearColor(m_GLStateBeforeBlit.clearColor[0],
550                  m_GLStateBeforeBlit.clearColor[1],
551                  m_GLStateBeforeBlit.clearColor[2],
552                  m_GLStateBeforeBlit.clearColor[3]);
553 #endif
554 }
555 
getNextTransferQueueIndex()556 int TransferQueue::getNextTransferQueueIndex()
557 {
558     return (m_transferQueueIndex + 1) % ST_BUFFER_NUMBER;
559 }
560 
561 } // namespace WebCore
562 
563 #endif // USE(ACCELERATED_COMPOSITING
564