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 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::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. 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 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. 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. 227 bool TransferQueue::getHasGLContext() 228 { 229 return m_hasGLContext; 230 } 231 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() 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 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. 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 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 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. 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 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 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 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 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. 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. 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 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 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 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 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 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 597 int TransferQueue::getNextTransferQueueIndex() 598 { 599 return (m_transferQueueIndex + 1) % m_transferQueueSize; 600 } 601 602 } // namespace WebCore 603 604 #endif // USE(ACCELERATED_COMPOSITING 605