Bug 1357299 - P3: Support DXGI texture type for WR. v2. r=nical
authorJerryShih <hshih@mozilla.com>
Mon, 07 Aug 2017 18:15:22 +0800
changeset 373158 1299e43ad52839a253cb303e2d7b0b79c45af7b0
parent 373157 9801c56ba0f6707e69dfcd981c66266eaa6c4edd
child 373159 c39eda1b5bb35091ba15405dbec8d25de1957384
push id93457
push userhshih@mozilla.com
push dateMon, 07 Aug 2017 10:16:37 +0000
treeherdermozilla-inbound@6ca40fe1ef4c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnical
bugs1357299
milestone57.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 1357299 - P3: Support DXGI texture type for WR. v2. r=nical Create the corresponding RenderTextureHost type and WR commands for DXGI texture type. The DXGITextureHostD3D11 will use 1 or 2 image keys for non-nv12 and nv12 texture format. The DXGIYCbCrTextureHostD3D11 is a special case. The WR uses ANGLE in windows platform, but the ANGLE doesn't support A8 format directx texture directly. So, we use libyuv to convert the DXGIYCbCrTextureHostD3D11 texture buffer into RGBA format buffer and use WR::AddImage() for that image. This is a slow code path. We will refine this case later. The whole RenderD3D11TextureHostOGL implementation is in the next patch. MozReview-Commit-ID: F4mPCALj1OY
gfx/layers/d3d11/TextureD3D11.cpp
gfx/layers/d3d11/TextureD3D11.h
gfx/webrender_bindings/RenderD3D11TextureHostOGL.cpp
gfx/webrender_bindings/RenderD3D11TextureHostOGL.h
gfx/webrender_bindings/RenderTextureHostOGL.h
gfx/webrender_bindings/moz.build
--- a/gfx/layers/d3d11/TextureD3D11.cpp
+++ b/gfx/layers/d3d11/TextureD3D11.cpp
@@ -11,16 +11,18 @@
 #include "gfx2DGlue.h"
 #include "gfxPrefs.h"
 #include "ReadbackManagerD3D11.h"
 #include "mozilla/gfx/DataSurfaceHelpers.h"
 #include "mozilla/gfx/DeviceManagerDx.h"
 #include "mozilla/gfx/gfxVars.h"
 #include "mozilla/gfx/Logging.h"
 #include "mozilla/layers/CompositorBridgeChild.h"
+#include "mozilla/webrender/RenderD3D11TextureHostOGL.h"
+#include "mozilla/webrender/RenderThread.h"
 #include "mozilla/webrender/WebRenderAPI.h"
 
 namespace mozilla {
 
 using namespace gfx;
 
 namespace layers {
 
@@ -963,38 +965,128 @@ DXGITextureHostD3D11::AcquireTextureSour
   if (!EnsureTextureSource()) {
     return false;
   }
   aTexture = mTextureSource;
   return true;
 }
 
 void
+DXGITextureHostD3D11::CreateRenderTexture(const wr::ExternalImageId& aExternalImageId)
+{
+  RefPtr<wr::RenderTextureHost> texture =
+      new wr::RenderDXGITextureHostOGL(mHandle, mFormat, mSize);
+
+  wr::RenderThread::Get()->RegisterExternalImage(wr::AsUint64(aExternalImageId), texture.forget());
+}
+
+void
 DXGITextureHostD3D11::GetWRImageKeys(nsTArray<wr::ImageKey>& aImageKeys,
                                      const std::function<wr::ImageKey()>& aImageKeyAllocator)
 {
-  MOZ_ASSERT_UNREACHABLE("No GetWRImageKeys() implementation for this DXGITextureHostD3D11 type.");
+  MOZ_ASSERT(aImageKeys.IsEmpty());
+
+  switch (GetFormat()) {
+    case gfx::SurfaceFormat::R8G8B8X8:
+    case gfx::SurfaceFormat::R8G8B8A8:
+    case gfx::SurfaceFormat::B8G8R8A8:
+    case gfx::SurfaceFormat::B8G8R8X8: {
+      // 1 image key
+      aImageKeys.AppendElement(aImageKeyAllocator());
+      MOZ_ASSERT(aImageKeys.Length() == 1);
+      break;
+    }
+    case gfx::SurfaceFormat::NV12: {
+      // 2 image key
+      aImageKeys.AppendElement(aImageKeyAllocator());
+      aImageKeys.AppendElement(aImageKeyAllocator());
+      MOZ_ASSERT(aImageKeys.Length() == 2);
+      break;
+    }
+    default: {
+      MOZ_ASSERT_UNREACHABLE("unexpected to be called");
+    }
+  }
 }
 
 void
 DXGITextureHostD3D11::AddWRImage(wr::WebRenderAPI* aAPI,
                                  Range<const wr::ImageKey>& aImageKeys,
                                  const wr::ExternalImageId& aExtID)
 {
-  MOZ_ASSERT_UNREACHABLE("No AddWRImage() implementation for this DXGITextureHostD3D11 type.");
+  MOZ_ASSERT(mHandle);
+
+  switch (mFormat) {
+    case gfx::SurfaceFormat::R8G8B8X8:
+    case gfx::SurfaceFormat::R8G8B8A8:
+    case gfx::SurfaceFormat::B8G8R8A8:
+    case gfx::SurfaceFormat::B8G8R8X8: {
+      MOZ_ASSERT(aImageKeys.length() == 1);
+
+      wr::ImageDescriptor descriptor(GetSize(), GetFormat());
+      aAPI->AddExternalImage(aImageKeys[0],
+                             descriptor,
+                             aExtID,
+                             wr::WrExternalImageBufferType::Texture2DHandle,
+                             0);
+      break;
+    }
+    case gfx::SurfaceFormat::NV12: {
+      MOZ_ASSERT(aImageKeys.length() == 2);
+
+      wr::ImageDescriptor descriptor0(GetSize(), gfx::SurfaceFormat::A8);
+      wr::ImageDescriptor descriptor1(GetSize() / 2, gfx::SurfaceFormat::R8G8);
+      aAPI->AddExternalImage(aImageKeys[0],
+                             descriptor0,
+                             aExtID,
+                             wr::WrExternalImageBufferType::TextureExternalHandle,
+                             0);
+      aAPI->AddExternalImage(aImageKeys[1],
+                             descriptor1,
+                             aExtID,
+                             wr::WrExternalImageBufferType::TextureExternalHandle,
+                             1);
+      break;
+    }
+    default: {
+      MOZ_ASSERT_UNREACHABLE("unexpected to be called");
+    }
+  }
 }
 
 void
 DXGITextureHostD3D11::PushExternalImage(wr::DisplayListBuilder& aBuilder,
                                         const wr::LayoutRect& aBounds,
                                         const wr::LayoutRect& aClip,
                                         wr::ImageRendering aFilter,
                                         Range<const wr::ImageKey>& aImageKeys)
 {
-  MOZ_ASSERT_UNREACHABLE("No PushExternalImage() implementation for this DXGITextureHostD3D11 type.");
+  switch (GetFormat()) {
+    case gfx::SurfaceFormat::R8G8B8X8:
+    case gfx::SurfaceFormat::R8G8B8A8:
+    case gfx::SurfaceFormat::B8G8R8A8:
+    case gfx::SurfaceFormat::B8G8R8X8: {
+      MOZ_ASSERT(aImageKeys.length() == 1);
+      aBuilder.PushImage(aBounds, aClip, aFilter, aImageKeys[0]);
+      break;
+    }
+    case gfx::SurfaceFormat::NV12: {
+      MOZ_ASSERT(aImageKeys.length() == 2);
+      aBuilder.PushNV12Image(aBounds,
+                             aClip,
+                             aImageKeys[0],
+                             aImageKeys[1],
+                             wr::WrYuvColorSpace::Rec601,
+                             aFilter);
+      break;
+    }
+    default: {
+      MOZ_ASSERT_UNREACHABLE("unexpected to be called");
+    }
+  }
 }
 
 DXGIYCbCrTextureHostD3D11::DXGIYCbCrTextureHostD3D11(TextureFlags aFlags,
   const SurfaceDescriptorDXGIYCbCr& aDescriptor)
   : TextureHost(aFlags)
   , mSize(aDescriptor.size())
   , mIsLocked(false)
 {
@@ -1130,38 +1222,73 @@ DXGIYCbCrTextureHostD3D11::BindTextureSo
   MOZ_ASSERT(mIsLocked);
   // If Lock was successful we must have a valid TextureSource.
   MOZ_ASSERT(mTextureSources[0] && mTextureSources[1] && mTextureSources[2]);
   aTexture = mTextureSources[0].get();
   return !!aTexture;
 }
 
 void
+DXGIYCbCrTextureHostD3D11::CreateRenderTexture(const wr::ExternalImageId& aExternalImageId)
+{
+  // We use AddImage() directly. It's no corresponding RenderTextureHost.
+}
+
+void
 DXGIYCbCrTextureHostD3D11::GetWRImageKeys(nsTArray<wr::ImageKey>& aImageKeys,
                                           const std::function<wr::ImageKey()>& aImageKeyAllocator)
 {
-  MOZ_ASSERT_UNREACHABLE("No GetWRImageKeys() implementation for this DXGIYCbCrTextureHostD3D11 type.");
+  MOZ_ASSERT(aImageKeys.IsEmpty());
+
+  // 1 image key
+  aImageKeys.AppendElement(aImageKeyAllocator());
+  MOZ_ASSERT(aImageKeys.Length() == 1);
 }
 
 void
 DXGIYCbCrTextureHostD3D11::AddWRImage(wr::WebRenderAPI* aAPI,
                                       Range<const wr::ImageKey>& aImageKeys,
                                       const wr::ExternalImageId& aExtID)
 {
-  MOZ_ASSERT_UNREACHABLE("No AddWRImage() implementation for this DXGIYCbCrTextureHostD3D11 type.");
+  MOZ_ASSERT(mTextures[0] && mTextures[1] && mTextures[2]);
+  MOZ_ASSERT(aImageKeys.length() == 1);
+
+  // There are 3 A8 channel data in DXGIYCbCrTextureHostD3D11, but ANGLE doesn't
+  // support for converting the D3D A8 texture to OpenGL texture handle. So, we
+  // use the DataSourceSurface to get the raw buffer and push that raw buffer
+  // into WR using AddImage().
+  NS_WARNING("WR doesn't support DXGIYCbCrTextureHostD3D11 directly. It's a slower path.");
+
+  RefPtr<DataSourceSurface> dataSourceSurface = GetAsSurface();
+  if (!dataSourceSurface) {
+    return;
+  }
+  DataSourceSurface::MappedSurface map;
+  if (!dataSourceSurface->Map(gfx::DataSourceSurface::MapType::READ, &map)) {
+    return;
+  }
+
+  IntSize size = dataSourceSurface->GetSize();
+  wr::ImageDescriptor descriptor(size, map.mStride, dataSourceSurface->GetFormat());
+  auto slice = Range<uint8_t>(map.mData, size.height * map.mStride);
+  aAPI->AddImage(aImageKeys[0], descriptor, slice);
+
+  dataSourceSurface->Unmap();
 }
 
 void
 DXGIYCbCrTextureHostD3D11::PushExternalImage(wr::DisplayListBuilder& aBuilder,
                                              const wr::LayoutRect& aBounds,
                                              const wr::LayoutRect& aClip,
                                              wr::ImageRendering aFilter,
                                              Range<const wr::ImageKey>& aImageKeys)
 {
-  MOZ_ASSERT_UNREACHABLE("No PushExternalImage() implementation for this DXGIYCbCrTextureHostD3D11 type.");
+  // 1 image key
+  MOZ_ASSERT(aImageKeys.length() == 1);
+  aBuilder.PushImage(aBounds, aClip, aFilter, aImageKeys[0]);
 }
 
 bool
 DXGIYCbCrTextureHostD3D11::AcquireTextureSource(CompositableTextureSourceRef& aTexture)
 {
   if (!EnsureTextureSource()) {
     return false;
   }
--- a/gfx/layers/d3d11/TextureD3D11.h
+++ b/gfx/layers/d3d11/TextureD3D11.h
@@ -318,16 +318,18 @@ public:
 
   virtual bool LockWithoutCompositor() override;
   virtual void UnlockWithoutCompositor() override;
 
   virtual gfx::IntSize GetSize() const override { return mSize; }
 
   virtual already_AddRefed<gfx::DataSourceSurface> GetAsSurface() override;
 
+  virtual void CreateRenderTexture(const wr::ExternalImageId& aExternalImageId) override;
+
   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,
@@ -379,16 +381,18 @@ public:
 
   virtual gfx::IntSize GetSize() const override { return mSize; }
 
   virtual already_AddRefed<gfx::DataSourceSurface> GetAsSurface() override
   {
     return nullptr;
   }
 
+  virtual void CreateRenderTexture(const wr::ExternalImageId& aExternalImageId) override;
+
   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,
new file mode 100644
--- /dev/null
+++ b/gfx/webrender_bindings/RenderD3D11TextureHostOGL.cpp
@@ -0,0 +1,72 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * 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/. */
+
+#include "RenderD3D11TextureHostOGL.h"
+
+namespace mozilla {
+namespace wr {
+
+RenderDXGITextureHostOGL::RenderDXGITextureHostOGL(WindowsHandle aHandle,
+                                                   gfx::SurfaceFormat aFormat,
+                                                   gfx::IntSize aSize)
+  : mTextureHandle{ 0, 0 }
+  , mFormat(aFormat)
+  , mSize(aSize)
+{
+  MOZ_COUNT_CTOR_INHERITED(RenderDXGITextureHostOGL, RenderTextureHostOGL);
+}
+
+RenderDXGITextureHostOGL::~RenderDXGITextureHostOGL()
+{
+  MOZ_COUNT_DTOR_INHERITED(RenderDXGITextureHostOGL, RenderTextureHostOGL);
+}
+
+void
+RenderDXGITextureHostOGL::SetGLContext(gl::GLContext* aContext)
+{
+  MOZ_ASSERT_UNREACHABLE("No implementation for RenderDXGITextureHostOGL.");
+}
+
+bool
+RenderDXGITextureHostOGL::Lock()
+{
+  // TODO: Convert the d3d shared-handle to gl handle.
+  MOZ_ASSERT_UNREACHABLE("No implementation for RenderDXGITextureHostOGL.");
+  return true;
+}
+
+void
+RenderDXGITextureHostOGL::Unlock()
+{
+  MOZ_ASSERT_UNREACHABLE("No implementation for RenderDXGITextureHostOGL.");
+}
+
+GLuint
+RenderDXGITextureHostOGL::GetGLHandle(uint8_t aChannelIndex) const
+{
+  MOZ_ASSERT(mFormat != gfx::SurfaceFormat::NV12 || aChannelIndex < 2);
+  MOZ_ASSERT(mFormat == gfx::SurfaceFormat::NV12 || aChannelIndex < 1);
+
+  // TODO: return the corresponding gl handle for channel index.
+  MOZ_ASSERT_UNREACHABLE("No implementation for RenderDXGITextureHostOGL.");
+  return 0;
+}
+
+gfx::IntSize
+RenderDXGITextureHostOGL::GetSize(uint8_t aChannelIndex) const
+{
+  MOZ_ASSERT(mFormat != gfx::SurfaceFormat::NV12 || aChannelIndex < 2);
+  MOZ_ASSERT(mFormat == gfx::SurfaceFormat::NV12 || aChannelIndex < 1);
+
+  if (aChannelIndex == 0) {
+    return mSize;
+  } else {
+    // The CbCr channel size is a half of Y channel size in NV12 format.
+    return mSize / 2;
+  }
+}
+
+} // namespace wr
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/gfx/webrender_bindings/RenderD3D11TextureHostOGL.h
@@ -0,0 +1,44 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * 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 MOZILLA_GFX_RENDERD3D11TEXTUREHOSTOGL_H
+#define MOZILLA_GFX_RENDERD3D11TEXTUREHOSTOGL_H
+
+#include "RenderTextureHostOGL.h"
+
+namespace mozilla {
+
+namespace wr {
+
+class RenderDXGITextureHostOGL final : public RenderTextureHostOGL
+{
+public:
+  explicit RenderDXGITextureHostOGL(WindowsHandle aHandle,
+                                    gfx::SurfaceFormat aFormat,
+                                    gfx::IntSize aSize);
+
+  virtual void SetGLContext(gl::GLContext* aContext) override;
+
+  virtual bool Lock() override;
+  virtual void Unlock() override;
+
+  virtual gfx::IntSize GetSize(uint8_t aChannelIndex) const;
+  virtual GLuint GetGLHandle(uint8_t aChannelIndex) const;
+
+private:
+  virtual ~RenderDXGITextureHostOGL();
+
+  // We could use NV12 format for this texture. So, we might have 2 gl texture
+  // handles for Y and CbCr data.
+  GLuint mTextureHandle[2];
+
+  gfx::SurfaceFormat mFormat;
+  gfx::IntSize mSize;
+};
+
+} // namespace wr
+} // namespace mozilla
+
+#endif // MOZILLA_GFX_RENDERD3D11TEXTUREHOSTOGL_H
--- a/gfx/webrender_bindings/RenderTextureHostOGL.h
+++ b/gfx/webrender_bindings/RenderTextureHostOGL.h
@@ -4,16 +4,21 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef MOZILLA_GFX_RENDERTEXTUREHOSTOGL_H
 #define MOZILLA_GFX_RENDERTEXTUREHOSTOGL_H
 
 #include "RenderTextureHost.h"
 
 namespace mozilla {
+
+namespace gl {
+class GLContext;
+}
+
 namespace wr {
 
 class RenderTextureHostOGL : public RenderTextureHost
 {
 public:
   RenderTextureHostOGL();
 
   virtual void SetGLContext(gl::GLContext* aContext) = 0;
--- a/gfx/webrender_bindings/moz.build
+++ b/gfx/webrender_bindings/moz.build
@@ -32,11 +32,20 @@ UNIFIED_SOURCES += [
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
     EXPORTS.mozilla.webrender += [
         'RenderMacIOSurfaceTextureHostOGL.h',
     ]
     UNIFIED_SOURCES += [
         'RenderMacIOSurfaceTextureHostOGL.cpp',
     ]
 
+if CONFIG['MOZ_ENABLE_D3D10_LAYER']:
+    DEFINES['MOZ_ENABLE_D3D10_LAYER'] = True
+    EXPORTS.mozilla.webrender += [
+        'RenderD3D11TextureHostOGL.h',
+    ]
+    UNIFIED_SOURCES += [
+        'RenderD3D11TextureHostOGL.cpp',
+    ]
+
 include('/ipc/chromium/chromium-config.mozbuild')
 
 FINAL_LIBRARY = 'xul'