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