Bug 1545416 - Make the remote decoder shutdown async. r=mjf
☠☠ backed out by 0ce3633f8b80 ☠ ☠
authorAlex Chronopoulos <achronop@gmail.com>
Tue, 23 Apr 2019 17:23:33 +0000
changeset 470517 7b326aa4930cad966e0a01d2d3d3d585d35002e2
parent 470516 9bc2f8e17d8062bd98fef67460ef0e74d5e0df17
child 470518 63ab1f26526681b3a14ba1e839a9f0ad13eb390d
push id35906
push useraciure@mozilla.com
push dateTue, 23 Apr 2019 22:14:56 +0000
treeherdermozilla-central@0ce3633f8b80 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmjf
bugs1545416
milestone68.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 1545416 - Make the remote decoder shutdown async. r=mjf Create a new IPDL message `ShutdownComplete`, direction from parent (RDD) to child (content), to inform the child when the decoder shutdown has been completed. The remote decoder child uses that message to resolve the shutdown promise. Differential Revision: https://phabricator.services.mozilla.com/D28340
dom/media/ipc/IRemoteDecoderChild.h
dom/media/ipc/PRemoteDecoder.ipdl
dom/media/ipc/PVideoDecoder.ipdl
dom/media/ipc/RemoteDecoderChild.cpp
dom/media/ipc/RemoteDecoderChild.h
dom/media/ipc/RemoteDecoderParent.cpp
dom/media/ipc/RemoteMediaDataDecoder.cpp
dom/media/ipc/VideoDecoderChild.cpp
dom/media/ipc/VideoDecoderChild.h
dom/media/ipc/VideoDecoderParent.cpp
--- a/dom/media/ipc/IRemoteDecoderChild.h
+++ b/dom/media/ipc/IRemoteDecoderChild.h
@@ -2,33 +2,34 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 #ifndef include_dom_media_ipc_IRemoteDecoderChild_h
 #define include_dom_media_ipc_IRemoteDecoderChild_h
 
 #include "PlatformDecoderModule.h"
+#include "mozilla/TaskQueue.h"
 
 namespace mozilla {
 
 // This interface mirrors the MediaDataDecoder plus a bit (DestroyIPDL)
 // to allow proxying to a remote decoder in RemoteDecoderModule or
 // GpuDecoderModule. RemoteAudioDecoderChild, RemoteVideoDecoderChild,
 // and VideoDecoderChild (for GPU) implement this interface.
 class IRemoteDecoderChild {
  public:
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(IRemoteDecoderChild);
 
   virtual RefPtr<MediaDataDecoder::InitPromise> Init() = 0;
   virtual RefPtr<MediaDataDecoder::DecodePromise> Decode(
       MediaRawData* aSample) = 0;
   virtual RefPtr<MediaDataDecoder::DecodePromise> Drain() = 0;
   virtual RefPtr<MediaDataDecoder::FlushPromise> Flush() = 0;
-  virtual void Shutdown() = 0;
+  virtual RefPtr<ShutdownPromise> Shutdown() = 0;
   virtual bool IsHardwareAccelerated(nsACString& aFailureReason) const {
     return false;
   }
   virtual nsCString GetDescriptionName() const = 0;
   virtual void SetSeekThreshold(const media::TimeUnit& aTime) {}
   virtual MediaDataDecoder::ConversionRequired NeedsConversion() const {
     return MediaDataDecoder::ConversionRequired::kNeedNone;
   }
--- a/dom/media/ipc/PRemoteDecoder.ipdl
+++ b/dom/media/ipc/PRemoteDecoder.ipdl
@@ -60,16 +60,17 @@ parent:
 
 child:
   async InitComplete(TrackType trackType,
                      nsCString decoderDescription,
                      ConversionRequired conversion);
   async InitFailed(nsresult reason);
 
   async FlushComplete();
+  async ShutdownComplete();
 
   async Output(DecodedOutputIPDL data);
   async InputExhausted();
   async DrainComplete();
   async Error(nsresult error);
 };
 
 } // namespace mozilla
--- a/dom/media/ipc/PVideoDecoder.ipdl
+++ b/dom/media/ipc/PVideoDecoder.ipdl
@@ -40,16 +40,17 @@ parent:
 
   async __delete__();
 
 child:
   async InitComplete(nsCString decoderDescription, bool hardware, nsCString hardwareReason, uint32_t conversion);
   async InitFailed(nsresult reason);
 
   async FlushComplete();
+  async ShutdownComplete();
 
   // Each output includes a SurfaceDescriptorGPUVideo that represents the decoded
   // frame. This SurfaceDescriptor can be used on the Layers IPDL protocol, but
   // must be released explicitly using DeallocateSurfaceDescriptorGPUVideo
   // on the manager protocol.
   async Output(VideoDataIPDL data);
   async InputExhausted();
   async DrainComplete();
--- a/dom/media/ipc/RemoteDecoderChild.cpp
+++ b/dom/media/ipc/RemoteDecoderChild.cpp
@@ -32,16 +32,17 @@ mozilla::ipc::IPCResult RemoteDecoderChi
 }
 
 mozilla::ipc::IPCResult RemoteDecoderChild::RecvError(const nsresult& aError) {
   AssertOnManagerThread();
   mDecodedData = MediaDataDecoder::DecodedData();
   mDecodePromise.RejectIfExists(aError, __func__);
   mDrainPromise.RejectIfExists(aError, __func__);
   mFlushPromise.RejectIfExists(aError, __func__);
+  mShutdownPromise.RejectIfExists(false, __func__);
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult RemoteDecoderChild::RecvInitComplete(
     const TrackInfo::TrackType& trackType, const nsCString& aDecoderDescription,
     const ConversionRequired& aConversion) {
   AssertOnManagerThread();
   mInitPromise.ResolveIfExists(trackType, __func__);
@@ -59,16 +60,22 @@ mozilla::ipc::IPCResult RemoteDecoderChi
 }
 
 mozilla::ipc::IPCResult RemoteDecoderChild::RecvFlushComplete() {
   AssertOnManagerThread();
   mFlushPromise.ResolveIfExists(true, __func__);
   return IPC_OK();
 }
 
+mozilla::ipc::IPCResult RemoteDecoderChild::RecvShutdownComplete() {
+  AssertOnManagerThread();
+  mShutdownPromise.ResolveIfExists(true, __func__);
+  return IPC_OK();
+}
+
 void RemoteDecoderChild::ActorDestroy(ActorDestroyReason aWhy) {
   mCanSend = false;
 }
 
 void RemoteDecoderChild::DestroyIPDL() {
   if (mCanSend) {
     PRemoteDecoderChild::Send__delete__(this);
   }
@@ -137,23 +144,25 @@ RefPtr<MediaDataDecoder::DecodePromise> 
   if (!mCanSend) {
     return MediaDataDecoder::DecodePromise::CreateAndReject(
         NS_ERROR_DOM_MEDIA_DECODE_ERR, __func__);
   }
   SendDrain();
   return mDrainPromise.Ensure(__func__);
 }
 
-void RemoteDecoderChild::Shutdown() {
+RefPtr<ShutdownPromise> RemoteDecoderChild::Shutdown() {
   AssertOnManagerThread();
   mInitPromise.RejectIfExists(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
-  if (mCanSend) {
-    SendShutdown();
+  if (!mCanSend) {
+    return ShutdownPromise::CreateAndReject(false, __func__);
   }
+  SendShutdown();
   mInitialized = false;
+  return mShutdownPromise.Ensure(__func__);
 }
 
 bool RemoteDecoderChild::IsHardwareAccelerated(
     nsACString& aFailureReason) const {
   AssertOnManagerThread();
   aFailureReason = mHardwareAcceleratedReason;
   return mIsHardwareAccelerated;
 }
--- a/dom/media/ipc/RemoteDecoderChild.h
+++ b/dom/media/ipc/RemoteDecoderChild.h
@@ -26,26 +26,27 @@ class RemoteDecoderChild : public PRemot
   IPCResult RecvInputExhausted();
   IPCResult RecvDrainComplete();
   IPCResult RecvError(const nsresult& aError);
   IPCResult RecvInitComplete(const TrackInfo::TrackType& trackType,
                              const nsCString& aDecoderDescription,
                              const ConversionRequired& aConversion);
   IPCResult RecvInitFailed(const nsresult& aReason);
   IPCResult RecvFlushComplete();
+  IPCResult RecvShutdownComplete();
 
   void ActorDestroy(ActorDestroyReason aWhy) override;
 
   // IRemoteDecoderChild
   RefPtr<MediaDataDecoder::InitPromise> Init() override;
   RefPtr<MediaDataDecoder::DecodePromise> Decode(
       MediaRawData* aSample) override;
   RefPtr<MediaDataDecoder::DecodePromise> Drain() override;
   RefPtr<MediaDataDecoder::FlushPromise> Flush() override;
-  void Shutdown() override;
+  RefPtr<ShutdownPromise> Shutdown() override;
   bool IsHardwareAccelerated(nsACString& aFailureReason) const override;
   nsCString GetDescriptionName() const override;
   void SetSeekThreshold(const media::TimeUnit& aTime) override;
   MediaDataDecoder::ConversionRequired NeedsConversion() const override;
   void DestroyIPDL() override;
 
   // Called from IPDL when our actor has been destroyed
   void IPDLActorDestroyed();
@@ -62,16 +63,17 @@ class RemoteDecoderChild : public PRemot
 
  private:
   RefPtr<nsIThread> mThread;
 
   MozPromiseHolder<MediaDataDecoder::InitPromise> mInitPromise;
   MozPromiseHolder<MediaDataDecoder::DecodePromise> mDecodePromise;
   MozPromiseHolder<MediaDataDecoder::DecodePromise> mDrainPromise;
   MozPromiseHolder<MediaDataDecoder::FlushPromise> mFlushPromise;
+  MozPromiseHolder<ShutdownPromise> mShutdownPromise;
 
   nsCString mHardwareAcceleratedReason;
   nsCString mDescription;
   bool mInitialized = false;
   bool mIsHardwareAccelerated = false;
   MediaDataDecoder::ConversionRequired mConversion =
       MediaDataDecoder::ConversionRequired::kNeedNone;
 };
--- a/dom/media/ipc/RemoteDecoderParent.cpp
+++ b/dom/media/ipc/RemoteDecoderParent.cpp
@@ -133,17 +133,28 @@ mozilla::ipc::IPCResult RemoteDecoderPar
       [self](const MediaResult& aError) { self->Error(aError); });
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult RemoteDecoderParent::RecvShutdown() {
   MOZ_ASSERT(!mDestroyed);
   MOZ_ASSERT(OnManagerThread());
   if (mDecoder) {
-    mDecoder->Shutdown();
+    RefPtr<RemoteDecoderParent> self = this;
+    mDecoder->Shutdown()->Then(
+        mManagerTaskQueue, __func__,
+        [self](const ShutdownPromise::ResolveOrRejectValue& aValue) {
+          if (aValue.IsResolve()) {
+            if (!self->mDestroyed) {
+              Unused << self->SendShutdownComplete();
+            }
+          } else {
+            self->Error(NS_ERROR_DOM_MEDIA_DECODE_ERR);
+          }
+        });
   }
   mDecoder = nullptr;
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult RemoteDecoderParent::RecvSetSeekThreshold(
     const TimeUnit& aTime) {
   MOZ_ASSERT(!mDestroyed);
@@ -151,17 +162,28 @@ mozilla::ipc::IPCResult RemoteDecoderPar
   mDecoder->SetSeekThreshold(aTime);
   return IPC_OK();
 }
 
 void RemoteDecoderParent::ActorDestroy(ActorDestroyReason aWhy) {
   MOZ_ASSERT(!mDestroyed);
   MOZ_ASSERT(OnManagerThread());
   if (mDecoder) {
-    mDecoder->Shutdown();
+    RefPtr<RemoteDecoderParent> self = this;
+    mDecoder->Shutdown()->Then(
+        mManagerTaskQueue, __func__,
+        [self](const ShutdownPromise::ResolveOrRejectValue& aValue) {
+          if (aValue.IsResolve()) {
+            if (!self->mDestroyed) {
+              Unused << self->SendShutdownComplete();
+            }
+          } else {
+            self->Error(NS_ERROR_DOM_MEDIA_DECODE_ERR);
+          }
+        });
     mDecoder = nullptr;
   }
 }
 
 void RemoteDecoderParent::Error(const MediaResult& aError) {
   MOZ_ASSERT(OnManagerThread());
   if (!mDestroyed) {
     Unused << SendError(aError);
--- a/dom/media/ipc/RemoteMediaDataDecoder.cpp
+++ b/dom/media/ipc/RemoteMediaDataDecoder.cpp
@@ -76,20 +76,23 @@ RefPtr<MediaDataDecoder::FlushPromise> R
 RefPtr<MediaDataDecoder::DecodePromise> RemoteMediaDataDecoder::Drain() {
   RefPtr<RemoteMediaDataDecoder> self = this;
   return InvokeAsync(mAbstractManagerThread, __func__,
                      [self]() { return self->mChild->Drain(); });
 }
 
 RefPtr<ShutdownPromise> RemoteMediaDataDecoder::Shutdown() {
   RefPtr<RemoteMediaDataDecoder> self = this;
-  return InvokeAsync(mAbstractManagerThread, __func__, [self]() {
-    self->mChild->Shutdown();
-    return ShutdownPromise::CreateAndResolve(true, __func__);
-  });
+  return InvokeAsync(mAbstractManagerThread, __func__,
+                     [self]() { return self->mChild->Shutdown(); })
+      ->Then(mAbstractManagerThread, __func__,
+             [self](const ShutdownPromise::ResolveOrRejectValue& aValue) {
+               return ShutdownPromise::CreateAndResolveOrReject(aValue,
+                                                                __func__);
+             });
 }
 
 bool RemoteMediaDataDecoder::IsHardwareAccelerated(
     nsACString& aFailureReason) const {
   aFailureReason = mHardwareAcceleratedReason;
   return mIsHardwareAccelerated;
 }
 
--- a/dom/media/ipc/VideoDecoderChild.cpp
+++ b/dom/media/ipc/VideoDecoderChild.cpp
@@ -110,16 +110,22 @@ mozilla::ipc::IPCResult VideoDecoderChil
 }
 
 mozilla::ipc::IPCResult VideoDecoderChild::RecvFlushComplete() {
   AssertOnManagerThread();
   mFlushPromise.ResolveIfExists(true, __func__);
   return IPC_OK();
 }
 
+mozilla::ipc::IPCResult VideoDecoderChild::RecvShutdownComplete() {
+  AssertOnManagerThread();
+  mShutdownPromise.ResolveIfExists(true, __func__);
+  return IPC_OK();
+}
+
 void VideoDecoderChild::ActorDestroy(ActorDestroyReason aWhy) {
   if (aWhy == AbnormalShutdown) {
     // GPU process crashed, record the time and send back to MFR for telemetry.
     mGPUCrashTime = TimeStamp::Now();
 
     // Defer reporting an error until we've recreated the manager so that
     // it'll be safe for MediaFormatReader to recreate decoders
     RefPtr<VideoDecoderChild> ref = this;
@@ -271,23 +277,30 @@ RefPtr<MediaDataDecoder::DecodePromise> 
     return MediaDataDecoder::DecodePromise::CreateAndReject(error, __func__);
   }
   if (mCanSend) {
     SendDrain();
   }
   return mDrainPromise.Ensure(__func__);
 }
 
-void VideoDecoderChild::Shutdown() {
+RefPtr<ShutdownPromise> VideoDecoderChild::Shutdown() {
   AssertOnManagerThread();
   mInitPromise.RejectIfExists(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
-  if (mCanSend) {
-    SendShutdown();
+  if (mNeedNewDecoder) {
+    MediaResult error(NS_ERROR_DOM_MEDIA_NEED_NEW_DECODER);
+    error.SetGPUCrashTimeStamp(mGPUCrashTime);
+    return ShutdownPromise::CreateAndReject(false, __func__);
   }
+  if (!mCanSend) {
+    return ShutdownPromise::CreateAndReject(false, __func__);
+  }
+  SendShutdown();
   mInitialized = false;
+  return mShutdownPromise.Ensure(__func__);
 }
 
 bool VideoDecoderChild::IsHardwareAccelerated(
     nsACString& aFailureReason) const {
   AssertOnManagerThread();
   aFailureReason = mHardwareAcceleratedReason;
   return mIsHardwareAccelerated;
 }
--- a/dom/media/ipc/VideoDecoderChild.h
+++ b/dom/media/ipc/VideoDecoderChild.h
@@ -31,25 +31,26 @@ class VideoDecoderChild final : public P
   IPCResult RecvDrainComplete();
   IPCResult RecvError(const nsresult& aError);
   IPCResult RecvInitComplete(const nsCString& aDecoderDescription,
                              const bool& aHardware,
                              const nsCString& aHardwareReason,
                              const uint32_t& aConversion);
   IPCResult RecvInitFailed(const nsresult& aReason);
   IPCResult RecvFlushComplete();
+  IPCResult RecvShutdownComplete();
 
   void ActorDestroy(ActorDestroyReason aWhy) override;
 
   RefPtr<MediaDataDecoder::InitPromise> Init() override;
   RefPtr<MediaDataDecoder::DecodePromise> Decode(
       MediaRawData* aSample) override;
   RefPtr<MediaDataDecoder::DecodePromise> Drain() override;
   RefPtr<MediaDataDecoder::FlushPromise> Flush() override;
-  void Shutdown() override;
+  RefPtr<ShutdownPromise> Shutdown() override;
   bool IsHardwareAccelerated(nsACString& aFailureReason) const override;
   nsCString GetDescriptionName() const override;
   void SetSeekThreshold(const media::TimeUnit& aTime) override;
   MediaDataDecoder::ConversionRequired NeedsConversion() const override;
   void DestroyIPDL() override;
 
   MOZ_IS_CLASS_INIT
   MediaResult InitIPDL(const VideoInfo& aVideoInfo, float aFramerate,
@@ -68,16 +69,17 @@ class VideoDecoderChild final : public P
 
   RefPtr<VideoDecoderChild> mIPDLSelfRef;
   RefPtr<nsIThread> mThread;
 
   MozPromiseHolder<MediaDataDecoder::InitPromise> mInitPromise;
   MozPromiseHolder<MediaDataDecoder::DecodePromise> mDecodePromise;
   MozPromiseHolder<MediaDataDecoder::DecodePromise> mDrainPromise;
   MozPromiseHolder<MediaDataDecoder::FlushPromise> mFlushPromise;
+  MozPromiseHolder<ShutdownPromise> mShutdownPromise;
 
   nsCString mHardwareAcceleratedReason;
   nsCString mDescription;
   bool mCanSend;
   bool mInitialized;
   bool mIsHardwareAccelerated;
   MediaDataDecoder::ConversionRequired mConversion;
 
--- a/dom/media/ipc/VideoDecoderParent.cpp
+++ b/dom/media/ipc/VideoDecoderParent.cpp
@@ -238,17 +238,28 @@ mozilla::ipc::IPCResult VideoDecoderPare
       [self](const MediaResult& aError) { self->Error(aError); });
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult VideoDecoderParent::RecvShutdown() {
   MOZ_ASSERT(!mDestroyed);
   MOZ_ASSERT(OnManagerThread());
   if (mDecoder) {
-    mDecoder->Shutdown();
+    RefPtr<VideoDecoderParent> self = this;
+    mDecoder->Shutdown()->Then(
+        mManagerTaskQueue, __func__,
+        [self](const ShutdownPromise::ResolveOrRejectValue& aValue) {
+          if (aValue.IsResolve()) {
+            if (!self->mDestroyed) {
+              Unused << self->SendShutdownComplete();
+            }
+          } else {
+            self->Error(NS_ERROR_DOM_MEDIA_DECODE_ERR);
+          }
+        });
   }
   mDecoder = nullptr;
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult VideoDecoderParent::RecvSetSeekThreshold(
     const TimeUnit& aTime) {
   MOZ_ASSERT(!mDestroyed);
@@ -256,22 +267,30 @@ mozilla::ipc::IPCResult VideoDecoderPare
   mDecoder->SetSeekThreshold(aTime);
   return IPC_OK();
 }
 
 void VideoDecoderParent::ActorDestroy(ActorDestroyReason aWhy) {
   MOZ_ASSERT(!mDestroyed);
   MOZ_ASSERT(OnManagerThread());
   if (mDecoder) {
-    mDecoder->Shutdown();
+    RefPtr<VideoDecoderParent> self = this;
+    mDecoder->Shutdown()->Then(
+        mManagerTaskQueue, __func__,
+        [self](const ShutdownPromise::ResolveOrRejectValue& aValue) {
+          if (aValue.IsResolve()) {
+            if (!self->mDestroyed) {
+              Unused << self->SendShutdownComplete();
+            }
+          } else {
+            self->Error(NS_ERROR_DOM_MEDIA_DECODE_ERR);
+          }
+        });
     mDecoder = nullptr;
   }
-  if (mDecodeTaskQueue) {
-    mDecodeTaskQueue->BeginShutdown();
-  }
 }
 
 void VideoDecoderParent::Error(const MediaResult& aError) {
   MOZ_ASSERT(OnManagerThread());
   if (!mDestroyed) {
     Unused << SendError(aError);
   }
 }