Bug 1366502 - Update BufferTextureHost and RenderBufferTextureHost for video pipeline. r=sotaro
authorJerryShih <hshih@mozilla.com>
Wed, 07 Jun 2017 23:44:04 +0800
changeset 410834 b46936cf531ecac952dd3fa87918a040d8712593
parent 410833 8aee729888017908497d38bacbceca1149603596
child 410835 82db60ad7fbcdb9e5d4f4d44538b433904a0bda2
push id7391
push usermtabara@mozilla.com
push dateMon, 12 Jun 2017 13:08:53 +0000
treeherdermozilla-beta@2191d7f87e2e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssotaro
bugs1366502
milestone55.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 1366502 - Update BufferTextureHost and RenderBufferTextureHost for video pipeline. r=sotaro WR supports the planar-ycbcr image format. We turn to use the planar-ycbcr image to get rid of the software-ycbcr-to-rgb color format conversion(using libyuv) in gecko. The BufferTextureHost will use 3 image keys for SurfaceFormat::YUV format. The RenderBufferTextureHost will also use 3 DataSourceSurfaces to represent the 3 channel data in planar-ycbcr format. MozReview-Commit-ID: 3mMreSzKnMv
gfx/layers/composite/TextureHost.cpp
gfx/layers/composite/TextureHost.h
gfx/webrender_bindings/RenderBufferTextureHost.cpp
gfx/webrender_bindings/RenderBufferTextureHost.h
--- a/gfx/layers/composite/TextureHost.cpp
+++ b/gfx/layers/composite/TextureHost.cpp
@@ -552,40 +552,90 @@ BufferTextureHost::Lock()
 void
 BufferTextureHost::Unlock()
 {
   MOZ_ASSERT(mLocked);
   mLocked = false;
 }
 
 void
+BufferTextureHost::GetWRImageKeys(nsTArray<wr::ImageKey>& aImageKeys,
+                                  const std::function<wr::ImageKey()>& aImageKeyAllocator)
+{
+  MOZ_ASSERT(aImageKeys.IsEmpty());
+
+  if (GetFormat() != gfx::SurfaceFormat::YUV) {
+    // 1 image key
+    aImageKeys.AppendElement(aImageKeyAllocator());
+    MOZ_ASSERT(aImageKeys.Length() == 1);
+  } else {
+    // 3 image key
+    aImageKeys.AppendElement(aImageKeyAllocator());
+    aImageKeys.AppendElement(aImageKeyAllocator());
+    aImageKeys.AppendElement(aImageKeyAllocator());
+    MOZ_ASSERT(aImageKeys.Length() == 3);
+  }
+}
+
+void
 BufferTextureHost::AddWRImage(wr::WebRenderAPI* aAPI,
                               Range<const wr::ImageKey>& aImageKeys,
                               const wr::ExternalImageId& aExtID)
 {
-  MOZ_ASSERT(aImageKeys.length() == 1);
-  // XXX handling YUV
-  gfx::SurfaceFormat wrFormat =
-      (GetFormat() == gfx::SurfaceFormat::YUV) ? gfx::SurfaceFormat::B8G8R8A8
-                                               : GetFormat();
-  gfx::SurfaceFormat format = GetFormat();
-  uint32_t wrStride = 0;
+  if (GetFormat() != gfx::SurfaceFormat::YUV) {
+    MOZ_ASSERT(aImageKeys.length() == 1);
+
+    wr::ImageDescriptor descriptor(GetSize(),
+                                   ImageDataSerializer::ComputeRGBStride(GetFormat(), GetSize().width),
+                                   GetFormat());
+    aAPI->AddExternalImageBuffer(aImageKeys[0], descriptor, aExtID);
+  } else {
+    MOZ_ASSERT(aImageKeys.length() == 3);
 
-  if (format == gfx::SurfaceFormat::YUV) {
-    // XXX this stride is used until yuv image rendering by webrender is used.
-    // Software converted RGB buffers strides are aliened to 16
-    wrStride = gfx::GetAlignedStride<16>(GetSize().width, BytesPerPixel(gfx::SurfaceFormat::B8G8R8A8));
+    const layers::YCbCrDescriptor& desc = mDescriptor.get_YCbCrDescriptor();
+    wr::ImageDescriptor yDescriptor(desc.ySize(), desc.ySize().width, gfx::SurfaceFormat::A8);
+    wr::ImageDescriptor cbcrDescriptor(desc.cbCrSize(), desc.cbCrSize().width, gfx::SurfaceFormat::A8);
+    aAPI->AddExternalImage(aImageKeys[0],
+                           yDescriptor,
+                           aExtID,
+                           WrExternalImageBufferType::ExternalBuffer,
+                           0);
+    aAPI->AddExternalImage(aImageKeys[1],
+                           cbcrDescriptor,
+                           aExtID,
+                           WrExternalImageBufferType::ExternalBuffer,
+                           1);
+    aAPI->AddExternalImage(aImageKeys[2],
+                           cbcrDescriptor,
+                           aExtID,
+                           WrExternalImageBufferType::ExternalBuffer,
+                           2);
+  }
+}
+
+void
+BufferTextureHost::PushExternalImage(wr::DisplayListBuilder& aBuilder,
+                                     const WrRect& aBounds,
+                                     const WrClipRegionToken aClip,
+                                     wr::ImageRendering aFilter,
+                                     Range<const wr::ImageKey>& aImageKeys)
+{
+  if (GetFormat() != gfx::SurfaceFormat::YUV) {
+    MOZ_ASSERT(aImageKeys.length() == 1);
+    aBuilder.PushImage(aBounds, aClip, aFilter, aImageKeys[0]);
   } else {
-    wrStride = ImageDataSerializer::ComputeRGBStride(format, GetSize().width);
+    MOZ_ASSERT(aImageKeys.length() == 3);
+    aBuilder.PushYCbCrPlanarImage(aBounds,
+                                  aClip,
+                                  aImageKeys[0],
+                                  aImageKeys[1],
+                                  aImageKeys[2],
+                                  WrYuvColorSpace::Rec601,
+                                  aFilter);
   }
-
-  wr::ImageDescriptor descriptor(GetSize(), wrStride, wrFormat);
-  aAPI->AddExternalImageBuffer(aImageKeys[0],
-                               descriptor,
-                               aExtID);
 }
 
 void
 TextureHost::DeserializeReadLock(const ReadLockDescriptor& aDesc,
                                  ISurfaceAllocator* aAllocator)
 {
   RefPtr<TextureReadLock> lock = TextureReadLock::Deserialize(aDesc, aAllocator);
   if (!lock) {
--- a/gfx/layers/composite/TextureHost.h
+++ b/gfx/layers/composite/TextureHost.h
@@ -711,20 +711,29 @@ public:
   virtual already_AddRefed<gfx::DataSourceSurface> GetAsSurface() override;
 
   virtual bool HasIntermediateBuffer() const override { return mHasIntermediateBuffer; }
 
   virtual BufferTextureHost* AsBufferTextureHost() override { return this; }
 
   const BufferDescriptor& GetBufferDescriptor() const { return mDescriptor; }
 
+  virtual void GetWRImageKeys(nsTArray<wr::ImageKey>& aImageKeys,
+                              const std::function<wr::ImageKey()>& aImageKeyAllocator) override;
+
   virtual void AddWRImage(wr::WebRenderAPI* aAPI,
                           Range<const wr::ImageKey>& aImageKeys,
                           const wr::ExternalImageId& aExtID) override;
 
+  virtual void PushExternalImage(wr::DisplayListBuilder& aBuilder,
+                                 const WrRect& aBounds,
+                                 const WrClipRegionToken aClip,
+                                 wr::ImageRendering aFilter,
+                                 Range<const wr::ImageKey>& aImageKeys) override;
+
 protected:
   bool Upload(nsIntRegion *aRegion = nullptr);
   bool MaybeUpload(nsIntRegion *aRegion = nullptr);
   bool EnsureWrappingTextureSource();
 
   virtual void UpdatedInternal(const nsIntRegion* aRegion = nullptr) override;
 
   BufferDescriptor mDescriptor;
--- a/gfx/webrender_bindings/RenderBufferTextureHost.cpp
+++ b/gfx/webrender_bindings/RenderBufferTextureHost.cpp
@@ -38,73 +38,106 @@ RenderBufferTextureHost::RenderBufferTex
   }
 }
 
 RenderBufferTextureHost::~RenderBufferTextureHost()
 {
   MOZ_COUNT_DTOR_INHERITED(RenderBufferTextureHost, RenderTextureHost);
 }
 
-already_AddRefed<gfx::DataSourceSurface>
-RenderBufferTextureHost::GetAsSurface()
-{
-  RefPtr<gfx::DataSourceSurface> result;
-  if (mFormat == gfx::SurfaceFormat::YUV) {
-    result = layers::ImageDataSerializer::DataSourceSurfaceFromYCbCrDescriptor(
-      GetBuffer(), mDescriptor.get_YCbCrDescriptor());
-    if (NS_WARN_IF(!result)) {
-      return nullptr;
-    }
-  } else {
-    result =
-      gfx::Factory::CreateWrappingDataSourceSurface(GetBuffer(),
-          layers::ImageDataSerializer::GetRGBStride(mDescriptor.get_RGBDescriptor()),
-        mSize, mFormat);
-  }
-  return result.forget();
-}
-
 bool
 RenderBufferTextureHost::Lock()
 {
-  MOZ_ASSERT(!mLocked);
+  if (!mLocked) {
+    if (mFormat != gfx::SurfaceFormat::YUV) {
+      mSurface = gfx::Factory::CreateWrappingDataSourceSurface(GetBuffer(),
+                                                               layers::ImageDataSerializer::GetRGBStride(mDescriptor.get_RGBDescriptor()),
+                                                               mSize,
+                                                               mFormat);
+      if (NS_WARN_IF(!mSurface)) {
+        return false;
+      }
+      if (NS_WARN_IF(!mSurface->Map(gfx::DataSourceSurface::MapType::READ_WRITE, &mMap))) {
+        mSurface = nullptr;
+        return false;
+      }
+    } else {
+      const layers::YCbCrDescriptor& desc = mDescriptor.get_YCbCrDescriptor();
 
-  // XXX temporal workaround for YUV handling
-  if (!mSurface) {
-    mSurface = GetAsSurface();
-    if (!mSurface) {
-      return false;
+      mYSurface = gfx::Factory::CreateWrappingDataSourceSurface(layers::ImageDataSerializer::GetYChannel(GetBuffer(), desc),
+                                                                desc.ySize().width,
+                                                                desc.ySize(),
+                                                                gfx::SurfaceFormat::A8);
+      mCbSurface = gfx::Factory::CreateWrappingDataSourceSurface(layers::ImageDataSerializer::GetCbChannel(GetBuffer(), desc),
+                                                                 desc.cbCrSize().width,
+                                                                 desc.cbCrSize(),
+                                                                 gfx::SurfaceFormat::A8);
+      mCrSurface = gfx::Factory::CreateWrappingDataSourceSurface(layers::ImageDataSerializer::GetCrChannel(GetBuffer(), desc),
+                                                                 desc.cbCrSize().width,
+                                                                 desc.cbCrSize(),
+                                                                 gfx::SurfaceFormat::A8);
+      if (NS_WARN_IF(!mYSurface || !mCbSurface || !mCrSurface)) {
+        mYSurface = mCbSurface = mCrSurface = nullptr;
+        return false;
+      }
+      if (NS_WARN_IF(!mYSurface->Map(gfx::DataSourceSurface::MapType::READ_WRITE, &mYMap) ||
+                     !mCbSurface->Map(gfx::DataSourceSurface::MapType::READ_WRITE, &mCbMap) ||
+                     !mCrSurface->Map(gfx::DataSourceSurface::MapType::READ_WRITE, &mCrMap))) {
+        mYSurface = mCbSurface = mCrSurface = nullptr;
+        return false;
+      }
     }
+    mLocked = true;
   }
 
-  if (NS_WARN_IF(!mSurface->Map(gfx::DataSourceSurface::MapType::READ_WRITE, &mMap))) {
-    mSurface = nullptr;
-    return false;
-  }
-
-  mLocked = true;
   return true;
 }
 
 void
 RenderBufferTextureHost::Unlock()
 {
-  MOZ_ASSERT(mLocked);
-  mLocked = false;
-  if (mSurface) {
-    mSurface->Unmap();
+  if (mLocked) {
+    if (mSurface) {
+      mSurface->Unmap();
+      mSurface = nullptr;
+    } else if (mYSurface) {
+      mYSurface->Unmap();
+      mCbSurface->Unmap();
+      mCrSurface->Unmap();
+      mYSurface = mCbSurface = mCrSurface = nullptr;
+    }
+    mLocked = false;
   }
-  mSurface = nullptr;
 }
 
 RenderBufferTextureHost::RenderBufferData
 RenderBufferTextureHost::GetBufferDataForRender(uint8_t aChannelIndex)
 {
-  // TODO: handle multiple channel bufferTextureHost(e.g. yuv textureHost)
-  MOZ_ASSERT(aChannelIndex < 1);
+  MOZ_ASSERT(mFormat != gfx::SurfaceFormat::YUV || aChannelIndex < 3);
+  MOZ_ASSERT(mFormat == gfx::SurfaceFormat::YUV || aChannelIndex < 1);
+  MOZ_ASSERT(mLocked);
+
+  if (mFormat != gfx::SurfaceFormat::YUV) {
+    MOZ_ASSERT(mSurface);
+
+    return RenderBufferData(mMap.mData, mMap.mStride * mSurface->GetSize().height);
+  } else {
+    MOZ_ASSERT(mYSurface && mCbSurface && mCrSurface);
 
-  MOZ_ASSERT(mLocked);
-  MOZ_ASSERT(mSurface);
-  return RenderBufferData(mMap.mData, mMap.mStride * mSurface->GetSize().height);
+    switch (aChannelIndex) {
+      case 0:
+        return RenderBufferData(mYMap.mData, mYMap.mStride * mYSurface->GetSize().height);
+        break;
+      case 1:
+        return RenderBufferData(mCbMap.mData, mCbMap.mStride * mCbSurface->GetSize().height);
+        break;
+      case 2:
+        return RenderBufferData(mCrMap.mData, mCrMap.mStride * mCrSurface->GetSize().height);
+        break;
+      default:
+        MOZ_ASSERT_UNREACHABLE("unexpected to be called");
+        return RenderBufferData(nullptr, 0);
+    }
+  }
 }
 
 } // namespace wr
 } // namespace mozilla
--- a/gfx/webrender_bindings/RenderBufferTextureHost.h
+++ b/gfx/webrender_bindings/RenderBufferTextureHost.h
@@ -37,27 +37,35 @@ public:
     size_t mBufferSize;
   };
 
   RenderBufferData GetBufferDataForRender(uint8_t aChannelIndex);
 
 private:
   virtual ~RenderBufferTextureHost();
 
-  already_AddRefed<gfx::DataSourceSurface> GetAsSurface();
   uint8_t* GetBuffer() const
   {
     return mBuffer;
   }
 
   uint8_t* mBuffer;
   layers::BufferDescriptor mDescriptor;
   gfx::IntSize mSize;
   gfx::SurfaceFormat mFormat;
+
   RefPtr<gfx::DataSourceSurface> mSurface;
   gfx::DataSourceSurface::MappedSurface mMap;
+
+  RefPtr<gfx::DataSourceSurface> mYSurface;
+  RefPtr<gfx::DataSourceSurface> mCbSurface;
+  RefPtr<gfx::DataSourceSurface> mCrSurface;
+  gfx::DataSourceSurface::MappedSurface mYMap;
+  gfx::DataSourceSurface::MappedSurface mCbMap;
+  gfx::DataSourceSurface::MappedSurface mCrMap;
+
   bool mLocked;
 };
 
 } // namespace wr
 } // namespace mozilla
 
 #endif // MOZILLA_GFX_RENDERBUFFERTEXTUREHOST_H