Chromium Code Reviews| Index: Source/platform/graphics/Canvas2DLayerBridge.cpp |
| diff --git a/Source/platform/graphics/Canvas2DLayerBridge.cpp b/Source/platform/graphics/Canvas2DLayerBridge.cpp |
| index 492dc2b439a70f7a66dd6b2d0108bf753482c6ba..5103c98b694316fcf0537522316289aec8f263d3 100644 |
| --- a/Source/platform/graphics/Canvas2DLayerBridge.cpp |
| +++ b/Source/platform/graphics/Canvas2DLayerBridge.cpp |
| @@ -41,6 +41,10 @@ |
| using blink::WebExternalTextureLayer; |
| using blink::WebGraphicsContext3D; |
| +namespace { |
| +const size_t MaxSize = ~static_cast<size_t>(0); |
|
eseidel
2013/12/19 02:56:32
std::limits?
|
| +} |
| + |
| namespace WebCore { |
| static PassRefPtr<SkSurface> createSkSurface(GraphicsContext3D* context3D, const IntSize& size, int msaaSampleCount) |
| @@ -58,7 +62,7 @@ static PassRefPtr<SkSurface> createSkSurface(GraphicsContext3D* context3D, const |
| return adoptRef(SkSurface::NewRenderTarget(gr, info, msaaSampleCount)); |
| } |
| -PassRefPtr<Canvas2DLayerBridge> Canvas2DLayerBridge::create(const IntSize& size, OpacityMode opacityMode, int msaaSampleCount) |
| +PassRefPtr<Canvas2DLayerBridge> Canvas2DLayerBridge::create(Canvas2DLayerBridgeClient* client, const IntSize& size, OpacityMode opacityMode, int msaaSampleCount) |
| { |
| TRACE_EVENT_INSTANT0("test_gpu", "Canvas2DLayerBridgeCreation"); |
| RefPtr<GraphicsContext3D> context = SharedGraphicsContext3D::get(); |
| @@ -67,25 +71,29 @@ PassRefPtr<Canvas2DLayerBridge> Canvas2DLayerBridge::create(const IntSize& size, |
| return 0; |
| RefPtr<Canvas2DLayerBridge> layerBridge; |
| OwnPtr<SkDeferredCanvas> canvas = adoptPtr(SkDeferredCanvas::Create(surface.get())); |
| - layerBridge = adoptRef(new Canvas2DLayerBridge(context, canvas.release(), msaaSampleCount, opacityMode)); |
| + layerBridge = adoptRef(new Canvas2DLayerBridge(client, context, canvas.release(), msaaSampleCount, opacityMode)); |
| return layerBridge.release(); |
| } |
| -Canvas2DLayerBridge::Canvas2DLayerBridge(PassRefPtr<GraphicsContext3D> context, PassOwnPtr<SkDeferredCanvas> canvas, int msaaSampleCount, OpacityMode opacityMode) |
| - : m_canvas(canvas) |
| +Canvas2DLayerBridge::Canvas2DLayerBridge(Canvas2DLayerBridgeClient* client, PassRefPtr<GraphicsContext3D> context, PassOwnPtr<SkDeferredCanvas> canvas, int msaaSampleCount, OpacityMode opacityMode) |
| + : m_client(client) |
| + , m_canvas(canvas) |
| , m_context(context) |
| , m_msaaSampleCount(msaaSampleCount) |
| , m_bytesAllocated(0) |
| , m_didRecordDrawCommand(false) |
| , m_surfaceIsValid(true) |
| , m_framesPending(0) |
| + , m_framesSinceMailboxRelease(0) |
| , m_destructionInProgress(false) |
| , m_rateLimitingEnabled(false) |
| , m_next(0) |
| , m_prev(0) |
| , m_lastImageId(0) |
| + , m_releasedMailboxInfo(0) |
| { |
| ASSERT(m_canvas); |
| + ASSERT(m_client); |
| // Used by browser tests to detect the use of a Canvas2DLayerBridge. |
| TRACE_EVENT_INSTANT0("test_gpu", "Canvas2DLayerBridgeCreation"); |
| m_layer = adoptPtr(blink::Platform::current()->compositorSupport()->createExternalTextureLayer(this)); |
| @@ -100,18 +108,14 @@ Canvas2DLayerBridge::~Canvas2DLayerBridge() |
| { |
| ASSERT(m_destructionInProgress); |
| m_layer.clear(); |
| + freeReleasedMailbox(); |
| +#if !ASSERT_DISABLED |
| Vector<MailboxInfo>::iterator mailboxInfo; |
| for (mailboxInfo = m_mailboxes.begin(); mailboxInfo < m_mailboxes.end(); mailboxInfo++) { |
| ASSERT(mailboxInfo->m_status != MailboxInUse); |
| - if (mailboxInfo->m_status == MailboxReleased) { |
| - if (mailboxInfo->m_mailbox.syncPoint) { |
| - context()->waitSyncPoint(mailboxInfo->m_mailbox.syncPoint); |
| - mailboxInfo->m_mailbox.syncPoint = 0; |
| - } |
| - // Invalidate texture state in case the compositor altered it since the copy-on-write. |
| - mailboxInfo->m_image->getTexture()->invalidateCachedState(); |
| - } |
| + ASSERT(mailboxInfo->m_status != MailboxReleased); |
| } |
| +#endif |
| m_mailboxes.clear(); |
| } |
| @@ -129,6 +133,23 @@ void Canvas2DLayerBridge::beginDestruction() |
| m_layer->layer()->removeFromParent(); |
| } |
| +bool Canvas2DLayerBridge::hidden() const |
| +{ |
| + return m_destructionInProgress || m_client->hidden(); |
| +} |
| + |
| +void Canvas2DLayerBridge::freeTransientResources() |
| +{ |
| + freeReleasedMailbox(); |
| + flush(); |
| + freeMemoryIfPossible(MaxSize); |
| +} |
| + |
| +bool Canvas2DLayerBridge::hasTransientResources() const |
| +{ |
| + return hasReleasedMailbox() || bytesAllocated(); |
| +} |
| + |
| void Canvas2DLayerBridge::limitPendingFrames() |
| { |
| ASSERT(!m_destructionInProgress); |
| @@ -144,6 +165,9 @@ void Canvas2DLayerBridge::limitPendingFrames() |
| flush(); |
| } |
| } |
| + if (m_releasedMailboxInfo && ++m_framesSinceMailboxRelease >= 2) { |
| + freeReleasedMailbox(); |
| + } |
| } |
| void Canvas2DLayerBridge::prepareForDraw() |
| @@ -214,10 +238,27 @@ void Canvas2DLayerBridge::flush() |
| ASSERT(!m_destructionInProgress); |
| if (m_canvas->hasPendingCommands()) { |
| TRACE_EVENT0("cc", "Canvas2DLayerBridge::flush"); |
| + freeReleasedMailbox(); // To avoid unnecessary triple-buffering |
| m_canvas->flush(); |
| } |
| } |
| +void Canvas2DLayerBridge::freeReleasedMailbox() |
| +{ |
| + if (m_releasedMailboxInfo) { |
| + ASSERT(m_releasedMailboxInfo->m_status == MailboxReleased); |
| + if (m_releasedMailboxInfo->m_mailbox.syncPoint) { |
| + context()->waitSyncPoint(m_releasedMailboxInfo->m_mailbox.syncPoint); |
| + m_releasedMailboxInfo->m_mailbox.syncPoint = 0; |
| + } |
| + // Invalidate texture state in case the compositor altered it since the copy-on-write. |
| + m_releasedMailboxInfo->m_image->getTexture()->invalidateCachedState(); |
| + m_releasedMailboxInfo->m_image.clear(); |
| + m_releasedMailboxInfo->m_status = MailboxAvailable; |
| + m_releasedMailboxInfo = 0; |
| + } |
| +} |
| + |
| blink::WebGraphicsContext3D* Canvas2DLayerBridge::context() |
| { |
| // Check on m_layer is necessary because context() may be called during |
| @@ -277,28 +318,18 @@ bool Canvas2DLayerBridge::prepareMailbox(blink::WebExternalTextureMailbox* outMa |
| // order to cap maximum gpu memory consumption. |
| m_context->makeContextCurrent(); |
| flush(); |
| - Vector<MailboxInfo>::iterator mailboxInfo; |
| - for (mailboxInfo = m_mailboxes.begin(); mailboxInfo < m_mailboxes.end(); mailboxInfo++) { |
| - if (mailboxInfo->m_status == MailboxReleased) { |
| - if (mailboxInfo->m_mailbox.syncPoint) { |
| - context()->waitSyncPoint(mailboxInfo->m_mailbox.syncPoint); |
| - mailboxInfo->m_mailbox.syncPoint = 0; |
| - } |
| - // Invalidate texture state in case the compositor altered it since the copy-on-write. |
| - mailboxInfo->m_image->getTexture()->invalidateCachedState(); |
| - mailboxInfo->m_image.reset(0); |
| - mailboxInfo->m_status = MailboxAvailable; |
| - } |
| - } |
| - SkAutoTUnref<SkImage> image(m_canvas->newImageSnapshot()); |
| + |
| + RefPtr<SkImage> image = adoptRef(m_canvas->newImageSnapshot()); |
| + |
| // Early exit if canvas was not drawn to since last prepareMailbox |
| if (image->uniqueID() == m_lastImageId) |
| return false; |
| m_lastImageId = image->uniqueID(); |
| - mailboxInfo = createMailboxInfo(); |
| + MailboxInfo* mailboxInfo = createMailboxInfo(); |
| mailboxInfo->m_status = MailboxInUse; |
| - mailboxInfo->m_image.swap(&image); |
| + mailboxInfo->m_image = image; |
| + |
| // Because of texture sharing with the compositor, we must invalidate |
| // the state cached in skia so that the deferred copy on write |
| // in SkSurface_Gpu does not make any false assumptions. |
| @@ -355,6 +386,7 @@ Canvas2DLayerBridge::MailboxInfo* Canvas2DLayerBridge::createMailboxInfo() { |
| void Canvas2DLayerBridge::mailboxReleased(const blink::WebExternalTextureMailbox& mailbox) |
| { |
| + freeReleasedMailbox(); // Never have more than one mailbox in the released state. |
| Vector<MailboxInfo>::iterator mailboxInfo; |
| for (mailboxInfo = m_mailboxes.begin(); mailboxInfo < m_mailboxes.end(); mailboxInfo++) { |
| if (!memcmp(mailboxInfo->m_mailbox.name, mailbox.name, sizeof(mailbox.name))) { |
| @@ -366,6 +398,13 @@ void Canvas2DLayerBridge::mailboxReleased(const blink::WebExternalTextureMailbox |
| // referenced. |
| ASSERT(mailboxInfo->m_parentLayerBridge.get() == this); |
| mailboxInfo->m_parentLayerBridge.clear(); |
| + m_releasedMailboxInfo = mailboxInfo; |
| + m_framesSinceMailboxRelease = 0; |
| + if (hidden()) { |
| + freeReleasedMailbox(); |
| + } else { |
| + Canvas2DLayerManager::get().setLayerHasFreeableResources(this); |
| + } |
| return; |
| } |
| } |
| @@ -401,10 +440,10 @@ Platform3DObject Canvas2DLayerBridge::getBackingTexture() |
| Canvas2DLayerBridge::MailboxInfo::MailboxInfo(const MailboxInfo& other) { |
| // This copy constructor should only be used for Vector reallocation |
| - // Assuming 'other' is to be destroyed, we swap m_image ownership |
| + // Assuming 'other' is to be destroyed, we transfer m_image ownership |
| // rather than do a refcount dance. |
| memcpy(&m_mailbox, &other.m_mailbox, sizeof(m_mailbox)); |
| - m_image.swap(const_cast<SkAutoTUnref<SkImage>*>(&other.m_image)); |
| + m_image = const_cast<MailboxInfo*>(&other)->m_image.release(); |
| m_status = other.m_status; |
| } |