1/* 2 * Copyright (C) 2012 Google Inc. All rights reserved. 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 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 18 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 21 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#include "config.h" 27 28#include "platform/graphics/Canvas2DLayerBridge.h" 29 30#include "GrContext.h" 31#include "SkDevice.h" 32#include "SkSurface.h" 33#include "platform/TraceEvent.h" 34#include "platform/graphics/Canvas2DLayerManager.h" 35#include "platform/graphics/GraphicsLayer.h" 36#include "public/platform/Platform.h" 37#include "public/platform/WebCompositorSupport.h" 38#include "public/platform/WebGraphicsContext3D.h" 39#include "public/platform/WebGraphicsContext3DProvider.h" 40#include "wtf/RefCountedLeakCounter.h" 41 42namespace { 43enum { 44 InvalidMailboxIndex = -1, 45}; 46 47DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, canvas2DLayerBridgeInstanceCounter, ("Canvas2DLayerBridge")); 48} 49 50namespace blink { 51 52static PassRefPtr<SkSurface> createSkSurface(GrContext* gr, const IntSize& size, int msaaSampleCount = 0) 53{ 54 if (!gr) 55 return nullptr; 56 gr->resetContext(); 57 SkImageInfo info = SkImageInfo::MakeN32Premul(size.width(), size.height()); 58 return adoptRef(SkSurface::NewRenderTarget(gr, info, msaaSampleCount)); 59} 60 61PassRefPtr<Canvas2DLayerBridge> Canvas2DLayerBridge::create(const IntSize& size, OpacityMode opacityMode, int msaaSampleCount) 62{ 63 TRACE_EVENT_INSTANT0("test_gpu", "Canvas2DLayerBridgeCreation"); 64 OwnPtr<WebGraphicsContext3DProvider> contextProvider = adoptPtr(Platform::current()->createSharedOffscreenGraphicsContext3DProvider()); 65 if (!contextProvider) 66 return nullptr; 67 RefPtr<SkSurface> surface(createSkSurface(contextProvider->grContext(), size, msaaSampleCount)); 68 if (!surface) 69 return nullptr; 70 RefPtr<Canvas2DLayerBridge> layerBridge; 71 OwnPtr<SkDeferredCanvas> canvas = adoptPtr(SkDeferredCanvas::Create(surface.get())); 72 layerBridge = adoptRef(new Canvas2DLayerBridge(contextProvider.release(), canvas.release(), surface.release(), msaaSampleCount, opacityMode)); 73 return layerBridge.release(); 74} 75 76Canvas2DLayerBridge::Canvas2DLayerBridge(PassOwnPtr<WebGraphicsContext3DProvider> contextProvider, PassOwnPtr<SkDeferredCanvas> canvas, PassRefPtr<SkSurface> surface, int msaaSampleCount, OpacityMode opacityMode) 77 : m_canvas(canvas) 78 , m_surface(surface) 79 , m_contextProvider(contextProvider) 80 , m_imageBuffer(0) 81 , m_msaaSampleCount(msaaSampleCount) 82 , m_bytesAllocated(0) 83 , m_didRecordDrawCommand(false) 84 , m_isSurfaceValid(true) 85 , m_framesPending(0) 86 , m_framesSinceMailboxRelease(0) 87 , m_destructionInProgress(false) 88 , m_rateLimitingEnabled(false) 89 , m_isHidden(false) 90 , m_next(0) 91 , m_prev(0) 92 , m_lastImageId(0) 93 , m_releasedMailboxInfoIndex(InvalidMailboxIndex) 94{ 95 ASSERT(m_canvas); 96 ASSERT(m_surface); 97 ASSERT(m_contextProvider); 98 // Used by browser tests to detect the use of a Canvas2DLayerBridge. 99 TRACE_EVENT_INSTANT0("test_gpu", "Canvas2DLayerBridgeCreation"); 100 m_layer = adoptPtr(Platform::current()->compositorSupport()->createExternalTextureLayer(this)); 101 m_layer->setOpaque(opacityMode == Opaque); 102 m_layer->setBlendBackgroundColor(opacityMode != Opaque); 103 GraphicsLayer::registerContentsLayer(m_layer->layer()); 104 m_layer->setRateLimitContext(m_rateLimitingEnabled); 105 m_canvas->setNotificationClient(this); 106#ifndef NDEBUG 107 canvas2DLayerBridgeInstanceCounter.increment(); 108#endif 109} 110 111Canvas2DLayerBridge::~Canvas2DLayerBridge() 112{ 113 ASSERT(m_destructionInProgress); 114 ASSERT(!Canvas2DLayerManager::get().isInList(this)); 115 m_layer.clear(); 116 freeReleasedMailbox(); 117#if ENABLE(ASSERT) 118 Vector<MailboxInfo>::iterator mailboxInfo; 119 for (mailboxInfo = m_mailboxes.begin(); mailboxInfo < m_mailboxes.end(); ++mailboxInfo) { 120 ASSERT(mailboxInfo->m_status != MailboxInUse); 121 ASSERT(mailboxInfo->m_status != MailboxReleased || m_contextProvider->context3d()->isContextLost() || !m_isSurfaceValid); 122 } 123#endif 124 m_mailboxes.clear(); 125#ifndef NDEBUG 126 canvas2DLayerBridgeInstanceCounter.decrement(); 127#endif 128} 129 130void Canvas2DLayerBridge::beginDestruction() 131{ 132 ASSERT(!m_destructionInProgress); 133 setRateLimitingEnabled(false); 134 m_canvas->silentFlush(); 135 m_imageBuffer = 0; 136 freeTransientResources(); 137 setIsHidden(true); 138 m_destructionInProgress = true; 139 GraphicsLayer::unregisterContentsLayer(m_layer->layer()); 140 m_canvas->setNotificationClient(0); 141 m_surface.clear(); 142 m_canvas.clear(); 143 m_layer->clearTexture(); 144 // Orphaning the layer is required to trigger the recration of a new layer 145 // in the case where destruction is caused by a canvas resize. Test: 146 // virtual/gpu/fast/canvas/canvas-resize-after-paint-without-layout.html 147 m_layer->layer()->removeFromParent(); 148 // To anyone who ever hits this assert: Please update crbug.com/344666 149 // with repro steps. 150 ASSERT(!m_bytesAllocated); 151} 152 153void Canvas2DLayerBridge::setIsHidden(bool hidden) 154{ 155 ASSERT(!m_destructionInProgress); 156 bool newHiddenValue = hidden || m_destructionInProgress; 157 if (m_isHidden == newHiddenValue) 158 return; 159 160 m_isHidden = newHiddenValue; 161 if (isHidden()) { 162 freeTransientResources(); 163 } 164} 165 166void Canvas2DLayerBridge::willAccessPixels() 167{ 168 // A readback operation may alter the texture parameters, which may affect 169 // the compositor's behavior. Therefore, we must trigger copy-on-write 170 // even though we are not technically writing to the texture, only to its 171 // parameters. 172 m_surface->notifyContentWillChange(SkSurface::kRetain_ContentChangeMode); 173} 174 175void Canvas2DLayerBridge::freeTransientResources() 176{ 177 ASSERT(!m_destructionInProgress); 178 if (!m_isSurfaceValid) 179 return; 180 freeReleasedMailbox(); 181 flush(); 182 freeMemoryIfPossible(bytesAllocated()); 183 ASSERT(!hasTransientResources()); 184} 185 186bool Canvas2DLayerBridge::hasTransientResources() const 187{ 188 return !m_destructionInProgress && (hasReleasedMailbox() || bytesAllocated()); 189} 190 191void Canvas2DLayerBridge::limitPendingFrames() 192{ 193 ASSERT(!m_destructionInProgress); 194 if (isHidden()) { 195 freeTransientResources(); 196 return; 197 } 198 if (m_didRecordDrawCommand) { 199 m_framesPending++; 200 m_didRecordDrawCommand = false; 201 if (m_framesPending > 1) { 202 // Turn on the rate limiter if this layer tends to accumulate a 203 // non-discardable multi-frame backlog of draw commands. 204 setRateLimitingEnabled(true); 205 } 206 if (m_rateLimitingEnabled) { 207 flush(); 208 } 209 } 210 ++m_framesSinceMailboxRelease; 211 if (releasedMailboxHasExpired()) { 212 freeReleasedMailbox(); 213 } 214} 215 216void Canvas2DLayerBridge::prepareForDraw() 217{ 218 ASSERT(!m_destructionInProgress); 219 ASSERT(m_layer); 220 if (!checkSurfaceValid()) { 221 if (m_canvas) { 222 // drop pending commands because there is no surface to draw to 223 m_canvas->silentFlush(); 224 } 225 return; 226 } 227} 228 229void Canvas2DLayerBridge::storageAllocatedForRecordingChanged(size_t bytesAllocated) 230{ 231 ASSERT(!m_destructionInProgress); 232 intptr_t delta = (intptr_t)bytesAllocated - (intptr_t)m_bytesAllocated; 233 m_bytesAllocated = bytesAllocated; 234 Canvas2DLayerManager::get().layerTransientResourceAllocationChanged(this, delta); 235} 236 237size_t Canvas2DLayerBridge::storageAllocatedForRecording() 238{ 239 return m_canvas->storageAllocatedForRecording(); 240} 241 242void Canvas2DLayerBridge::flushedDrawCommands() 243{ 244 ASSERT(!m_destructionInProgress); 245 storageAllocatedForRecordingChanged(storageAllocatedForRecording()); 246 m_framesPending = 0; 247} 248 249void Canvas2DLayerBridge::skippedPendingDrawCommands() 250{ 251 ASSERT(!m_destructionInProgress); 252 // Stop triggering the rate limiter if SkDeferredCanvas is detecting 253 // and optimizing overdraw. 254 setRateLimitingEnabled(false); 255 flushedDrawCommands(); 256} 257 258void Canvas2DLayerBridge::setRateLimitingEnabled(bool enabled) 259{ 260 ASSERT(!m_destructionInProgress); 261 if (m_rateLimitingEnabled != enabled) { 262 m_rateLimitingEnabled = enabled; 263 m_layer->setRateLimitContext(m_rateLimitingEnabled); 264 } 265} 266 267size_t Canvas2DLayerBridge::freeMemoryIfPossible(size_t bytesToFree) 268{ 269 ASSERT(!m_destructionInProgress); 270 size_t bytesFreed = m_canvas->freeMemoryIfPossible(bytesToFree); 271 m_bytesAllocated -= bytesFreed; 272 if (bytesFreed) 273 Canvas2DLayerManager::get().layerTransientResourceAllocationChanged(this, -((intptr_t)bytesFreed)); 274 return bytesFreed; 275} 276 277void Canvas2DLayerBridge::flush() 278{ 279 ASSERT(!m_destructionInProgress); 280 if (m_canvas->hasPendingCommands()) { 281 TRACE_EVENT0("cc", "Canvas2DLayerBridge::flush"); 282 freeReleasedMailbox(); // To avoid unnecessary triple-buffering 283 m_canvas->flush(); 284 } 285} 286 287bool Canvas2DLayerBridge::releasedMailboxHasExpired() 288{ 289 // This heuristic indicates that the canvas is not being 290 // actively presented by the compositor (3 frames rendered since 291 // last mailbox release), suggesting that double buffering is not required. 292 return hasReleasedMailbox() && m_framesSinceMailboxRelease > 2; 293} 294 295Canvas2DLayerBridge::MailboxInfo* Canvas2DLayerBridge::releasedMailboxInfo() 296{ 297 return hasReleasedMailbox() ? &m_mailboxes[m_releasedMailboxInfoIndex] : 0; 298} 299 300bool Canvas2DLayerBridge::hasReleasedMailbox() const 301{ 302 return m_releasedMailboxInfoIndex != InvalidMailboxIndex; 303} 304 305void Canvas2DLayerBridge::freeReleasedMailbox() 306{ 307 if (!m_isSurfaceValid || m_contextProvider->context3d()->isContextLost()) 308 return; 309 MailboxInfo* mailboxInfo = releasedMailboxInfo(); 310 if (!mailboxInfo) 311 return; 312 313 ASSERT(mailboxInfo->m_status == MailboxReleased); 314 if (mailboxInfo->m_mailbox.syncPoint) { 315 context()->waitSyncPoint(mailboxInfo->m_mailbox.syncPoint); 316 mailboxInfo->m_mailbox.syncPoint = 0; 317 } 318 // Invalidate texture state in case the compositor altered it since the copy-on-write. 319 if (mailboxInfo->m_image) { 320 if (isHidden() || releasedMailboxHasExpired()) 321 mailboxInfo->m_image->getTexture()->resetFlag(static_cast<GrTextureFlags>(GrTexture::kReturnToCache_FlagBit)); 322 mailboxInfo->m_image->getTexture()->textureParamsModified(); 323 mailboxInfo->m_image.clear(); 324 } 325 mailboxInfo->m_status = MailboxAvailable; 326 m_releasedMailboxInfoIndex = InvalidMailboxIndex; 327 Canvas2DLayerManager::get().layerTransientResourceAllocationChanged(this); 328} 329 330WebGraphicsContext3D* Canvas2DLayerBridge::context() 331{ 332 // Check on m_layer is necessary because context() may be called during 333 // the destruction of m_layer 334 if (m_layer && !m_destructionInProgress) 335 checkSurfaceValid(); // To ensure rate limiter is disabled if context is lost. 336 return m_contextProvider ? m_contextProvider->context3d() : 0; 337} 338 339bool Canvas2DLayerBridge::checkSurfaceValid() 340{ 341 ASSERT(!m_destructionInProgress); 342 if (m_destructionInProgress || !m_isSurfaceValid) 343 return false; 344 if (m_contextProvider->context3d()->isContextLost()) { 345 m_isSurfaceValid = false; 346 m_surface.clear(); 347 if (m_imageBuffer) 348 m_imageBuffer->notifySurfaceInvalid(); 349 setRateLimitingEnabled(false); 350 } 351 return m_isSurfaceValid; 352} 353 354bool Canvas2DLayerBridge::restoreSurface() 355{ 356 ASSERT(!m_destructionInProgress); 357 if (m_destructionInProgress) 358 return false; 359 ASSERT(m_layer && !m_isSurfaceValid); 360 361 WebGraphicsContext3D* sharedContext = 0; 362 // We must clear the mailboxes before calling m_layer->clearTexture() to prevent 363 // re-entry via mailboxReleased from operating on defunct GrContext objects. 364 m_mailboxes.clear(); 365 m_releasedMailboxInfoIndex = InvalidMailboxIndex; 366 m_layer->clearTexture(); 367 m_contextProvider = adoptPtr(Platform::current()->createSharedOffscreenGraphicsContext3DProvider()); 368 if (m_contextProvider) 369 sharedContext = m_contextProvider->context3d(); 370 371 if (sharedContext && !sharedContext->isContextLost()) { 372 IntSize size(m_canvas->getTopDevice()->width(), m_canvas->getTopDevice()->height()); 373 RefPtr<SkSurface> surface(createSkSurface(m_contextProvider->grContext(), size, m_msaaSampleCount)); 374 if (surface.get()) { 375 m_surface = surface.release(); 376 m_canvas->setSurface(m_surface.get()); 377 m_isSurfaceValid = true; 378 // FIXME: draw sad canvas picture into new buffer crbug.com/243842 379 } 380 } 381 382 return m_isSurfaceValid; 383} 384 385bool Canvas2DLayerBridge::prepareMailbox(WebExternalTextureMailbox* outMailbox, WebExternalBitmap* bitmap) 386{ 387 if (m_destructionInProgress) { 388 // It can be hit in the following sequence. 389 // 1. Canvas draws something. 390 // 2. The compositor begins the frame. 391 // 3. Javascript makes a context be lost. 392 // 4. Here. 393 return false; 394 } 395 if (bitmap) { 396 // Using accelerated 2d canvas with software renderer, which 397 // should only happen in tests that use fake graphics contexts 398 // or in Android WebView in software mode. In this case, we do 399 // not care about producing any results for this canvas. 400 m_canvas->silentFlush(); 401 m_lastImageId = 0; 402 return false; 403 } 404 if (!checkSurfaceValid()) 405 return false; 406 407 WebGraphicsContext3D* webContext = context(); 408 409 // Release to skia textures that were previouosly released by the 410 // compositor. We do this before acquiring the next snapshot in 411 // order to cap maximum gpu memory consumption. 412 flush(); 413 414 RefPtr<SkImage> image = adoptRef(m_canvas->newImageSnapshot()); 415 416 // Early exit if canvas was not drawn to since last prepareMailbox 417 if (image->uniqueID() == m_lastImageId) 418 return false; 419 m_lastImageId = image->uniqueID(); 420 421 MailboxInfo* mailboxInfo = createMailboxInfo(); 422 mailboxInfo->m_status = MailboxInUse; 423 mailboxInfo->m_image = image; 424 425 ASSERT(mailboxInfo->m_mailbox.syncPoint == 0); 426 ASSERT(mailboxInfo->m_image.get()); 427 428 // set m_parentLayerBridge to make sure 'this' stays alive as long as it has 429 // live mailboxes 430 ASSERT(!mailboxInfo->m_parentLayerBridge); 431 mailboxInfo->m_parentLayerBridge = this; 432 *outMailbox = mailboxInfo->m_mailbox; 433 434 GrContext* grContext = m_contextProvider->grContext(); 435 if (!grContext) 436 return true; // for testing: skip gl stuff when using a mock graphics context. 437 438 ASSERT(mailboxInfo->m_image->getTexture()); 439 440 // Because of texture sharing with the compositor, we must invalidate 441 // the state cached in skia so that the deferred copy on write 442 // in SkSurface_Gpu does not make any false assumptions. 443 mailboxInfo->m_image->getTexture()->textureParamsModified(); 444 445 webContext->bindTexture(GL_TEXTURE_2D, mailboxInfo->m_image->getTexture()->getTextureHandle()); 446 webContext->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 447 webContext->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 448 webContext->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 449 webContext->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 450 webContext->produceTextureCHROMIUM(GL_TEXTURE_2D, mailboxInfo->m_mailbox.name); 451 if (isHidden()) { 452 // With hidden canvases, we release the SkImage immediately because 453 // there is no need for animations to be double buffered. 454 mailboxInfo->m_image.clear(); 455 } else { 456 webContext->flush(); 457 mailboxInfo->m_mailbox.syncPoint = webContext->insertSyncPoint(); 458 } 459 webContext->bindTexture(GL_TEXTURE_2D, 0); 460 // Because we are changing the texture binding without going through skia, 461 // we must dirty the context. 462 grContext->resetContext(kTextureBinding_GrGLBackendState); 463 464 return true; 465} 466 467Canvas2DLayerBridge::MailboxInfo* Canvas2DLayerBridge::createMailboxInfo() { 468 ASSERT(!m_destructionInProgress); 469 MailboxInfo* mailboxInfo; 470 for (mailboxInfo = m_mailboxes.begin(); mailboxInfo < m_mailboxes.end(); mailboxInfo++) { 471 if (mailboxInfo->m_status == MailboxAvailable) { 472 return mailboxInfo; 473 } 474 } 475 476 // No available mailbox: create one. 477 m_mailboxes.grow(m_mailboxes.size() + 1); 478 mailboxInfo = &m_mailboxes.last(); 479 context()->genMailboxCHROMIUM(mailboxInfo->m_mailbox.name); 480 // Worst case, canvas is triple buffered. More than 3 active mailboxes 481 // means there is a problem. 482 // For the single-threaded case, this value needs to be at least 483 // kMaxSwapBuffersPending+1 (in render_widget.h). 484 // Because of crbug.com/247874, it needs to be kMaxSwapBuffersPending+2. 485 // TODO(piman): fix this. 486 ASSERT(m_mailboxes.size() <= 4); 487 ASSERT(mailboxInfo < m_mailboxes.end()); 488 return mailboxInfo; 489} 490 491void Canvas2DLayerBridge::mailboxReleased(const WebExternalTextureMailbox& mailbox, bool lostResource) 492{ 493 freeReleasedMailbox(); // Never have more than one mailbox in the released state. 494 bool contextLost = !m_isSurfaceValid || m_contextProvider->context3d()->isContextLost(); 495 Vector<MailboxInfo>::iterator mailboxInfo; 496 for (mailboxInfo = m_mailboxes.begin(); mailboxInfo < m_mailboxes.end(); ++mailboxInfo) { 497 if (nameEquals(mailboxInfo->m_mailbox, mailbox)) { 498 mailboxInfo->m_mailbox.syncPoint = mailbox.syncPoint; 499 ASSERT(mailboxInfo->m_status == MailboxInUse); 500 ASSERT(mailboxInfo->m_parentLayerBridge.get() == this); 501 502 if (contextLost) { 503 // No need to clean up the mailbox resource, but make sure the 504 // mailbox can also be reusable once the context is restored. 505 mailboxInfo->m_status = MailboxAvailable; 506 m_releasedMailboxInfoIndex = InvalidMailboxIndex; 507 Canvas2DLayerManager::get().layerTransientResourceAllocationChanged(this); 508 } else if (lostResource) { 509 // In case of the resource is lost, we need to delete the backing 510 // texture and remove the mailbox from list to avoid reusing it 511 // in future. 512 if (mailboxInfo->m_image) { 513 GrTexture* texture = mailboxInfo->m_image->getTexture(); 514 if (texture) { 515 texture->resetFlag(static_cast<GrTextureFlags>(GrTexture::kReturnToCache_FlagBit)); 516 texture->textureParamsModified(); 517 } 518 mailboxInfo->m_image.clear(); 519 } 520 if (m_destructionInProgress) { 521 mailboxInfo->m_status = MailboxAvailable; // To satisfy assert in destructor 522 523 // The following line may trigger self destruction. We do not care about 524 // not cleaning up m_mailboxes during destruction sequence because 525 // mailboxes will not be recycled after this point. Calling remove() 526 // could trigger a memory use after free, so we just clear the self 527 // reference to be safe, and we let the Canvas2DLayerBridge destructor 528 // take care of freeing m_mailboxes. 529 mailboxInfo->m_parentLayerBridge.clear(); 530 } else { 531 size_t i = mailboxInfo - m_mailboxes.begin(); 532 m_mailboxes.remove(i); // indirectly clears mailboxInfo->m_parentLayerBridge 533 Canvas2DLayerManager::get().layerTransientResourceAllocationChanged(this); 534 } 535 // mailboxInfo is not valid from this point, so we return immediately. 536 return; 537 } else { 538 mailboxInfo->m_status = MailboxReleased; 539 m_releasedMailboxInfoIndex = mailboxInfo - m_mailboxes.begin(); 540 m_framesSinceMailboxRelease = 0; 541 if (isHidden()) { 542 freeReleasedMailbox(); 543 } else { 544 ASSERT(!m_destructionInProgress); 545 Canvas2DLayerManager::get().layerTransientResourceAllocationChanged(this); 546 } 547 } 548 // Trigger Canvas2DLayerBridge self-destruction if this is the 549 // last live mailbox and the layer bridge is not externally 550 // referenced. 551 mailboxInfo->m_parentLayerBridge.clear(); 552 return; 553 } 554 } 555} 556 557WebLayer* Canvas2DLayerBridge::layer() const 558{ 559 ASSERT(!m_destructionInProgress); 560 ASSERT(m_layer); 561 return m_layer->layer(); 562} 563 564void Canvas2DLayerBridge::finalizeFrame(const FloatRect &dirtyRect) 565{ 566 ASSERT(!m_destructionInProgress); 567 Canvas2DLayerManager::get().layerDidDraw(this); 568 m_layer->layer()->invalidateRect(dirtyRect); 569 m_didRecordDrawCommand = true; 570} 571 572Platform3DObject Canvas2DLayerBridge::getBackingTexture() 573{ 574 ASSERT(!m_destructionInProgress); 575 if (!checkSurfaceValid()) 576 return 0; 577 m_canvas->flush(); 578 context()->flush(); 579 GrRenderTarget* renderTarget = m_canvas->getTopDevice()->accessRenderTarget(); 580 if (renderTarget) { 581 return renderTarget->asTexture()->getTextureHandle(); 582 } 583 return 0; 584} 585 586Canvas2DLayerBridge::MailboxInfo::MailboxInfo(const MailboxInfo& other) { 587 // This copy constructor should only be used for Vector reallocation 588 // Assuming 'other' is to be destroyed, we transfer m_image and 589 // m_parentLayerBridge ownership rather than do a refcount dance. 590 memcpy(&m_mailbox, &other.m_mailbox, sizeof(m_mailbox)); 591 m_image = const_cast<MailboxInfo*>(&other)->m_image.release(); 592 m_parentLayerBridge = const_cast<MailboxInfo*>(&other)->m_parentLayerBridge.release(); 593 m_status = other.m_status; 594} 595 596} // namespace blink 597