summaryrefslogtreecommitdiff
path: root/vcl/opengl/win
diff options
context:
space:
mode:
authorMarkus Mohrhard <markus.mohrhard@collabora.co.uk>2014-11-24 16:46:15 +0100
committerMarkus Mohrhard <markus.mohrhard@googlemail.com>2014-11-27 21:18:29 +0100
commit40ad9eea885db925fc7ad8872d529a7c5cb43a5a (patch)
tree7ecbcdb4dc1e874ffe9f7e76462075344e4d1d45 /vcl/opengl/win
parent4feaf96f50fa89eccb4e7a638220099e9a8482f1 (diff)
implement windows OpenGL blacklist, first step
Change-Id: I408b76855693c64473dba3bb3fa94374fff01fae
Diffstat (limited to 'vcl/opengl/win')
-rw-r--r--vcl/opengl/win/WinDeviceInfo.cxx633
1 files changed, 633 insertions, 0 deletions
diff --git a/vcl/opengl/win/WinDeviceInfo.cxx b/vcl/opengl/win/WinDeviceInfo.cxx
new file mode 100644
index 000000000000..b1ddf2f981cf
--- /dev/null
+++ b/vcl/opengl/win/WinDeviceInfo.cxx
@@ -0,0 +1,633 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * 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 "opengl/win/WinDeviceInfo.hxx"
+
+#include <windows.h>
+#include <setupapi.h>
+#include <cstdint>
+
+OUString* WinOpenGLDeviceInfo::mpDeviceVendors[wgl::DeviceVendorMax];
+
+namespace {
+
+
+void GetDLLVersion(const sal_Unicode* aDLLPath, OUString& aVersion)
+{
+ DWORD versInfoSize, vers[4] = {0};
+ // version info not available case
+ aVersion = OUString("0.0.0.0");
+ versInfoSize = GetFileVersionInfoSizeW(aDLLPath, nullptr);
+ std::vector<char> versionInfo(512, 0);
+
+ if (versInfoSize == 0)
+ {
+ return;
+ }
+ versionInfo.resize(uint32_t(versInfoSize));
+
+ if (!GetFileVersionInfoW(aDLLPath, 0, versInfoSize,
+ LPBYTE(&versionInfo[0])))
+ {
+ return;
+ }
+
+ UINT len = 0;
+ VS_FIXEDFILEINFO *fileInfo = nullptr;
+ if (!VerQueryValue(LPBYTE(&versionInfo[0]), TEXT("\\"),
+ (LPVOID *)&fileInfo, &len) ||
+ len == 0 ||
+ fileInfo == nullptr)
+ {
+ return;
+ }
+
+ DWORD fileVersMS = fileInfo->dwFileVersionMS;
+ DWORD fileVersLS = fileInfo->dwFileVersionLS;
+
+ vers[0] = HIWORD(fileVersMS);
+ vers[1] = LOWORD(fileVersMS);
+ vers[2] = HIWORD(fileVersLS);
+ vers[3] = LOWORD(fileVersLS);
+
+ char buf[256];
+ sprintf(buf, "%d.%d.%d.%d", vers[0], vers[1], vers[2], vers[3]);
+ OString aBuf(buf);
+ aVersion = OStringToOUString(aBuf, RTL_TEXTENCODING_UTF8);
+}
+
+/*
+* * Compute the length of an array with constant length. (Use of this method
+* * with a non-array pointer will not compile.)
+* *
+* * Beware of the implicit trailing '\0' when using this with string constants.
+* */
+template<typename T, size_t N>
+size_t ArrayLength(T (&aArr)[N])
+{
+ return N;
+}
+
+#define GFX_DRIVER_VERSION(a,b,c,d) \
+((uint64_t(a)<<48) | (uint64_t(b)<<32) | (uint64_t(c)<<16) | uint64_t(d))
+
+bool GetKeyValue(const WCHAR* keyLocation, const WCHAR* keyName, OUString& destString, int type)
+{
+ HKEY key;
+ DWORD dwcbData;
+ DWORD dValue;
+ DWORD resultType;
+ LONG result;
+ bool retval = true;
+
+ result = RegOpenKeyExW(HKEY_LOCAL_MACHINE, keyLocation, 0, KEY_QUERY_VALUE, &key);
+ if (result != ERROR_SUCCESS) {
+ return false;
+ }
+
+ 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 += OUString::number(int32_t(dValue));
+ } else {
+ retval = false;
+ }
+ 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 = OUString(wCharValue);
+
+ } else {
+ retval = false;
+ }
+
+ 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.
+void normalizeDriverId(OUString& driverid) {
+ driverid = driverid.toAsciiUpperCase();
+ int32_t rev = driverid.indexOf("&REV_");
+ if (rev != -1) {
+ driverid = driverid.copy(0, rev - 1);
+ }
+}
+
+// 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 OUString &key, const char *prefix, int length)
+{
+ OUString id = key.toAsciiUpperCase();
+ OUString aPrefix = OUString::fromUtf8(prefix);
+ int32_t start = id.indexOf(aPrefix);
+ if (start != -1) {
+ id = id.copy(start + aPrefix.getLength(), length);
+ }
+ return id.toUInt32(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,
+ kWindows10 = 0x60004
+};
+
+int32_t WindowsOSVersion()
+{
+ static int32_t winVersion = kWindowsUnknown;
+
+ OSVERSIONINFO vinfo;
+
+ if (winVersion == kWindowsUnknown) {
+ 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;
+}
+
+// This allows us to pad driver version 'substrings' with 0s, this
+// effectively allows us to treat the version numbers as 'decimals'. This is
+// a little strange but this method seems to do the right thing for all
+// different vendor's driver strings. i.e. .98 will become 9800, which is
+// larger than .978 which would become 9780.
+void PadDriverDecimal(char *aString)
+{
+ for (int i = 0; i < 4; i++) {
+ if (!aString[i]) {
+ for (int c = i; c < 4; c++) {
+ aString[c] = '0';
+ }
+ break;
+ }
+ }
+ aString[4] = 0;
+}
+
+// All destination string storage needs to have at least 5 bytes available.
+bool SplitDriverVersion(const char *aSource, char *aAStr, char *aBStr, char *aCStr, char *aDStr)
+{
+ // sscanf doesn't do what we want here to we parse this manually.
+ int len = strlen(aSource);
+ char *dest[4] = { aAStr, aBStr, aCStr, aDStr };
+ unsigned destIdx = 0;
+ unsigned destPos = 0;
+
+ for (int i = 0; i < len; i++) {
+ if (destIdx > ArrayLength(dest)) {
+ // Invalid format found. Ensure we don't access dest beyond bounds.
+ return false;
+ }
+
+ if (aSource[i] == '.') {
+ dest[destIdx++][destPos] = 0;
+ destPos = 0;
+ continue;
+ }
+
+ if (destPos > 3) {
+ // Ignore more than 4 chars. Ensure we never access dest[destIdx]
+ // beyond its bounds.
+ continue;
+ }
+
+ dest[destIdx][destPos++] = aSource[i];
+ }
+
+ // Add last terminator.
+ dest[destIdx][destPos] = 0;
+
+ if (destIdx != ArrayLength(dest) - 1) {
+ return false;
+ }
+ return true;
+}
+
+bool ParseDriverVersion(const OUString& aVersion, uint64_t *aNumericVersion)
+{
+ *aNumericVersion = 0;
+
+#if defined(WIN32)
+ int a, b, c, d;
+ char aStr[8], bStr[8], cStr[8], dStr[8];
+ /* honestly, why do I even bother */
+ OString aOVersion = OUStringToOString(aVersion, RTL_TEXTENCODING_UTF8);
+ if (!SplitDriverVersion(aOVersion.getStr(), aStr, bStr, cStr, dStr))
+ return false;
+
+ PadDriverDecimal(bStr);
+ PadDriverDecimal(cStr);
+ PadDriverDecimal(dStr);
+
+ a = atoi(aStr);
+ b = atoi(bStr);
+ c = atoi(cStr);
+ d = atoi(dStr);
+
+ if (a < 0 || a > 0xffff) return false;
+ if (b < 0 || b > 0xffff) return false;
+ if (c < 0 || c > 0xffff) return false;
+ if (d < 0 || d > 0xffff) return false;
+
+ *aNumericVersion = GFX_DRIVER_VERSION(a, b, c, d);
+ return true;
+#else
+ return false;
+#endif
+}
+/* Other interesting places for info:
+ * IDXGIAdapter::GetDesc()
+ * IDirectDraw7::GetAvailableVidMem()
+ * e->GetAvailableTextureMem()
+ * */
+
+template<typename T> void appendIntegerWithPadding(OUString& rString, T value, sal_uInt32 nChars)
+{
+ OUString aValue = OUString::number(value, 16);
+ sal_Int32 nLength = aValue.getLength();
+ sal_Int32 nPadLength = nChars - nLength;
+ assert(nPadLength >= 0);
+ OUStringBuffer aBuffer;
+ for (sal_uInt32 i = 0; i < nPadLength; ++i)
+ {
+ aBuffer.append("0");
+ }
+ rString += aBuffer.makeStringAndClear() + aValue;
+}
+
+#define DEVICE_KEY_PREFIX L"\\Registry\\Machine\\"
+}
+
+WinOpenGLDeviceInfo::WinOpenGLDeviceInfo():
+ mbHasDualGPU(false),
+ mbHasDriverVersionMismatch(false),
+ mbRDP(false)
+{
+ GetData();
+}
+
+WinOpenGLDeviceInfo::~WinOpenGLDeviceInfo()
+{
+}
+
+bool WinOpenGLDeviceInfo::isDeviceBlocked()
+{
+ SAL_INFO("vcl.opengl", maDriverVersion);
+ SAL_INFO("vcl.opengl", maDriverDate);
+ SAL_INFO("vcl.opengl", maDeviceID);
+ SAL_INFO("vcl.opengl", maAdapterVendorID);
+ SAL_INFO("vcl.opengl", maAdapterDeviceID);
+ SAL_INFO("vcl.opengl", maAdapterSubsysID);
+ SAL_INFO("vcl.opengl", maDeviceKey);
+ SAL_INFO("vcl.opengl", maDeviceString);
+ return false;
+}
+
+void WinOpenGLDeviceInfo::GetData()
+{
+ DISPLAY_DEVICEW displayDevice;
+ displayDevice.cb = sizeof(displayDevice);
+
+ mnWindowsVersion = WindowsOSVersion();
+ int deviceIndex = 0;
+
+ while (EnumDisplayDevicesW(nullptr, deviceIndex, &displayDevice, 0)) {
+ if (displayDevice.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) {
+ 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
+ SAL_WARN("vcl.opengl", "no null pointer");
+ return;
+ }
+
+ /* 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)
+ {
+ SAL_WARN("vcl.opengl", "incorrect DeviceKey");
+ return;
+ }
+
+ // chop off DEVICE_KEY_PREFIX
+ maDeviceKey = displayDevice.DeviceKey + ArrayLength(DEVICE_KEY_PREFIX)-1;
+
+ maDeviceID = displayDevice.DeviceID;
+ maDeviceString = displayDevice.DeviceString;
+
+ if (maDeviceID.isEmpty() &&
+ maDeviceString == "RDPUDD Chained DD")
+ {
+ // TODO: moggi: we need to block RDP as it does not provide OpenGL 2.1+
+ mbRDP = true;
+ SAL_WARN("vcl.opengl", "RDP => blocked");
+ return;
+ }
+
+ /* create a device information set composed of the current display device */
+ HDEVINFO devinfo = SetupDiGetClassDevsW(nullptr, maDeviceID.getStr(), 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);
+ OUString aDriverKeyPre("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)) {
+ OUString driverKey(aDriverKeyPre);
+ driverKey += value;
+ result = RegOpenKeyExW(HKEY_LOCAL_MACHINE, driverKey.getStr(), 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) {
+ maDriverVersion = OUString(value);
+ } else {
+ // If the entry wasn't found, assume the worst (0.0.0.0).
+ maDriverVersion = OUString("0.0.0.0");
+ }
+ dwcbData = sizeof(value);
+ result = RegQueryValueExW(key, L"DriverDate", nullptr, nullptr,
+ (LPBYTE)value, &dwcbData);
+ if (result == ERROR_SUCCESS) {
+ maDriverDate = value;
+ } else {
+ // Again, assume the worst
+ maDriverDate = OUString("01-01-1970");
+ }
+ RegCloseKey(key);
+ break;
+ }
+ }
+ }
+
+ SetupDiDestroyDeviceInfoList(devinfo);
+ }
+ else
+ {
+ SAL_WARN("vcl.opengl", "invalid handle value");
+ }
+
+ appendIntegerWithPadding(maAdapterVendorID, ParseIDFromDeviceID(maDeviceID, "VEN_", 4), 4);
+ appendIntegerWithPadding(maAdapterDeviceID, ParseIDFromDeviceID(maDeviceID, "&DEV_", 4), 4);
+ appendIntegerWithPadding(maAdapterSubsysID, ParseIDFromDeviceID(maDeviceID, "&SUBSYS_", 8), 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);
+
+ OUString aAdapterDriver2;
+ OUString aDeviceID2;
+ OUString aDriverVersion2;
+ OUString aDriverDate2;
+ uint32_t adapterVendorID2;
+ uint32_t adapterDeviceID2;
+
+ OUString aDriverKeyPre("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)) {
+ OUString driverKey2(aDriverKeyPre);
+ driverKey2 += value;
+ result = RegOpenKeyExW(HKEY_LOCAL_MACHINE, driverKey2.getStr(), 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;
+ }
+ aDeviceID2 = value;
+ OUString aAdapterVendorID2String;
+ OUString aAdapterDeviceID2String;
+ adapterVendorID2 = ParseIDFromDeviceID(aDeviceID2, "VEN_", 4);
+ appendIntegerWithPadding(aAdapterVendorID2String, adapterVendorID2, 4);
+ adapterDeviceID2 = ParseIDFromDeviceID(aDeviceID2, "&DEV_", 4);
+ appendIntegerWithPadding(aAdapterDeviceID2String, adapterDeviceID2, 4);
+ if (maAdapterVendorID == aAdapterVendorID2String &&
+ maAdapterDeviceID == aAdapterDeviceID2String) {
+ RegCloseKey(key);
+ continue;
+ }
+
+ // If this device is missing driver information, it is unlikely to
+ // be a real display adapter.
+ if (!GetKeyValue(driverKey2.getStr(), L"InstalledDisplayDrivers",
+ aAdapterDriver2, 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;
+ }
+ aDriverVersion2 = value;
+ dwcbData = sizeof(value);
+ result = RegQueryValueExW(key, L"DriverDate", nullptr, nullptr,
+ (LPBYTE)value, &dwcbData);
+ if (result != ERROR_SUCCESS) {
+ RegCloseKey(key);
+ continue;
+ }
+ aDriverDate2 = 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) {
+ mbHasDualGPU = true;
+ maDeviceString2 = value;
+ maDeviceID2 = aDeviceID2;
+ maDeviceKey2 = driverKey2;
+ maDriverVersion2 = aDriverVersion2;
+ maDriverDate2 = aDriverDate2;
+ appendIntegerWithPadding(maAdapterVendorID2, adapterVendorID2, 4);
+ appendIntegerWithPadding(maAdapterDeviceID2, adapterDeviceID2, 4);
+ appendIntegerWithPadding(maAdapterSubsysID2, ParseIDFromDeviceID(maDeviceID2, "&SUBSYS_", 8), 8);
+ break;
+ }
+ }
+ }
+ }
+
+ SetupDiDestroyDeviceInfoList(devinfo);
+ }
+ }
+
+ mbHasDriverVersionMismatch = false;
+ if (maAdapterVendorID == GetDeviceVendor(wgl::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.
+ OUString aDLLFileName("igd10umd32.dll");
+ OUString aDLLFileName2("igd10iumd32.dll");
+ OUString aDLLVersion, aDLLVersion2;
+ GetDLLVersion(aDLLFileName.getStr(), aDLLVersion);
+ GetDLLVersion(aDLLFileName2.getStr(), aDLLVersion2);
+
+ uint64_t dllNumericVersion = 0, dllNumericVersion2 = 0,
+ driverNumericVersion = 0, knownSafeMismatchVersion = 0;
+ ParseDriverVersion(aDLLVersion, &dllNumericVersion);
+ ParseDriverVersion(aDLLVersion2, &dllNumericVersion2);
+ ParseDriverVersion(maDriverVersion, &driverNumericVersion);
+ ParseDriverVersion("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)) {
+ mbHasDriverVersionMismatch = true;
+ }
+ }
+}
+
+
+
+// Macro for assigning a device vendor id to a string.
+#define DECLARE_VENDOR_ID(name, deviceId) \
+ case name: \
+ *mpDeviceVendors[id] = OUString(deviceId); \
+break;
+
+OUString WinOpenGLDeviceInfo::GetDeviceVendor(wgl::DeviceVendor id)
+{
+ assert(id >= 0 && id < wgl::DeviceVendorMax);
+
+ if (mpDeviceVendors[id])
+ return *mpDeviceVendors[id];
+
+ mpDeviceVendors[id] = new OUString();
+
+ switch (id) {
+ DECLARE_VENDOR_ID(wgl::VendorAll, "");
+ DECLARE_VENDOR_ID(wgl::VendorIntel, "0x8086");
+ DECLARE_VENDOR_ID(wgl::VendorNVIDIA, "0x10de");
+ DECLARE_VENDOR_ID(wgl::VendorAMD, "0x1022");
+ DECLARE_VENDOR_ID(wgl::VendorATI, "0x1002");
+ DECLARE_VENDOR_ID(wgl::VendorMicrosoft, "0x1414");
+ // Suppress a warning.
+ DECLARE_VENDOR_ID(wgl::DeviceVendorMax, "");
+ }
+
+ return *mpDeviceVendors[id];
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */