Bug 1366446 - Ensure layers TextureClient always lives as long as the SourceSurface using it. r=jrmuizel, a=jcristau
authorLee Salzman <lsalzman@mozilla.com>
Sun, 28 May 2017 13:30:32 -0400
changeset 396459 380ace0289a50ccba079fffd32de61a541676aa4
parent 396458 30ba0234b771e65510a852e5c8318f50195c9bdb
child 396460 eb133d8ca1f1a4f5fe6a69bf95cf1096dbe63001
push id1468
push userasasaki@mozilla.com
push dateMon, 05 Jun 2017 19:31:07 +0000
treeherdermozilla-release@0641fc6ee9d1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjrmuizel, jcristau
bugs1366446
milestone54.0
Bug 1366446 - Ensure layers TextureClient always lives as long as the SourceSurface using it. r=jrmuizel, a=jcristau MozReview-Commit-ID: HU3TBQQgotE
gfx/layers/ipc/SharedRGBImage.cpp
--- a/gfx/layers/ipc/SharedRGBImage.cpp
+++ b/gfx/layers/ipc/SharedRGBImage.cpp
@@ -97,16 +97,24 @@ SharedRGBImage::GetSize()
 }
 
 TextureClient*
 SharedRGBImage::GetTextureClient(KnowsCompositor* aForwarder)
 {
   return mTextureClient.get();
 }
 
+static void
+ReleaseTextureClient(void* aData)
+{
+  RELEASE_MANUALLY(static_cast<TextureClient*>(aData));
+}
+
+static gfx::UserDataKey sTextureClientKey;
+
 already_AddRefed<gfx::SourceSurface>
 SharedRGBImage::GetAsSourceSurface()
 {
   NS_ASSERTION(NS_IsMainThread(), "Must be main thread");
 
   if (mSourceSurface) {
     RefPtr<gfx::SourceSurface> surface(mSourceSurface);
     return surface.forget();
@@ -122,16 +130,28 @@ SharedRGBImage::GetAsSourceSurface()
       mTextureClient->GetInternalData()->AsBufferTextureData();
     RefPtr<gfx::DrawTarget> drawTarget = decoded_buffer->BorrowDrawTarget();
 
     if (!drawTarget) {
       return nullptr;
     }
 
     surface = drawTarget->Snapshot();
+    if (!surface) {
+      return nullptr;
+    }
+
+    // The surface may outlive the owning TextureClient. So, we need to ensure
+    // that the surface keeps the TextureClient alive via a reference held in
+    // user data. The TextureClient's DrawTarget only has a weak reference to the
+    // surface, so we won't create any cycles by just referencing the TextureClient.
+    if (!surface->GetUserData(&sTextureClientKey)) {
+      surface->AddUserData(&sTextureClientKey, mTextureClient, ReleaseTextureClient);
+      ADDREF_MANUALLY(mTextureClient);
+    }
   }
 
   mSourceSurface = surface;
   return surface.forget();
 }
 
 } // namespace layers
 } // namespace mozilla