diff -r 000000000000 -r 6474c204b198 widget/windows/GfxInfo.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/widget/windows/GfxInfo.cpp Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,1108 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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 "mozilla/ArrayUtils.h" + +#include +#include +#include "gfxWindowsPlatform.h" +#include "GfxInfo.h" +#include "GfxInfoWebGL.h" +#include "nsUnicharUtils.h" +#include "prenv.h" +#include "prprf.h" +#include "GfxDriverInfo.h" +#include "mozilla/Preferences.h" +#include "nsPrintfCString.h" + +#if defined(MOZ_CRASHREPORTER) +#include "nsExceptionHandler.h" +#include "nsICrashReporter.h" +#define NS_CRASHREPORTER_CONTRACTID "@mozilla.org/toolkit/crash-reporter;1" +#endif + +using namespace mozilla; +using namespace mozilla::widget; + +#ifdef DEBUG +NS_IMPL_ISUPPORTS_INHERITED(GfxInfo, GfxInfoBase, nsIGfxInfoDebug) +#endif + +static const uint32_t allWindowsVersions = 0xffffffff; + +GfxInfo::GfxInfo() + : mWindowsVersion(0), + mHasDualGPU(false), + mIsGPU2Active(false) +{ +} + +/* GetD2DEnabled and GetDwriteEnabled shouldn't be called until after gfxPlatform initialization + * has occurred because they depend on it for information. (See bug 591561) */ +nsresult +GfxInfo::GetD2DEnabled(bool *aEnabled) +{ + *aEnabled = gfxWindowsPlatform::GetPlatform()->GetRenderMode() == gfxWindowsPlatform::RENDER_DIRECT2D; + return NS_OK; +} + +nsresult +GfxInfo::GetDWriteEnabled(bool *aEnabled) +{ + *aEnabled = gfxWindowsPlatform::GetPlatform()->DWriteEnabled(); + return NS_OK; +} + +/* readonly attribute DOMString DWriteVersion; */ +NS_IMETHODIMP +GfxInfo::GetDWriteVersion(nsAString & aDwriteVersion) +{ + gfxWindowsPlatform::GetDLLVersion(L"dwrite.dll", aDwriteVersion); + return NS_OK; +} + +#define PIXEL_STRUCT_RGB 1 +#define PIXEL_STRUCT_BGR 2 + +/* readonly attribute DOMString cleartypeParameters; */ +NS_IMETHODIMP +GfxInfo::GetCleartypeParameters(nsAString & aCleartypeParams) +{ + nsTArray clearTypeParams; + + gfxWindowsPlatform::GetPlatform()->GetCleartypeParams(clearTypeParams); + uint32_t d, numDisplays = clearTypeParams.Length(); + bool displayNames = (numDisplays > 1); + bool foundData = false; + nsString outStr; + + for (d = 0; d < numDisplays; d++) { + ClearTypeParameterInfo& params = clearTypeParams[d]; + + if (displayNames) { + outStr.AppendPrintf("%s [ ", params.displayName.get()); + } + + if (params.gamma >= 0) { + foundData = true; + outStr.AppendPrintf("Gamma: %d ", params.gamma); + } + + if (params.pixelStructure >= 0) { + foundData = true; + if (params.pixelStructure == PIXEL_STRUCT_RGB || + params.pixelStructure == PIXEL_STRUCT_BGR) + { + outStr.AppendPrintf("Pixel Structure: %s ", + (params.pixelStructure == PIXEL_STRUCT_RGB ? + L"RGB" : L"BGR")); + } else { + outStr.AppendPrintf("Pixel Structure: %d ", params.pixelStructure); + } + } + + if (params.clearTypeLevel >= 0) { + foundData = true; + outStr.AppendPrintf("ClearType Level: %d ", params.clearTypeLevel); + } + + if (params.enhancedContrast >= 0) { + foundData = true; + outStr.AppendPrintf("Enhanced Contrast: %d ", params.enhancedContrast); + } + + if (displayNames) { + outStr.Append(MOZ_UTF16("] ")); + } + } + + if (foundData) { + aCleartypeParams.Assign(outStr); + return NS_OK; + } + return NS_ERROR_FAILURE; +} + +static nsresult GetKeyValue(const WCHAR* keyLocation, const WCHAR* keyName, nsAString& destString, int type) +{ + HKEY key; + DWORD dwcbData; + DWORD dValue; + DWORD resultType; + LONG result; + nsresult retval = NS_OK; + + result = RegOpenKeyExW(HKEY_LOCAL_MACHINE, keyLocation, 0, KEY_QUERY_VALUE, &key); + if (result != ERROR_SUCCESS) { + return NS_ERROR_FAILURE; + } + + switch (type) { + case REG_DWORD: { + // We only use this for vram size + dwcbData = sizeof(dValue); + result = RegQueryValueExW(key, keyName, nullptr, &resultType, + (LPBYTE)&dValue, &dwcbData); + if (result == ERROR_SUCCESS && resultType == REG_DWORD) { + dValue = dValue / 1024 / 1024; + destString.AppendInt(int32_t(dValue)); + } else { + retval = NS_ERROR_FAILURE; + } + break; + } + case REG_MULTI_SZ: { + // A chain of null-separated strings; we convert the nulls to spaces + WCHAR wCharValue[1024]; + dwcbData = sizeof(wCharValue); + + result = RegQueryValueExW(key, keyName, nullptr, &resultType, + (LPBYTE)wCharValue, &dwcbData); + if (result == ERROR_SUCCESS && resultType == REG_MULTI_SZ) { + // This bit here could probably be cleaner. + bool isValid = false; + + DWORD strLen = dwcbData/sizeof(wCharValue[0]); + for (DWORD i = 0; i < strLen; i++) { + if (wCharValue[i] == '\0') { + if (i < strLen - 1 && wCharValue[i + 1] == '\0') { + isValid = true; + break; + } else { + wCharValue[i] = ' '; + } + } + } + + // ensure wCharValue is null terminated + wCharValue[strLen-1] = '\0'; + + if (isValid) + destString = wCharValue; + + } else { + retval = NS_ERROR_FAILURE; + } + + break; + } + } + RegCloseKey(key); + + return retval; +} + +// The driver ID is a string like PCI\VEN_15AD&DEV_0405&SUBSYS_040515AD, possibly +// followed by &REV_XXXX. We uppercase the string, and strip the &REV_ part +// from it, if found. +static void normalizeDriverId(nsString& driverid) { + ToUpperCase(driverid); + int32_t rev = driverid.Find(NS_LITERAL_CSTRING("&REV_")); + if (rev != -1) { + driverid.Cut(rev, driverid.Length()); + } +} + +// The device ID is a string like PCI\VEN_15AD&DEV_0405&SUBSYS_040515AD +// this function is used to extract the id's out of it +uint32_t +ParseIDFromDeviceID(const nsAString &key, const char *prefix, int length) +{ + nsAutoString id(key); + ToUpperCase(id); + int32_t start = id.Find(prefix); + if (start != -1) { + id.Cut(0, start + strlen(prefix)); + id.Truncate(length); + } + nsresult err; + return id.ToInteger(&err, 16); +} + +// OS version in 16.16 major/minor form +// based on http://msdn.microsoft.com/en-us/library/ms724834(VS.85).aspx +enum { + kWindowsUnknown = 0, + kWindowsXP = 0x50001, + kWindowsServer2003 = 0x50002, + kWindowsVista = 0x60000, + kWindows7 = 0x60001, + kWindows8 = 0x60002, + kWindows8_1 = 0x60003 +}; + +static int32_t +WindowsOSVersion() +{ + static int32_t winVersion = UNINITIALIZED_VALUE; + + OSVERSIONINFO vinfo; + + if (winVersion == UNINITIALIZED_VALUE) { + vinfo.dwOSVersionInfoSize = sizeof (vinfo); +#pragma warning(push) +#pragma warning(disable:4996) + if (!GetVersionEx(&vinfo)) { +#pragma warning(pop) + winVersion = kWindowsUnknown; + } else { + winVersion = int32_t(vinfo.dwMajorVersion << 16) + vinfo.dwMinorVersion; + } + } + + return winVersion; +} + +/* Other interesting places for info: + * IDXGIAdapter::GetDesc() + * IDirectDraw7::GetAvailableVidMem() + * e->GetAvailableTextureMem() + * */ + +#define DEVICE_KEY_PREFIX L"\\Registry\\Machine\\" +nsresult +GfxInfo::Init() +{ + nsresult rv = GfxInfoBase::Init(); + + DISPLAY_DEVICEW displayDevice; + displayDevice.cb = sizeof(displayDevice); + int deviceIndex = 0; + + const char *spoofedWindowsVersion = PR_GetEnv("MOZ_GFX_SPOOF_WINDOWS_VERSION"); + if (spoofedWindowsVersion) { + PR_sscanf(spoofedWindowsVersion, "%x", &mWindowsVersion); + } else { + mWindowsVersion = WindowsOSVersion(); + } + + mDeviceKeyDebug = NS_LITERAL_STRING("PrimarySearch"); + + 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) + 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 = ParseIDFromDeviceID(mDeviceID, "&SUBSYS_", 8); + + // We now check for second display adapter. + + // 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); + + 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); + + nsAutoString adapterDriver2; + nsAutoString deviceID2; + nsAutoString driverVersion2; + nsAutoString driverDate2; + uint32_t adapterVendorID2; + uint32_t adapterDeviceID2; + + 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 driverKey2(driverKeyPre); + driverKey2 += value; + result = RegOpenKeyExW(HKEY_LOCAL_MACHINE, driverKey2.get(), 0, KEY_QUERY_VALUE, &key); + if (result == ERROR_SUCCESS) { + dwcbData = sizeof(value); + result = RegQueryValueExW(key, L"MatchingDeviceId", nullptr, + nullptr, (LPBYTE)value, &dwcbData); + if (result != ERROR_SUCCESS) { + continue; + } + deviceID2 = value; + nsAutoString adapterVendorID2String; + nsAutoString adapterDeviceID2String; + adapterVendorID2 = ParseIDFromDeviceID(deviceID2, "VEN_", 4); + adapterVendorID2String.AppendPrintf("0x%04x", adapterVendorID2); + adapterDeviceID2 = ParseIDFromDeviceID(deviceID2, "&DEV_", 4); + adapterDeviceID2String.AppendPrintf("0x%04x", adapterDeviceID2); + if (mAdapterVendorID == adapterVendorID2String && + mAdapterDeviceID == adapterDeviceID2String) { + RegCloseKey(key); + continue; + } + + // If this device is missing driver information, it is unlikely to + // be a real display adapter. + if (NS_FAILED(GetKeyValue(driverKey2.get(), L"InstalledDisplayDrivers", + adapterDriver2, REG_MULTI_SZ))) { + RegCloseKey(key); + continue; + } + dwcbData = sizeof(value); + result = RegQueryValueExW(key, L"DriverVersion", nullptr, nullptr, + (LPBYTE)value, &dwcbData); + if (result != ERROR_SUCCESS) { + RegCloseKey(key); + continue; + } + driverVersion2 = value; + dwcbData = sizeof(value); + result = RegQueryValueExW(key, L"DriverDate", nullptr, nullptr, + (LPBYTE)value, &dwcbData); + if (result != ERROR_SUCCESS) { + RegCloseKey(key); + continue; + } + driverDate2 = value; + dwcbData = sizeof(value); + result = RegQueryValueExW(key, L"Device Description", nullptr, + nullptr, (LPBYTE)value, &dwcbData); + if (result != ERROR_SUCCESS) { + dwcbData = sizeof(value); + result = RegQueryValueExW(key, L"DriverDesc", nullptr, nullptr, + (LPBYTE)value, &dwcbData); + } + RegCloseKey(key); + if (result == ERROR_SUCCESS) { + mHasDualGPU = true; + mDeviceString2 = value; + mDeviceID2 = deviceID2; + mDeviceKey2 = driverKey2; + mDriverVersion2 = driverVersion2; + mDriverDate2 = driverDate2; + mAdapterVendorID2.AppendPrintf("0x%04x", adapterVendorID2); + mAdapterDeviceID2.AppendPrintf("0x%04x", adapterDeviceID2); + mAdapterSubsysID2 = ParseIDFromDeviceID(mDeviceID2, "&SUBSYS_", 8); + break; + } + } + } + } + + SetupDiDestroyDeviceInfoList(devinfo); + } + } + + 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 + ? MOZ_UTF16("igd10umd64.dll") + : MOZ_UTF16("igd10umd32.dll"), + *dllFileName2 = is64bitApp + ? MOZ_UTF16("igd10iumd64.dll") + : MOZ_UTF16("igd10iumd32.dll"); + nsString dllVersion, dllVersion2; + gfxWindowsPlatform::GetDLLVersion((char16_t*)dllFileName, dllVersion); + gfxWindowsPlatform::GetDLLVersion((char16_t*)dllFileName2, dllVersion2); + + uint64_t dllNumericVersion = 0, dllNumericVersion2 = 0, + driverNumericVersion = 0, knownSafeMismatchVersion = 0; + ParseDriverVersion(dllVersion, &dllNumericVersion); + ParseDriverVersion(dllVersion2, &dllNumericVersion2); + ParseDriverVersion(mDriverVersion, &driverNumericVersion); + ParseDriverVersion(NS_LITERAL_STRING("9.17.10.0"), &knownSafeMismatchVersion); + + // If there's a driver version mismatch, consider this harmful only when + // the driver version is less than knownSafeMismatchVersion. See the + // above comment about crashes with old mismatches. If the GetDllVersion + // call fails, then they return 0, so that will be considered a mismatch. + if (dllNumericVersion != driverNumericVersion && + dllNumericVersion2 != driverNumericVersion && + (driverNumericVersion < knownSafeMismatchVersion || + std::max(dllNumericVersion, dllNumericVersion2) < knownSafeMismatchVersion)) { + mHasDriverVersionMismatch = true; + } + } + + const char *spoofedDriverVersionString = PR_GetEnv("MOZ_GFX_SPOOF_DRIVER_VERSION"); + if (spoofedDriverVersionString) { + mDriverVersion.AssignASCII(spoofedDriverVersionString); + } + + const char *spoofedVendor = PR_GetEnv("MOZ_GFX_SPOOF_VENDOR_ID"); + if (spoofedVendor) { + mAdapterVendorID.AssignASCII(spoofedVendor); + } + + const char *spoofedDevice = PR_GetEnv("MOZ_GFX_SPOOF_DEVICE_ID"); + if (spoofedDevice) { + mAdapterDeviceID.AssignASCII(spoofedDevice); + } + + AddCrashReportAnnotations(); + + return rv; +} + +/* readonly attribute DOMString adapterDescription; */ +NS_IMETHODIMP +GfxInfo::GetAdapterDescription(nsAString & aAdapterDescription) +{ + aAdapterDescription = mDeviceString; + return NS_OK; +} + +/* readonly attribute DOMString adapterDescription2; */ +NS_IMETHODIMP +GfxInfo::GetAdapterDescription2(nsAString & aAdapterDescription) +{ + aAdapterDescription = mDeviceString2; + return NS_OK; +} + +/* readonly attribute DOMString adapterRAM; */ +NS_IMETHODIMP +GfxInfo::GetAdapterRAM(nsAString & aAdapterRAM) +{ + if (NS_FAILED(GetKeyValue(mDeviceKey.get(), L"HardwareInformation.MemorySize", aAdapterRAM, REG_DWORD))) + aAdapterRAM = L"Unknown"; + return NS_OK; +} + +/* readonly attribute DOMString adapterRAM2; */ +NS_IMETHODIMP +GfxInfo::GetAdapterRAM2(nsAString & aAdapterRAM) +{ + if (!mHasDualGPU) { + aAdapterRAM.AssignLiteral(""); + } else if (NS_FAILED(GetKeyValue(mDeviceKey2.get(), L"HardwareInformation.MemorySize", aAdapterRAM, REG_DWORD))) { + aAdapterRAM = L"Unknown"; + } + return NS_OK; +} + +/* readonly attribute DOMString adapterDriver; */ +NS_IMETHODIMP +GfxInfo::GetAdapterDriver(nsAString & aAdapterDriver) +{ + if (NS_FAILED(GetKeyValue(mDeviceKey.get(), L"InstalledDisplayDrivers", aAdapterDriver, REG_MULTI_SZ))) + aAdapterDriver = L"Unknown"; + return NS_OK; +} + +/* readonly attribute DOMString adapterDriver2; */ +NS_IMETHODIMP +GfxInfo::GetAdapterDriver2(nsAString & aAdapterDriver) +{ + if (!mHasDualGPU) { + aAdapterDriver.AssignLiteral(""); + } else if (NS_FAILED(GetKeyValue(mDeviceKey2.get(), L"InstalledDisplayDrivers", aAdapterDriver, REG_MULTI_SZ))) { + aAdapterDriver = L"Unknown"; + } + return NS_OK; +} + +/* readonly attribute DOMString adapterDriverVersion; */ +NS_IMETHODIMP +GfxInfo::GetAdapterDriverVersion(nsAString & aAdapterDriverVersion) +{ + aAdapterDriverVersion = mDriverVersion; + return NS_OK; +} + +/* readonly attribute DOMString adapterDriverDate; */ +NS_IMETHODIMP +GfxInfo::GetAdapterDriverDate(nsAString & aAdapterDriverDate) +{ + aAdapterDriverDate = mDriverDate; + return NS_OK; +} + +/* readonly attribute DOMString adapterDriverVersion2; */ +NS_IMETHODIMP +GfxInfo::GetAdapterDriverVersion2(nsAString & aAdapterDriverVersion) +{ + aAdapterDriverVersion = mDriverVersion2; + return NS_OK; +} + +/* readonly attribute DOMString adapterDriverDate2; */ +NS_IMETHODIMP +GfxInfo::GetAdapterDriverDate2(nsAString & aAdapterDriverDate) +{ + aAdapterDriverDate = mDriverDate2; + return NS_OK; +} + +/* readonly attribute DOMString adapterVendorID; */ +NS_IMETHODIMP +GfxInfo::GetAdapterVendorID(nsAString & aAdapterVendorID) +{ + aAdapterVendorID = mAdapterVendorID; + return NS_OK; +} + +/* readonly attribute DOMString adapterVendorID2; */ +NS_IMETHODIMP +GfxInfo::GetAdapterVendorID2(nsAString & aAdapterVendorID) +{ + aAdapterVendorID = mAdapterVendorID2; + return NS_OK; +} + +/* readonly attribute DOMString adapterDeviceID; */ +NS_IMETHODIMP +GfxInfo::GetAdapterDeviceID(nsAString & aAdapterDeviceID) +{ + aAdapterDeviceID = mAdapterDeviceID; + return NS_OK; +} + +/* readonly attribute DOMString adapterDeviceID2; */ +NS_IMETHODIMP +GfxInfo::GetAdapterDeviceID2(nsAString & aAdapterDeviceID) +{ + aAdapterDeviceID = mAdapterDeviceID2; + return NS_OK; +} + +/* readonly attribute boolean isGPU2Active; */ +NS_IMETHODIMP +GfxInfo::GetIsGPU2Active(bool* aIsGPU2Active) +{ + *aIsGPU2Active = mIsGPU2Active; + return NS_OK; +} + +#if defined(MOZ_CRASHREPORTER) +/* Cisco's VPN software can cause corruption of the floating point state. + * Make a note of this in our crash reports so that some weird crashes + * make more sense */ +static void +CheckForCiscoVPN() { + LONG result; + HKEY key; + /* This will give false positives, but hopefully no false negatives */ + result = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"Software\\Cisco Systems\\VPN Client", 0, KEY_QUERY_VALUE, &key); + if (result == ERROR_SUCCESS) { + RegCloseKey(key); + CrashReporter::AppendAppNotesToCrashReport(NS_LITERAL_CSTRING("Cisco VPN\n")); + } +} +#endif + +void +GfxInfo::AddCrashReportAnnotations() +{ +#if defined(MOZ_CRASHREPORTER) + CheckForCiscoVPN(); + + nsString deviceID, vendorID; + nsCString narrowDeviceID, narrowVendorID; + nsAutoString adapterDriverVersionString; + + GetAdapterDeviceID(deviceID); + CopyUTF16toUTF8(deviceID, narrowDeviceID); + GetAdapterVendorID(vendorID); + CopyUTF16toUTF8(vendorID, narrowVendorID); + GetAdapterDriverVersion(adapterDriverVersionString); + + CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("AdapterVendorID"), + narrowVendorID); + CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("AdapterDeviceID"), + narrowDeviceID); + + /* Add an App Note for now so that we get the data immediately. These + * can go away after we store the above in the socorro db */ + nsAutoCString note; + /* AppendPrintf only supports 32 character strings, mrghh. */ + note.Append("AdapterVendorID: "); + note.Append(narrowVendorID); + note.Append(", AdapterDeviceID: "); + note.Append(narrowDeviceID); + note.AppendPrintf(", AdapterSubsysID: %08x, ", mAdapterSubsysID); + note.Append("AdapterDriverVersion: "); + note.Append(NS_LossyConvertUTF16toASCII(adapterDriverVersionString)); + + if (vendorID == GfxDriverInfo::GetDeviceVendor(VendorAll)) { + /* if we didn't find a valid vendorID lets append the mDeviceID string to try to find out why */ + note.Append(", "); + LossyAppendUTF16toASCII(mDeviceID, note); + note.Append(", "); + LossyAppendUTF16toASCII(mDeviceKeyDebug, note); + LossyAppendUTF16toASCII(mDeviceKeyDebug, note); + } + note.Append("\n"); + + if (mHasDualGPU) { + nsString deviceID2, vendorID2; + nsAutoString adapterDriverVersionString2; + nsCString narrowDeviceID2, narrowVendorID2; + + note.AppendLiteral("Has dual GPUs. GPU #2: "); + GetAdapterDeviceID2(deviceID2); + CopyUTF16toUTF8(deviceID2, narrowDeviceID2); + GetAdapterVendorID2(vendorID2); + CopyUTF16toUTF8(vendorID2, narrowVendorID2); + GetAdapterDriverVersion2(adapterDriverVersionString2); + note.Append("AdapterVendorID2: "); + note.Append(narrowVendorID2); + note.Append(", AdapterDeviceID2: "); + note.Append(narrowDeviceID2); + note.AppendPrintf(", AdapterSubsysID2: %08x, ", mAdapterSubsysID2); + note.AppendPrintf("AdapterDriverVersion2: "); + note.Append(NS_LossyConvertUTF16toASCII(adapterDriverVersionString2)); + } + CrashReporter::AppendAppNotesToCrashReport(note); + +#endif +} + +static OperatingSystem +WindowsVersionToOperatingSystem(int32_t aWindowsVersion) +{ + switch(aWindowsVersion) { + case kWindowsXP: + return DRIVER_OS_WINDOWS_XP; + case kWindowsServer2003: + return DRIVER_OS_WINDOWS_SERVER_2003; + case kWindowsVista: + return DRIVER_OS_WINDOWS_VISTA; + case kWindows7: + return DRIVER_OS_WINDOWS_7; + case kWindows8: + return DRIVER_OS_WINDOWS_8; + case kWindows8_1: + return DRIVER_OS_WINDOWS_8_1; + case kWindowsUnknown: + default: + return DRIVER_OS_UNKNOWN; + }; +} + +const nsTArray& +GfxInfo::GetGfxDriverInfo() +{ + if (!mDriverInfo->Length()) { + /* + * It should be noted here that more specialized rules on certain features + * should be inserted -before- more generalized restriction. As the first + * match for feature/OS/device found in the list will be used for the final + * blacklisting call. + */ + + /* + * NVIDIA entries + */ + APPEND_TO_DRIVER_BLOCKLIST( DRIVER_OS_WINDOWS_VISTA, + (nsAString&) GfxDriverInfo::GetDeviceVendor(VendorNVIDIA), GfxDriverInfo::allDevices, + nsIGfxInfo::FEATURE_DIRECT2D, nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION, + DRIVER_LESS_THAN, V(8,17,12,5721), "257.21" ); + APPEND_TO_DRIVER_BLOCKLIST( DRIVER_OS_WINDOWS_7, + (nsAString&) GfxDriverInfo::GetDeviceVendor(VendorNVIDIA), GfxDriverInfo::allDevices, + nsIGfxInfo::FEATURE_DIRECT2D, nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION, + DRIVER_LESS_THAN, V(8,17,12,5721), "257.21" ); + APPEND_TO_DRIVER_BLOCKLIST( DRIVER_OS_WINDOWS_XP, + (nsAString&) GfxDriverInfo::GetDeviceVendor(VendorNVIDIA), GfxDriverInfo::allDevices, + GfxDriverInfo::allFeatures, nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION, + DRIVER_LESS_THAN, V(6,14,11,8265), "182.65" ); + APPEND_TO_DRIVER_BLOCKLIST( DRIVER_OS_WINDOWS_VISTA, + (nsAString&) GfxDriverInfo::GetDeviceVendor(VendorNVIDIA), GfxDriverInfo::allDevices, + GfxDriverInfo::allFeatures, nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION, + DRIVER_LESS_THAN, V(8,17,11,8265), "182.65" ); + APPEND_TO_DRIVER_BLOCKLIST( DRIVER_OS_WINDOWS_7, + (nsAString&) GfxDriverInfo::GetDeviceVendor(VendorNVIDIA), GfxDriverInfo::allDevices, + GfxDriverInfo::allFeatures, nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION, + DRIVER_LESS_THAN, V(8,17,11,8265), "182.65" ); + + /* + * AMD/ATI entries + */ + APPEND_TO_DRIVER_BLOCKLIST( DRIVER_OS_ALL, + (nsAString&) GfxDriverInfo::GetDeviceVendor(VendorATI), GfxDriverInfo::allDevices, + nsIGfxInfo::FEATURE_DIRECT2D, nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION, + DRIVER_LESS_THAN, V(8,741,0,0), "10.6" ); + APPEND_TO_DRIVER_BLOCKLIST( DRIVER_OS_ALL, + (nsAString&) GfxDriverInfo::GetDeviceVendor(VendorAMD), GfxDriverInfo::allDevices, + nsIGfxInfo::FEATURE_DIRECT2D, nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION, + DRIVER_LESS_THAN, V(8,741,0,0), "10.6" ); + APPEND_TO_DRIVER_BLOCKLIST( DRIVER_OS_ALL, + (nsAString&) GfxDriverInfo::GetDeviceVendor(VendorATI), GfxDriverInfo::allDevices, + GfxDriverInfo::allFeatures, nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION, + DRIVER_LESS_THAN, V(8,62,0,0), "9.6" ); + APPEND_TO_DRIVER_BLOCKLIST( DRIVER_OS_ALL, + (nsAString&) GfxDriverInfo::GetDeviceVendor(VendorAMD), GfxDriverInfo::allDevices, + GfxDriverInfo::allFeatures, nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION, + DRIVER_LESS_THAN, V(8,62,0,0), "9.6" ); + + /* + * Bug 783517 - crashes in AMD driver on Windows 8 + */ + APPEND_TO_DRIVER_BLOCKLIST_RANGE( DRIVER_OS_WINDOWS_8, + (nsAString&) GfxDriverInfo::GetDeviceVendor(VendorATI), GfxDriverInfo::allDevices, + GfxDriverInfo::allFeatures, nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION, + DRIVER_BETWEEN_INCLUSIVE_START, V(8,982,0,0), V(8,983,0,0), "!= 8.982.*.*" ); + APPEND_TO_DRIVER_BLOCKLIST_RANGE( DRIVER_OS_WINDOWS_8, + (nsAString&) GfxDriverInfo::GetDeviceVendor(VendorAMD), GfxDriverInfo::allDevices, + GfxDriverInfo::allFeatures, nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION, + DRIVER_BETWEEN_INCLUSIVE_START, V(8,982,0,0), V(8,983,0,0), "!= 8.982.*.*" ); + + /* OpenGL on any ATI/AMD hardware is discouraged + * See: + * bug 619773 - WebGL: Crash with blue screen : "NMI: Parity Check / Memory Parity Error" + * bugs 584403, 584404, 620924 - crashes in atioglxx + * + many complaints about incorrect rendering + */ + APPEND_TO_DRIVER_BLOCKLIST2( DRIVER_OS_ALL, + (nsAString&) GfxDriverInfo::GetDeviceVendor(VendorATI), GfxDriverInfo::allDevices, + nsIGfxInfo::FEATURE_OPENGL_LAYERS, nsIGfxInfo::FEATURE_DISCOURAGED, + DRIVER_LESS_THAN, GfxDriverInfo::allDriverVersions ); + APPEND_TO_DRIVER_BLOCKLIST2( DRIVER_OS_ALL, + (nsAString&) GfxDriverInfo::GetDeviceVendor(VendorATI), GfxDriverInfo::allDevices, + nsIGfxInfo::FEATURE_WEBGL_OPENGL, nsIGfxInfo::FEATURE_DISCOURAGED, + DRIVER_LESS_THAN, GfxDriverInfo::allDriverVersions ); + APPEND_TO_DRIVER_BLOCKLIST2( DRIVER_OS_ALL, + (nsAString&) GfxDriverInfo::GetDeviceVendor(VendorAMD), GfxDriverInfo::allDevices, + nsIGfxInfo::FEATURE_OPENGL_LAYERS, nsIGfxInfo::FEATURE_DISCOURAGED, + DRIVER_LESS_THAN, GfxDriverInfo::allDriverVersions ); + APPEND_TO_DRIVER_BLOCKLIST2( DRIVER_OS_ALL, + (nsAString&) GfxDriverInfo::GetDeviceVendor(VendorAMD), GfxDriverInfo::allDevices, + nsIGfxInfo::FEATURE_WEBGL_OPENGL, nsIGfxInfo::FEATURE_DISCOURAGED, + DRIVER_LESS_THAN, GfxDriverInfo::allDriverVersions ); + + /* + * Intel entries + */ + + /* implement the blocklist from bug 594877 + * Block all features on any drivers before this, as there's a crash when a MS Hotfix is installed. + * The crash itself is Direct2D-related, but for safety we block all features. + */ + #define IMPLEMENT_INTEL_DRIVER_BLOCKLIST(winVer, devFamily, driverVer) \ + APPEND_TO_DRIVER_BLOCKLIST2( winVer, \ + (nsAString&) GfxDriverInfo::GetDeviceVendor(VendorIntel), (GfxDeviceFamily*) GfxDriverInfo::GetDeviceFamily(devFamily), \ + GfxDriverInfo::allFeatures, nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION, \ + DRIVER_LESS_THAN, driverVer ) + #define IMPLEMENT_INTEL_DRIVER_BLOCKLIST_D2D(winVer, devFamily, driverVer) \ + APPEND_TO_DRIVER_BLOCKLIST2( winVer, \ + (nsAString&) GfxDriverInfo::GetDeviceVendor(VendorIntel), (GfxDeviceFamily*) GfxDriverInfo::GetDeviceFamily(devFamily), \ + nsIGfxInfo::FEATURE_DIRECT2D, nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION, \ + DRIVER_LESS_THAN, driverVer ) + + IMPLEMENT_INTEL_DRIVER_BLOCKLIST_D2D(DRIVER_OS_WINDOWS_VISTA, IntelGMA500, V(7,14,10,1006)); + IMPLEMENT_INTEL_DRIVER_BLOCKLIST_D2D(DRIVER_OS_WINDOWS_VISTA, IntelGMA900, GfxDriverInfo::allDriverVersions); + IMPLEMENT_INTEL_DRIVER_BLOCKLIST_D2D(DRIVER_OS_WINDOWS_VISTA, IntelGMA950, V(7,14,10,1504)); + IMPLEMENT_INTEL_DRIVER_BLOCKLIST_D2D(DRIVER_OS_WINDOWS_VISTA, IntelGMA3150, V(7,14,10,2124)); + IMPLEMENT_INTEL_DRIVER_BLOCKLIST_D2D(DRIVER_OS_WINDOWS_VISTA, IntelGMAX3000, V(7,15,10,1666)); + IMPLEMENT_INTEL_DRIVER_BLOCKLIST_D2D(DRIVER_OS_WINDOWS_VISTA, IntelGMAX4500HD, V(8,15,10,2202)); + + IMPLEMENT_INTEL_DRIVER_BLOCKLIST_D2D(DRIVER_OS_WINDOWS_7, IntelGMA500, V(5,0,0,2026)); + IMPLEMENT_INTEL_DRIVER_BLOCKLIST_D2D(DRIVER_OS_WINDOWS_7, IntelGMA900, GfxDriverInfo::allDriverVersions); + IMPLEMENT_INTEL_DRIVER_BLOCKLIST_D2D(DRIVER_OS_WINDOWS_7, IntelGMA950, V(8,15,10,1930)); + IMPLEMENT_INTEL_DRIVER_BLOCKLIST_D2D(DRIVER_OS_WINDOWS_7, IntelGMA3150, V(8,14,10,2117)); + IMPLEMENT_INTEL_DRIVER_BLOCKLIST_D2D(DRIVER_OS_WINDOWS_7, IntelGMAX3000, V(8,15,10,1930)); + IMPLEMENT_INTEL_DRIVER_BLOCKLIST_D2D(DRIVER_OS_WINDOWS_7, IntelGMAX4500HD, V(8,15,10,2202)); + + IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_XP, IntelGMA500, V(3,0,20,3200)); + IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_XP, IntelGMA900, V(6,14,10,4764)); + IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_XP, IntelGMA950, V(6,14,10,4926)); + IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_XP, IntelGMA3150, V(6,14,10,5134)); + IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_XP, IntelGMAX3000, V(6,14,10,5218)); + IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_XP, IntelGMAX4500HD, V(6,14,10,4969)); + + // StrechRect seems to suffer from precision issues which leads to artifacting + // during content drawing starting with at least version 6.14.10.5082 + // and going until 6.14.10.5218. See bug 919454 and bug 949275 for more info. + APPEND_TO_DRIVER_BLOCKLIST_RANGE(DRIVER_OS_WINDOWS_XP, + const_cast(GfxDriverInfo::GetDeviceVendor(VendorIntel)), + const_cast(GfxDriverInfo::GetDeviceFamily(IntelGMAX4500HD)), + GfxDriverInfo::allFeatures, nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION, + DRIVER_BETWEEN_EXCLUSIVE, V(6,14,10,5076), V(6,14,10,5218), "6.14.10.5218"); + + IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_VISTA, IntelGMA500, V(3,0,20,3200)); + IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_VISTA, IntelGMA900, GfxDriverInfo::allDriverVersions); + IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_VISTA, IntelGMA950, V(7,14,10,1504)); + IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_VISTA, IntelGMA3150, V(7,14,10,1910)); + IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_VISTA, IntelGMAX3000, V(7,15,10,1666)); + IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_VISTA, IntelGMAX4500HD, V(7,15,10,1666)); + + IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_7, IntelGMA500, V(5,0,0,2026)); + IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_7, IntelGMA900, GfxDriverInfo::allDriverVersions); + IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_7, IntelGMA950, V(8,15,10,1930)); + IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_7, IntelGMA3150, V(8,14,10,1972)); + IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_7, IntelGMAX3000, V(7,15,10,1666)); + IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_7, IntelGMAX4500HD, V(7,15,10,1666)); + + /* OpenGL on any Intel hardware is discouraged */ + APPEND_TO_DRIVER_BLOCKLIST2( DRIVER_OS_ALL, + (nsAString&) GfxDriverInfo::GetDeviceVendor(VendorIntel), GfxDriverInfo::allDevices, + nsIGfxInfo::FEATURE_OPENGL_LAYERS, nsIGfxInfo::FEATURE_DISCOURAGED, + DRIVER_LESS_THAN, GfxDriverInfo::allDriverVersions ); + APPEND_TO_DRIVER_BLOCKLIST2( DRIVER_OS_ALL, + (nsAString&) GfxDriverInfo::GetDeviceVendor(VendorIntel), GfxDriverInfo::allDevices, + nsIGfxInfo::FEATURE_WEBGL_OPENGL, nsIGfxInfo::FEATURE_DISCOURAGED, + DRIVER_LESS_THAN, GfxDriverInfo::allDriverVersions ); + + /* Disable D2D on Win7 on Intel HD Graphics on driver <= 8.15.10.2302 + * See bug 806786 + */ + APPEND_TO_DRIVER_BLOCKLIST2( DRIVER_OS_WINDOWS_7, + (nsAString&) GfxDriverInfo::GetDeviceVendor(VendorIntel), (GfxDeviceFamily*) GfxDriverInfo::GetDeviceFamily(IntelMobileHDGraphics), + nsIGfxInfo::FEATURE_DIRECT2D, nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION, + DRIVER_LESS_THAN_OR_EQUAL, V(8,15,10,2302) ); + + /* Disable D2D on Win8 on Intel HD Graphics on driver <= 8.15.10.2302 + * See bug 804144 and 863683 + */ + APPEND_TO_DRIVER_BLOCKLIST2( DRIVER_OS_WINDOWS_8, + (nsAString&) GfxDriverInfo::GetDeviceVendor(VendorIntel), (GfxDeviceFamily*) GfxDriverInfo::GetDeviceFamily(IntelMobileHDGraphics), + nsIGfxInfo::FEATURE_DIRECT2D, nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION, + DRIVER_LESS_THAN_OR_EQUAL, V(8,15,10,2302) ); + + /* Disable D3D9 layers on NVIDIA 6100/6150/6200 series due to glitches + * whilst scrolling. See bugs: 612007, 644787 & 645872. + */ + APPEND_TO_DRIVER_BLOCKLIST2( DRIVER_OS_ALL, + (nsAString&) GfxDriverInfo::GetDeviceVendor(VendorNVIDIA), (GfxDeviceFamily*) GfxDriverInfo::GetDeviceFamily(NvidiaBlockD3D9Layers), + nsIGfxInfo::FEATURE_DIRECT3D_9_LAYERS, nsIGfxInfo::FEATURE_BLOCKED_DEVICE, + DRIVER_LESS_THAN, GfxDriverInfo::allDriverVersions ); + + /* Microsoft RemoteFX; blocked less than 6.2.0.0 */ + APPEND_TO_DRIVER_BLOCKLIST( DRIVER_OS_ALL, + (nsAString&) GfxDriverInfo::GetDeviceVendor(VendorMicrosoft), GfxDriverInfo::allDevices, + GfxDriverInfo::allFeatures, nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION, + DRIVER_LESS_THAN, V(6,2,0,0), "< 6.2.0.0" ); + } + return *mDriverInfo; +} + +nsresult +GfxInfo::GetFeatureStatusImpl(int32_t aFeature, + int32_t *aStatus, + nsAString & aSuggestedDriverVersion, + const nsTArray& aDriverInfo, + OperatingSystem* aOS /* = nullptr */) +{ + NS_ENSURE_ARG_POINTER(aStatus); + aSuggestedDriverVersion.SetIsVoid(true); + OperatingSystem os = WindowsVersionToOperatingSystem(mWindowsVersion); + *aStatus = nsIGfxInfo::FEATURE_STATUS_UNKNOWN; + if (aOS) + *aOS = os; + + // Don't evaluate special cases if we're checking the downloaded blocklist. + if (!aDriverInfo.Length()) { + nsAutoString adapterVendorID; + nsAutoString adapterDeviceID; + nsAutoString adapterDriverVersionString; + if (NS_FAILED(GetAdapterVendorID(adapterVendorID)) || + NS_FAILED(GetAdapterDeviceID(adapterDeviceID)) || + NS_FAILED(GetAdapterDriverVersion(adapterDriverVersionString))) + { + return NS_ERROR_FAILURE; + } + + if (!adapterVendorID.Equals(GfxDriverInfo::GetDeviceVendor(VendorIntel), nsCaseInsensitiveStringComparator()) && + !adapterVendorID.Equals(GfxDriverInfo::GetDeviceVendor(VendorNVIDIA), nsCaseInsensitiveStringComparator()) && + !adapterVendorID.Equals(GfxDriverInfo::GetDeviceVendor(VendorAMD), nsCaseInsensitiveStringComparator()) && + !adapterVendorID.Equals(GfxDriverInfo::GetDeviceVendor(VendorATI), nsCaseInsensitiveStringComparator()) && + !adapterVendorID.Equals(GfxDriverInfo::GetDeviceVendor(VendorMicrosoft), nsCaseInsensitiveStringComparator()) && + // FIXME - these special hex values are currently used in xpcshell tests introduced by + // bug 625160 patch 8/8. Maybe these tests need to be adjusted now that we're only whitelisting + // intel/ati/nvidia. + !adapterVendorID.LowerCaseEqualsLiteral("0xabcd") && + !adapterVendorID.LowerCaseEqualsLiteral("0xdcba") && + !adapterVendorID.LowerCaseEqualsLiteral("0xabab") && + !adapterVendorID.LowerCaseEqualsLiteral("0xdcdc")) + { + *aStatus = FEATURE_BLOCKED_DEVICE; + return NS_OK; + } + + uint64_t driverVersion; + if (!ParseDriverVersion(adapterDriverVersionString, &driverVersion)) { + return NS_ERROR_FAILURE; + } + + // special-case the WinXP test slaves: they have out-of-date drivers, but we still want to + // whitelist them, actually we do know that this combination of device and driver version + // works well. + if (mWindowsVersion == kWindowsXP && + adapterVendorID.Equals(GfxDriverInfo::GetDeviceVendor(VendorNVIDIA), nsCaseInsensitiveStringComparator()) && + adapterDeviceID.LowerCaseEqualsLiteral("0x0861") && // GeForce 9400 + driverVersion == V(6,14,11,7756)) + { + *aStatus = FEATURE_NO_INFO; + return NS_OK; + } + + // Windows Server 2003 should be just like Windows XP for present purpose, but still has a different version number. + // OTOH Windows Server 2008 R1 and R2 already have the same version numbers as Vista and Seven respectively + if (os == DRIVER_OS_WINDOWS_SERVER_2003) + os = DRIVER_OS_WINDOWS_XP; + + if (mHasDriverVersionMismatch) { + if (aFeature == nsIGfxInfo::FEATURE_DIRECT3D_10_LAYERS || + aFeature == nsIGfxInfo::FEATURE_DIRECT3D_10_1_LAYERS || + aFeature == nsIGfxInfo::FEATURE_DIRECT2D) + { + *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION; + return NS_OK; + } + } + } + + return GfxInfoBase::GetFeatureStatusImpl(aFeature, aStatus, aSuggestedDriverVersion, aDriverInfo, &os); +} + +#ifdef DEBUG + +// Implement nsIGfxInfoDebug + +/* void spoofVendorID (in DOMString aVendorID); */ +NS_IMETHODIMP GfxInfo::SpoofVendorID(const nsAString & aVendorID) +{ + mAdapterVendorID = aVendorID; + return NS_OK; +} + +/* void spoofDeviceID (in unsigned long aDeviceID); */ +NS_IMETHODIMP GfxInfo::SpoofDeviceID(const nsAString & aDeviceID) +{ + mAdapterDeviceID = aDeviceID; + return NS_OK; +} + +/* void spoofDriverVersion (in DOMString aDriverVersion); */ +NS_IMETHODIMP GfxInfo::SpoofDriverVersion(const nsAString & aDriverVersion) +{ + mDriverVersion = aDriverVersion; + return NS_OK; +} + +/* void spoofOSVersion (in unsigned long aVersion); */ +NS_IMETHODIMP GfxInfo::SpoofOSVersion(uint32_t aVersion) +{ + mWindowsVersion = aVersion; + return NS_OK; +} + +#endif