1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 #include <opengl/win/WinDeviceInfo.hxx>
12 #include <opengl/win/blocklist_parser.hxx>
13 #include <config_folders.h>
15 #if !defined WIN32_LEAN_AND_MEAN
16 # define WIN32_LEAN_AND_MEAN
25 #include <osl/file.hxx>
26 #include <rtl/bootstrap.hxx>
27 #include <rtl/ustrbuf.hxx>
28 #include <tools/stream.hxx>
29 #include <o3tl/char16_t2wchar_t.hxx>
31 #include <desktop/crashreport.hxx>
33 OUString
* WinOpenGLDeviceInfo::mpDeviceVendors
[wgl::DeviceVendorMax
];
34 std::vector
<wgl::DriverInfo
> WinOpenGLDeviceInfo::maDriverInfo
;
39 * Compute the length of an array with constant length. (Use of this method
40 * with a non-array pointer will not compile.)
42 * Beware of the implicit trailing '\0' when using this with string constants.
44 template<typename T
, size_t N
>
45 size_t ArrayLength(T (&)[N
])
50 #define GFX_DRIVER_VERSION(a,b,c,d) \
51 ((uint64_t(a)<<48) | (uint64_t(b)<<32) | (uint64_t(c)<<16) | uint64_t(d))
53 bool GetKeyValue(const WCHAR
* keyLocation
, const WCHAR
* keyName
, OUString
& destString
, int type
)
62 result
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
, keyLocation
, 0, KEY_QUERY_VALUE
, &key
);
63 if (result
!= ERROR_SUCCESS
)
72 // We only use this for vram size
73 dwcbData
= sizeof(dValue
);
74 result
= RegQueryValueExW(key
, keyName
, nullptr, &resultType
,
75 reinterpret_cast<LPBYTE
>(&dValue
), &dwcbData
);
76 if (result
== ERROR_SUCCESS
&& resultType
== REG_DWORD
)
78 dValue
= dValue
/ 1024 / 1024;
79 destString
+= OUString::number(int32_t(dValue
));
89 // A chain of null-separated strings; we convert the nulls to spaces
90 WCHAR wCharValue
[1024];
91 dwcbData
= sizeof(wCharValue
);
93 result
= RegQueryValueExW(key
, keyName
, nullptr, &resultType
,
94 reinterpret_cast<LPBYTE
>(wCharValue
), &dwcbData
);
95 if (result
== ERROR_SUCCESS
&& resultType
== REG_MULTI_SZ
)
97 // This bit here could probably be cleaner.
100 DWORD strLen
= dwcbData
/sizeof(wCharValue
[0]);
101 for (DWORD i
= 0; i
< strLen
; i
++)
103 if (wCharValue
[i
] == '\0')
105 if (i
< strLen
- 1 && wCharValue
[i
+ 1] == '\0')
117 // ensure wCharValue is null terminated
118 wCharValue
[strLen
-1] = '\0';
121 destString
= OUString(o3tl::toU(wCharValue
));
137 // The device ID is a string like PCI\VEN_15AD&DEV_0405&SUBSYS_040515AD
138 // this function is used to extract the id's out of it
139 uint32_t ParseIDFromDeviceID(const OUString
&key
, const char *prefix
, int length
)
141 OUString id
= key
.toAsciiUpperCase();
142 OUString aPrefix
= OUString::fromUtf8(prefix
);
143 int32_t start
= id
.indexOf(aPrefix
);
146 id
= id
.copy(start
+ aPrefix
.getLength(), length
);
148 return id
.toUInt32(16);
151 // OS version in 16.16 major/minor form
152 // based on http://msdn.microsoft.com/en-us/library/ms724834(VS.85).aspx
155 kWindowsXP
= 0x00050001,
156 kWindowsServer2003
= 0x00050002,
157 kWindowsVista
= 0x00060000,
158 kWindows7
= 0x00060001,
159 kWindows8
= 0x00060002,
160 kWindows8_1
= 0x00060003,
161 kWindows10
= 0x000A0000 // Major 10 Minor 0
165 wgl::OperatingSystem
WindowsVersionToOperatingSystem(int32_t aWindowsVersion
)
167 switch(aWindowsVersion
)
170 return wgl::DRIVER_OS_WINDOWS_XP
;
171 case kWindowsServer2003
:
172 return wgl::DRIVER_OS_WINDOWS_SERVER_2003
;
174 return wgl::DRIVER_OS_WINDOWS_VISTA
;
176 return wgl::DRIVER_OS_WINDOWS_7
;
178 return wgl::DRIVER_OS_WINDOWS_8
;
180 return wgl::DRIVER_OS_WINDOWS_8_1
;
182 return wgl::DRIVER_OS_WINDOWS_10
;
183 case kWindowsUnknown
:
185 return wgl::DRIVER_OS_UNKNOWN
;
190 int32_t WindowsOSVersion()
192 static int32_t winVersion
= kWindowsUnknown
;
194 if (winVersion
== kWindowsUnknown
)
196 // GetVersion(Ex) and VersionHelpers (based on VerifyVersionInfo) API are
197 // subject to manifest-based behavior since Windows 8.1, so give wrong results.
198 // Another approach would be to use NetWkstaGetInfo, but that has some small
199 // reported delays (some milliseconds), and might get slower in domains with
200 // poor network connections.
201 // So go with a solution described at https://msdn.microsoft.com/en-us/library/ms724429
202 HINSTANCE hLibrary
= LoadLibraryW(L
"kernel32.dll");
203 if (hLibrary
!= nullptr)
205 wchar_t szPath
[MAX_PATH
];
206 DWORD dwCount
= GetModuleFileNameW(hLibrary
, szPath
, SAL_N_ELEMENTS(szPath
));
207 FreeLibrary(hLibrary
);
208 if (dwCount
!= 0 && dwCount
< SAL_N_ELEMENTS(szPath
))
210 dwCount
= GetFileVersionInfoSizeW(szPath
, nullptr);
213 std::unique_ptr
<char> ver(new char[dwCount
]);
214 if (GetFileVersionInfoW(szPath
, 0, dwCount
, ver
.get()) != FALSE
)
216 void* pBlock
= nullptr;
218 if (VerQueryValueW(ver
.get(), L
"\\", &pBlock
, &dwBlockSz
) != FALSE
&& dwBlockSz
>= sizeof(VS_FIXEDFILEINFO
))
220 VS_FIXEDFILEINFO
*vinfo
= static_cast<VS_FIXEDFILEINFO
*>(pBlock
);
221 winVersion
= int32_t(vinfo
->dwProductVersionMS
);
232 // This allows us to pad driver version 'substrings' with 0s, this
233 // effectively allows us to treat the version numbers as 'decimals'. This is
234 // a little strange but this method seems to do the right thing for all
235 // different vendor's driver strings. i.e. .98 will become 9800, which is
236 // larger than .978 which would become 9780.
237 void PadDriverDecimal(char *aString
)
239 for (int i
= 0; i
< 4; i
++)
243 for (int c
= i
; c
< 4; c
++)
253 // All destination string storage needs to have at least 5 bytes available.
254 bool SplitDriverVersion(const char *aSource
, char *aAStr
, char *aBStr
, char *aCStr
, char *aDStr
)
256 // sscanf doesn't do what we want here to we parse this manually.
257 int len
= strlen(aSource
);
258 char *dest
[4] = { aAStr
, aBStr
, aCStr
, aDStr
};
259 unsigned destIdx
= 0;
260 unsigned destPos
= 0;
262 for (int i
= 0; i
< len
; i
++)
264 if (destIdx
>= ArrayLength(dest
))
266 // Invalid format found. Ensure we don't access dest beyond bounds.
270 if (aSource
[i
] == '.')
272 dest
[destIdx
++][destPos
] = 0;
279 // Ignore more than 4 chars. Ensure we never access dest[destIdx]
280 // beyond its bounds.
284 dest
[destIdx
][destPos
++] = aSource
[i
];
287 // Add last terminator.
288 dest
[destIdx
][destPos
] = 0;
290 if (destIdx
!= ArrayLength(dest
) - 1)
297 /* Other interesting places for info:
298 * IDXGIAdapter::GetDesc()
299 * IDirectDraw7::GetAvailableVidMem()
300 * e->GetAvailableTextureMem()
303 template<typename T
> void appendIntegerWithPadding(OUString
& rString
, T value
, sal_uInt32 nChars
)
306 OUString aValue
= OUString::number(value
, 16);
307 sal_Int32 nLength
= aValue
.getLength();
308 sal_uInt32 nPadLength
= nChars
- nLength
;
309 assert(nPadLength
>= 0);
310 OUStringBuffer aBuffer
;
311 for (sal_uInt32 i
= 0; i
< nPadLength
; ++i
)
315 rString
+= aBuffer
.makeStringAndClear() + aValue
;
318 #define DEVICE_KEY_PREFIX L"\\Registry\\Machine\\"
323 bool ParseDriverVersion(const OUString
& aVersion
, uint64_t& rNumericVersion
)
329 char aStr
[8], bStr
[8], cStr
[8], dStr
[8];
330 /* honestly, why do I even bother */
331 OString aOVersion
= OUStringToOString(aVersion
, RTL_TEXTENCODING_UTF8
);
332 if (!SplitDriverVersion(aOVersion
.getStr(), aStr
, bStr
, cStr
, dStr
))
335 PadDriverDecimal(bStr
);
336 PadDriverDecimal(cStr
);
337 PadDriverDecimal(dStr
);
344 if (a
< 0 || a
> 0xffff) return false;
345 if (b
< 0 || b
> 0xffff) return false;
346 if (c
< 0 || c
> 0xffff) return false;
347 if (d
< 0 || d
> 0xffff) return false;
349 rNumericVersion
= GFX_DRIVER_VERSION(a
, b
, c
, d
);
356 uint64_t DriverInfo::allDriverVersions
= ~(uint64_t(0));
358 DriverInfo::DriverInfo()
359 : meOperatingSystem(wgl::DRIVER_OS_UNKNOWN
),
360 mnOperatingSystemVersion(0),
361 maAdapterVendor(WinOpenGLDeviceInfo::GetDeviceVendor(VendorAll
)),
362 mbWhitelisted(false),
363 meComparisonOp(DRIVER_COMPARISON_IGNORED
),
365 mnDriverVersionMax(0)
368 DriverInfo::DriverInfo(OperatingSystem os
, const OUString
& vendor
,
369 VersionComparisonOp op
,
370 uint64_t driverVersion
,
372 const char *suggestedVersion
/* = nullptr */)
373 : meOperatingSystem(os
),
374 mnOperatingSystemVersion(0),
375 maAdapterVendor(vendor
),
376 mbWhitelisted(bWhitelisted
),
378 mnDriverVersion(driverVersion
),
379 mnDriverVersionMax(0)
381 if (suggestedVersion
)
382 maSuggestedVersion
= OStringToOUString(OString(suggestedVersion
), RTL_TEXTENCODING_UTF8
);
385 DriverInfo::~DriverInfo()
391 WinOpenGLDeviceInfo::WinOpenGLDeviceInfo():
399 WinOpenGLDeviceInfo::~WinOpenGLDeviceInfo()
405 struct compareIgnoreAsciiCase
407 explicit compareIgnoreAsciiCase(const OUString
& rString
)
412 bool operator()(const OUString
& rCompare
)
414 return maString
.equalsIgnoreAsciiCase(rCompare
);
423 bool WinOpenGLDeviceInfo::FindBlocklistedDeviceInList(std::vector
<wgl::DriverInfo
>& aDeviceInfos
,
424 OUString
const & sDriverVersion
, OUString
const & sAdapterVendorID
,
425 OUString
const & sAdapterDeviceID
, uint32_t nWindowsVersion
)
427 uint64_t driverVersion
;
428 wgl::ParseDriverVersion(sDriverVersion
, driverVersion
);
430 wgl::OperatingSystem eOS
= WindowsVersionToOperatingSystem(nWindowsVersion
);
432 for (std::vector
<wgl::DriverInfo
>::size_type i
= 0; i
< aDeviceInfos
.size(); i
++)
434 if (aDeviceInfos
[i
].meOperatingSystem
!= wgl::DRIVER_OS_ALL
&&
435 aDeviceInfos
[i
].meOperatingSystem
!= eOS
)
440 if (aDeviceInfos
[i
].mnOperatingSystemVersion
&& aDeviceInfos
[i
].mnOperatingSystemVersion
!= nWindowsVersion
)
445 if (!aDeviceInfos
[i
].maAdapterVendor
.equalsIgnoreAsciiCase(GetDeviceVendor(wgl::VendorAll
)) &&
446 !aDeviceInfos
[i
].maAdapterVendor
.equalsIgnoreAsciiCase(sAdapterVendorID
))
451 if (std::none_of(aDeviceInfos
[i
].maDevices
.begin(), aDeviceInfos
[i
].maDevices
.end(), compareIgnoreAsciiCase("all")) &&
452 std::none_of(aDeviceInfos
[i
].maDevices
.begin(), aDeviceInfos
[i
].maDevices
.end(), compareIgnoreAsciiCase(sAdapterDeviceID
)))
457 switch (aDeviceInfos
[i
].meComparisonOp
)
459 case wgl::DRIVER_LESS_THAN
:
460 match
= driverVersion
< aDeviceInfos
[i
].mnDriverVersion
;
462 case wgl::DRIVER_LESS_THAN_OR_EQUAL
:
463 match
= driverVersion
<= aDeviceInfos
[i
].mnDriverVersion
;
465 case wgl::DRIVER_GREATER_THAN
:
466 match
= driverVersion
> aDeviceInfos
[i
].mnDriverVersion
;
468 case wgl::DRIVER_GREATER_THAN_OR_EQUAL
:
469 match
= driverVersion
>= aDeviceInfos
[i
].mnDriverVersion
;
471 case wgl::DRIVER_EQUAL
:
472 match
= driverVersion
== aDeviceInfos
[i
].mnDriverVersion
;
474 case wgl::DRIVER_NOT_EQUAL
:
475 match
= driverVersion
!= aDeviceInfos
[i
].mnDriverVersion
;
477 case wgl::DRIVER_BETWEEN_EXCLUSIVE
:
478 match
= driverVersion
> aDeviceInfos
[i
].mnDriverVersion
&& driverVersion
< aDeviceInfos
[i
].mnDriverVersionMax
;
480 case wgl::DRIVER_BETWEEN_INCLUSIVE
:
481 match
= driverVersion
>= aDeviceInfos
[i
].mnDriverVersion
&& driverVersion
<= aDeviceInfos
[i
].mnDriverVersionMax
;
483 case wgl::DRIVER_BETWEEN_INCLUSIVE_START
:
484 match
= driverVersion
>= aDeviceInfos
[i
].mnDriverVersion
&& driverVersion
< aDeviceInfos
[i
].mnDriverVersionMax
;
486 case wgl::DRIVER_COMPARISON_IGNORED
:
487 // We don't have a comparison op, so we match everything.
491 SAL_WARN("vcl.opengl", "Bogus op in GfxDriverInfo");
495 if (match
|| aDeviceInfos
[i
].mnDriverVersion
== wgl::DriverInfo::allDriverVersions
)
497 // white listed drivers
498 if (aDeviceInfos
[i
].mbWhitelisted
)
500 SAL_WARN("vcl.opengl", "whitelisted driver");
505 SAL_WARN("vcl.opengl", "use : " << aDeviceInfos
[i
].maSuggestedVersion
);
510 SAL_INFO("vcl.opengl", (match
? "BLACKLISTED" : "not blacklisted"));
514 bool WinOpenGLDeviceInfo::FindBlocklistedDeviceInList()
516 return FindBlocklistedDeviceInList(maDriverInfo
, maDriverVersion
, maAdapterVendorID
, maAdapterDeviceID
, mnWindowsVersion
);
521 OUString
getCacheFolder()
523 OUString
url("${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER
"/" SAL_CONFIGFILE("bootstrap") ":UserInstallation}/cache/");
524 rtl::Bootstrap::expandMacros(url
);
526 osl::Directory::create(url
);
531 void writeToLog(SvStream
& rStrm
, const char* pKey
, const OUString
& rVal
)
533 rStrm
.WriteCharPtr(pKey
);
534 rStrm
.WriteCharPtr(": ");
535 rStrm
.WriteOString(OUStringToOString(rVal
, RTL_TEXTENCODING_UTF8
));
536 rStrm
.WriteChar('\n');
541 bool WinOpenGLDeviceInfo::isDeviceBlocked()
543 CrashReporter::AddKeyValue("OpenGLVendor", maAdapterVendorID
);
544 CrashReporter::AddKeyValue("OpenGLDevice", maAdapterDeviceID
);
545 CrashReporter::AddKeyValue("OpenGLDriver", maDriverVersion
);
547 SAL_INFO("vcl.opengl", maDriverVersion
);
548 SAL_INFO("vcl.opengl", maDriverDate
);
549 SAL_INFO("vcl.opengl", maDeviceID
);
550 SAL_INFO("vcl.opengl", maAdapterVendorID
);
551 SAL_INFO("vcl.opengl", maAdapterDeviceID
);
552 SAL_INFO("vcl.opengl", maAdapterSubsysID
);
553 SAL_INFO("vcl.opengl", maDeviceKey
);
554 SAL_INFO("vcl.opengl", maDeviceString
);
556 OUString aCacheFolder
= getCacheFolder();
558 OUString
aCacheFile(aCacheFolder
+ "/opengl_device.log");
559 SvFileStream
aOpenGLLogFile(aCacheFile
, StreamMode::WRITE
);
561 writeToLog(aOpenGLLogFile
, "DriverVersion", maDriverVersion
);
562 writeToLog(aOpenGLLogFile
, "DriverDate", maDriverDate
);
563 writeToLog(aOpenGLLogFile
, "DeviceID", maDeviceID
);
564 writeToLog(aOpenGLLogFile
, "AdapterVendorID", maAdapterVendorID
);
565 writeToLog(aOpenGLLogFile
, "AdapterDeviceID", maAdapterDeviceID
);
566 writeToLog(aOpenGLLogFile
, "AdapterSubsysID", maAdapterSubsysID
);
567 writeToLog(aOpenGLLogFile
, "DeviceKey", maDeviceKey
);
568 writeToLog(aOpenGLLogFile
, "DeviceString", maDeviceString
);
570 // Check if the device is blocked from the downloaded blocklist. If not, check
571 // the static list after that. This order is used so that we can later escape
572 // out of static blocks (i.e. if we were wrong or something was patched, we
573 // can back out our static block without doing a release).
576 SAL_WARN("vcl.opengl", "all OpenGL blocked for RDP sessions");
580 return FindBlocklistedDeviceInList();
583 void WinOpenGLDeviceInfo::GetData()
585 DISPLAY_DEVICEW displayDevice
;
586 displayDevice
.cb
= sizeof(displayDevice
);
588 mnWindowsVersion
= WindowsOSVersion();
591 while (EnumDisplayDevicesW(nullptr, deviceIndex
, &displayDevice
, 0))
593 if (displayDevice
.StateFlags
& DISPLAY_DEVICE_PRIMARY_DEVICE
)
600 // make sure the string is null terminated
601 // (using the term "null" here to mean a zero UTF-16 unit)
602 if (wcsnlen(displayDevice
.DeviceKey
, ArrayLength(displayDevice
.DeviceKey
))
603 == ArrayLength(displayDevice
.DeviceKey
))
605 // we did not find a null
606 SAL_WARN("vcl.opengl", "string not null terminated");
610 /* DeviceKey is "reserved" according to MSDN so we'll be careful with it */
611 /* check that DeviceKey begins with DEVICE_KEY_PREFIX */
612 /* some systems have a DeviceKey starting with \REGISTRY\Machine\ so we need to compare case insensitively */
613 if (_wcsnicmp(displayDevice
.DeviceKey
, DEVICE_KEY_PREFIX
, ArrayLength(DEVICE_KEY_PREFIX
)-1) != 0)
615 SAL_WARN("vcl.opengl", "incorrect DeviceKey");
619 // chop off DEVICE_KEY_PREFIX
620 maDeviceKey
= o3tl::toU(displayDevice
.DeviceKey
) + ArrayLength(DEVICE_KEY_PREFIX
)-1;
622 maDeviceID
= o3tl::toU(displayDevice
.DeviceID
);
623 maDeviceString
= o3tl::toU(displayDevice
.DeviceString
);
625 if (maDeviceID
.isEmpty() &&
626 (maDeviceString
== "RDPDD Chained DD" ||
627 (maDeviceString
== "RDPUDD Chained DD")))
629 // we need to block RDP as it does not provide OpenGL 2.1+
631 SAL_WARN("vcl.opengl", "RDP => blocked");
635 /* create a device information set composed of the current display device */
636 HDEVINFO devinfo
= SetupDiGetClassDevsW(nullptr, o3tl::toW(maDeviceID
.getStr()), nullptr,
637 DIGCF_PRESENT
| DIGCF_PROFILE
| DIGCF_ALLCLASSES
);
639 if (devinfo
!= INVALID_HANDLE_VALUE
)
645 SP_DEVINFO_DATA devinfoData
;
646 DWORD memberIndex
= 0;
648 devinfoData
.cbSize
= sizeof(devinfoData
);
649 /* enumerate device information elements in the device information set */
650 while (SetupDiEnumDeviceInfo(devinfo
, memberIndex
++, &devinfoData
))
652 /* get a string that identifies the device's driver key */
653 if (SetupDiGetDeviceRegistryPropertyW(devinfo
,
657 reinterpret_cast<PBYTE
>(value
),
661 OUString
driverKey("System\\CurrentControlSet\\Control\\Class\\");
662 driverKey
+= o3tl::toU(value
);
663 result
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
, o3tl::toW(driverKey
.getStr()), 0, KEY_QUERY_VALUE
, &key
);
664 if (result
== ERROR_SUCCESS
)
666 /* we've found the driver we're looking for */
667 dwcbData
= sizeof(value
);
668 result
= RegQueryValueExW(key
, L
"DriverVersion", nullptr, nullptr,
669 reinterpret_cast<LPBYTE
>(value
), &dwcbData
);
670 if (result
== ERROR_SUCCESS
)
672 maDriverVersion
= OUString(o3tl::toU(value
));
676 // If the entry wasn't found, assume the worst (0.0.0.0).
677 maDriverVersion
= OUString("0.0.0.0");
679 dwcbData
= sizeof(value
);
680 result
= RegQueryValueExW(key
, L
"DriverDate", nullptr, nullptr,
681 reinterpret_cast<LPBYTE
>(value
), &dwcbData
);
682 if (result
== ERROR_SUCCESS
)
684 maDriverDate
= o3tl::toU(value
);
688 // Again, assume the worst
689 maDriverDate
= OUString("01-01-1970");
697 SetupDiDestroyDeviceInfoList(devinfo
);
701 SAL_WARN("vcl.opengl", "invalid handle value");
704 appendIntegerWithPadding(maAdapterVendorID
, ParseIDFromDeviceID(maDeviceID
, "VEN_", 4), 4);
705 appendIntegerWithPadding(maAdapterDeviceID
, ParseIDFromDeviceID(maDeviceID
, "&DEV_", 4), 4);
706 appendIntegerWithPadding(maAdapterSubsysID
, ParseIDFromDeviceID(maDeviceID
, "&SUBSYS_", 8), 8);
708 // We now check for second display adapter.
710 // Device interface class for display adapters.
711 CLSID GUID_DISPLAY_DEVICE_ARRIVAL
;
712 HRESULT hresult
= CLSIDFromString(L
"{1CA05180-A699-450A-9A0C-DE4FBE3DDD89}",
713 &GUID_DISPLAY_DEVICE_ARRIVAL
);
714 if (hresult
== NOERROR
)
716 devinfo
= SetupDiGetClassDevsW(&GUID_DISPLAY_DEVICE_ARRIVAL
,
718 DIGCF_PRESENT
| DIGCF_INTERFACEDEVICE
);
720 if (devinfo
!= INVALID_HANDLE_VALUE
)
726 SP_DEVINFO_DATA devinfoData
;
727 DWORD memberIndex
= 0;
728 devinfoData
.cbSize
= sizeof(devinfoData
);
730 OUString aAdapterDriver2
;
732 OUString aDriverVersion2
;
733 OUString aDriverDate2
;
734 uint32_t adapterVendorID2
;
735 uint32_t adapterDeviceID2
;
737 /* enumerate device information elements in the device information set */
738 while (SetupDiEnumDeviceInfo(devinfo
, memberIndex
++, &devinfoData
))
740 /* get a string that identifies the device's driver key */
741 if (SetupDiGetDeviceRegistryPropertyW(devinfo
,
745 reinterpret_cast<PBYTE
>(value
),
749 OUString
driverKey2("System\\CurrentControlSet\\Control\\Class\\");
750 driverKey2
+= o3tl::toU(value
);
751 result
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
, o3tl::toW(driverKey2
.getStr()), 0, KEY_QUERY_VALUE
, &key
);
752 if (result
== ERROR_SUCCESS
)
754 dwcbData
= sizeof(value
);
755 result
= RegQueryValueExW(key
, L
"MatchingDeviceId", nullptr,
756 nullptr, reinterpret_cast<LPBYTE
>(value
), &dwcbData
);
757 if (result
!= ERROR_SUCCESS
)
761 aDeviceID2
= o3tl::toU(value
);
762 OUString aAdapterVendorID2String
;
763 OUString aAdapterDeviceID2String
;
764 adapterVendorID2
= ParseIDFromDeviceID(aDeviceID2
, "VEN_", 4);
765 appendIntegerWithPadding(aAdapterVendorID2String
, adapterVendorID2
, 4);
766 adapterDeviceID2
= ParseIDFromDeviceID(aDeviceID2
, "&DEV_", 4);
767 appendIntegerWithPadding(aAdapterDeviceID2String
, adapterDeviceID2
, 4);
768 if (maAdapterVendorID
== aAdapterVendorID2String
&&
769 maAdapterDeviceID
== aAdapterDeviceID2String
)
775 // If this device is missing driver information, it is unlikely to
776 // be a real display adapter.
777 if (!GetKeyValue(o3tl::toW(driverKey2
.getStr()), L
"InstalledDisplayDrivers",
778 aAdapterDriver2
, REG_MULTI_SZ
))
783 dwcbData
= sizeof(value
);
784 result
= RegQueryValueExW(key
, L
"DriverVersion", nullptr, nullptr,
785 reinterpret_cast<LPBYTE
>(value
), &dwcbData
);
786 if (result
!= ERROR_SUCCESS
)
791 aDriverVersion2
= o3tl::toU(value
);
792 dwcbData
= sizeof(value
);
793 result
= RegQueryValueExW(key
, L
"DriverDate", nullptr, nullptr,
794 reinterpret_cast<LPBYTE
>(value
), &dwcbData
);
795 if (result
!= ERROR_SUCCESS
)
800 aDriverDate2
= o3tl::toU(value
);
801 dwcbData
= sizeof(value
);
802 result
= RegQueryValueExW(key
, L
"Device Description", nullptr,
803 nullptr, reinterpret_cast<LPBYTE
>(value
), &dwcbData
);
804 if (result
!= ERROR_SUCCESS
)
806 dwcbData
= sizeof(value
);
807 result
= RegQueryValueExW(key
, L
"DriverDesc", nullptr, nullptr,
808 reinterpret_cast<LPBYTE
>(value
), &dwcbData
);
811 if (result
== ERROR_SUCCESS
)
814 maDeviceString2
= o3tl::toU(value
);
815 maDeviceID2
= aDeviceID2
;
816 maDeviceKey2
= driverKey2
;
817 maDriverVersion2
= aDriverVersion2
;
818 maDriverDate2
= aDriverDate2
;
819 appendIntegerWithPadding(maAdapterVendorID2
, adapterVendorID2
, 4);
820 appendIntegerWithPadding(maAdapterDeviceID2
, adapterDeviceID2
, 4);
821 appendIntegerWithPadding(maAdapterSubsysID2
, ParseIDFromDeviceID(maDeviceID2
, "&SUBSYS_", 8), 8);
828 SetupDiDestroyDeviceInfoList(devinfo
);
833 // Macro for assigning a device vendor id to a string.
834 #define DECLARE_VENDOR_ID(name, deviceId) \
836 *mpDeviceVendors[id] = deviceId; \
839 OUString
WinOpenGLDeviceInfo::GetDeviceVendor(wgl::DeviceVendor id
)
841 assert(id
>= 0 && id
< wgl::DeviceVendorMax
);
843 if (mpDeviceVendors
[id
])
844 return *mpDeviceVendors
[id
];
846 mpDeviceVendors
[id
] = new OUString();
850 DECLARE_VENDOR_ID(wgl::VendorAll
, "");
851 DECLARE_VENDOR_ID(wgl::VendorIntel
, "0x8086");
852 DECLARE_VENDOR_ID(wgl::VendorNVIDIA
, "0x10de");
853 DECLARE_VENDOR_ID(wgl::VendorAMD
, "0x1022");
854 DECLARE_VENDOR_ID(wgl::VendorATI
, "0x1002");
855 DECLARE_VENDOR_ID(wgl::VendorMicrosoft
, "0x1414");
856 // Suppress a warning.
857 DECLARE_VENDOR_ID(wgl::DeviceVendorMax
, "");
860 return *mpDeviceVendors
[id
];
866 OUString
getBlacklistFile()
868 OUString
url("$BRAND_BASE_DIR/" LIBO_SHARE_FOLDER
);
869 rtl::Bootstrap::expandMacros(url
);
871 return url
+ "/opengl/opengl_blacklist_windows.xml";
877 void WinOpenGLDeviceInfo::FillBlacklist()
879 OUString aURL
= getBlacklistFile();
880 WinBlocklistParser
aParser(aURL
, maDriverInfo
);
886 SAL_WARN("vcl.opengl", "error parsing blacklist");
887 maDriverInfo
.clear();
892 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */