Bug 1331944 - Part 1. Add SourceSurfaceSharedDataWrapper and SourceSurfaceSharedData::HandleLock. r=jrmuizel
☠☠ backed out by 719f1c2189d2 ☠ ☠
authorAndrew Osmond <aosmond@mozilla.com>
Mon, 30 Oct 2017 09:10:44 -0400
changeset 389005 7e1da430d9f9323ef4fd0690459fd87c8d1ba0ef
parent 389004 97415d233c163fc85ca33edc0c9aaaf0a3d473a6
child 389006 83cc1f67e9f78482484d8945e6caed4517810dcf
push id96759
push useraosmond@gmail.com
push dateMon, 30 Oct 2017 13:11:04 +0000
treeherdermozilla-inbound@7c56a10468d7 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjrmuizel
bugs1331944
milestone58.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 1331944 - Part 1. Add SourceSurfaceSharedDataWrapper and SourceSurfaceSharedData::HandleLock. r=jrmuizel
gfx/layers/SourceSurfaceSharedData.cpp
gfx/layers/SourceSurfaceSharedData.h
--- a/gfx/layers/SourceSurfaceSharedData.cpp
+++ b/gfx/layers/SourceSurfaceSharedData.cpp
@@ -7,16 +7,53 @@
 
 #include "mozilla/Likely.h"
 #include "mozilla/Types.h" // for decltype
 
 namespace mozilla {
 namespace gfx {
 
 bool
+SourceSurfaceSharedDataWrapper::Init(const IntSize& aSize,
+                                     int32_t aStride,
+                                     SurfaceFormat aFormat,
+                                     const SharedMemoryBasic::Handle& aHandle,
+                                     base::ProcessId aCreatorPid)
+{
+  MOZ_ASSERT(!mBuf);
+  mSize = aSize;
+  mStride = aStride;
+  mFormat = aFormat;
+  mCreatorPid = aCreatorPid;
+
+  size_t len = GetAlignedDataLength();
+  mBuf = new SharedMemoryBasic();
+  if (NS_WARN_IF(!mBuf->SetHandle(aHandle, ipc::SharedMemory::RightsReadOnly)) ||
+      NS_WARN_IF(!mBuf->Map(len))) {
+    mBuf = nullptr;
+    return false;
+  }
+
+  mBuf->CloseHandle();
+  return true;
+}
+
+void
+SourceSurfaceSharedDataWrapper::Init(SourceSurfaceSharedData* aSurface)
+{
+  MOZ_ASSERT(!mBuf);
+  MOZ_ASSERT(aSurface);
+  mSize = aSurface->mSize;
+  mStride = aSurface->mStride;
+  mFormat = aSurface->mFormat;
+  mCreatorPid = base::GetCurrentProcId();
+  mBuf = aSurface->mBuf;
+}
+
+bool
 SourceSurfaceSharedData::Init(const IntSize &aSize,
                               int32_t aStride,
                               SurfaceFormat aFormat)
 {
   mSize = aSize;
   mStride = aStride;
   mFormat = aFormat;
 
@@ -62,16 +99,17 @@ SourceSurfaceSharedData::GetDataInternal
   return static_cast<uint8_t*>(mBuf->memory());
 }
 
 nsresult
 SourceSurfaceSharedData::ShareToProcess(base::ProcessId aPid,
                                         SharedMemoryBasic::Handle& aHandle)
 {
   MutexAutoLock lock(mMutex);
+  MOZ_ASSERT(mHandleCount > 0);
 
   if (mClosed) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   bool shared = mBuf->ShareToProcess(aPid, &aHandle);
   if (MOZ_UNLIKELY(!shared)) {
     return NS_ERROR_FAILURE;
@@ -81,29 +119,33 @@ SourceSurfaceSharedData::ShareToProcess(
 }
 
 void
 SourceSurfaceSharedData::CloseHandleInternal()
 {
   mMutex.AssertCurrentThreadOwns();
 
   if (mClosed) {
+    MOZ_ASSERT(mHandleCount == 0);
+    MOZ_ASSERT(mFinalized);
+    MOZ_ASSERT(mShared);
     return;
   }
 
   if (mFinalized && mShared) {
     mBuf->CloseHandle();
     mClosed = true;
   }
 }
 
 bool
 SourceSurfaceSharedData::ReallocHandle()
 {
   MutexAutoLock lock(mMutex);
+  MOZ_ASSERT(mHandleCount > 0);
   MOZ_ASSERT(mClosed);
   MOZ_ASSERT(mFinalized);
 
   size_t len = GetAlignedDataLength();
   RefPtr<SharedMemoryBasic> buf = new SharedMemoryBasic();
   if (NS_WARN_IF(!buf->Create(len)) ||
       NS_WARN_IF(!buf->Map(len))) {
     return false;
--- a/gfx/layers/SourceSurfaceSharedData.h
+++ b/gfx/layers/SourceSurfaceSharedData.h
@@ -8,39 +8,123 @@
 
 #include "mozilla/gfx/2D.h"
 #include "mozilla/Mutex.h"
 #include "mozilla/ipc/SharedMemoryBasic.h"
 
 namespace mozilla {
 namespace gfx {
 
+class SourceSurfaceSharedData;
+
+class SourceSurfaceSharedDataWrapper final : public DataSourceSurface
+{
+  typedef mozilla::ipc::SharedMemoryBasic SharedMemoryBasic;
+
+public:
+  MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(SourceSurfaceSharedDataWrapper, override)
+
+  SourceSurfaceSharedDataWrapper()
+    : mStride(0)
+    , mFormat(SurfaceFormat::UNKNOWN)
+  { }
+
+  bool Init(const IntSize& aSize,
+            int32_t aStride,
+            SurfaceFormat aFormat,
+            const SharedMemoryBasic::Handle& aHandle,
+            base::ProcessId aCreatorPid);
+
+  void Init(SourceSurfaceSharedData *aSurface);
+
+  base::ProcessId GetCreatorPid() const
+  {
+    return mCreatorPid;
+  }
+
+  int32_t Stride() override { return mStride; }
+
+  SurfaceType GetType() const override { return SurfaceType::DATA; }
+  IntSize GetSize() const override { return mSize; }
+  SurfaceFormat GetFormat() const override { return mFormat; }
+
+  uint8_t* GetData() override
+  {
+    return static_cast<uint8_t*>(mBuf->memory());
+  }
+
+  bool OnHeap() const override
+  {
+    return false;
+  }
+
+  bool Map(MapType, MappedSurface *aMappedSurface) override
+  {
+    aMappedSurface->mData = GetData();
+    aMappedSurface->mStride = mStride;
+    return true;
+  }
+
+  void Unmap() override
+  { }
+
+  bool AddConsumer()
+  {
+    return ++mConsumers == 1;
+  }
+
+  bool RemoveConsumer()
+  {
+    MOZ_ASSERT(mConsumers > 0);
+    return --mConsumers == 0;
+  }
+
+private:
+  size_t GetDataLength() const
+  {
+    return static_cast<size_t>(mStride) * mSize.height;
+  }
+
+  size_t GetAlignedDataLength() const
+  {
+    return mozilla::ipc::SharedMemory::PageAlignedSize(GetDataLength());
+  }
+
+  int32_t mStride;
+  uint32_t mConsumers;
+  IntSize mSize;
+  RefPtr<SharedMemoryBasic> mBuf;
+  SurfaceFormat mFormat;
+  base::ProcessId mCreatorPid;
+};
+
 /**
  * This class is used to wrap shared (as in process) data buffers used by a
  * source surface.
  */
 class SourceSurfaceSharedData final : public DataSourceSurface
 {
   typedef mozilla::ipc::SharedMemoryBasic SharedMemoryBasic;
 
 public:
   MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(SourceSurfaceSharedData, override)
 
   SourceSurfaceSharedData()
     : mMutex("SourceSurfaceSharedData")
     , mStride(0)
     , mMapCount(0)
+    , mHandleCount(0)
     , mFormat(SurfaceFormat::UNKNOWN)
     , mClosed(false)
     , mFinalized(false)
     , mShared(false)
   {
   }
 
-  bool Init(const IntSize &aSize,
+  bool Init(const IntSize& aSize,
             int32_t aStride,
             SurfaceFormat aFormat);
 
   uint8_t* GetData() override
   {
     MutexAutoLock lock(mMutex);
     return GetDataInternal();
   }
@@ -128,27 +212,75 @@ public:
    * Allocate a new shared memory buffer so that we can get a new handle for
    * sharing to new processes. ShareToProcess must have failed with
    * NS_ERROR_NOT_AVAILABLE in order for this to be safe to call. Returns true
    * if the operation succeeds. If it fails, there is no state change.
    */
   bool ReallocHandle();
 
   /**
-   * Indicates we have finished writing to the buffer and it may be marked as
+   * Signals we have finished writing to the buffer and it may be marked as
    * read only. May release the handle if possible (see CloseHandleInternal).
    */
   void Finalize();
 
+  /**
+   * Indicates whether or not the buffer can change. If this returns true, it is
+   * guaranteed to continue to do so for the remainder of the surface's life.
+   */
+  bool IsFinalized() const
+  {
+    MutexAutoLock lock(mMutex);
+    return mFinalized;
+  }
+
+  /**
+   * While a HandleLock exists for the given surface, the shared memory handle
+   * cannot be released.
+   */
+  class MOZ_STACK_CLASS HandleLock final {
+  public:
+    explicit HandleLock(SourceSurfaceSharedData* aSurface)
+      : mSurface(aSurface)
+    {
+      mSurface->LockHandle();
+    }
+
+    ~HandleLock()
+    {
+      mSurface->UnlockHandle();
+    }
+
+  private:
+    RefPtr<SourceSurfaceSharedData> mSurface;
+  };
+
 private:
+  friend class SourceSurfaceSharedDataWrapper;
+
   ~SourceSurfaceSharedData() override
   {
     MOZ_ASSERT(mMapCount == 0);
   }
 
+  void LockHandle()
+  {
+    MutexAutoLock lock(mMutex);
+    ++mHandleCount;
+  }
+
+  void UnlockHandle()
+  {
+    MutexAutoLock lock(mMutex);
+    MOZ_ASSERT(mHandleCount > 0);
+    --mHandleCount;
+    mShared = true;
+    CloseHandleInternal();
+  }
+
   uint8_t* GetDataInternal() const;
 
   size_t GetDataLength() const
   {
     return static_cast<size_t>(mStride) * mSize.height;
   }
 
   size_t GetAlignedDataLength() const
@@ -160,16 +292,17 @@ private:
    * Attempt to close the handle. Only if the buffer has been both finalized
    * and we have completed sharing will it be released.
    */
   void CloseHandleInternal();
 
   mutable Mutex mMutex;
   int32_t mStride;
   int32_t mMapCount;
+  int32_t mHandleCount;
   IntSize mSize;
   RefPtr<SharedMemoryBasic> mBuf;
   RefPtr<SharedMemoryBasic> mOldBuf;
   SurfaceFormat mFormat;
   bool mClosed : 1;
   bool mFinalized : 1;
   bool mShared : 1;
 };