Bug 1162358 - Defer processing GMP DecodingComplete() calls until intr shmem allocs are finished. r=jesup, a=lizzard
authorChris Pearce <cpearce@mozilla.com>
Fri, 08 May 2015 13:36:34 +1200
changeset 267482 b0cc8cf43e9281ad174e6c48d46582121c68c45a
parent 267481 3bb36b3ef64e408a3123eee2d617af6e68cde2ca
child 267483 1e919db8738fcc93c1f8dcd6cb3787496a895a0d
push id830
push userraliiev@mozilla.com
push dateFri, 19 Jun 2015 19:24:37 +0000
treeherdermozilla-release@932614382a68 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjesup, lizzard
bugs1162358
milestone39.0
Bug 1162358 - Defer processing GMP DecodingComplete() calls until intr shmem allocs are finished. r=jesup, a=lizzard
dom/media/gmp/GMPChild.cpp
dom/media/gmp/GMPVideoDecoderChild.cpp
dom/media/gmp/GMPVideoDecoderChild.h
--- a/dom/media/gmp/GMPChild.cpp
+++ b/dom/media/gmp/GMPChild.cpp
@@ -532,23 +532,25 @@ GMPChild::DeallocPCrashReporterChild(PCr
 {
   delete aCrashReporter;
   return true;
 }
 
 PGMPVideoDecoderChild*
 GMPChild::AllocPGMPVideoDecoderChild()
 {
-  return new GMPVideoDecoderChild(this);
+  GMPVideoDecoderChild* actor = new GMPVideoDecoderChild(this);
+  actor->AddRef();
+  return actor;
 }
 
 bool
 GMPChild::DeallocPGMPVideoDecoderChild(PGMPVideoDecoderChild* aActor)
 {
-  delete aActor;
+  static_cast<GMPVideoDecoderChild*>(aActor)->Release();
   return true;
 }
 
 PGMPDecryptorChild*
 GMPChild::AllocPGMPDecryptorChild()
 {
   GMPDecryptorChild* actor = new GMPDecryptorChild(this, mPluginVoucher, mSandboxVoucher);
   actor->AddRef();
--- a/dom/media/gmp/GMPVideoDecoderChild.cpp
+++ b/dom/media/gmp/GMPVideoDecoderChild.cpp
@@ -4,31 +4,35 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "GMPVideoDecoderChild.h"
 #include "GMPVideoi420FrameImpl.h"
 #include "GMPChild.h"
 #include <stdio.h>
 #include "mozilla/unused.h"
 #include "GMPVideoEncodedFrameImpl.h"
+#include "runnable_utils.h"
 
 namespace mozilla {
 namespace gmp {
 
 GMPVideoDecoderChild::GMPVideoDecoderChild(GMPChild* aPlugin)
-: GMPSharedMemManager(aPlugin),
-  mPlugin(aPlugin),
-  mVideoDecoder(nullptr),
-  mVideoHost(this)
+  : GMPSharedMemManager(aPlugin)
+  , mPlugin(aPlugin)
+  , mVideoDecoder(nullptr)
+  , mVideoHost(this)
+  , mNeedShmemIntrCount(0)
+  , mPendingDecodeComplete(false)
 {
   MOZ_ASSERT(mPlugin);
 }
 
 GMPVideoDecoderChild::~GMPVideoDecoderChild()
 {
+  MOZ_ASSERT(!mNeedShmemIntrCount);
 }
 
 void
 GMPVideoDecoderChild::Init(GMPVideoDecoder* aDecoder)
 {
   MOZ_ASSERT(aDecoder, "Cannot initialize video decoder child without a video decoder!");
   mVideoDecoder = aDecoder;
 }
@@ -179,25 +183,71 @@ GMPVideoDecoderChild::RecvDrain()
   mVideoDecoder->Drain();
 
   return true;
 }
 
 bool
 GMPVideoDecoderChild::RecvDecodingComplete()
 {
+  MOZ_ASSERT(mPlugin->GMPMessageLoop() == MessageLoop::current());
+
+  if (mNeedShmemIntrCount) {
+    // There's a GMP blocked in Alloc() waiting for the CallNeedShem() to
+    // return a frame they can use. Don't call the GMP's DecodingComplete()
+    // now and don't delete the GMPVideoDecoderChild, defer processing the
+    // DecodingComplete() until once the Alloc() finishes.
+    mPendingDecodeComplete = true;
+    return true;
+  }
   if (mVideoDecoder) {
     // Ignore any return code. It is OK for this to fail without killing the process.
     mVideoDecoder->DecodingComplete();
     mVideoDecoder = nullptr;
   }
 
   mVideoHost.DoneWithAPI();
 
   mPlugin = nullptr;
 
   unused << Send__delete__(this);
 
   return true;
 }
 
+bool
+GMPVideoDecoderChild::Alloc(size_t aSize,
+                            Shmem::SharedMemory::SharedMemoryType aType,
+                            Shmem* aMem)
+{
+  MOZ_ASSERT(mPlugin->GMPMessageLoop() == MessageLoop::current());
+
+  bool rv;
+#ifndef SHMEM_ALLOC_IN_CHILD
+  ++mNeedShmemIntrCount;
+  rv = CallNeedShmem(aSize, aMem);
+  --mNeedShmemIntrCount;
+  if (mPendingDecodeComplete) {
+    auto t = NewRunnableMethod(this, &GMPVideoDecoderChild::RecvDecodingComplete);
+    mPlugin->GMPMessageLoop()->PostTask(FROM_HERE, t);
+  }
+#else
+#ifdef GMP_SAFE_SHMEM
+  rv = AllocShmem(aSize, aType, aMem);
+#else
+  rv = AllocUnsafeShmem(aSize, aType, aMem);
+#endif
+#endif
+  return rv;
+}
+
+void
+GMPVideoDecoderChild::Dealloc(Shmem& aMem)
+{
+#ifndef SHMEM_ALLOC_IN_CHILD
+  SendParentShmemForPool(aMem);
+#else
+  DeallocShmem(aMem);
+#endif
+}
+
 } // namespace gmp
 } // namespace mozilla
--- a/dom/media/gmp/GMPVideoDecoderChild.h
+++ b/dom/media/gmp/GMPVideoDecoderChild.h
@@ -18,68 +18,58 @@ namespace gmp {
 
 class GMPChild;
 
 class GMPVideoDecoderChild : public PGMPVideoDecoderChild,
                              public GMPVideoDecoderCallback,
                              public GMPSharedMemManager
 {
 public:
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(GMPVideoDecoderChild);
+
   explicit GMPVideoDecoderChild(GMPChild* aPlugin);
-  virtual ~GMPVideoDecoderChild();
 
   void Init(GMPVideoDecoder* aDecoder);
   GMPVideoHostImpl& Host();
 
   // GMPVideoDecoderCallback
   virtual void Decoded(GMPVideoi420Frame* decodedFrame) override;
   virtual void ReceivedDecodedReferenceFrame(const uint64_t pictureId) override;
   virtual void ReceivedDecodedFrame(const uint64_t pictureId) override;
   virtual void InputDataExhausted() override;
   virtual void DrainComplete() override;
   virtual void ResetComplete() override;
   virtual void Error(GMPErr aError) override;
 
   // GMPSharedMemManager
-  virtual bool Alloc(size_t aSize, Shmem::SharedMemory::SharedMemoryType aType, Shmem* aMem) override
-  {
-#ifndef SHMEM_ALLOC_IN_CHILD
-    return CallNeedShmem(aSize, aMem);
-#else
-#ifdef GMP_SAFE_SHMEM
-    return AllocShmem(aSize, aType, aMem);
-#else
-    return AllocUnsafeShmem(aSize, aType, aMem);
-#endif
-#endif
-  }
-  virtual void Dealloc(Shmem& aMem) override
-  {
-#ifndef SHMEM_ALLOC_IN_CHILD
-    SendParentShmemForPool(aMem);
-#else
-    DeallocShmem(aMem);
-#endif
-  }
+  virtual bool Alloc(size_t aSize, Shmem::SharedMemory::SharedMemoryType aType, Shmem* aMem) override;
+  virtual void Dealloc(Shmem& aMem) override;
 
 private:
+  virtual ~GMPVideoDecoderChild();
+
   // PGMPVideoDecoderChild
   virtual bool RecvInitDecode(const GMPVideoCodec& aCodecSettings,
                               InfallibleTArray<uint8_t>&& aCodecSpecific,
                               const int32_t& aCoreCount) override;
   virtual bool RecvDecode(const GMPVideoEncodedFrameData& aInputFrame,
                           const bool& aMissingFrames,
                           InfallibleTArray<uint8_t>&& aCodecSpecificInfo,
                           const int64_t& aRenderTimeMs) override;
   virtual bool RecvChildShmemForPool(Shmem&& aFrameBuffer) override;
   virtual bool RecvReset() override;
   virtual bool RecvDrain() override;
   virtual bool RecvDecodingComplete() override;
 
   GMPChild* mPlugin;
   GMPVideoDecoder* mVideoDecoder;
   GMPVideoHostImpl mVideoHost;
+
+  // Non-zero when a GMP is blocked spinning the IPC message loop while
+  // waiting on an NeedShmem to complete.
+  int mNeedShmemIntrCount;
+  bool mPendingDecodeComplete;
 };
 
 } // namespace gmp
 } // namespace mozilla
 
 #endif // GMPVideoDecoderChild_h_