Bug 1352016 - P3. Check if NV12 rendering is usable when allocating D3D11 surface. r?mattwoodrow draft
authorJean-Yves Avenard <jyavenard@mozilla.com>
Sun, 10 Sep 2017 17:54:31 +0200
changeset 663995 b879d13d161fc66eb47a81b16016b34f39b02b68
parent 663994 c4998cac20e8805eaf075a19069d343436c1ff42
child 663996 517aadb4a6ebf32c4c574389cc3fb1c5e8b3c679
push id79585
push userbmo:jyavenard@mozilla.com
push dateWed, 13 Sep 2017 15:54:16 +0000
reviewersmattwoodrow
bugs1352016
milestone57.0a1
Bug 1352016 - P3. Check if NV12 rendering is usable when allocating D3D11 surface. r?mattwoodrow MozReview-Commit-ID: EgA6lEeIyBj
gfx/ipc/GraphicsMessages.ipdlh
gfx/layers/D3D11ShareHandleImage.cpp
gfx/thebes/D3D11Checks.cpp
gfx/thebes/D3D11Checks.h
gfx/thebes/DeviceManagerDx.cpp
gfx/thebes/DeviceManagerDx.h
--- a/gfx/ipc/GraphicsMessages.ipdlh
+++ b/gfx/ipc/GraphicsMessages.ipdlh
@@ -17,16 +17,17 @@ namespace gfx {
 
 struct D3D11DeviceStatus
 {
   bool isWARP;
   bool textureSharingWorks;
   uint32_t featureLevel;
   DxgiAdapterDesc adapter;
   int32_t sequenceNumber;
+  bool useNV12;
 };
 
 struct DevicePrefs
 {
   FeatureStatus hwCompositing;
   FeatureStatus d3d11Compositing;
   FeatureStatus oglCompositing;
   FeatureStatus advancedLayers;
--- a/gfx/layers/D3D11ShareHandleImage.cpp
+++ b/gfx/layers/D3D11ShareHandleImage.cpp
@@ -29,17 +29,18 @@ D3D11ShareHandleImage::D3D11ShareHandleI
    mPictureRect(aRect)
 {
 }
 
 bool
 D3D11ShareHandleImage::AllocateTexture(D3D11RecycleAllocator* aAllocator, ID3D11Device* aDevice)
 {
   if (aAllocator) {
-    if (gfxPrefs::PDMWMFUseNV12Format()) {
+    if (gfxPrefs::PDMWMFUseNV12Format() &&
+        gfx::DeviceManagerDx::Get()->CanUseNV12()) {
       mTextureClient = aAllocator->CreateOrRecycleClient(gfx::SurfaceFormat::NV12, mSize);
     } else {
       mTextureClient = aAllocator->CreateOrRecycleClient(gfx::SurfaceFormat::B8G8R8A8, mSize);
     }
     if (mTextureClient) {
       mTexture = static_cast<D3D11TextureData*>(mTextureClient->GetInternalData())->GetD3D11Texture();
       return true;
     }
--- a/gfx/thebes/D3D11Checks.cpp
+++ b/gfx/thebes/D3D11Checks.cpp
@@ -1,14 +1,15 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * 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 "D3D11Checks.h"
+#include "DXVA2Manager.h"
 #include "gfxConfig.h"
 #include "GfxDriverInfo.h"
 #include "gfxPrefs.h"
 #include "gfxWindowsPlatform.h"
 #include "mozilla/RefPtr.h"
 #include "mozilla/gfx/Logging.h"
 #include "mozilla/layers/TextureD3D11.h"
 #include "nsIGfxInfo.h"
@@ -404,10 +405,28 @@ D3D11Checks::WarnOnAdapterMismatch(ID3D1
 D3D11Checks::DoesRemotePresentWork(IDXGIAdapter* adapter)
 {
   // Remote presentation was added in DXGI 1.2, for Windows 8 and the Platform Update to Windows 7.
   RefPtr<IDXGIAdapter2> check;
   HRESULT hr = adapter->QueryInterface(__uuidof(IDXGIAdapter2), getter_AddRefs(check));
   return SUCCEEDED(hr) && check;
 }
 
+/* static */ bool
+D3D11Checks::DoesNV12Work(ID3D11Device* device)
+{
+  DXGI_ADAPTER_DESC desc;
+  PodZero(&desc);
+  if (!GetDxgiDesc(device, &desc)) {
+    // Failed to retrieve device information, assume it doesn't work
+    return false;
+  }
+
+  nsString version;
+  nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo();
+  if (gfxInfo) {
+    gfxInfo->GetAdapterDriverVersion(version);
+  }
+  return DXVA2Manager::IsNV12Supported(desc.VendorId, desc.DeviceId, version);
+}
+
 } // namespace gfx
 } // namespace mozilla
--- a/gfx/thebes/D3D11Checks.h
+++ b/gfx/thebes/D3D11Checks.h
@@ -12,19 +12,20 @@ struct DXGI_ADAPTER_DESC;
 
 namespace mozilla {
 namespace gfx {
 
 struct D3D11Checks
 {
   static bool DoesRenderTargetViewNeedRecreating(ID3D11Device* aDevice);
   static bool DoesDeviceWork();
-  static bool DoesTextureSharingWork(ID3D11Device *device);
-  static bool DoesAlphaTextureSharingWork(ID3D11Device *device);
+  static bool DoesTextureSharingWork(ID3D11Device* device);
+  static bool DoesAlphaTextureSharingWork(ID3D11Device* device);
   static void WarnOnAdapterMismatch(ID3D11Device* device);
   static bool GetDxgiDesc(ID3D11Device* device, DXGI_ADAPTER_DESC* out);
   static bool DoesRemotePresentWork(IDXGIAdapter* adapter);
+  static bool DoesNV12Work(ID3D11Device* device);
 };
 
 } // namespace gfx
 } // namespace mozilla
 
 #endif // mozilla_gfx_thebes_D3D11Checks_h
--- a/gfx/thebes/DeviceManagerDx.cpp
+++ b/gfx/thebes/DeviceManagerDx.cpp
@@ -390,27 +390,29 @@ DeviceManagerDx::CreateCompositorDevice(
                          "RenderTargetViews need recreating");
   }
   if (XRE_IsParentProcess()) {
     // It seems like this may only happen when we're using the NVIDIA gpu
     D3D11Checks::WarnOnAdapterMismatch(device);
   }
 
   uint32_t featureLevel = device->GetFeatureLevel();
+  bool useNV12 = D3D11Checks::DoesNV12Work(device);
   {
     MutexAutoLock lock(mDeviceLock);
     mCompositorDevice = device;
 
     int32_t sequenceNumber = GetNextDeviceCounter();
     mDeviceStatus = Some(D3D11DeviceStatus(
       false,
       textureSharingWorks,
       featureLevel,
       DxgiAdapterDesc::From(desc),
-      sequenceNumber));
+      sequenceNumber,
+      useNV12));
   }
   mCompositorDevice->SetExceptionMode(0);
 }
 
 bool
 DeviceManagerDx::CreateDevice(IDXGIAdapter* aAdapter,
                                  D3D_DRIVER_TYPE aDriverType,
                                  UINT aFlags,
@@ -496,27 +498,30 @@ DeviceManagerDx::CreateWARPCompositorDev
   if (IsWin8OrLater()) {
     textureSharingWorks = D3D11Checks::DoesTextureSharingWork(device);
   }
 
   DxgiAdapterDesc nullAdapter;
   PodZero(&nullAdapter);
 
   int featureLevel = device->GetFeatureLevel();
+
+  bool useNV12 = D3D11Checks::DoesNV12Work(device);
   {
     MutexAutoLock lock(mDeviceLock);
     mCompositorDevice = device;
 
     int32_t sequenceNumber = GetNextDeviceCounter();
     mDeviceStatus = Some(D3D11DeviceStatus(
       true,
       textureSharingWorks,
       featureLevel,
       nullAdapter,
-      sequenceNumber));
+      sequenceNumber,
+      useNV12));
   }
   mCompositorDevice->SetExceptionMode(0);
 
   reporterWARP.SetSuccessful();
 }
 
 FeatureStatus
 DeviceManagerDx::CreateContentDevice()
@@ -996,16 +1001,26 @@ DeviceManagerDx::IsWARP()
 {
   MutexAutoLock lock(mDeviceLock);
   if (!mDeviceStatus) {
     return false;
   }
   return mDeviceStatus->isWARP();
 }
 
+bool
+DeviceManagerDx::CanUseNV12()
+{
+  MutexAutoLock lock(mDeviceLock);
+  if (!mDeviceStatus) {
+    return false;
+  }
+  return mDeviceStatus->useNV12();
+}
+
 void
 DeviceManagerDx::InitializeDirectDraw()
 {
   MOZ_ASSERT(layers::CompositorThreadHolder::IsInCompositorThread());
 
   if (mDirectDraw) {
     // Already initialized.
     return;
--- a/gfx/thebes/DeviceManagerDx.h
+++ b/gfx/thebes/DeviceManagerDx.h
@@ -59,16 +59,17 @@ public:
   RefPtr<ID3D11Device> GetContentDevice();
   RefPtr<ID3D11Device> CreateDecoderDevice();
   RefPtr<layers::MLGDevice> GetMLGDevice();
   IDirectDraw7* GetDirectDraw();
 
   unsigned GetCompositorFeatureLevel() const;
   bool TextureSharingWorks();
   bool IsWARP();
+  bool CanUseNV12();
 
   // Returns true if we can create a texture with
   // D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX and also
   // upload texture data during the CreateTexture2D
   // call. This crashes on some devices, so we might
   // need to avoid it.
   bool CanInitializeKeyedMutexTextures();