Bug 1162358 - Defer processing GMP DecodingComplete() calls until intr shmem allocs are finished. r=jesup
authorChris Pearce <cpearce@mozilla.com>
Fri, 08 May 2015 13:36:34 +1200
changeset 274281 b0ebc8d237f08cff537ed569a7e7f1a5eb0d6deb
parent 274280 03dc784d54560da7a828b1b7ec5a3654507a31d5
child 274282 34d3296e698003390af28ba07353b7a09c16ca4e
push id863
push userraliiev@mozilla.com
push dateMon, 03 Aug 2015 13:22:43 +0000
treeherdermozilla-release@f6321b14228d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjesup
bugs1162358
milestone40.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 1162358 - Defer processing GMP DecodingComplete() calls until intr shmem allocs are finished. r=jesup
dom/media/gmp/GMPContentChild.cpp
dom/media/gmp/GMPVideoDecoderChild.cpp
dom/media/gmp/GMPVideoDecoderChild.h
--- a/dom/media/gmp/GMPContentChild.cpp
+++ b/dom/media/gmp/GMPContentChild.cpp
@@ -73,23 +73,25 @@ GMPContentChild::DeallocPGMPDecryptorChi
 {
   static_cast<GMPDecryptorChild*>(aActor)->Release();
   return true;
 }
 
 PGMPVideoDecoderChild*
 GMPContentChild::AllocPGMPVideoDecoderChild()
 {
-  return new GMPVideoDecoderChild(this);
+  GMPVideoDecoderChild* actor = new GMPVideoDecoderChild(this);
+  actor->AddRef();
+  return actor;
 }
 
 bool
 GMPContentChild::DeallocPGMPVideoDecoderChild(PGMPVideoDecoderChild* aActor)
 {
-  delete aActor;
+  static_cast<GMPVideoDecoderChild*>(aActor)->Release();
   return true;
 }
 
 PGMPVideoEncoderChild*
 GMPContentChild::AllocPGMPVideoEncoderChild()
 {
   return new GMPVideoEncoderChild(this);
 }
--- 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 "GMPContentChild.h"
 #include <stdio.h>
 #include "mozilla/unused.h"
 #include "GMPVideoEncodedFrameImpl.h"
+#include "runnable_utils.h"
 
 namespace mozilla {
 namespace gmp {
 
 GMPVideoDecoderChild::GMPVideoDecoderChild(GMPContentChild* 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 GMPContentChild;
 
 class GMPVideoDecoderChild : public PGMPVideoDecoderChild,
                              public GMPVideoDecoderCallback,
                              public GMPSharedMemManager
 {
 public:
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(GMPVideoDecoderChild);
+
   explicit GMPVideoDecoderChild(GMPContentChild* 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;
 
   GMPContentChild* 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_