--- a/dom/media/platforms/wmf/WMFVideoMFTManager.cpp
+++ b/dom/media/platforms/wmf/WMFVideoMFTManager.cpp
@@ -9,28 +9,31 @@
#include "MediaDecoderReader.h"
#include "MediaPrefs.h"
#include "WMFUtils.h"
#include "ImageContainer.h"
#include "VideoUtils.h"
#include "DXVA2Manager.h"
#include "nsThreadUtils.h"
#include "Layers.h"
+#include "mozilla/ClearOnShutdown.h"
#include "mozilla/layers/LayersTypes.h"
#include "MediaInfo.h"
#include "MediaPrefs.h"
#include "mozilla/Logging.h"
+#include "mozilla/Preferences.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"
+#include "GMPUtils.h" // For SplitAt. TODO: Move SplitAt to a central place.
extern mozilla::LogModule* GetPDMLog();
#define LOG(...) MOZ_LOG(GetPDMLog(), mozilla::LogLevel::Debug, (__VA_ARGS__))
using mozilla::layers::Image;
using mozilla::layers::IMFYCbCrImage;
using mozilla::layers::LayerManager;
using mozilla::layers::LayersBackend;
@@ -146,123 +149,154 @@ 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
-{
- constexpr
- BlacklistedD3D11DLL(LPCWSTR aName, DWORD a, DWORD b, DWORD c, DWORD d)
- : name(aName), ms((a << 16) | b), ls((c << 16) | d)
- {}
- LPCWSTR name;
- DWORD ms;
- DWORD ls;
-};
-static constexpr BlacklistedD3D11DLL sBlacklistedD3D11DLL[] =
+struct D3D11BlacklistingCache
{
- // Keep same DLL names together.
- BlacklistedD3D11DLL(L"igd10umd32.dll", 9,17,10,2857),
- BlacklistedD3D11DLL(L"isonyvideoprocessor.dll", 4,1,2247,8090),
- BlacklistedD3D11DLL(L"isonyvideoprocessor.dll", 4,1,2153,6200),
- BlacklistedD3D11DLL(L"tosqep.dll", 1,2,15,526),
- BlacklistedD3D11DLL(L"tosqep.dll", 1,1,12,201),
- BlacklistedD3D11DLL(L"tosqep.dll", 1,0,11,318),
- BlacklistedD3D11DLL(L"tosqep.dll", 1,0,11,215),
- BlacklistedD3D11DLL(L"tosqep64.dll", 1,1,12,201),
- BlacklistedD3D11DLL(L"tosqep64.dll", 1,0,11,215),
- // Keep this last.
- BlacklistedD3D11DLL(nullptr, 0,0,0,0)
+ // D3D11-blacklist pref last seen.
+ nsCString mBlacklistPref;
+ // Non-empty if a D3D11-blacklisted DLL was found.
+ nsCString mBlacklistedDLL;
};
+StaticAutoPtr<D3D11BlacklistingCache> sD3D11BlacklistingCache;
-// If a blacklisted DLL is found, return its information, otherwise nullptr.
-static const BlacklistedD3D11DLL*
-IsD3D11DLLBlacklisted()
+// If a blacklisted DLL is found, return its information, otherwise "".
+static const nsACString&
+FindD3D11BlacklistedDLL()
{
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;
+
+ if (!sD3D11BlacklistingCache) {
+ // First time here, create persistent data that will be reused in all
+ // D3D11-blacklisting checks.
+ sD3D11BlacklistingCache = new D3D11BlacklistingCache();
+ ClearOnShutdown(&sD3D11BlacklistingCache);
+ }
+
+ nsAdoptingCString blacklist =
+ Preferences::GetCString("media.wmf.disable-d3d11-for-dlls");
+ if (blacklist.IsEmpty()) {
+ // Empty blacklist -> No blacklisting.
+ sD3D11BlacklistingCache->mBlacklistPref.SetLength(0);
+ sD3D11BlacklistingCache->mBlacklistedDLL.SetLength(0);
+ return sD3D11BlacklistingCache->mBlacklistedDLL;
}
- 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;
+ // Detect changes in pref.
+ if (sD3D11BlacklistingCache->mBlacklistPref.Equals(blacklist)) {
+ // Same blacklist -> Return same result (i.e., don't check DLLs again).
+ return sD3D11BlacklistingCache->mBlacklistedDLL;
+ }
+ // Adopt new pref now, so we don't work on it again.
+ sD3D11BlacklistingCache->mBlacklistPref = blacklist;
+
+ // media.wmf.disable-d3d11-for-dlls format: (whitespace is trimmed)
+ // "dll1.dll: 1.2.3.4[, more versions...][; more dlls...]"
+ nsTArray<nsCString> dlls;
+ SplitAt(";", blacklist, dlls);
+ for (const auto& dll : dlls) {
+ nsTArray<nsCString> nameAndVersions;
+ SplitAt(":", dll, nameAndVersions);
+ if (nameAndVersions.Length() != 2) {
+ NS_WARNING("Skipping incorrect 'media.wmf.disable-d3d11-for-dlls' dll:versions format");
+ continue;
+ }
+
+ nameAndVersions[0].CompressWhitespace();
+ NS_ConvertUTF8toUTF16 name(nameAndVersions[0]);
+ WCHAR systemPath[MAX_PATH + 1];
+ if (!ConstructSystem32Path(name.get(), systemPath, MAX_PATH + 1)) {
+ // Cannot build path -> Assume it's not the blacklisted DLL.
+ continue;
+ }
- for (const BlacklistedD3D11DLL* dll = sBlacklistedD3D11DLL; ; ++dll) {
- if (!dll->name) {
- // End of list, no blacklisting.
- sAlreadySearched = dll;
- return nullptr;
+ DWORD zero;
+ DWORD infoSize = GetFileVersionInfoSizeW(systemPath, &zero);
+ if (infoSize == 0) {
+ // Can't get file info -> Assume we don't have the blacklisted DLL.
+ continue;
+ }
+ // vInfo is a pointer into infoData, that's why we keep it outside of the loop.
+ auto infoData = MakeUnique<unsigned char[]>(infoSize);
+ VS_FIXEDFILEINFO *vInfo;
+ UINT vInfoLen;
+ if (!GetFileVersionInfoW(systemPath, 0, infoSize, infoData.get())
+ || !VerQueryValueW(infoData.get(), L"\\", (LPVOID*)&vInfo, &vInfoLen)
+ || !vInfo) {
+ // Can't find version -> Assume it's not blacklisted.
+ continue;
}
- // 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.
+
+ nsTArray<nsCString> versions;
+ SplitAt(",", nameAndVersions[1], versions);
+ for (const auto& version : versions) {
+ nsTArray<nsCString> numberStrings;
+ SplitAt(".", version, numberStrings);
+ if (numberStrings.Length() != 4) {
+ NS_WARNING("Skipping incorrect 'media.wmf.disable-d3d11-for-dlls' a.b.c.d version format");
+ continue;
+ }
+ DWORD numbers[4];
+ nsresult errorCode = NS_OK;
+ for (int i = 0; i < 4; ++i) {
+ numberStrings[i].CompressWhitespace();
+ numbers[i] = DWORD(numberStrings[i].ToInteger(&errorCode));
+ if (NS_FAILED(errorCode)) {
+ break;
+ }
+ if (numbers[i] > UINT16_MAX) {
+ errorCode = NS_ERROR_FAILURE;
+ break;
+ }
+ }
+
+ if (NS_FAILED(errorCode)) {
+ NS_WARNING("Skipping incorrect 'media.wmf.disable-d3d11-for-dlls' a.b.c.d version format");
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->dwFileVersionMS == ((numbers[0] << 16) | numbers[1])
+ && vInfo->dwFileVersionLS == ((numbers[2] << 16) | numbers[3])) {
+ // Blacklisted! Record bad DLL.
+ sD3D11BlacklistingCache->mBlacklistedDLL.SetLength(0);
+ sD3D11BlacklistingCache->mBlacklistedDLL.AppendPrintf(
+ "%s (%lu.%lu.%lu.%lu)",
+ nameAndVersions[0].get(), numbers[0], numbers[1], numbers[2], numbers[3]);
+ return sD3D11BlacklistingCache->mBlacklistedDLL;
}
}
+ }
- if (vInfo
- && vInfo->dwFileVersionMS == dll->ms
- && vInfo->dwFileVersionLS == dll->ls) {
- // Blacklisted! Keep pointer to bad DLL.
- sAlreadySearched = dll;
- return dll;
- }
- }
+ // No blacklisted DLL.
+ sD3D11BlacklistingCache->mBlacklistedDLL.SetLength(0);
+ return sD3D11BlacklistingCache->mBlacklistedDLL;
}
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()) {
- 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);
+ const nsACString& blacklistedDLL = FindD3D11BlacklistedDLL();
+ if (!blacklistedDLL.IsEmpty()) {
+ failureReason->AppendPrintf("D3D11 blacklisted with DLL %s",
+ blacklistedDLL);
} 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.
@@ -293,17 +327,19 @@ WMFVideoMFTManager::InitializeDXVA(bool
if (mLayersBackend != LayersBackend::LAYERS_D3D9 &&
mLayersBackend != LayersBackend::LAYERS_D3D11) {
mDXVAFailureReason.AssignLiteral("Unsupported layers backend");
return false;
}
// The DXVA manager must be created on the main thread.
RefPtr<CreateDXVAManagerEvent> event =
- new CreateDXVAManagerEvent(aForceD3D9 ? LayersBackend::LAYERS_D3D9 : mLayersBackend, mDXVAFailureReason);
+ new CreateDXVAManagerEvent(aForceD3D9 ? LayersBackend::LAYERS_D3D9
+ : mLayersBackend,
+ mDXVAFailureReason);
if (NS_IsMainThread()) {
event->Run();
} else {
NS_DispatchToMainThread(event, NS_DISPATCH_SYNC);
}
mDXVA2Manager = event->mDXVA2Manager;
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -313,16 +313,17 @@ pref("media.mp4.enabled", true);
// decoder works on all platforms.
pref("media.use-blank-decoder", false);
#ifdef MOZ_WMF
pref("media.wmf.enabled", true);
pref("media.wmf.decoder.thread-count", -1);
pref("media.wmf.low-latency.enabled", false);
pref("media.wmf.skip-blacklist", false);
pref("media.windows-media-foundation.allow-d3d11-dxva", true);
+pref("media.wmf.disable-d3d11-for-dlls", "igd10umd32.dll: 9.17.10.2857; isonyvideoprocessor.dll: 4.1.2247.8090, 4.1.2153.6200; tosqep.dll: 1.2.15.526, 1.1.12.201, 1.0.11.318, 1.0.11.215; tosqep64.dll: 1.1.12.201, 1.0.11.215");
#endif
#if defined(MOZ_FFMPEG)
#if defined(XP_MACOSX)
pref("media.ffmpeg.enabled", false);
#else
pref("media.ffmpeg.enabled", true);
#endif
#endif