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 <sal/log.hxx>
29 #include <tools/stream.hxx>
30 #include <o3tl/char16_t2wchar_t.hxx>
32 #include <desktop/crashreport.hxx>
34 OUString
* WinOpenGLDeviceInfo::mpDeviceVendors
[wgl::DeviceVendorMax
];
35 std::vector
<wgl::DriverInfo
> WinOpenGLDeviceInfo::maDriverInfo
;
40 * Compute the length of an array with constant length. (Use of this method
41 * with a non-array pointer will not compile.)
43 * Beware of the implicit trailing '\0' when using this with string constants.
45 template<typename T
, size_t N
>
46 size_t ArrayLength(T (&)[N
])
51 #define GFX_DRIVER_VERSION(a,b,c,d) \
52 ((uint64_t(a)<<48) | (uint64_t(b)<<32) | (uint64_t(c)<<16) | uint64_t(d))
54 bool GetKeyValue(const WCHAR
* keyLocation
, const WCHAR
* keyName
, OUString
& destString
, int type
)
63 result
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
, keyLocation
, 0, KEY_QUERY_VALUE
, &key
);
64 if (result
!= ERROR_SUCCESS
)
73 // We only use this for vram size
74 dwcbData
= sizeof(dValue
);
75 result
= RegQueryValueExW(key
, keyName
, nullptr, &resultType
,
76 reinterpret_cast<LPBYTE
>(&dValue
), &dwcbData
);
77 if (result
== ERROR_SUCCESS
&& resultType
== REG_DWORD
)
79 dValue
= dValue
/ 1024 / 1024;
80 destString
+= OUString::number(int32_t(dValue
));
90 // A chain of null-separated strings; we convert the nulls to spaces
91 WCHAR wCharValue
[1024];
92 dwcbData
= sizeof(wCharValue
);
94 result
= RegQueryValueExW(key
, keyName
, nullptr, &resultType
,
95 reinterpret_cast<LPBYTE
>(wCharValue
), &dwcbData
);
96 if (result
== ERROR_SUCCESS
&& resultType
== REG_MULTI_SZ
)
98 // This bit here could probably be cleaner.
101 DWORD strLen
= dwcbData
/sizeof(wCharValue
[0]);
102 for (DWORD i
= 0; i
< strLen
; i
++)
104 if (wCharValue
[i
] == '\0')
106 if (i
< strLen
- 1 && wCharValue
[i
+ 1] == '\0')
118 // ensure wCharValue is null terminated
119 wCharValue
[strLen
-1] = '\0';
122 destString
= OUString(o3tl::toU(wCharValue
));
138 // The device ID is a string like PCI\VEN_15AD&DEV_0405&SUBSYS_040515AD
139 // this function is used to extract the id's out of it
140 uint32_t ParseIDFromDeviceID(const OUString
&key
, const char *prefix
, int length
)
142 OUString id
= key
.toAsciiUpperCase();
143 OUString aPrefix
= OUString::fromUtf8(prefix
);
144 int32_t start
= id
.indexOf(aPrefix
);
147 id
= id
.copy(start
+ aPrefix
.getLength(), length
);
149 return id
.toUInt32(16);
152 // OS version in 16.16 major/minor form
153 // based on http://msdn.microsoft.com/en-us/library/ms724834(VS.85).aspx
156 kWindows7
= 0x00060001,
157 kWindows8
= 0x00060002,
158 kWindows8_1
= 0x00060003,
159 kWindows10
= 0x000A0000 // Major 10 Minor 0
163 wgl::OperatingSystem
WindowsVersionToOperatingSystem(int32_t aWindowsVersion
)
165 switch(aWindowsVersion
)
168 return wgl::DRIVER_OS_WINDOWS_7
;
170 return wgl::DRIVER_OS_WINDOWS_8
;
172 return wgl::DRIVER_OS_WINDOWS_8_1
;
174 return wgl::DRIVER_OS_WINDOWS_10
;
175 case kWindowsUnknown
:
177 return wgl::DRIVER_OS_UNKNOWN
;
182 int32_t WindowsOSVersion()
184 static int32_t winVersion
= [&]()
186 // GetVersion(Ex) and VersionHelpers (based on VerifyVersionInfo) API are
187 // subject to manifest-based behavior since Windows 8.1, so give wrong results.
188 // Another approach would be to use NetWkstaGetInfo, but that has some small
189 // reported delays (some milliseconds), and might get slower in domains with
190 // poor network connections.
191 // So go with a solution described at https://msdn.microsoft.com/en-us/library/ms724429
192 HINSTANCE hLibrary
= LoadLibraryW(L
"kernel32.dll");
193 if (hLibrary
!= nullptr)
195 wchar_t szPath
[MAX_PATH
];
196 DWORD dwCount
= GetModuleFileNameW(hLibrary
, szPath
, SAL_N_ELEMENTS(szPath
));
197 FreeLibrary(hLibrary
);
198 if (dwCount
!= 0 && dwCount
< SAL_N_ELEMENTS(szPath
))
200 dwCount
= GetFileVersionInfoSizeW(szPath
, nullptr);
203 std::unique_ptr
<char[]> ver(new char[dwCount
]);
204 if (GetFileVersionInfoW(szPath
, 0, dwCount
, ver
.get()) != FALSE
)
206 void* pBlock
= nullptr;
208 if (VerQueryValueW(ver
.get(), L
"\\", &pBlock
, &dwBlockSz
) != FALSE
&& dwBlockSz
>= sizeof(VS_FIXEDFILEINFO
))
210 VS_FIXEDFILEINFO
*vinfo
= static_cast<VS_FIXEDFILEINFO
*>(pBlock
);
211 return int32_t(vinfo
->dwProductVersionMS
);
217 return int32_t(kWindowsUnknown
);
223 // This allows us to pad driver version 'substrings' with 0s, this
224 // effectively allows us to treat the version numbers as 'decimals'. This is
225 // a little strange but this method seems to do the right thing for all
226 // different vendor's driver strings. i.e. .98 will become 9800, which is
227 // larger than .978 which would become 9780.
228 void PadDriverDecimal(char *aString
)
230 for (int i
= 0; i
< 4; i
++)
234 for (int c
= i
; c
< 4; c
++)
244 // All destination string storage needs to have at least 5 bytes available.
245 bool SplitDriverVersion(const char *aSource
, char *aAStr
, char *aBStr
, char *aCStr
, char *aDStr
)
247 // sscanf doesn't do what we want here to we parse this manually.
248 int len
= strlen(aSource
);
249 char *dest
[4] = { aAStr
, aBStr
, aCStr
, aDStr
};
250 unsigned destIdx
= 0;
251 unsigned destPos
= 0;
253 for (int i
= 0; i
< len
; i
++)
255 if (destIdx
>= ArrayLength(dest
))
257 // Invalid format found. Ensure we don't access dest beyond bounds.
261 if (aSource
[i
] == '.')
263 dest
[destIdx
++][destPos
] = 0;
270 // Ignore more than 4 chars. Ensure we never access dest[destIdx]
271 // beyond its bounds.
275 dest
[destIdx
][destPos
++] = aSource
[i
];
278 // Add last terminator.
279 dest
[destIdx
][destPos
] = 0;
281 if (destIdx
!= ArrayLength(dest
) - 1)
288 /* Other interesting places for info:
289 * IDXGIAdapter::GetDesc()
290 * IDirectDraw7::GetAvailableVidMem()
291 * e->GetAvailableTextureMem()
294 template<typename T
> void appendIntegerWithPadding(OUString
& rString
, T value
, sal_uInt32 nChars
)
297 OUString aValue
= OUString::number(value
, 16);
298 sal_Int32 nLength
= aValue
.getLength();
299 sal_uInt32 nPadLength
= nChars
- nLength
;
300 assert(nPadLength
>= 0);
301 OUStringBuffer aBuffer
;
302 for (sal_uInt32 i
= 0; i
< nPadLength
; ++i
)
306 rString
+= aBuffer
.makeStringAndClear() + aValue
;
309 #define DEVICE_KEY_PREFIX L"\\Registry\\Machine\\"
314 bool ParseDriverVersion(const OUString
& aVersion
, uint64_t& rNumericVersion
)
320 char aStr
[8], bStr
[8], cStr
[8], dStr
[8];
321 /* honestly, why do I even bother */
322 OString aOVersion
= OUStringToOString(aVersion
, RTL_TEXTENCODING_UTF8
);
323 if (!SplitDriverVersion(aOVersion
.getStr(), aStr
, bStr
, cStr
, dStr
))
326 PadDriverDecimal(bStr
);
327 PadDriverDecimal(cStr
);
328 PadDriverDecimal(dStr
);
335 if (a
< 0 || a
> 0xffff) return false;
336 if (b
< 0 || b
> 0xffff) return false;
337 if (c
< 0 || c
> 0xffff) return false;
338 if (d
< 0 || d
> 0xffff) return false;
340 rNumericVersion
= GFX_DRIVER_VERSION(a
, b
, c
, d
);
347 uint64_t DriverInfo::allDriverVersions
= ~(uint64_t(0));
349 DriverInfo::DriverInfo()
350 : meOperatingSystem(wgl::DRIVER_OS_UNKNOWN
),
351 mnOperatingSystemVersion(0),
352 maAdapterVendor(WinOpenGLDeviceInfo::GetDeviceVendor(VendorAll
)),
353 mbWhitelisted(false),
354 meComparisonOp(DRIVER_COMPARISON_IGNORED
),
356 mnDriverVersionMax(0)
359 DriverInfo::DriverInfo(OperatingSystem os
, const OUString
& vendor
,
360 VersionComparisonOp op
,
361 uint64_t driverVersion
,
363 const char *suggestedVersion
/* = nullptr */)
364 : meOperatingSystem(os
),
365 mnOperatingSystemVersion(0),
366 maAdapterVendor(vendor
),
367 mbWhitelisted(bWhitelisted
),
369 mnDriverVersion(driverVersion
),
370 mnDriverVersionMax(0)
372 if (suggestedVersion
)
373 maSuggestedVersion
= OStringToOUString(OString(suggestedVersion
), RTL_TEXTENCODING_UTF8
);
376 DriverInfo::~DriverInfo()
382 WinOpenGLDeviceInfo::WinOpenGLDeviceInfo():
390 WinOpenGLDeviceInfo::~WinOpenGLDeviceInfo()
396 struct compareIgnoreAsciiCase
398 explicit compareIgnoreAsciiCase(const OUString
& rString
)
403 bool operator()(const OUString
& rCompare
)
405 return maString
.equalsIgnoreAsciiCase(rCompare
);
414 bool WinOpenGLDeviceInfo::FindBlocklistedDeviceInList(std::vector
<wgl::DriverInfo
>& aDeviceInfos
,
415 OUString
const & sDriverVersion
, OUString
const & sAdapterVendorID
,
416 OUString
const & sAdapterDeviceID
, uint32_t nWindowsVersion
)
418 uint64_t driverVersion
;
419 wgl::ParseDriverVersion(sDriverVersion
, driverVersion
);
421 wgl::OperatingSystem eOS
= WindowsVersionToOperatingSystem(nWindowsVersion
);
423 for (std::vector
<wgl::DriverInfo
>::size_type i
= 0; i
< aDeviceInfos
.size(); i
++)
425 if (aDeviceInfos
[i
].meOperatingSystem
!= wgl::DRIVER_OS_ALL
&&
426 aDeviceInfos
[i
].meOperatingSystem
!= eOS
)
431 if (aDeviceInfos
[i
].mnOperatingSystemVersion
&& aDeviceInfos
[i
].mnOperatingSystemVersion
!= nWindowsVersion
)
436 if (!aDeviceInfos
[i
].maAdapterVendor
.equalsIgnoreAsciiCase(GetDeviceVendor(wgl::VendorAll
)) &&
437 !aDeviceInfos
[i
].maAdapterVendor
.equalsIgnoreAsciiCase(sAdapterVendorID
))
442 if (std::none_of(aDeviceInfos
[i
].maDevices
.begin(), aDeviceInfos
[i
].maDevices
.end(), compareIgnoreAsciiCase("all")) &&
443 std::none_of(aDeviceInfos
[i
].maDevices
.begin(), aDeviceInfos
[i
].maDevices
.end(), compareIgnoreAsciiCase(sAdapterDeviceID
)))
448 switch (aDeviceInfos
[i
].meComparisonOp
)
450 case wgl::DRIVER_LESS_THAN
:
451 match
= driverVersion
< aDeviceInfos
[i
].mnDriverVersion
;
453 case wgl::DRIVER_LESS_THAN_OR_EQUAL
:
454 match
= driverVersion
<= aDeviceInfos
[i
].mnDriverVersion
;
456 case wgl::DRIVER_GREATER_THAN
:
457 match
= driverVersion
> aDeviceInfos
[i
].mnDriverVersion
;
459 case wgl::DRIVER_GREATER_THAN_OR_EQUAL
:
460 match
= driverVersion
>= aDeviceInfos
[i
].mnDriverVersion
;
462 case wgl::DRIVER_EQUAL
:
463 match
= driverVersion
== aDeviceInfos
[i
].mnDriverVersion
;
465 case wgl::DRIVER_NOT_EQUAL
:
466 match
= driverVersion
!= aDeviceInfos
[i
].mnDriverVersion
;
468 case wgl::DRIVER_BETWEEN_EXCLUSIVE
:
469 match
= driverVersion
> aDeviceInfos
[i
].mnDriverVersion
&& driverVersion
< aDeviceInfos
[i
].mnDriverVersionMax
;
471 case wgl::DRIVER_BETWEEN_INCLUSIVE
:
472 match
= driverVersion
>= aDeviceInfos
[i
].mnDriverVersion
&& driverVersion
<= aDeviceInfos
[i
].mnDriverVersionMax
;
474 case wgl::DRIVER_BETWEEN_INCLUSIVE_START
:
475 match
= driverVersion
>= aDeviceInfos
[i
].mnDriverVersion
&& driverVersion
< aDeviceInfos
[i
].mnDriverVersionMax
;
477 case wgl::DRIVER_COMPARISON_IGNORED
:
478 // We don't have a comparison op, so we match everything.
482 SAL_WARN("vcl.opengl", "Bogus op in GfxDriverInfo");
486 if (match
|| aDeviceInfos
[i
].mnDriverVersion
== wgl::DriverInfo::allDriverVersions
)
488 // white listed drivers
489 if (aDeviceInfos
[i
].mbWhitelisted
)
491 SAL_WARN("vcl.opengl", "whitelisted driver");
496 SAL_WARN("vcl.opengl", "use : " << aDeviceInfos
[i
].maSuggestedVersion
);
501 SAL_INFO("vcl.opengl", (match
? "BLACKLISTED" : "not blacklisted"));
505 bool WinOpenGLDeviceInfo::FindBlocklistedDeviceInList()
507 return FindBlocklistedDeviceInList(maDriverInfo
, maDriverVersion
, maAdapterVendorID
, maAdapterDeviceID
, mnWindowsVersion
);
512 OUString
getCacheFolder()
514 OUString
url("${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER
"/" SAL_CONFIGFILE("bootstrap") ":UserInstallation}/cache/");
515 rtl::Bootstrap::expandMacros(url
);
517 osl::Directory::create(url
);
522 void writeToLog(SvStream
& rStrm
, const char* pKey
, const OUString
& rVal
)
524 rStrm
.WriteCharPtr(pKey
);
525 rStrm
.WriteCharPtr(": ");
526 rStrm
.WriteOString(OUStringToOString(rVal
, RTL_TEXTENCODING_UTF8
));
527 rStrm
.WriteChar('\n');
532 bool WinOpenGLDeviceInfo::isDeviceBlocked()
534 CrashReporter::addKeyValue("OpenGLVendor", maAdapterVendorID
, CrashReporter::AddItem
);
535 CrashReporter::addKeyValue("OpenGLDevice", maAdapterDeviceID
, CrashReporter::AddItem
);
536 CrashReporter::addKeyValue("OpenGLDriver", maDriverVersion
, CrashReporter::Write
);
538 SAL_INFO("vcl.opengl", maDriverVersion
);
539 SAL_INFO("vcl.opengl", maDriverDate
);
540 SAL_INFO("vcl.opengl", maDeviceID
);
541 SAL_INFO("vcl.opengl", maAdapterVendorID
);
542 SAL_INFO("vcl.opengl", maAdapterDeviceID
);
543 SAL_INFO("vcl.opengl", maAdapterSubsysID
);
544 SAL_INFO("vcl.opengl", maDeviceKey
);
545 SAL_INFO("vcl.opengl", maDeviceString
);
547 OUString aCacheFolder
= getCacheFolder();
549 OUString
aCacheFile(aCacheFolder
+ "/opengl_device.log");
550 SvFileStream
aOpenGLLogFile(aCacheFile
, StreamMode::WRITE
);
552 writeToLog(aOpenGLLogFile
, "DriverVersion", maDriverVersion
);
553 writeToLog(aOpenGLLogFile
, "DriverDate", maDriverDate
);
554 writeToLog(aOpenGLLogFile
, "DeviceID", maDeviceID
);
555 writeToLog(aOpenGLLogFile
, "AdapterVendorID", maAdapterVendorID
);
556 writeToLog(aOpenGLLogFile
, "AdapterDeviceID", maAdapterDeviceID
);
557 writeToLog(aOpenGLLogFile
, "AdapterSubsysID", maAdapterSubsysID
);
558 writeToLog(aOpenGLLogFile
, "DeviceKey", maDeviceKey
);
559 writeToLog(aOpenGLLogFile
, "DeviceString", maDeviceString
);
561 // Check if the device is blocked from the downloaded blocklist. If not, check
562 // the static list after that. This order is used so that we can later escape
563 // out of static blocks (i.e. if we were wrong or something was patched, we
564 // can back out our static block without doing a release).
567 SAL_WARN("vcl.opengl", "all OpenGL blocked for RDP sessions");
571 return FindBlocklistedDeviceInList();
574 void WinOpenGLDeviceInfo::GetData()
576 DISPLAY_DEVICEW displayDevice
;
577 displayDevice
.cb
= sizeof(displayDevice
);
579 mnWindowsVersion
= WindowsOSVersion();
582 while (EnumDisplayDevicesW(nullptr, deviceIndex
, &displayDevice
, 0))
584 if (displayDevice
.StateFlags
& DISPLAY_DEVICE_PRIMARY_DEVICE
)
591 // make sure the string is null terminated
592 // (using the term "null" here to mean a zero UTF-16 unit)
593 if (wcsnlen(displayDevice
.DeviceKey
, ArrayLength(displayDevice
.DeviceKey
))
594 == ArrayLength(displayDevice
.DeviceKey
))
596 // we did not find a null
597 SAL_WARN("vcl.opengl", "string not null terminated");
601 /* DeviceKey is "reserved" according to MSDN so we'll be careful with it */
602 /* check that DeviceKey begins with DEVICE_KEY_PREFIX */
603 /* some systems have a DeviceKey starting with \REGISTRY\Machine\ so we need to compare case insensitively */
604 if (_wcsnicmp(displayDevice
.DeviceKey
, DEVICE_KEY_PREFIX
, ArrayLength(DEVICE_KEY_PREFIX
)-1) != 0)
606 SAL_WARN("vcl.opengl", "incorrect DeviceKey");
610 // chop off DEVICE_KEY_PREFIX
611 maDeviceKey
= o3tl::toU(displayDevice
.DeviceKey
) + ArrayLength(DEVICE_KEY_PREFIX
)-1;
613 maDeviceID
= o3tl::toU(displayDevice
.DeviceID
);
614 maDeviceString
= o3tl::toU(displayDevice
.DeviceString
);
616 if (maDeviceID
.isEmpty() &&
617 (maDeviceString
== "RDPDD Chained DD" ||
618 (maDeviceString
== "RDPUDD Chained DD")))
620 // we need to block RDP as it does not provide OpenGL 2.1+
622 SAL_WARN("vcl.opengl", "RDP => blocked");
626 /* create a device information set composed of the current display device */
627 HDEVINFO devinfo
= SetupDiGetClassDevsW(nullptr, o3tl::toW(maDeviceID
.getStr()), nullptr,
628 DIGCF_PRESENT
| DIGCF_PROFILE
| DIGCF_ALLCLASSES
);
630 if (devinfo
!= INVALID_HANDLE_VALUE
)
636 SP_DEVINFO_DATA devinfoData
;
637 DWORD memberIndex
= 0;
639 devinfoData
.cbSize
= sizeof(devinfoData
);
640 /* enumerate device information elements in the device information set */
641 while (SetupDiEnumDeviceInfo(devinfo
, memberIndex
++, &devinfoData
))
643 /* get a string that identifies the device's driver key */
644 if (SetupDiGetDeviceRegistryPropertyW(devinfo
,
648 reinterpret_cast<PBYTE
>(value
),
652 OUString
driverKey(OUStringLiteral("System\\CurrentControlSet\\Control\\Class\\") + o3tl::toU(value
));
653 result
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
, o3tl::toW(driverKey
.getStr()), 0, KEY_QUERY_VALUE
, &key
);
654 if (result
== ERROR_SUCCESS
)
656 /* we've found the driver we're looking for */
657 dwcbData
= sizeof(value
);
658 result
= RegQueryValueExW(key
, L
"DriverVersion", nullptr, nullptr,
659 reinterpret_cast<LPBYTE
>(value
), &dwcbData
);
660 if (result
== ERROR_SUCCESS
)
662 maDriverVersion
= OUString(o3tl::toU(value
));
666 // If the entry wasn't found, assume the worst (0.0.0.0).
667 maDriverVersion
= OUString("0.0.0.0");
669 dwcbData
= sizeof(value
);
670 result
= RegQueryValueExW(key
, L
"DriverDate", nullptr, nullptr,
671 reinterpret_cast<LPBYTE
>(value
), &dwcbData
);
672 if (result
== ERROR_SUCCESS
)
674 maDriverDate
= o3tl::toU(value
);
678 // Again, assume the worst
679 maDriverDate
= OUString("01-01-1970");
687 SetupDiDestroyDeviceInfoList(devinfo
);
691 SAL_WARN("vcl.opengl", "invalid handle value");
694 appendIntegerWithPadding(maAdapterVendorID
, ParseIDFromDeviceID(maDeviceID
, "VEN_", 4), 4);
695 appendIntegerWithPadding(maAdapterDeviceID
, ParseIDFromDeviceID(maDeviceID
, "&DEV_", 4), 4);
696 appendIntegerWithPadding(maAdapterSubsysID
, ParseIDFromDeviceID(maDeviceID
, "&SUBSYS_", 8), 8);
698 // We now check for second display adapter.
700 // Device interface class for display adapters.
701 CLSID GUID_DISPLAY_DEVICE_ARRIVAL
;
702 HRESULT hresult
= CLSIDFromString(L
"{1CA05180-A699-450A-9A0C-DE4FBE3DDD89}",
703 &GUID_DISPLAY_DEVICE_ARRIVAL
);
704 if (hresult
== NOERROR
)
706 devinfo
= SetupDiGetClassDevsW(&GUID_DISPLAY_DEVICE_ARRIVAL
,
708 DIGCF_PRESENT
| DIGCF_INTERFACEDEVICE
);
710 if (devinfo
!= INVALID_HANDLE_VALUE
)
716 SP_DEVINFO_DATA devinfoData
;
717 DWORD memberIndex
= 0;
718 devinfoData
.cbSize
= sizeof(devinfoData
);
720 OUString aAdapterDriver2
;
722 OUString aDriverVersion2
;
723 OUString aDriverDate2
;
724 uint32_t adapterVendorID2
;
725 uint32_t adapterDeviceID2
;
727 /* enumerate device information elements in the device information set */
728 while (SetupDiEnumDeviceInfo(devinfo
, memberIndex
++, &devinfoData
))
730 /* get a string that identifies the device's driver key */
731 if (SetupDiGetDeviceRegistryPropertyW(devinfo
,
735 reinterpret_cast<PBYTE
>(value
),
739 OUString
driverKey2(OUStringLiteral("System\\CurrentControlSet\\Control\\Class\\") + o3tl::toU(value
));
740 result
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
, o3tl::toW(driverKey2
.getStr()), 0, KEY_QUERY_VALUE
, &key
);
741 if (result
== ERROR_SUCCESS
)
743 dwcbData
= sizeof(value
);
744 result
= RegQueryValueExW(key
, L
"MatchingDeviceId", nullptr,
745 nullptr, reinterpret_cast<LPBYTE
>(value
), &dwcbData
);
746 if (result
!= ERROR_SUCCESS
)
750 aDeviceID2
= o3tl::toU(value
);
751 OUString aAdapterVendorID2String
;
752 OUString aAdapterDeviceID2String
;
753 adapterVendorID2
= ParseIDFromDeviceID(aDeviceID2
, "VEN_", 4);
754 appendIntegerWithPadding(aAdapterVendorID2String
, adapterVendorID2
, 4);
755 adapterDeviceID2
= ParseIDFromDeviceID(aDeviceID2
, "&DEV_", 4);
756 appendIntegerWithPadding(aAdapterDeviceID2String
, adapterDeviceID2
, 4);
757 if (maAdapterVendorID
== aAdapterVendorID2String
&&
758 maAdapterDeviceID
== aAdapterDeviceID2String
)
764 // If this device is missing driver information, it is unlikely to
765 // be a real display adapter.
766 if (!GetKeyValue(o3tl::toW(driverKey2
.getStr()), L
"InstalledDisplayDrivers",
767 aAdapterDriver2
, REG_MULTI_SZ
))
772 dwcbData
= sizeof(value
);
773 result
= RegQueryValueExW(key
, L
"DriverVersion", nullptr, nullptr,
774 reinterpret_cast<LPBYTE
>(value
), &dwcbData
);
775 if (result
!= ERROR_SUCCESS
)
780 aDriverVersion2
= o3tl::toU(value
);
781 dwcbData
= sizeof(value
);
782 result
= RegQueryValueExW(key
, L
"DriverDate", nullptr, nullptr,
783 reinterpret_cast<LPBYTE
>(value
), &dwcbData
);
784 if (result
!= ERROR_SUCCESS
)
789 aDriverDate2
= o3tl::toU(value
);
790 dwcbData
= sizeof(value
);
791 result
= RegQueryValueExW(key
, L
"Device Description", nullptr,
792 nullptr, reinterpret_cast<LPBYTE
>(value
), &dwcbData
);
793 if (result
!= ERROR_SUCCESS
)
795 dwcbData
= sizeof(value
);
796 result
= RegQueryValueExW(key
, L
"DriverDesc", nullptr, nullptr,
797 reinterpret_cast<LPBYTE
>(value
), &dwcbData
);
800 if (result
== ERROR_SUCCESS
)
803 maDeviceString2
= o3tl::toU(value
);
804 maDeviceID2
= aDeviceID2
;
805 maDeviceKey2
= driverKey2
;
806 maDriverVersion2
= aDriverVersion2
;
807 maDriverDate2
= aDriverDate2
;
808 appendIntegerWithPadding(maAdapterVendorID2
, adapterVendorID2
, 4);
809 appendIntegerWithPadding(maAdapterDeviceID2
, adapterDeviceID2
, 4);
810 appendIntegerWithPadding(maAdapterSubsysID2
, ParseIDFromDeviceID(maDeviceID2
, "&SUBSYS_", 8), 8);
817 SetupDiDestroyDeviceInfoList(devinfo
);
822 OUString
WinOpenGLDeviceInfo::GetDeviceVendor(wgl::DeviceVendor id
)
824 assert(id
>= 0 && id
< wgl::DeviceVendorMax
);
826 if (mpDeviceVendors
[id
])
827 return *mpDeviceVendors
[id
];
829 mpDeviceVendors
[id
] = new OUString();
834 *mpDeviceVendors
[id
] = "";
836 case wgl::VendorIntel
:
837 *mpDeviceVendors
[id
] = "0x8086";
839 case wgl::VendorNVIDIA
:
840 *mpDeviceVendors
[id
] = "0x10de";
843 *mpDeviceVendors
[id
] = "0x1022";
846 *mpDeviceVendors
[id
] = "0x1002";
848 case wgl::VendorMicrosoft
:
849 *mpDeviceVendors
[id
] = "0x1414";
851 case wgl::DeviceVendorMax
: // Suppress a warning.
855 return *mpDeviceVendors
[id
];
861 OUString
getBlacklistFile()
863 OUString
url("$BRAND_BASE_DIR/" LIBO_SHARE_FOLDER
);
864 rtl::Bootstrap::expandMacros(url
);
866 return url
+ "/opengl/opengl_blacklist_windows.xml";
872 void WinOpenGLDeviceInfo::FillBlacklist()
874 OUString aURL
= getBlacklistFile();
875 WinBlocklistParser
aParser(aURL
, maDriverInfo
);
881 SAL_WARN("vcl.opengl", "error parsing blacklist");
882 maDriverInfo
.clear();
887 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */