Bug 1286653 - Re-run blacklist on DXGI adapter used for device creation draft
authoreyim <eyim@mozilla.com>
Thu, 11 Aug 2016 18:20:21 -0400
changeset 399706 e99b742e2fdcda3ec1e1165d39c57426425c69ad
parent 398604 6cf0089510fad8deb866136f5b92bbced9498447
child 528032 7f7f8f963f08d136832c8f33fd8024066a684a37
push id25952
push userbmo:eyim@mozilla.com
push dateThu, 11 Aug 2016 22:21:23 +0000
bugs1286653
milestone51.0a1
Bug 1286653 - Re-run blacklist on DXGI adapter used for device creation MozReview-Commit-ID: 9QV8QFu5WYR
gfx/thebes/DeviceManagerD3D11.cpp
widget/GfxInfoBase.cpp
widget/GfxInfoBase.h
widget/nsIGfxInfo.idl
widget/windows/GfxInfo.cpp
widget/windows/GfxInfo.h
--- a/gfx/thebes/DeviceManagerD3D11.cpp
+++ b/gfx/thebes/DeviceManagerD3D11.cpp
@@ -87,16 +87,45 @@ DeviceManagerD3D11::CreateDevices()
   // Check if a failure was injected for testing.
   if (gfxPrefs::DeviceFailForTesting()) {
     d3d11.SetFailed(FeatureStatus::Failed, "Direct3D11 device failure simulated by preference",
                     NS_LITERAL_CSTRING("FEATURE_FAILURE_D3D11_SIM"));
     return;
   }
 
   if (XRE_IsParentProcess()) {
+    // reset the primary adapter information, given the adapter from device creation
+    RefPtr<IDXGIAdapter1> adapter = GetDXGIAdapter();
+    DXGI_ADAPTER_DESC adapterDesc;
+    nsString vendorID;
+    nsString deviceID;
+
+    if (!adapter) { // no dxgiadapter
+      d3d11.SetFailed(FeatureStatus::Failed, "No DXGI adapter found",
+                      NS_LITERAL_CSTRING("FEATURE_FAILURE_D3D11_DXGIADAPTER"));
+      return;
+    }
+
+    adapter->GetDesc(&adapterDesc);
+
+    vendorID.AppendPrintf("0x%04x", adapterDesc.VendorId);
+    deviceID.AppendPrintf("0x%04x", adapterDesc.DeviceId);
+
+    if (nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo()) {
+      gfxInfo->Reset(vendorID, deviceID);
+
+      // check device to see if blacklisted after device creation successful
+      nsCString message;
+      nsCString failureId;
+      if (!gfxPlatform::IsGfxInfoStatusOkay(nsIGfxInfo::FEATURE_DIRECT3D_11_LAYERS, &message, failureId)) {
+        d3d11.Disable(FeatureStatus::Blacklisted, message.get(), failureId);
+        return;
+      }
+    }
+
     if (!gfxConfig::UseFallback(Fallback::USE_D3D11_WARP_COMPOSITOR)) {
       AttemptD3D11DeviceCreation(d3d11);
       if (d3d11.GetValue() == FeatureStatus::CrashedInHandler) {
         return;
       }
 
       // If we failed to get a device, but WARP is allowed and might work,
       // re-enable D3D11 and switch to WARP.
--- a/widget/GfxInfoBase.cpp
+++ b/widget/GfxInfoBase.cpp
@@ -571,16 +571,23 @@ GfxInfoBase::Init()
   if (os) {
     os->AddObserver(this, "blocklist-data-gfxItems", true);
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
+GfxInfoBase::Reset(const nsAString& aVendorID, const nsAString& aDeviceID)
+{
+  NS_ABORT();
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
 GfxInfoBase::GetFeatureStatus(int32_t aFeature, nsACString& aFailureId, int32_t* aStatus)
 {
   int32_t blocklistAll = gfxPrefs::BlocklistAll();
   if (blocklistAll > 0) {
     gfxCriticalErrorOnce(gfxCriticalError::DefaultOptions(false)) << "Forcing blocklisting all features";
     *aStatus = FEATURE_BLOCKED_DEVICE;
     aFailureId = "FEATURE_FAILURE_BLOCK_ALL";
     return NS_OK;
--- a/widget/GfxInfoBase.h
+++ b/widget/GfxInfoBase.h
@@ -54,16 +54,18 @@ public:
   NS_IMETHOD GetMonitors(JSContext* cx, JS::MutableHandleValue _retval) override;
   NS_IMETHOD GetFailures(uint32_t *failureCount, int32_t** indices, char ***failures) override;
   NS_IMETHOD_(void) LogFailure(const nsACString &failure) override;
   NS_IMETHOD GetInfo(JSContext*, JS::MutableHandle<JS::Value>) override;
   NS_IMETHOD GetFeatures(JSContext*, JS::MutableHandle<JS::Value>) override;
   NS_IMETHOD GetFeatureLog(JSContext*, JS::MutableHandle<JS::Value>) override;
   NS_IMETHOD GetActiveCrashGuards(JSContext*, JS::MutableHandle<JS::Value>) override;
 
+  NS_IMETHOD Reset(const nsAString& aVendorID, const nsAString& aDeviceID) override;
+
   // Initialization function. If you override this, you must call this class's
   // version of Init first.
   // We need Init to be called separately from the constructor so we can
   // register as an observer after all derived classes have been constructed
   // and we know we have a non-zero refcount.
   // Ideally, Init() would be void-return, but the rules of
   // NS_GENERIC_FACTORY_CONSTRUCTOR_INIT require it be nsresult return.
   virtual nsresult Init();
--- a/widget/nsIGfxInfo.idl
+++ b/widget/nsIGfxInfo.idl
@@ -151,16 +151,22 @@ interface nsIGfxInfo : nsISupports
    * "shading_language_version", "extensions".  These return info from
    * underlying GL impl that's used to implement WebGL.
    */
   DOMString getWebGLParameter(in DOMString aParam);
 
   // only useful on X11
   [noscript, notxpcom] void GetData();
 
+  /**
+   * At startup we sometimes have to make a guess what device we're going to be
+   * using. We can reset this once we've gotten an exact device.
+   */
+  [noscript] void Reset (in AString aVendorID, in AString aDeviceID);
+
   [implicit_jscontext]
   jsval getInfo();
 
   // Return an object describing all features that have been configured:
   //
   //   "features": [
   //     // For each feature:
   //     {
--- a/widget/windows/GfxInfo.cpp
+++ b/widget/windows/GfxInfo.cpp
@@ -294,124 +294,27 @@ GfxInfo::Init()
   while (EnumDisplayDevicesW(nullptr, deviceIndex, &displayDevice, 0)) {
     if (displayDevice.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) {
       mDeviceKeyDebug = NS_LITERAL_STRING("NullSearch");
       break;
     }
     deviceIndex++;
   }
 
-  // make sure the string is nullptr terminated
-  if (wcsnlen(displayDevice.DeviceKey, ArrayLength(displayDevice.DeviceKey))
-      == ArrayLength(displayDevice.DeviceKey)) {
-    // we did not find a nullptr
-    return rv;
-  }
-
-  mDeviceKeyDebug = displayDevice.DeviceKey;
-
-  /* DeviceKey is "reserved" according to MSDN so we'll be careful with it */
-  /* check that DeviceKey begins with DEVICE_KEY_PREFIX */
-  /* some systems have a DeviceKey starting with \REGISTRY\Machine\ so we need to compare case insenstively */
-  if (_wcsnicmp(displayDevice.DeviceKey, DEVICE_KEY_PREFIX, ArrayLength(DEVICE_KEY_PREFIX)-1) != 0)
+  rv = UpdatePrimaryDeviceInfo(displayDevice);
+  if (rv != NS_OK) {
     return rv;
-
-  // chop off DEVICE_KEY_PREFIX
-  mDeviceKey = displayDevice.DeviceKey + ArrayLength(DEVICE_KEY_PREFIX)-1;
-
-  mDeviceID = displayDevice.DeviceID;
-  mDeviceString = displayDevice.DeviceString;
-
-  // On Windows 8 and Server 2012 hosts, we want to not block RDP
-  // sessions from attempting hardware acceleration.  RemoteFX
-  // provides features and functionaltiy that can give a good D3D10 +
-  // D2D + DirectWrite experience emulated via a software GPU.
-  //
-  // Unfortunately, the Device ID is nullptr, and we can't enumerate
-  // it using the setup infrastructure (SetupDiGetClassDevsW below
-  // will return INVALID_HANDLE_VALUE).
-  if (mWindowsVersion == kWindows8 &&
-      mDeviceID.Length() == 0 &&
-      mDeviceString.EqualsLiteral("RDPUDD Chained DD"))
-  {
-    WCHAR sysdir[255];
-    UINT len = GetSystemDirectory(sysdir, sizeof(sysdir));
-    if (len < sizeof(sysdir)) {
-      nsString rdpudd(sysdir);
-      rdpudd.AppendLiteral("\\rdpudd.dll");
-      gfxWindowsPlatform::GetDLLVersion(rdpudd.BeginReading(), mDriverVersion);
-      mDriverDate.AssignLiteral("01-01-1970");
-
-      // 0x1414 is Microsoft; 0xfefe is an invented (and unused) code
-      mDeviceID.AssignLiteral("PCI\\VEN_1414&DEV_FEFE&SUBSYS_00000000");
-    }
-  }
-
-  /* create a device information set composed of the current display device */
-  HDEVINFO devinfo = SetupDiGetClassDevsW(nullptr, mDeviceID.get(), nullptr,
-                                          DIGCF_PRESENT | DIGCF_PROFILE | DIGCF_ALLCLASSES);
-
-  if (devinfo != INVALID_HANDLE_VALUE) {
-    HKEY key;
-    LONG result;
-    WCHAR value[255];
-    DWORD dwcbData;
-    SP_DEVINFO_DATA devinfoData;
-    DWORD memberIndex = 0;
-
-    devinfoData.cbSize = sizeof(devinfoData);
-    NS_NAMED_LITERAL_STRING(driverKeyPre, "System\\CurrentControlSet\\Control\\Class\\");
-    /* enumerate device information elements in the device information set */
-    while (SetupDiEnumDeviceInfo(devinfo, memberIndex++, &devinfoData)) {
-      /* get a string that identifies the device's driver key */
-      if (SetupDiGetDeviceRegistryPropertyW(devinfo,
-                                            &devinfoData,
-                                            SPDRP_DRIVER,
-                                            nullptr,
-                                            (PBYTE)value,
-                                            sizeof(value),
-                                            nullptr)) {
-        nsAutoString driverKey(driverKeyPre);
-        driverKey += value;
-        result = RegOpenKeyExW(HKEY_LOCAL_MACHINE, driverKey.get(), 0, KEY_QUERY_VALUE, &key);
-        if (result == ERROR_SUCCESS) {
-          /* we've found the driver we're looking for */
-          dwcbData = sizeof(value);
-          result = RegQueryValueExW(key, L"DriverVersion", nullptr, nullptr,
-                                    (LPBYTE)value, &dwcbData);
-          if (result == ERROR_SUCCESS) {
-            mDriverVersion = value;
-          } else {
-            // If the entry wasn't found, assume the worst (0.0.0.0).
-            mDriverVersion.AssignLiteral("0.0.0.0");
-          }
-          dwcbData = sizeof(value);
-          result = RegQueryValueExW(key, L"DriverDate", nullptr, nullptr,
-                                    (LPBYTE)value, &dwcbData);
-          if (result == ERROR_SUCCESS) {
-            mDriverDate = value;
-          } else {
-            // Again, assume the worst
-            mDriverDate.AssignLiteral("01-01-1970");
-          }
-          RegCloseKey(key);
-          break;
-        }
-      }
-    }
-
-    SetupDiDestroyDeviceInfoList(devinfo);
   }
 
   mAdapterVendorID.AppendPrintf("0x%04x", ParseIDFromDeviceID(mDeviceID, "VEN_", 4));
   mAdapterDeviceID.AppendPrintf("0x%04x", ParseIDFromDeviceID(mDeviceID, "&DEV_", 4));
   mAdapterSubsysID.AppendPrintf("%08x", ParseIDFromDeviceID(mDeviceID,  "&SUBSYS_", 8));
 
   // We now check for second display adapter.
-
+  HDEVINFO devinfo;
   // Device interface class for display adapters.
   CLSID GUID_DISPLAY_DEVICE_ARRIVAL;
   HRESULT hresult = CLSIDFromString(L"{1CA05180-A699-450A-9A0C-DE4FBE3DDD89}",
                                &GUID_DISPLAY_DEVICE_ARRIVAL);
   if (hresult == NOERROR) {
     devinfo = SetupDiGetClassDevsW(&GUID_DISPLAY_DEVICE_ARRIVAL,
                                    nullptr, nullptr,
                                    DIGCF_PRESENT | DIGCF_INTERFACEDEVICE);
@@ -513,16 +416,193 @@ GfxInfo::Init()
           }
         }
       }
 
       SetupDiDestroyDeviceInfoList(devinfo);
     }
   }
 
+  CheckAndUpdateDriverInfo();
+
+  AddCrashReportAnnotations();
+
+  return rv;
+}
+
+nsresult
+GfxInfo::Reset(const nsAString& aVendorID, const nsAString& aDeviceID)
+{
+  nsresult rv = NS_OK;
+  if (aVendorID.IsEmpty() || aDeviceID.IsEmpty()) {
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+
+  DISPLAY_DEVICEW displayDevice;
+  displayDevice.cb = sizeof(displayDevice);
+  int deviceIndex = 0;
+
+  nsString tempDeviceID;
+  nsString tempAdapterVendorID;
+  nsString tempAdapterDeviceID;
+  nsString tempAdapterSubsysID;
+
+  while (EnumDisplayDevicesW(nullptr, deviceIndex, &displayDevice, 0)) {
+    // reset these strings due to append later
+    tempAdapterVendorID = NS_LITERAL_STRING("");
+    tempAdapterDeviceID = NS_LITERAL_STRING("");
+    tempAdapterSubsysID = NS_LITERAL_STRING("");
+
+    tempDeviceID = displayDevice.DeviceID;
+    tempAdapterVendorID.AppendPrintf("0x%04x", ParseIDFromDeviceID(tempDeviceID, "VEN_", 4));
+    tempAdapterDeviceID.AppendPrintf("0x%04x", ParseIDFromDeviceID(tempDeviceID, "&DEV_", 4));
+    tempAdapterSubsysID.AppendPrintf("%08x", ParseIDFromDeviceID(tempDeviceID,  "&SUBSYS_", 8));
+
+    // look for device that has the same vendor and device id as given
+    if (mAdapterVendorID.Equals(aVendorID) && mAdapterDeviceID.Equals(aDeviceID)){
+      break;
+    }
+
+    deviceIndex++;
+  }
+
+  if (tempAdapterVendorID.Equals(aVendorID) && tempAdapterDeviceID.Equals(aDeviceID)) {
+    mDeviceID = tempDeviceID;
+    mAdapterVendorID = tempAdapterVendorID;
+    mAdapterDeviceID = tempAdapterDeviceID;
+    mAdapterSubsysID = tempAdapterSubsysID;
+  } else { // vendorid and deviceid given cannot be found
+    return NS_ERROR_UNEXPECTED;
+  }
+
+  rv = UpdatePrimaryDeviceInfo(displayDevice);
+  if (rv != NS_OK) {
+    return rv;
+  }
+
+  CheckAndUpdateDriverInfo();
+
+  AddCrashReportAnnotations();
+
+  return rv;
+}
+
+nsresult
+GfxInfo::UpdatePrimaryDeviceInfo(DISPLAY_DEVICEW &displayDevice)
+{
+  nsresult rv = NS_ERROR_FAILURE;
+  // make sure the string is nullptr terminated
+  if (wcsnlen(displayDevice.DeviceKey, ArrayLength(displayDevice.DeviceKey))
+      == ArrayLength(displayDevice.DeviceKey)) {
+    // we did not find a nullptr
+    return rv;
+  }
+
+  mDeviceKeyDebug = displayDevice.DeviceKey;
+
+  /* DeviceKey is "reserved" according to MSDN so we'll be careful with it */
+  /* check that DeviceKey begins with DEVICE_KEY_PREFIX */
+  /* some systems have a DeviceKey starting with \REGISTRY\Machine\ so we need to compare case insenstively */
+  if (_wcsnicmp(displayDevice.DeviceKey, DEVICE_KEY_PREFIX, ArrayLength(DEVICE_KEY_PREFIX)-1) != 0)
+    return rv;
+
+  // chop off DEVICE_KEY_PREFIX
+  mDeviceKey = displayDevice.DeviceKey + ArrayLength(DEVICE_KEY_PREFIX)-1;
+
+  mDeviceID = displayDevice.DeviceID;
+  mDeviceString = displayDevice.DeviceString;
+
+  // On Windows 8 and Server 2012 hosts, we want to not block RDP
+  // sessions from attempting hardware acceleration.  RemoteFX
+  // provides features and functionaltiy that can give a good D3D10 +
+  // D2D + DirectWrite experience emulated via a software GPU.
+  //
+  // Unfortunately, the Device ID is nullptr, and we can't enumerate
+  // it using the setup infrastructure (SetupDiGetClassDevsW below
+  // will return INVALID_HANDLE_VALUE).
+  if (mWindowsVersion == kWindows8 &&
+      mDeviceID.Length() == 0 &&
+      mDeviceString.EqualsLiteral("RDPUDD Chained DD"))
+  {
+    WCHAR sysdir[255];
+    UINT len = GetSystemDirectory(sysdir, sizeof(sysdir));
+    if (len < sizeof(sysdir)) {
+      nsString rdpudd(sysdir);
+      rdpudd.AppendLiteral("\\rdpudd.dll");
+      gfxWindowsPlatform::GetDLLVersion(rdpudd.BeginReading(), mDriverVersion);
+      mDriverDate.AssignLiteral("01-01-1970");
+
+      // 0x1414 is Microsoft; 0xfefe is an invented (and unused) code
+      mDeviceID.AssignLiteral("PCI\\VEN_1414&DEV_FEFE&SUBSYS_00000000");
+    }
+  }
+
+  /* create a device information set composed of the current display device */
+  HDEVINFO devinfo = SetupDiGetClassDevsW(nullptr, mDeviceID.get(), nullptr,
+                                          DIGCF_PRESENT | DIGCF_PROFILE | DIGCF_ALLCLASSES);
+
+  if (devinfo != INVALID_HANDLE_VALUE) {
+    HKEY key;
+    LONG result;
+    WCHAR value[255];
+    DWORD dwcbData;
+    SP_DEVINFO_DATA devinfoData;
+    DWORD memberIndex = 0;
+
+    devinfoData.cbSize = sizeof(devinfoData);
+    NS_NAMED_LITERAL_STRING(driverKeyPre, "System\\CurrentControlSet\\Control\\Class\\");
+    /* enumerate device information elements in the device information set */
+    while (SetupDiEnumDeviceInfo(devinfo, memberIndex++, &devinfoData)) {
+      /* get a string that identifies the device's driver key */
+      if (SetupDiGetDeviceRegistryPropertyW(devinfo,
+                                            &devinfoData,
+                                            SPDRP_DRIVER,
+                                            nullptr,
+                                            (PBYTE)value,
+                                            sizeof(value),
+                                            nullptr)) {
+        nsAutoString driverKey(driverKeyPre);
+        driverKey += value;
+        result = RegOpenKeyExW(HKEY_LOCAL_MACHINE, driverKey.get(), 0, KEY_QUERY_VALUE, &key);
+        if (result == ERROR_SUCCESS) {
+          /* we've found the driver we're looking for */
+          dwcbData = sizeof(value);
+          result = RegQueryValueExW(key, L"DriverVersion", nullptr, nullptr,
+                                    (LPBYTE)value, &dwcbData);
+          if (result == ERROR_SUCCESS) {
+            mDriverVersion = value;
+          } else {
+            // If the entry wasn't found, assume the worst (0.0.0.0).
+            mDriverVersion.AssignLiteral("0.0.0.0");
+          }
+          dwcbData = sizeof(value);
+          result = RegQueryValueExW(key, L"DriverDate", nullptr, nullptr,
+                                    (LPBYTE)value, &dwcbData);
+          if (result == ERROR_SUCCESS) {
+            mDriverDate = value;
+          } else {
+            // Again, assume the worst
+            mDriverDate.AssignLiteral("01-01-1970");
+          }
+          RegCloseKey(key);
+          break;
+        }
+      }
+    }
+
+    SetupDiDestroyDeviceInfoList(devinfo);
+  }
+  return NS_OK;
+}
+
+
+void
+GfxInfo::CheckAndUpdateDriverInfo()
+{
+
   mHasDriverVersionMismatch = false;
   if (mAdapterVendorID == GfxDriverInfo::GetDeviceVendor(VendorIntel)) {
     // we've had big crashers (bugs 590373 and 595364) apparently correlated
     // with bad Intel driver installations where the DriverVersion reported
     // by the registry was not the version of the DLL.
     bool is64bitApp = sizeof(void*) == 8;
     const char16_t *dllFileName = is64bitApp
                                  ? u"igd10umd64.dll"
@@ -569,20 +649,16 @@ GfxInfo::Init()
   if (spoofedVendor) {
     mAdapterVendorID.AssignASCII(spoofedVendor);
   }
 
   const char *spoofedDevice = PR_GetEnv("MOZ_GFX_SPOOF_DEVICE_ID");
   if (spoofedDevice) {
     mAdapterDeviceID.AssignASCII(spoofedDevice);
   }
-
-  AddCrashReportAnnotations();
-
-  return rv;
 }
 
 NS_IMETHODIMP
 GfxInfo::GetAdapterDescription(nsAString & aAdapterDescription)
 {
   aAdapterDescription = mDeviceString;
   return NS_OK;
 }
--- a/widget/windows/GfxInfo.h
+++ b/widget/windows/GfxInfo.h
@@ -41,16 +41,18 @@ public:
   NS_IMETHOD GetAdapterRAM2(nsAString & aAdapterRAM) override;
   NS_IMETHOD GetAdapterDriverVersion2(nsAString & aAdapterDriverVersion) override;
   NS_IMETHOD GetAdapterDriverDate2(nsAString & aAdapterDriverDate) override;
   NS_IMETHOD GetIsGPU2Active(bool *aIsGPU2Active) override;
   using GfxInfoBase::GetFeatureStatus;
   using GfxInfoBase::GetFeatureSuggestedDriverVersion;
   using GfxInfoBase::GetWebGLParameter;
 
+  NS_IMETHOD Reset(const nsAString& aVendorID, const nsAString& aDeviceID) override;
+
   virtual nsresult Init() override;
 
   virtual uint32_t OperatingSystemVersion() override { return mWindowsVersion; }
 
   nsresult FindMonitors(JSContext* cx, JS::HandleObject array) override;
 
 #ifdef DEBUG
   NS_DECL_ISUPPORTS_INHERITED
@@ -67,16 +69,18 @@ protected:
                                         OperatingSystem* aOS = nullptr) override;
   virtual const nsTArray<GfxDriverInfo>& GetGfxDriverInfo() override;
 
   void DescribeFeatures(JSContext* cx, JS::Handle<JSObject*> aOut) override;
 
 private:
 
   void AddCrashReportAnnotations();
+  nsresult UpdatePrimaryDeviceInfo(DISPLAY_DEVICEW &displayDevice);
+  void CheckAndUpdateDriverInfo();
 
   nsString mDeviceString;
   nsString mDeviceID;
   nsString mDriverVersion;
   nsString mDriverDate;
   nsString mDeviceKey;
   nsString mDeviceKeyDebug;
   nsString mAdapterVendorID;