Home | History | Annotate | Download | only in graphics
      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 
     42 namespace {
     43 enum {
     44     InvalidMailboxIndex = -1,
     45 };
     46 
     47 DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, canvas2DLayerBridgeInstanceCounter, ("Canvas2DLayerBridge"));
     48 }
     49 
     50 namespace blink {
     51 
     52 static 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 
     61 PassRefPtr<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 
     76 Canvas2DLayerBridge::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 
    111 Canvas2DLayerBridge::~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 
    130 void 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 
    153 void 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 
    166 void 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 
    175 void 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 
    186 bool Canvas2DLayerBridge::hasTransientResources() const
    187 {
    188     return !m_destructionInProgress && (hasReleasedMailbox() || bytesAllocated());
    189 }
    190 
    191 void 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 
    216 void 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 
    229 void 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 
    237 size_t Canvas2DLayerBridge::storageAllocatedForRecording()
    238 {
    239     return m_canvas->storageAllocatedForRecording();
    240 }
    241 
    242 void Canvas2DLayerBridge::flushedDrawCommands()
    243 {
    244     ASSERT(!m_destructionInProgress);
    245     storageAllocatedForRecordingChanged(storageAllocatedForRecording());
    246     m_framesPending = 0;
    247 }
    248 
    249 void 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 
    258 void 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 
    267 size_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 
    277 void 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 
    287 bool 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 
    295 Canvas2DLayerBridge::MailboxInfo* Canvas2DLayerBridge::releasedMailboxInfo()
    296 {
    297     return hasReleasedMailbox() ? &m_mailboxes[m_releasedMailboxInfoIndex] : 0;
    298 }
    299 
    300 bool Canvas2DLayerBridge::hasReleasedMailbox() const
    301 {
    302     return m_releasedMailboxInfoIndex != InvalidMailboxIndex;
    303 }
    304 
    305 void 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 
    330 WebGraphicsContext3D* 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 
    339 bool 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 
    354 bool 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 
    385 bool 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 
    467 Canvas2DLayerBridge::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 
    491 void 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 
    557 WebLayer* Canvas2DLayerBridge::layer() const
    558 {
    559     ASSERT(!m_destructionInProgress);
    560     ASSERT(m_layer);
    561     return m_layer->layer();
    562 }
    563 
    564 void 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 
    572 Platform3DObject 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 
    586 Canvas2DLayerBridge::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