Bug 1504699 - Part 1. Add signalling for WebRender to let owning process that surface may be recycled. r=nical
authorAndrew Osmond <aosmond@mozilla.com>
Fri, 28 Sep 2018 15:11:15 -0400
changeset 503957 73ddcfe25fa19585d68b33e362a0659366f2f509
parent 503956 fa95b1364b4ae517bd92171143a21e402faae610
child 503958 944b5385a34248376ae0d92beabf4bcb8a045567
push id10290
push userffxbld-merge
push dateMon, 03 Dec 2018 16:23:23 +0000
treeherdermozilla-beta@700bed2445e6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnical
bugs1504699
milestone65.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1504699 - Part 1. Add signalling for WebRender to let owning process that surface may be recycled. r=nical When we replace the external image ID an image key points to, the previous external image ID may still be used by WebRender. We currently wait until the frame has been rendered to release our hold on said surface. With this patch, we will communicate the image key and previous external image ID pairing to the owning process when releasing to let it know that it can reuse it (e.g. for an animated image). Additionally we now use the new textures updated checkpoint which should happen sooner than the frame rendered checkpoint, but guarantee that WebRender is no longer using the old external image ID. Differential Revision: https://phabricator.services.mozilla.com/D10897
gfx/layers/ipc/PWebRenderBridge.ipdl
gfx/layers/wr/WebRenderBridgeChild.cpp
gfx/layers/wr/WebRenderBridgeChild.h
gfx/layers/wr/WebRenderBridgeParent.cpp
gfx/layers/wr/WebRenderBridgeParent.h
gfx/layers/wr/WebRenderMessageUtils.h
gfx/webrender_bindings/WebRenderTypes.h
--- a/gfx/layers/ipc/PWebRenderBridge.ipdl
+++ b/gfx/layers/ipc/PWebRenderBridge.ipdl
@@ -18,16 +18,17 @@ using mozilla::layers::APZTestData from 
 using mozilla::layers::ScrollUpdatesMap from "FrameMetrics.h";
 using struct mozilla::layers::ScrollableLayerGuid from "mozilla/layers/ScrollableLayerGuid.h";
 using struct mozilla::layers::TextureFactoryIdentifier from "mozilla/layers/CompositorTypes.h";
 using struct mozilla::layers::TextureInfo from "mozilla/layers/CompositorTypes.h";
 using mozilla::layers::CompositableHandle from "mozilla/layers/LayersTypes.h";
 using mozilla::wr::BuiltDisplayListDescriptor from "mozilla/webrender/webrender_ffi.h";
 using mozilla::wr::IdNamespace from "mozilla/webrender/WebRenderTypes.h";
 using mozilla::wr::MaybeIdNamespace from "mozilla/webrender/WebRenderTypes.h";
+using mozilla::wr::ExternalImageKeyPair from "mozilla/webrender/WebRenderTypes.h";
 using mozilla::layers::WebRenderScrollData from "mozilla/layers/WebRenderScrollData.h";
 using mozilla::layers::FocusTarget from "mozilla/layers/FocusTarget.h";
 using mozilla::layers::LayersObserverEpoch from "mozilla/layers/LayersTypes.h";
 using mozilla::layers::TransactionId from "mozilla/layers/LayersTypes.h";
 
 namespace mozilla {
 namespace layers {
 
@@ -79,13 +80,14 @@ parent:
   sync SetAsyncZoom(ViewID scrollId, float zoom);
   async FlushApzRepaints();
   sync GetAPZTestData() returns (APZTestData data);
 
   async Shutdown();
   sync ShutdownSync();
 child:
   async WrUpdated(IdNamespace aNewIdNamespace, TextureFactoryIdentifier textureFactoryIdentifier);
+  async WrReleasedImages(ExternalImageKeyPair[] pairs);
   async __delete__();
 };
 
 } // layers
 } // mozilla
--- a/gfx/layers/wr/WebRenderBridgeChild.cpp
+++ b/gfx/layers/wr/WebRenderBridgeChild.cpp
@@ -566,16 +566,22 @@ WebRenderBridgeChild::RecvWrUpdated(cons
   // Since usage of invalid keys could cause crash in webrender.
   mIdNamespace = aNewIdNamespace;
   // Just clear FontInstaceKeys/FontKeys, they are removed during WebRenderAPI destruction.
   mFontInstanceKeys.Clear();
   mFontKeys.Clear();
   return IPC_OK();
 }
 
+mozilla::ipc::IPCResult
+WebRenderBridgeChild::RecvWrReleasedImages(nsTArray<wr::ExternalImageKeyPair>&& aPairs)
+{
+  return IPC_OK();
+}
+
 void
 WebRenderBridgeChild::BeginClearCachedResources()
 {
   mIsInClearCachedResources = true;
   // Clear display list and animtaions at parent side before clearing cached
   // resources on client side. It prevents to clear resources before clearing
   // display list at parent side.
   SendClearCachedResources();
--- a/gfx/layers/wr/WebRenderBridgeChild.h
+++ b/gfx/layers/wr/WebRenderBridgeChild.h
@@ -206,16 +206,17 @@ private:
   bool InForwarderThread() override;
 
   void ActorDestroy(ActorDestroyReason why) override;
 
   void DoDestroy();
 
   mozilla::ipc::IPCResult RecvWrUpdated(const wr::IdNamespace& aNewIdNamespace,
                                         const TextureFactoryIdentifier& textureFactoryIdentifier) override;
+  mozilla::ipc::IPCResult RecvWrReleasedImages(nsTArray<wr::ExternalImageKeyPair>&& aPairs) override;
 
   void AddIPDLReference() {
     MOZ_ASSERT(mIPCOpen == false);
     mIPCOpen = true;
     AddRef();
   }
   void ReleaseIPDLReference() {
     MOZ_ASSERT(mIPCOpen == true);
--- a/gfx/layers/wr/WebRenderBridgeParent.cpp
+++ b/gfx/layers/wr/WebRenderBridgeParent.cpp
@@ -249,33 +249,42 @@ protected:
   TimeStamp mTxnStartTime;
 };
 
 
 class WebRenderBridgeParent::ScheduleSharedSurfaceRelease final
   : public wr::NotificationHandler
 {
 public:
-  ScheduleSharedSurfaceRelease()
+  explicit ScheduleSharedSurfaceRelease(WebRenderBridgeParent* aWrBridge)
+    : mWrBridge(aWrBridge)
+    , mSurfaces(20)
   { }
 
-  void Add(const wr::ExternalImageId& aId)
+  void Add(const wr::ImageKey& aKey,
+           const wr::ExternalImageId& aId)
   {
-    mSurfaces.AppendElement(aId);
+    mSurfaces.AppendElement(wr::ExternalImageKeyPair { aKey, aId });
   }
 
   void Notify(wr::Checkpoint) override
   {
-    for (const auto& id : mSurfaces) {
-      SharedSurfacesParent::Release(id);
-    }
+    CompositorThreadHolder::Loop()->PostTask(
+      NewRunnableMethod<nsTArray<wr::ExternalImageKeyPair>>(
+        "ObserveSharedSurfaceRelease",
+        mWrBridge,
+        &WebRenderBridgeParent::ObserveSharedSurfaceRelease,
+        std::move(mSurfaces)
+      )
+    );
   }
 
 private:
-  AutoTArray<wr::ExternalImageId, 20> mSurfaces;
+  RefPtr<WebRenderBridgeParent> mWrBridge;
+  nsTArray<wr::ExternalImageKeyPair> mSurfaces;
 };
 
 class MOZ_STACK_CLASS AutoWebRenderBridgeParentAsyncMessageSender
 {
 public:
   explicit AutoWebRenderBridgeParentAsyncMessageSender(WebRenderBridgeParent* aWebRenderBridgeParent,
                                                        InfallibleTArray<OpDestroy>* aDestroyActors = nullptr)
     : mWebRenderBridgeParent(aWebRenderBridgeParent)
@@ -535,17 +544,18 @@ WebRenderBridgeParent::UpdateResources(c
         aUpdates.DeleteFontInstance(op.key());
         break;
       }
       case OpUpdateResource::T__None: break;
     }
   }
 
   if (scheduleRelease) {
-    aUpdates.Notify(wr::Checkpoint::FrameRendered, std::move(scheduleRelease));
+    aUpdates.Notify(wr::Checkpoint::FrameTexturesUpdated,
+                    std::move(scheduleRelease));
   }
   return true;
 }
 
 bool
 WebRenderBridgeParent::AddExternalImage(wr::ExternalImageId aExtId, wr::ImageKey aKey,
                                         wr::TransactionBuilder& aResources)
 {
@@ -690,19 +700,19 @@ WebRenderBridgeParent::UpdateExternalIma
     return false;
   }
 
   if (!(it->second == aExtId)) {
     // We already have a mapping for this image key, so ensure we release the
     // previous external image ID. This can happen when an image is animated,
     // and it is changing the external image that the animation points to.
     if (!aScheduleRelease) {
-      aScheduleRelease = MakeUnique<ScheduleSharedSurfaceRelease>();
+      aScheduleRelease = MakeUnique<ScheduleSharedSurfaceRelease>(this);
     }
-    aScheduleRelease->Add(it->second);
+    aScheduleRelease->Add(aKey, it->second);
     it->second = aExtId;
   }
 
   if (!gfxEnv::EnableWebRenderRecording()) {
     wr::ImageDescriptor descriptor(dSurf->GetSize(), dSurf->Stride(),
                                    dSurf->GetFormat());
     aResources.UpdateExternalImageWithDirtyRect(aKey, descriptor, aExtId,
                                                 wr::WrExternalImageBufferType::ExternalBuffer,
@@ -720,16 +730,27 @@ WebRenderBridgeParent::UpdateExternalIma
   IntSize size = dSurf->GetSize();
   wr::ImageDescriptor descriptor(size, map.GetStride(), dSurf->GetFormat());
   wr::Vec<uint8_t> data;
   data.PushBytes(Range<uint8_t>(map.GetData(), size.height * map.GetStride()));
   aResources.UpdateImageBuffer(keys[0], descriptor, data);
   return true;
 }
 
+void
+WebRenderBridgeParent::ObserveSharedSurfaceRelease(const nsTArray<wr::ExternalImageKeyPair>& aPairs)
+{
+  if (!mDestroyed) {
+    Unused << SendWrReleasedImages(aPairs);
+  }
+  for (const auto& pair : aPairs) {
+    SharedSurfacesParent::Release(pair.id);
+  }
+}
+
 mozilla::ipc::IPCResult
 WebRenderBridgeParent::RecvUpdateResources(nsTArray<OpUpdateResource>&& aResourceUpdates,
                                            nsTArray<RefCountedShmem>&& aSmallShmems,
                                            nsTArray<ipc::Shmem>&& aLargeShmems,
                                            const bool& aScheduleComposite)
 {
   if (mDestroyed) {
     wr::IpcResourceUpdateQueue::ReleaseShmems(this, aSmallShmems);
--- a/gfx/layers/wr/WebRenderBridgeParent.h
+++ b/gfx/layers/wr/WebRenderBridgeParent.h
@@ -250,16 +250,17 @@ private:
                        const nsTArray<ipc::Shmem>& aLargeShmems,
                        wr::TransactionBuilder& aUpdates);
   bool AddExternalImage(wr::ExternalImageId aExtId, wr::ImageKey aKey,
                         wr::TransactionBuilder& aResources);
   bool UpdateExternalImage(wr::ExternalImageId aExtId, wr::ImageKey aKey,
                            const ImageIntRect& aDirtyRect,
                            wr::TransactionBuilder& aResources,
                            UniquePtr<ScheduleSharedSurfaceRelease>& aScheduleRelease);
+  void ObserveSharedSurfaceRelease(const nsTArray<wr::ExternalImageKeyPair>& aPairs);
 
   bool PushExternalImageForTexture(wr::ExternalImageId aExtId,
                                    wr::ImageKey aKey,
                                    TextureHost* aTexture,
                                    bool aIsUpdate,
                                    wr::TransactionBuilder& aResources);
 
   void AddPipelineIdForCompositable(const wr::PipelineId& aPipelineIds,
--- a/gfx/layers/wr/WebRenderMessageUtils.h
+++ b/gfx/layers/wr/WebRenderMessageUtils.h
@@ -184,11 +184,17 @@ struct ParamTraits<mozilla::wr::MemoryRe
 };
 
 template<>
 struct ParamTraits<mozilla::wr::OpacityType>
   : public PlainOldDataSerializer<mozilla::wr::OpacityType>
 {
 };
 
+template<>
+struct ParamTraits<mozilla::wr::ExternalImageKeyPair>
+  : public PlainOldDataSerializer<mozilla::wr::ExternalImageKeyPair>
+{
+};
+
 } // namespace IPC
 
 #endif // GFX_WEBRENDERMESSAGEUTILS_H
--- a/gfx/webrender_bindings/WebRenderTypes.h
+++ b/gfx/webrender_bindings/WebRenderTypes.h
@@ -45,16 +45,22 @@ typedef wr::WrDebugFlags DebugFlags;
 
 typedef mozilla::Maybe<mozilla::wr::IdNamespace> MaybeIdNamespace;
 typedef mozilla::Maybe<mozilla::wr::WrImageMask> MaybeImageMask;
 typedef Maybe<ExternalImageId> MaybeExternalImageId;
 
 typedef Maybe<FontInstanceOptions> MaybeFontInstanceOptions;
 typedef Maybe<FontInstancePlatformOptions> MaybeFontInstancePlatformOptions;
 
+struct ExternalImageKeyPair
+{
+  ImageKey key;
+  ExternalImageId id;
+};
+
 /* Generate a brand new window id and return it. */
 WindowId NewWindowId();
 
 inline DebugFlags NewDebugFlags(uint32_t aFlags) {
   DebugFlags flags;
   flags.mBits = aFlags;
   return flags;
 }