Bug 1268905 - Disable D3D11 with some Toshiba DLLs - r?cpearce draft
authorGerald Squelart <gsquelart@mozilla.com>
Tue, 17 May 2016 12:06:59 +1000
changeset 367636 b8381f52305a38970d50a7b7e2967abca95f4391
parent 367573 a884b96685aa13b65601feddb24e5f85ba861561
child 367639 c68d3a62b8ec577b11ea68917f940d119c351dcd
push id18302
push usergsquelart@mozilla.com
push dateTue, 17 May 2016 03:20:47 +0000
reviewerscpearce
bugs1268905
milestone49.0a1
Bug 1268905 - Disable D3D11 with some Toshiba DLLs - r?cpearce MozReview-Commit-ID: Eoyo7VszBnS
dom/media/platforms/wmf/WMFVideoMFTManager.cpp
--- a/dom/media/platforms/wmf/WMFVideoMFTManager.cpp
+++ b/dom/media/platforms/wmf/WMFVideoMFTManager.cpp
@@ -13,16 +13,17 @@
 #include "VideoUtils.h"
 #include "DXVA2Manager.h"
 #include "nsThreadUtils.h"
 #include "Layers.h"
 #include "mozilla/layers/LayersTypes.h"
 #include "MediaInfo.h"
 #include "MediaPrefs.h"
 #include "mozilla/Logging.h"
+#include "nsWindowsHelpers.h"
 #include "gfx2DGlue.h"
 #include "gfxWindowsPlatform.h"
 #include "IMFYCbCrImage.h"
 #include "mozilla/WindowsVersion.h"
 #include "mozilla/Telemetry.h"
 #include "nsPrintfCString.h"
 #include "MediaTelemetryConstants.h"
 
@@ -145,32 +146,124 @@ WMFVideoMFTManager::GetMediaSubtypeGUID(
   switch (mStreamType) {
     case H264: return MFVideoFormat_H264;
     case VP8: return MFVideoFormat_VP80;
     case VP9: return MFVideoFormat_VP90;
     default: return GUID_NULL;
   };
 }
 
+struct BlacklistedD3D11DLL
+{
+  LPCWSTR name;
+  DWORD ms;
+  DWORD ls;
+};
+#define DLLVER(a, b, c, d) \
+        ((DWORD(a) << 16) | DWORD(b)),  ((DWORD(c) << 16) | DWORD(d))
+static const BlacklistedD3D11DLL sBlacklistedD3D11DLL[] =
+{
+  // Keep same DLL names together.
+  { L"tosqep.dll", DLLVER(1,2,15,526) },
+  { L"tosqep.dll", DLLVER(1,1,12,201) },
+  { L"tosqep.dll", DLLVER(1,0,11,318) },
+  { L"tosqep.dll", DLLVER(1,0,11,215) },
+  { L"tosqep64.dll", DLLVER(1,1,12,201) },
+  { L"tosqep64.dll", DLLVER(1,0,11,215) },
+  // Keep this last.
+  { nullptr, 0u, 0u }
+};
+#undef DLLVER
+
+// If a blacklisted DLL is found, return its information, otherwise nullptr.
+static const BlacklistedD3D11DLL*
+IsD3D11DLLBlacklisted()
+{
+  NS_ASSERTION(NS_IsMainThread(), "Must be on main thread.");
+  // Cache the result, so we only check DLLs once per browser run.
+  static const BlacklistedD3D11DLL* sAlreadySearched = nullptr;
+  if (sAlreadySearched) {
+    // If we point at the last empty entry, there's no actual blacklisting.
+    return sAlreadySearched->name ? sAlreadySearched : nullptr;
+  }
+
+  WCHAR systemPath[MAX_PATH + 1];
+  LPCWSTR previousDLLName = L"";
+  VS_FIXEDFILEINFO *vInfo = nullptr;
+  // vInfo is a pointer into infoData, that's why we keep it outside of the loop.
+  UniquePtr<unsigned char[]> infoData;
+
+  for (const BlacklistedD3D11DLL* dll = sBlacklistedD3D11DLL; ; ++dll) {
+    if (!dll->name) {
+      // End of list, no blacklisting.
+      sAlreadySearched = dll;
+      return nullptr;
+    }
+    // Check if we need to check another DLL (compare by pointer to name string)
+    if (wcscmp(previousDLLName, dll->name) != 0) {
+      previousDLLName = dll->name;
+      vInfo = nullptr;
+      infoData = nullptr;
+      if (!ConstructSystem32Path(dll->name, systemPath, MAX_PATH + 1)) {
+        // Cannot build path -> Assume it's not the blacklisted DLL.
+        continue;
+      }
+
+      DWORD zero;
+      DWORD infoSize = GetFileVersionInfoSizeW(systemPath, &zero);
+      if (infoSize == 0) {
+        // Can't get file info -> Assume we don't have the blacklisted DLL.
+        continue;
+      }
+      infoData = MakeUnique<unsigned char[]>(infoSize);
+      UINT vInfoLen;
+      if (!GetFileVersionInfoW(systemPath, 0, infoSize, infoData.get())
+          || !VerQueryValueW(infoData.get(), L"\\", (LPVOID*)&vInfo, &vInfoLen)) {
+        // Can't find version -> Assume it's not blacklisted.
+        vInfo = nullptr;
+        infoData = nullptr;
+        continue;
+      }
+    }
+
+    if (vInfo
+        && vInfo->dwFileVersionMS == dll->ms
+        && vInfo->dwFileVersionLS == dll->ls) {
+      // Blacklisted! Keep pointer to bad DLL.
+      sAlreadySearched = dll;
+      return dll;
+    }
+  }
+}
+
 class CreateDXVAManagerEvent : public Runnable {
 public:
   CreateDXVAManagerEvent(LayersBackend aBackend, nsCString& aFailureReason)
     : mBackend(aBackend)
     , mFailureReason(aFailureReason)
   {}
 
   NS_IMETHOD Run() {
     NS_ASSERTION(NS_IsMainThread(), "Must be on main thread.");
     nsACString* failureReason = &mFailureReason;
     nsCString secondFailureReason;
     if (mBackend == LayersBackend::LAYERS_D3D11 &&
         MediaPrefs::PDMWMFAllowD3D11() && IsWin8OrLater()) {
-      mDXVA2Manager = DXVA2Manager::CreateD3D11DXVA(*failureReason);
-      if (mDXVA2Manager) {
-        return NS_OK;
+      const BlacklistedD3D11DLL* blacklistedDLL = IsD3D11DLLBlacklisted();
+      if (blacklistedDLL) {
+        failureReason->AppendPrintf(
+          "D3D11 blacklisted with DLL %s (%u.%u.%u.%u)",
+          blacklistedDLL->name,
+          blacklistedDLL->ms >> 16, blacklistedDLL->ms & 0xFFu,
+          blacklistedDLL->ls >> 16, blacklistedDLL->ls & 0xFFu);
+      } else {
+        mDXVA2Manager = DXVA2Manager::CreateD3D11DXVA(*failureReason);
+        if (mDXVA2Manager) {
+          return NS_OK;
+        }
       }
       // Try again with d3d9, but record the failure reason
       // into a new var to avoid overwriting the d3d11 failure.
       failureReason = &secondFailureReason;
       mFailureReason.Append(NS_LITERAL_CSTRING("; "));
     }
     mDXVA2Manager = DXVA2Manager::CreateD3D9DXVA(*failureReason);
     // Make sure we include the messages from both attempts (if applicable).