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 54namespace WebCore { 55 56TransferQueue::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 71TransferQueue::~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. 80void 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. 89void 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 101void 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. 143bool 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 161void 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. 215bool 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. 231bool TransferQueue::getHasGLContext() 232{ 233 return m_hasGLContext; 234} 235 236void TransferQueue::setHasGLContext(bool hasContext) 237{ 238 m_hasGLContext = hasContext; 239} 240 241// Call within a m_transferQueueItemLocks, now called by resetQueue() and 242// cleanupGLResoucesAndQueue() 243void 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 258void 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. 270void 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 288void 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 297void 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. 318void 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 396void 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 409bool 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 443void 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 454void 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. 464void 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. 480void 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 511void 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 525void 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 556void 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 567void 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 580void 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 601int TransferQueue::getNextTransferQueueIndex() 602{ 603 return (m_transferQueueIndex + 1) % m_transferQueueSize; 604} 605 606} // namespace WebCore 607 608#endif // USE(ACCELERATED_COMPOSITING 609