Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(207)

Unified Diff: Source/platform/graphics/Canvas2DLayerBridge.cpp

Issue 117703004: Free temporary GPU and memory resources held by inactive or hidden 2D canvases (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: fixed upstream git branch Created 7 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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;
}

Powered by Google App Engine
This is Rietveld 408576698