Bug 1540581 - P18. Move destination texture type choice to the D3D11 texture allocator. r=mattwoodrow
authorJean-Yves Avenard <jyavenard@mozilla.com>
Thu, 11 Apr 2019 12:39:12 +0000
changeset 469145 841b6b61757792b59cee7412512e16e9a61b8989
parent 469144 30dac503bc7aee22dde7ec7ce2ba7f7641fc8594
child 469146 3fb8442e64d7d4b20f7b819ae3bcf7703beee0c6
push id35856
push usercsabou@mozilla.com
push dateFri, 12 Apr 2019 03:19:48 +0000
treeherdermozilla-central@940684cd1065 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmattwoodrow
bugs1540581
milestone68.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 1540581 - P18. Move destination texture type choice to the D3D11 texture allocator. r=mattwoodrow It allows for more readable code, not having to store multiple times different storage type across multiple objects. Now each class does one task and only deal with a single texture data type. Differential Revision: https://phabricator.services.mozilla.com/D26473
dom/media/platforms/wmf/DXVA2Manager.cpp
dom/media/platforms/wmf/DXVA2Manager.h
gfx/layers/D3D11ShareHandleImage.cpp
gfx/layers/D3D11ShareHandleImage.h
--- a/dom/media/platforms/wmf/DXVA2Manager.cpp
+++ b/dom/media/platforms/wmf/DXVA2Manager.cpp
@@ -584,17 +584,17 @@ class D3D11DXVA2Manager : public DXVA2Ma
 
   IUnknown* GetDXVADeviceManager() override;
 
   // Copies a region (aRegion) of the video frame stored in aVideoSample
   // into an image which is returned by aOutImage.
   HRESULT CopyToImage(IMFSample* aVideoSample, const gfx::IntRect& aRegion,
                       Image** aOutImage) override;
 
-  HRESULT CopyToBGRATexture(ID3D11Texture2D* aInTexture, const GUID& aSubType,
+  HRESULT CopyToBGRATexture(ID3D11Texture2D* aInTexture,
                             ID3D11Texture2D** aOutTexture) override;
 
   HRESULT ConfigureForSize(IMFMediaType* aInputType,
                            gfx::YUVColorSpace aColorSpace, uint32_t aWidth,
                            uint32_t aHeight) override;
 
   bool IsD3D11() override { return true; }
 
@@ -671,33 +671,34 @@ D3D11DXVA2Manager::Init(layers::KnowsCom
 
   hr = InitInternal(aKnowsCompositor, aFailureReason, aDevice);
   NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
 
   if (layers::ImageBridgeChild::GetSingleton() || !aKnowsCompositor) {
     // There's no proper KnowsCompositor for ImageBridge currently (and it
     // implements the interface), so just use that if it's available.
     mTextureClientAllocator = new D3D11RecycleAllocator(
-        layers::ImageBridgeChild::GetSingleton().get(), mDevice);
+        layers::ImageBridgeChild::GetSingleton().get(), mDevice,
+        gfx::SurfaceFormat::NV12);
 
     if (ImageBridgeChild::GetSingleton() && gfxPrefs::PDMWMFUseSyncTexture() &&
         mDevice != DeviceManagerDx::Get()->GetCompositorDevice()) {
       // We use a syncobject to avoid the cost of the mutex lock when
       // compositing, and because it allows color conversion ocurring directly
       // from this texture DXVA does not seem to accept IDXGIKeyedMutex textures
       // as input.
       mSyncObject = layers::SyncObjectClient::CreateSyncObjectClient(
           layers::ImageBridgeChild::GetSingleton()
               ->GetTextureFactoryIdentifier()
               .mSyncHandle,
           mDevice);
     }
   } else {
-    mTextureClientAllocator =
-        new D3D11RecycleAllocator(aKnowsCompositor, mDevice);
+    mTextureClientAllocator = new D3D11RecycleAllocator(
+        aKnowsCompositor, mDevice, gfx::SurfaceFormat::NV12);
     if (gfxPrefs::PDMWMFUseSyncTexture()) {
       // We use a syncobject to avoid the cost of the mutex lock when
       // compositing, and because it allows color conversion ocurring directly
       // from this texture DXVA does not seem to accept IDXGIKeyedMutex textures
       // as input.
       mSyncObject = layers::SyncObjectClient::CreateSyncObjectClient(
           aKnowsCompositor->GetTextureFactoryIdentifier().mSyncHandle, mDevice);
     }
@@ -881,17 +882,17 @@ D3D11DXVA2Manager::CreateOutputSample(Re
 HRESULT
 D3D11DXVA2Manager::CopyToImage(IMFSample* aVideoSample,
                                const gfx::IntRect& aRegion, Image** aOutImage) {
   NS_ENSURE_TRUE(aVideoSample, E_POINTER);
   NS_ENSURE_TRUE(aOutImage, E_POINTER);
   MOZ_ASSERT(mTextureClientAllocator);
 
   RefPtr<D3D11ShareHandleImage> image = new D3D11ShareHandleImage(
-      gfx::IntSize(mWidth, mHeight), aRegion, mInputSubType, mYUVColorSpace);
+      gfx::IntSize(mWidth, mHeight), aRegion, mYUVColorSpace);
 
   // Retrieve the DXGI_FORMAT for the current video sample.
   RefPtr<IMFMediaBuffer> buffer;
   HRESULT hr = aVideoSample->GetBufferByIndex(0, getter_AddRefs(buffer));
   NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
 
   RefPtr<IMFDXGIBuffer> dxgiBuf;
   hr = buffer->QueryInterface((IMFDXGIBuffer**)getter_AddRefs(dxgiBuf));
@@ -923,16 +924,18 @@ D3D11DXVA2Manager::CopyToImage(IMFSample
     if (mutex && (FAILED(hr) || hr == WAIT_TIMEOUT || hr == WAIT_ABANDONED)) {
       return hr;
     }
 
     if (!mutex && mDevice != DeviceManagerDx::Get()->GetCompositorDevice()) {
       NS_ENSURE_TRUE(mSyncObject, E_FAIL);
     }
 
+    // The D3D11TextureClientAllocator may return a different texture format
+    // than preferred. In which case the destination texture will be BGRA32.
     if (outDesc.Format == inDesc.Format) {
       // Our video frame is stored in a non-sharable ID3D11Texture2D. We need
       // to create a copy of that frame as a sharable resource, save its share
       // handle, and put that handle into the rendering pipeline.
       UINT width = std::min(inDesc.Width, outDesc.Width);
       UINT height = std::min(inDesc.Height, outDesc.Height);
       D3D11_BOX srcBox = {0, 0, 0, width, height, 1};
 
@@ -969,17 +972,16 @@ D3D11DXVA2Manager::CopyToImage(IMFSample
 
   image.forget(aOutImage);
 
   return S_OK;
 }
 
 HRESULT
 D3D11DXVA2Manager::CopyToBGRATexture(ID3D11Texture2D* aInTexture,
-                                     const GUID& aSubType,
                                      ID3D11Texture2D** aOutTexture) {
   NS_ENSURE_TRUE(aInTexture, E_POINTER);
   NS_ENSURE_TRUE(aOutTexture, E_POINTER);
 
   HRESULT hr;
   RefPtr<ID3D11Texture2D> texture, inTexture;
 
   inTexture = aInTexture;
@@ -990,17 +992,31 @@ D3D11DXVA2Manager::CopyToBGRATexture(ID3
   if (!mInputType || desc.Width != mWidth || desc.Height != mHeight) {
     RefPtr<IMFMediaType> inputType;
     hr = wmf::MFCreateMediaType(getter_AddRefs(inputType));
     NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
 
     hr = inputType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video);
     NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
 
-    hr = inputType->SetGUID(MF_MT_SUBTYPE, aSubType);
+    const GUID subType = [&]() {
+      switch (desc.Format) {
+        case DXGI_FORMAT_NV12:
+          return MFVideoFormat_NV12;
+        case DXGI_FORMAT_P010:
+          return MFVideoFormat_P010;
+        case DXGI_FORMAT_P016:
+          return MFVideoFormat_P016;
+        default:
+          MOZ_ASSERT_UNREACHABLE("Unexpected texture type");
+          return MFVideoFormat_NV12;
+      }
+    }();
+
+    hr = inputType->SetGUID(MF_MT_SUBTYPE, subType);
     NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
 
     hr = inputType->SetUINT32(MF_MT_INTERLACE_MODE,
                               MFVideoInterlace_Progressive);
     NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
 
     hr = inputType->SetUINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, TRUE);
     NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
@@ -1131,16 +1147,31 @@ D3D11DXVA2Manager::ConfigureForSize(IMFM
   });
   NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
 
   mWidth = aWidth;
   mHeight = aHeight;
   mInputType = inputType;
   mInputSubType = subType;
   mYUVColorSpace = aColorSpace;
+  if (mTextureClientAllocator) {
+    gfx::SurfaceFormat format = [&]() {
+      if (subType == MFVideoFormat_NV12) {
+        return gfx::SurfaceFormat::NV12;
+      } else if (subType == MFVideoFormat_P010) {
+        return gfx::SurfaceFormat::P010;
+      } else if (subType == MFVideoFormat_P016) {
+        return gfx::SurfaceFormat::P016;
+      } else {
+        MOZ_ASSERT_UNREACHABLE("Unexpected texture type");
+        return gfx::SurfaceFormat::NV12;
+      }
+    }();
+    mTextureClientAllocator->SetPreferredSurfaceFormat(format);
+  }
   return S_OK;
 }
 
 bool D3D11DXVA2Manager::CanCreateDecoder(const D3D11_VIDEO_DECODER_DESC& aDesc,
                                          const float aFramerate) const {
   MOZ_ASSERT(NS_IsMainThread());
   if (IsUnsupportedResolution(aDesc.SampleWidth, aDesc.SampleHeight,
                               aFramerate)) {
--- a/dom/media/platforms/wmf/DXVA2Manager.h
+++ b/dom/media/platforms/wmf/DXVA2Manager.h
@@ -38,17 +38,16 @@ class DXVA2Manager {
   virtual IUnknown* GetDXVADeviceManager() = 0;
 
   // Creates an Image for the video frame stored in aVideoSample.
   virtual HRESULT CopyToImage(IMFSample* aVideoSample,
                               const gfx::IntRect& aRegion,
                               layers::Image** aOutImage) = 0;
 
   virtual HRESULT CopyToBGRATexture(ID3D11Texture2D* aInTexture,
-                                    const GUID& aSubType,
                                     ID3D11Texture2D** aOutTexture) {
     // Not implemented!
     MOZ_CRASH("CopyToBGRATexture not implemented on this manager.");
     return E_FAIL;
   }
 
   virtual HRESULT ConfigureForSize(IMFMediaType* aInputType,
                                    gfx::YUVColorSpace aColorSpace,
--- a/gfx/layers/D3D11ShareHandleImage.cpp
+++ b/gfx/layers/D3D11ShareHandleImage.cpp
@@ -20,45 +20,26 @@
 
 namespace mozilla {
 namespace layers {
 
 using namespace gfx;
 
 D3D11ShareHandleImage::D3D11ShareHandleImage(const gfx::IntSize& aSize,
                                              const gfx::IntRect& aRect,
-                                             const GUID& aSourceFormat,
                                              gfx::YUVColorSpace aColorSpace)
     : Image(nullptr, ImageFormat::D3D11_SHARE_HANDLE_TEXTURE),
       mSize(aSize),
       mPictureRect(aRect),
-      mSourceFormat(aSourceFormat),
       mYUVColorSpace(aColorSpace) {}
 
 bool D3D11ShareHandleImage::AllocateTexture(D3D11RecycleAllocator* aAllocator,
                                             ID3D11Device* aDevice) {
   if (aAllocator) {
-    if (mSourceFormat == MFVideoFormat_NV12 &&
-        gfxPrefs::PDMWMFUseNV12Format() &&
-        gfx::DeviceManagerDx::Get()->CanUseNV12()) {
-      mTextureClient = aAllocator->CreateOrRecycleClient(
-          gfx::SurfaceFormat::NV12, mYUVColorSpace, mSize);
-    } else if (((mSourceFormat == MFVideoFormat_P010 &&
-                 gfx::DeviceManagerDx::Get()->CanUseP010()) ||
-                (mSourceFormat == MFVideoFormat_P016 &&
-                 gfx::DeviceManagerDx::Get()->CanUseP016())) &&
-               gfxPrefs::PDMWMFUseNV12Format()) {
-      mTextureClient = aAllocator->CreateOrRecycleClient(
-          mSourceFormat == MFVideoFormat_P010 ? gfx::SurfaceFormat::P010
-                                              : gfx::SurfaceFormat::P016,
-          mYUVColorSpace, mSize);
-    } else {
-      mTextureClient = aAllocator->CreateOrRecycleClient(
-          gfx::SurfaceFormat::B8G8R8A8, gfx::YUVColorSpace::UNKNOWN, mSize);
-    }
+    mTextureClient = aAllocator->CreateOrRecycleClient(mYUVColorSpace, mSize);
     if (mTextureClient) {
       D3D11TextureData* textureData =
           mTextureClient->GetInternalData()->AsD3D11TextureData();
       MOZ_DIAGNOSTIC_ASSERT(textureData, "Wrong TextureDataType");
       mTexture = textureData->GetD3D11Texture();
       return true;
     }
     return false;
@@ -106,18 +87,17 @@ D3D11ShareHandleImage::GetAsSourceSurfac
 
     if (!manager) {
       gfxWarning() << "Failed to create DXVA2 manager!";
       return nullptr;
     }
 
     RefPtr<ID3D11Texture2D> outTexture;
 
-    hr = manager->CopyToBGRATexture(texture, mSourceFormat,
-                                    getter_AddRefs(outTexture));
+    hr = manager->CopyToBGRATexture(texture, getter_AddRefs(outTexture));
 
     if (FAILED(hr)) {
       gfxWarning() << "Failed to copy to BGRA texture.";
       return nullptr;
     }
 
     texture = outTexture;
     texture->GetDesc(&desc);
@@ -234,37 +214,63 @@ class MOZ_RAII D3D11TextureClientAllocat
                                         aAllocator->GetTextureForwarder());
   }
 
  private:
   gfx::YUVColorSpace mYUVColorSpace;
   const RefPtr<ID3D11Device> mDevice;
 };
 
+D3D11RecycleAllocator::D3D11RecycleAllocator(
+    KnowsCompositor* aAllocator, ID3D11Device* aDevice,
+    gfx::SurfaceFormat aPreferredFormat)
+    : TextureClientRecycleAllocator(aAllocator),
+      mDevice(aDevice),
+      mCanUseNV12(gfxPrefs::PDMWMFUseNV12Format() &&
+                  gfx::DeviceManagerDx::Get()->CanUseNV12()),
+      mCanUseP010(gfxPrefs::PDMWMFUseNV12Format() &&
+                  gfx::DeviceManagerDx::Get()->CanUseP010()),
+      mCanUseP016(gfxPrefs::PDMWMFUseNV12Format() &&
+                  gfx::DeviceManagerDx::Get()->CanUseP016()) {
+  SetPreferredSurfaceFormat(aPreferredFormat);
+}
+
+void D3D11RecycleAllocator::SetPreferredSurfaceFormat(
+    gfx::SurfaceFormat aPreferredFormat) {
+  if ((aPreferredFormat == gfx::SurfaceFormat::NV12 && mCanUseNV12) ||
+      (aPreferredFormat == gfx::SurfaceFormat::P010 && mCanUseP010) ||
+      (aPreferredFormat == gfx::SurfaceFormat::P016 && mCanUseP016)) {
+    mUsableSurfaceFormat = aPreferredFormat;
+    return;
+  }
+  // We can't handle the native source format, set it to BGRA which will
+  // force the caller to convert it later.
+  mUsableSurfaceFormat = gfx::SurfaceFormat::B8G8R8A8;
+}
+
 already_AddRefed<TextureClient> D3D11RecycleAllocator::CreateOrRecycleClient(
-    gfx::SurfaceFormat aFormat, gfx::YUVColorSpace aColorSpace,
-    const gfx::IntSize& aSize) {
+    gfx::YUVColorSpace aColorSpace, const gfx::IntSize& aSize) {
   // When CompositorDevice or ContentDevice is updated,
   // we could not reuse old D3D11Textures. It could cause video flickering.
   RefPtr<ID3D11Device> device = gfx::DeviceManagerDx::Get()->GetImageDevice();
   if (!!mImageDevice && mImageDevice != device) {
     ShrinkToMinimumSize();
   }
   mImageDevice = device;
 
   TextureAllocationFlags allocFlags = TextureAllocationFlags::ALLOC_DEFAULT;
   if (gfxPrefs::PDMWMFUseSyncTexture() ||
       mDevice == DeviceManagerDx::Get()->GetCompositorDevice()) {
     // If our device is the compositor device, we don't need any synchronization
     // in practice.
     allocFlags = TextureAllocationFlags::ALLOC_MANUAL_SYNCHRONIZATION;
   }
 
-  D3D11TextureClientAllocationHelper helper(aFormat, aColorSpace, aSize,
-                                            allocFlags, mDevice,
+  D3D11TextureClientAllocationHelper helper(mUsableSurfaceFormat, aColorSpace,
+                                            aSize, allocFlags, mDevice,
                                             layers::TextureFlags::DEFAULT);
 
   RefPtr<TextureClient> textureClient = CreateOrRecycle(helper);
   return textureClient.forget();
 }
 
 }  // namespace layers
 }  // namespace mozilla
--- a/gfx/layers/D3D11ShareHandleImage.h
+++ b/gfx/layers/D3D11ShareHandleImage.h
@@ -16,39 +16,43 @@
 #include "mozilla/layers/TextureClientRecycleAllocator.h"
 #include "mozilla/layers/TextureD3D11.h"
 
 namespace mozilla {
 namespace layers {
 
 class D3D11RecycleAllocator final : public TextureClientRecycleAllocator {
  public:
-  D3D11RecycleAllocator(KnowsCompositor* aAllocator, ID3D11Device* aDevice)
-      : TextureClientRecycleAllocator(aAllocator), mDevice(aDevice) {}
+  D3D11RecycleAllocator(KnowsCompositor* aAllocator, ID3D11Device* aDevice,
+                        gfx::SurfaceFormat aPreferredFormat);
 
   already_AddRefed<TextureClient> CreateOrRecycleClient(
-      gfx::SurfaceFormat aFormat, gfx::YUVColorSpace aColorSpace,
-      const gfx::IntSize& aSize);
+      gfx::YUVColorSpace aColorSpace, const gfx::IntSize& aSize);
+
+  void SetPreferredSurfaceFormat(gfx::SurfaceFormat aPreferredFormat);
 
- protected:
-  RefPtr<ID3D11Device> mDevice;
+ private:
+  const RefPtr<ID3D11Device> mDevice;
+  const bool mCanUseNV12;
+  const bool mCanUseP010;
+  const bool mCanUseP016;
   /**
    * Used for checking if CompositorDevice/ContentDevice is updated.
    */
   RefPtr<ID3D11Device> mImageDevice;
+  gfx::SurfaceFormat mUsableSurfaceFormat;
 };
 
 // Image class that wraps a ID3D11Texture2D. This class copies the image
 // passed into SetData(), so that it can be accessed from other D3D devices.
 // This class also manages the synchronization of the copy, to ensure the
 // resource is ready to use.
 class D3D11ShareHandleImage final : public Image {
  public:
   D3D11ShareHandleImage(const gfx::IntSize& aSize, const gfx::IntRect& aRect,
-                        const GUID& aSourceFormat,
                         gfx::YUVColorSpace aColorSpace);
   virtual ~D3D11ShareHandleImage() = default;
 
   bool AllocateTexture(D3D11RecycleAllocator* aAllocator,
                        ID3D11Device* aDevice);
 
   gfx::IntSize GetSize() const override;
   already_AddRefed<gfx::SourceSurface> GetAsSourceSurface() override;
@@ -57,17 +61,16 @@ class D3D11ShareHandleImage final : publ
 
   ID3D11Texture2D* GetTexture() const;
 
   gfx::YUVColorSpace GetYUVColorSpace() const { return mYUVColorSpace; }
 
  private:
   gfx::IntSize mSize;
   gfx::IntRect mPictureRect;
-  const GUID mSourceFormat;
   gfx::YUVColorSpace mYUVColorSpace;
   RefPtr<TextureClient> mTextureClient;
   RefPtr<ID3D11Texture2D> mTexture;
 };
 
 }  // namespace layers
 }  // namespace mozilla