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