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; |
} |