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