• 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 #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 
TransferQueue(bool useMinimalMem)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 
~TransferQueue()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.
resetQueue()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.
cleanupGLResources()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 
initGLResources(int width,int height)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.
checkObsolete(const TileTransferData * data)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 
blitTileFromQueue(GLuint fboID,TileTexture * destTex,GLuint srcTexId,GLenum srcTexTarget,int index)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.
readyForUpdate()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.
getHasGLContext()227 bool TransferQueue::getHasGLContext()
228 {
229     return m_hasGLContext;
230 }
231 
setHasGLContext(bool hasContext)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()
emptyAndAbandonQueue()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 
cleanupGLResourcesAndQueue()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.
setPendingDiscard()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 
clearPureColorQueue()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 
updatePureColorTiles()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.
updateDirtyTiles()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 
updateQueueWithBitmap(const TileRenderInfo * renderInfo,SkBitmap & bitmap)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 
tryUpdateQueueWithBitmap(const TileRenderInfo * renderInfo,SkBitmap & bitmap)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 
addItemInPureColorQueue(const TileRenderInfo * renderInfo)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 
clearItemInTranferQueue(int index)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.
addItemCommon(const TileRenderInfo * renderInfo,TextureUploadType type,TileTransferData * data)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.
addItemInTransferQueue(const TileRenderInfo * renderInfo,TextureUploadType type,SkBitmap & bitmap)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 
setTextureUploadType(TextureUploadType type)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
cleanupPendingDiscard()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 
saveGLState()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 
setGLStateForCopy(int width,int height)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 
restoreGLState()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 
getNextTransferQueueIndex()597 int TransferQueue::getNextTransferQueueIndex()
598 {
599     return (m_transferQueueIndex + 1) % m_transferQueueSize;
600 }
601 
602 } // namespace WebCore
603 
604 #endif // USE(ACCELERATED_COMPOSITING
605