From 2b702f7436acf6883b41508277441e5ea0a53d51 Mon Sep 17 00:00:00 2001 From: Luboš Luňák Date: Wed, 12 Feb 2020 10:23:54 +0100 Subject: make OpenGL blacklist file code generic and use it for Skia/Vulkan MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: Icc150b853f5d2d06afedcb7878f6a031aff57c2b Reviewed-on: https://gerrit.libreoffice.org/c/core/+/88533 Tested-by: Jenkins Reviewed-by: Luboš Luňák --- Repository.mk | 2 + include/sal/log-areas.dox | 1 + vcl/Library_vcl.mk | 2 +- vcl/Module_vcl.mk | 4 +- vcl/Package_skia_blacklist.mk | 16 + vcl/inc/driverblocklist.hxx | 158 +++++++ vcl/inc/opengl/win/WinDeviceInfo.hxx | 113 +---- vcl/inc/opengl/win/blocklist_parser.hxx | 42 -- vcl/opengl/win/WinDeviceInfo.cxx | 411 +----------------- vcl/opengl/win/blocklist_parser.cxx | 351 ---------------- vcl/qa/cppunit/blocklistparsertest.cxx | 94 +++-- vcl/skia/SkiaHelper.cxx | 39 +- vcl/skia/skia_blacklist_vulkan.xml | 30 ++ vcl/source/helper/driverblocklist.cxx | 711 ++++++++++++++++++++++++++++++++ vcl/source/opengl/OpenGLHelper.cxx | 4 +- 15 files changed, 1007 insertions(+), 971 deletions(-) create mode 100644 vcl/Package_skia_blacklist.mk create mode 100644 vcl/inc/driverblocklist.hxx delete mode 100644 vcl/inc/opengl/win/blocklist_parser.hxx delete mode 100644 vcl/opengl/win/blocklist_parser.cxx create mode 100644 vcl/skia/skia_blacklist_vulkan.xml create mode 100644 vcl/source/helper/driverblocklist.cxx diff --git a/Repository.mk b/Repository.mk index 7372a01319eb..864438ed63d2 100644 --- a/Repository.mk +++ b/Repository.mk @@ -951,6 +951,8 @@ $(eval $(call gb_Helper_register_packages_for_install,ooo,\ vcl_opengl_blacklist \ ) \ $(if $(ENABLE_OPENGL_CANVAS),canvas_opengl_shader) \ + $(if $(filter SKIA,$(BUILD_TYPE)), \ + vcl_skia_blacklist ) \ $(if $(DISABLE_PYTHON),,$(if $(filter-out AIX,$(OS)), \ Pyuno/commonwizards \ Pyuno/fax \ diff --git a/include/sal/log-areas.dox b/include/sal/log-areas.dox index 3ebe47afd2b4..ea0c34e5223f 100644 --- a/include/sal/log-areas.dox +++ b/include/sal/log-areas.dox @@ -463,6 +463,7 @@ certain functionality. @li @c vcl.control @li @c vcl.ct - CoreText-using code for macOS and iOS @li @c vcl.debugevent +@li @c vcl.driver Graphics driver handling @li @c vcl.emf - EMF/EMF+ processing @li @c vcl.eventtesting @li @c vcl.filter diff --git a/vcl/Library_vcl.mk b/vcl/Library_vcl.mk index 1b5a6db8ec65..ca818e271c22 100644 --- a/vcl/Library_vcl.mk +++ b/vcl/Library_vcl.mk @@ -369,6 +369,7 @@ $(eval $(call gb_Library_add_exception_objects,vcl,\ vcl/source/helper/canvastools \ vcl/source/helper/commandinfoprovider \ vcl/source/helper/displayconnectiondispatch \ + vcl/source/helper/driverblocklist \ vcl/source/helper/errcode \ vcl/source/helper/evntpost \ vcl/source/helper/lazydelete \ @@ -702,7 +703,6 @@ endif ifeq ($(OS),WNT) $(eval $(call gb_Library_add_exception_objects,vcl,\ vcl/opengl/win/WinDeviceInfo \ - vcl/opengl/win/blocklist_parser \ vcl/source/app/salplug \ )) diff --git a/vcl/Module_vcl.mk b/vcl/Module_vcl.mk index 5620f188c7f2..9736be35fedf 100644 --- a/vcl/Module_vcl.mk +++ b/vcl/Module_vcl.mk @@ -27,6 +27,8 @@ $(eval $(call gb_Module_add_targets,vcl,\ UIConfig_vcl \ $(if $(filter WNT,$(OS)), \ Package_opengl_blacklist ) \ + $(if $(filter SKIA,$(BUILD_TYPE)), \ + Package_skia_blacklist ) \ $(if $(filter DESKTOP,$(BUILD_TYPE)), \ StaticLibrary_vclmain \ $(if $(ENABLE_MACOSX_SANDBOX),, \ @@ -204,6 +206,7 @@ $(eval $(call gb_Module_add_check_targets,vcl,\ CppunitTest_vcl_png_test \ CppunitTest_vcl_widget_definition_reader_test \ CppunitTest_vcl_backend_test \ + CppunitTest_vcl_blocklistparser_test \ )) ifeq ($(USING_X11),TRUE) @@ -222,7 +225,6 @@ endif ifeq ($(OS),WNT) $(eval $(call gb_Module_add_check_targets,vcl,\ CppunitTest_vcl_timer \ - CppunitTest_vcl_blocklistparser_test \ )) endif diff --git a/vcl/Package_skia_blacklist.mk b/vcl/Package_skia_blacklist.mk new file mode 100644 index 000000000000..611766eb7aa3 --- /dev/null +++ b/vcl/Package_skia_blacklist.mk @@ -0,0 +1,16 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# 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/. +# + +$(eval $(call gb_Package_Package,vcl_skia_blacklist,$(SRCDIR)/vcl/skia)) + +$(eval $(call gb_Package_add_files,vcl_skia_blacklist,$(LIBO_SHARE_FOLDER)/skia,\ + skia_blacklist_vulkan.xml \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/inc/driverblocklist.hxx b/vcl/inc/driverblocklist.hxx new file mode 100644 index 000000000000..e8f99378fa24 --- /dev/null +++ b/vcl/inc/driverblocklist.hxx @@ -0,0 +1,158 @@ +/* -*- 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/. + */ + +#ifndef INCLUDED_VCL_DRIVERBLOCKLIST_HXX +#define INCLUDED_VCL_DRIVERBLOCKLIST_HXX + +#include +#include +#include + +namespace DriverBlocklist +{ +VCL_DLLPUBLIC bool IsDeviceBlocked(const OUString& blocklistURL, const OUString& driverVersion, + const OUString& vendorId, const OUString& deviceId); + +#ifdef _WIN32 +VCL_DLLPUBLIC int32_t GetWindowsVersion(); +#endif + +// The rest should be private (only for the unittest). + +struct InvalidFileException +{ +}; + +enum OperatingSystem +{ + DRIVER_OS_UNKNOWN = 0, + DRIVER_OS_WINDOWS_7, + DRIVER_OS_WINDOWS_8, + DRIVER_OS_WINDOWS_8_1, + DRIVER_OS_WINDOWS_10, + DRIVER_OS_LINUX, + DRIVER_OS_OSX_10_5, + DRIVER_OS_OSX_10_6, + DRIVER_OS_OSX_10_7, + DRIVER_OS_OSX_10_8, + DRIVER_OS_ANDROID, + DRIVER_OS_ALL +}; + +enum VersionComparisonOp +{ + DRIVER_LESS_THAN, // driver < version + DRIVER_LESS_THAN_OR_EQUAL, // driver <= version + DRIVER_GREATER_THAN, // driver > version + DRIVER_GREATER_THAN_OR_EQUAL, // driver >= version + DRIVER_EQUAL, // driver == version + DRIVER_NOT_EQUAL, // driver != version + DRIVER_BETWEEN_EXCLUSIVE, // driver > version && driver < versionMax + DRIVER_BETWEEN_INCLUSIVE, // driver >= version && driver <= versionMax + DRIVER_BETWEEN_INCLUSIVE_START, // driver >= version && driver < versionMax + DRIVER_COMPARISON_IGNORED +}; + +enum DeviceVendor +{ + VendorAll, + VendorIntel, + VendorNVIDIA, + VendorAMD, + VendorATI, + VendorMicrosoft, +}; +const int DeviceVendorMax = VendorMicrosoft + 1; + +struct DriverInfo +{ + DriverInfo(OperatingSystem os, const OUString& vendor, VersionComparisonOp op, + uint64_t driverVersion, bool bWhiteListed = false, + const char* suggestedVersion = nullptr); + + DriverInfo(); + + OperatingSystem meOperatingSystem; + OUString maAdapterVendor; + std::vector maDevices; + + bool mbWhitelisted; + + VersionComparisonOp meComparisonOp; + + /* versions are assumed to be A.B.C.D packed as 0xAAAABBBBCCCCDDDD */ + uint64_t mnDriverVersion; + uint64_t mnDriverVersionMax; + static uint64_t allDriverVersions; + + OUString maSuggestedVersion; + OUString maMsg; +}; + +class VCL_DLLPUBLIC Parser +{ +public: + Parser(const OUString& rURL, std::vector& rDriverList); + bool parse(); + +private: + void handleEntry(DriverInfo& rDriver, xmlreader::XmlReader& rReader); + void handleList(xmlreader::XmlReader& rReader); + void handleContent(xmlreader::XmlReader& rReader); + static void handleDevices(DriverInfo& rDriver, xmlreader::XmlReader& rReader); + + enum class BlockType + { + WHITELIST, + BLACKLIST, + UNKNOWN + }; + + BlockType meBlockType; + std::vector& mrDriverList; + OUString maURL; +}; + +OUString VCL_DLLPUBLIC GetVendorId(DeviceVendor id); + +bool VCL_DLLPUBLIC FindBlocklistedDeviceInList(std::vector& aDeviceInfos, + OUString const& sDriverVersion, + OUString const& sAdapterVendorID, + OUString const& sAdapterDeviceID, + OperatingSystem system, + const OUString& blocklistURL = OUString()); + +#define GFX_DRIVER_VERSION(a, b, c, d) \ + ((uint64_t(a) << 48) | (uint64_t(b) << 32) | (uint64_t(c) << 16) | uint64_t(d)) + +inline uint64_t V(uint32_t a, uint32_t b, uint32_t c, uint32_t d) +{ + // We make sure every driver number is padded by 0s, this will allow us the + // easiest 'compare as if decimals' approach. See ParseDriverVersion for a + // more extensive explanation of this approach. + while (b > 0 && b < 1000) + { + b *= 10; + } + while (c > 0 && c < 1000) + { + c *= 10; + } + while (d > 0 && d < 1000) + { + d *= 10; + } + return GFX_DRIVER_VERSION(a, b, c, d); +} + +} // namespace + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/opengl/win/WinDeviceInfo.hxx b/vcl/inc/opengl/win/WinDeviceInfo.hxx index 773be7af0f7d..04d97406b54a 100644 --- a/vcl/inc/opengl/win/WinDeviceInfo.hxx +++ b/vcl/inc/opengl/win/WinDeviceInfo.hxx @@ -13,108 +13,12 @@ #include #include +#include #include #include #include -namespace wgl { - -enum OperatingSystem { - DRIVER_OS_UNKNOWN = 0, - DRIVER_OS_WINDOWS_7, - DRIVER_OS_WINDOWS_8, - DRIVER_OS_WINDOWS_8_1, - DRIVER_OS_WINDOWS_10, - DRIVER_OS_LINUX, - DRIVER_OS_OS_X_10_5, - DRIVER_OS_OS_X_10_6, - DRIVER_OS_OS_X_10_7, - DRIVER_OS_OS_X_10_8, - DRIVER_OS_ANDROID, - DRIVER_OS_ALL -}; - -enum VersionComparisonOp { - DRIVER_LESS_THAN, // driver < version - DRIVER_LESS_THAN_OR_EQUAL, // driver <= version - DRIVER_GREATER_THAN, // driver > version - DRIVER_GREATER_THAN_OR_EQUAL, // driver >= version - DRIVER_EQUAL, // driver == version - DRIVER_NOT_EQUAL, // driver != version - DRIVER_BETWEEN_EXCLUSIVE, // driver > version && driver < versionMax - DRIVER_BETWEEN_INCLUSIVE, // driver >= version && driver <= versionMax - DRIVER_BETWEEN_INCLUSIVE_START, // driver >= version && driver < versionMax - DRIVER_COMPARISON_IGNORED -}; - -enum DeviceVendor { - VendorAll, - VendorIntel, - VendorNVIDIA, - VendorAMD, - VendorATI, - VendorMicrosoft, - DeviceVendorMax -}; - -bool ParseDriverVersion(const OUString& rString, uint64_t& rVersion); - -struct VCL_DLLPUBLIC DriverInfo -{ - - DriverInfo(OperatingSystem os, const OUString& vendor, VersionComparisonOp op, - uint64_t driverVersion, bool bWhiteListed = false, const char *suggestedVersion = nullptr); - - DriverInfo(); - virtual ~DriverInfo(); - - OperatingSystem meOperatingSystem; - uint32_t mnOperatingSystemVersion; - - OUString maAdapterVendor; - - std::vector maDevices; - - // Whether the mDevices array should be deleted when this structure is - // deallocated. False by default. - bool mbDeleteDevices; - - bool mbWhitelisted; - - VersionComparisonOp meComparisonOp; - - /* versions are assumed to be A.B.C.D packed as 0xAAAABBBBCCCCDDDD */ - uint64_t mnDriverVersion; - uint64_t mnDriverVersionMax; - static uint64_t allDriverVersions; - - OUString maSuggestedVersion; - OUString maMsg; -}; - -#define GFX_DRIVER_VERSION(a,b,c,d) \ - ((uint64_t(a)<<48) | (uint64_t(b)<<32) | (uint64_t(c)<<16) | uint64_t(d)) - -inline VCL_DLLPUBLIC uint64_t V(uint32_t a, uint32_t b, uint32_t c, uint32_t d) -{ - // We make sure every driver number is padded by 0s, this will allow us the - // easiest 'compare as if decimals' approach. See ParseDriverVersion for a - // more extensive explanation of this approach. - while (b > 0 && b < 1000) { - b *= 10; - } - while (c > 0 && c < 1000) { - c *= 10; - } - while (d > 0 && d < 1000) { - d *= 10; - } - return GFX_DRIVER_VERSION(a, b, c, d); -} - -} - class VCL_DLLPUBLIC WinOpenGLDeviceInfo : public OpenGLDeviceInfo { private: @@ -140,22 +44,16 @@ private: OUString maDeviceString; OUString maDeviceString2; - uint32_t mnWindowsVersion; bool mbHasDualGPU; bool mbRDP; void GetData(); - static void FillBlacklist(); bool FindBlocklistedDeviceInList(); - static OUString* mpDeviceVendors[wgl::DeviceVendorMax]; - static std::vector maDriverInfo; - public: WinOpenGLDeviceInfo(); - static OUString GetDeviceVendor(wgl::DeviceVendor eVendor); virtual ~WinOpenGLDeviceInfo() override; virtual bool isDeviceBlocked() override; @@ -198,15 +96,6 @@ public: { return maDeviceString; } - - sal_uInt32 GetWindowsVersion() const - { - return mnWindowsVersion; - } - - static bool FindBlocklistedDeviceInList(std::vector& aDeviceInfos, - OUString const & sDriverVersion, OUString const & sAdapterVendorID, - OUString const & sAdapterDeviceID, uint32_t nWindowsVersion); }; #endif diff --git a/vcl/inc/opengl/win/blocklist_parser.hxx b/vcl/inc/opengl/win/blocklist_parser.hxx deleted file mode 100644 index 1d1ea314d6f7..000000000000 --- a/vcl/inc/opengl/win/blocklist_parser.hxx +++ /dev/null @@ -1,42 +0,0 @@ -/* -*- 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 -#include -#include -#include - -class InvalidFileException -{ -}; - -class VCL_DLLPUBLIC WinBlocklistParser -{ -public: - WinBlocklistParser(const OUString& rURL, std::vector& rDriverList); - void parse(); - -private: - void handleEntry(wgl::DriverInfo& rDriver, xmlreader::XmlReader& rReader); - void handleList(xmlreader::XmlReader& rReader); - void handleContent(xmlreader::XmlReader& rReader); - - enum class BlockType - { - WHITELIST, - BLACKLIST, - UNKNOWN - }; - - BlockType meBlockType; - std::vector& mrDriverList; - OUString maURL; -}; - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/opengl/win/WinDeviceInfo.cxx b/vcl/opengl/win/WinDeviceInfo.cxx index 0e466ecd6d4e..3fb4035ec58c 100644 --- a/vcl/opengl/win/WinDeviceInfo.cxx +++ b/vcl/opengl/win/WinDeviceInfo.cxx @@ -9,7 +9,7 @@ #include -#include +#include #include #if !defined WIN32_LEAN_AND_MEAN @@ -31,23 +31,8 @@ #include -OUString* WinOpenGLDeviceInfo::mpDeviceVendors[wgl::DeviceVendorMax]; -std::vector WinOpenGLDeviceInfo::maDriverInfo; - namespace { -/* - * 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 -size_t ArrayLength(T (&)[N]) -{ - return N; -} - bool GetKeyValue(const WCHAR* keyLocation, const WCHAR* keyName, OUString& destString, int type) { HKEY key; @@ -146,142 +131,6 @@ uint32_t ParseIDFromDeviceID(const OUString &key, const char *prefix, int 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, - kWindows7 = 0x00060001, - kWindows8 = 0x00060002, - kWindows8_1 = 0x00060003, - kWindows10 = 0x000A0000 // Major 10 Minor 0 -}; - - -wgl::OperatingSystem WindowsVersionToOperatingSystem(int32_t aWindowsVersion) -{ - switch(aWindowsVersion) - { - case kWindows7: - return wgl::DRIVER_OS_WINDOWS_7; - case kWindows8: - return wgl::DRIVER_OS_WINDOWS_8; - case kWindows8_1: - return wgl::DRIVER_OS_WINDOWS_8_1; - case kWindows10: - return wgl::DRIVER_OS_WINDOWS_10; - case kWindowsUnknown: - default: - return wgl::DRIVER_OS_UNKNOWN; - }; -} - - -int32_t WindowsOSVersion() -{ - static int32_t winVersion = [&]() - { - // GetVersion(Ex) and VersionHelpers (based on VerifyVersionInfo) API are - // subject to manifest-based behavior since Windows 8.1, so give wrong results. - // Another approach would be to use NetWkstaGetInfo, but that has some small - // reported delays (some milliseconds), and might get slower in domains with - // poor network connections. - // So go with a solution described at https://msdn.microsoft.com/en-us/library/ms724429 - HINSTANCE hLibrary = LoadLibraryW(L"kernel32.dll"); - if (hLibrary != nullptr) - { - wchar_t szPath[MAX_PATH]; - DWORD dwCount = GetModuleFileNameW(hLibrary, szPath, SAL_N_ELEMENTS(szPath)); - FreeLibrary(hLibrary); - if (dwCount != 0 && dwCount < SAL_N_ELEMENTS(szPath)) - { - dwCount = GetFileVersionInfoSizeW(szPath, nullptr); - if (dwCount != 0) - { - std::unique_ptr ver(new char[dwCount]); - if (GetFileVersionInfoW(szPath, 0, dwCount, ver.get()) != FALSE) - { - void* pBlock = nullptr; - UINT dwBlockSz = 0; - if (VerQueryValueW(ver.get(), L"\\", &pBlock, &dwBlockSz) != FALSE && dwBlockSz >= sizeof(VS_FIXEDFILEINFO)) - { - VS_FIXEDFILEINFO *vinfo = static_cast(pBlock); - return int32_t(vinfo->dwProductVersionMS); - } - } - } - } - } - return int32_t(kWindowsUnknown); - }(); - - 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; -} - /* Other interesting places for info: * IDXGIAdapter::GetDesc() * IDirectDraw7::GetAvailableVidMem() @@ -306,202 +155,28 @@ template void appendIntegerWithPadding(OUString& rString, T value, s #define DEVICE_KEY_PREFIX L"\\Registry\\Machine\\" } -namespace wgl { - -bool ParseDriverVersion(const OUString& aVersion, uint64_t& rNumericVersion) -{ - rNumericVersion = 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; - - rNumericVersion = GFX_DRIVER_VERSION(a, b, c, d); - return true; -#else - return false; -#endif -} - -uint64_t DriverInfo::allDriverVersions = ~(uint64_t(0)); - -DriverInfo::DriverInfo() - : meOperatingSystem(wgl::DRIVER_OS_UNKNOWN), - mnOperatingSystemVersion(0), - maAdapterVendor(WinOpenGLDeviceInfo::GetDeviceVendor(VendorAll)), - mbWhitelisted(false), - meComparisonOp(DRIVER_COMPARISON_IGNORED), - mnDriverVersion(0), - mnDriverVersionMax(0) -{} - -DriverInfo::DriverInfo(OperatingSystem os, const OUString& vendor, - VersionComparisonOp op, - uint64_t driverVersion, - bool bWhitelisted, - const char *suggestedVersion /* = nullptr */) - : meOperatingSystem(os), - mnOperatingSystemVersion(0), - maAdapterVendor(vendor), - mbWhitelisted(bWhitelisted), - meComparisonOp(op), - mnDriverVersion(driverVersion), - mnDriverVersionMax(0) -{ - if (suggestedVersion) - maSuggestedVersion = OStringToOUString(OString(suggestedVersion), RTL_TEXTENCODING_UTF8); -} - -DriverInfo::~DriverInfo() -{ -} - -} - WinOpenGLDeviceInfo::WinOpenGLDeviceInfo(): mbHasDualGPU(false), mbRDP(false) { GetData(); - FillBlacklist(); } WinOpenGLDeviceInfo::~WinOpenGLDeviceInfo() { } -namespace { - -struct compareIgnoreAsciiCase +static OUString getBlacklistFile() { - explicit compareIgnoreAsciiCase(const OUString& rString) - : maString(rString) - { - } - - bool operator()(const OUString& rCompare) - { - return maString.equalsIgnoreAsciiCase(rCompare); - } - -private: - OUString maString; -}; - -} - -bool WinOpenGLDeviceInfo::FindBlocklistedDeviceInList(std::vector& aDeviceInfos, - OUString const & sDriverVersion, OUString const & sAdapterVendorID, - OUString const & sAdapterDeviceID, uint32_t nWindowsVersion) -{ - uint64_t driverVersion; - wgl::ParseDriverVersion(sDriverVersion, driverVersion); - - wgl::OperatingSystem eOS = WindowsVersionToOperatingSystem(nWindowsVersion); - bool match = false; - for (std::vector::size_type i = 0; i < aDeviceInfos.size(); i++) - { - if (aDeviceInfos[i].meOperatingSystem != wgl::DRIVER_OS_ALL && - aDeviceInfos[i].meOperatingSystem != eOS) - { - continue; - } - - if (aDeviceInfos[i].mnOperatingSystemVersion && aDeviceInfos[i].mnOperatingSystemVersion != nWindowsVersion) - { - continue; - } - - if (!aDeviceInfos[i].maAdapterVendor.equalsIgnoreAsciiCase(GetDeviceVendor(wgl::VendorAll)) && - !aDeviceInfos[i].maAdapterVendor.equalsIgnoreAsciiCase(sAdapterVendorID)) - { - continue; - } - - if (std::none_of(aDeviceInfos[i].maDevices.begin(), aDeviceInfos[i].maDevices.end(), compareIgnoreAsciiCase("all")) && - std::none_of(aDeviceInfos[i].maDevices.begin(), aDeviceInfos[i].maDevices.end(), compareIgnoreAsciiCase(sAdapterDeviceID))) - { - continue; - } - - switch (aDeviceInfos[i].meComparisonOp) - { - case wgl::DRIVER_LESS_THAN: - match = driverVersion < aDeviceInfos[i].mnDriverVersion; - break; - case wgl::DRIVER_LESS_THAN_OR_EQUAL: - match = driverVersion <= aDeviceInfos[i].mnDriverVersion; - break; - case wgl::DRIVER_GREATER_THAN: - match = driverVersion > aDeviceInfos[i].mnDriverVersion; - break; - case wgl::DRIVER_GREATER_THAN_OR_EQUAL: - match = driverVersion >= aDeviceInfos[i].mnDriverVersion; - break; - case wgl::DRIVER_EQUAL: - match = driverVersion == aDeviceInfos[i].mnDriverVersion; - break; - case wgl::DRIVER_NOT_EQUAL: - match = driverVersion != aDeviceInfos[i].mnDriverVersion; - break; - case wgl::DRIVER_BETWEEN_EXCLUSIVE: - match = driverVersion > aDeviceInfos[i].mnDriverVersion && driverVersion < aDeviceInfos[i].mnDriverVersionMax; - break; - case wgl::DRIVER_BETWEEN_INCLUSIVE: - match = driverVersion >= aDeviceInfos[i].mnDriverVersion && driverVersion <= aDeviceInfos[i].mnDriverVersionMax; - break; - case wgl::DRIVER_BETWEEN_INCLUSIVE_START: - match = driverVersion >= aDeviceInfos[i].mnDriverVersion && driverVersion < aDeviceInfos[i].mnDriverVersionMax; - break; - case wgl::DRIVER_COMPARISON_IGNORED: - // We don't have a comparison op, so we match everything. - match = true; - break; - default: - SAL_WARN("vcl.opengl", "Bogus op in GfxDriverInfo"); - break; - } - - if (match || aDeviceInfos[i].mnDriverVersion == wgl::DriverInfo::allDriverVersions) - { - // white listed drivers - if (aDeviceInfos[i].mbWhitelisted) - { - SAL_WARN("vcl.opengl", "whitelisted driver"); - return false; - } - - match = true; - SAL_WARN("vcl.opengl", "use : " << aDeviceInfos[i].maSuggestedVersion); - break; - } - } + OUString url("$BRAND_BASE_DIR/" LIBO_SHARE_FOLDER); + rtl::Bootstrap::expandMacros(url); - SAL_INFO("vcl.opengl", (match ? "BLACKLISTED" : "not blacklisted")); - return match; + return url + "/opengl/opengl_blacklist_windows.xml"; } bool WinOpenGLDeviceInfo::FindBlocklistedDeviceInList() { - return FindBlocklistedDeviceInList(maDriverInfo, maDriverVersion, maAdapterVendorID, maAdapterDeviceID, mnWindowsVersion); + return DriverBlocklist::IsDeviceBlocked( getBlacklistFile(), maDriverVersion, maAdapterVendorID, maAdapterDeviceID); } namespace { @@ -573,7 +248,6 @@ void WinOpenGLDeviceInfo::GetData() DISPLAY_DEVICEW displayDevice; displayDevice.cb = sizeof(displayDevice); - mnWindowsVersion = WindowsOSVersion(); int deviceIndex = 0; while (EnumDisplayDevicesW(nullptr, deviceIndex, &displayDevice, 0)) @@ -587,8 +261,8 @@ void WinOpenGLDeviceInfo::GetData() // make sure the string is null terminated // (using the term "null" here to mean a zero UTF-16 unit) - if (wcsnlen(displayDevice.DeviceKey, ArrayLength(displayDevice.DeviceKey)) - == ArrayLength(displayDevice.DeviceKey)) + if (wcsnlen(displayDevice.DeviceKey, SAL_N_ELEMENTS(displayDevice.DeviceKey)) + == SAL_N_ELEMENTS(displayDevice.DeviceKey)) { // we did not find a null SAL_WARN("vcl.opengl", "string not null terminated"); @@ -598,14 +272,14 @@ void WinOpenGLDeviceInfo::GetData() /* 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 insensitively */ - if (_wcsnicmp(displayDevice.DeviceKey, DEVICE_KEY_PREFIX, ArrayLength(DEVICE_KEY_PREFIX)-1) != 0) + if (_wcsnicmp(displayDevice.DeviceKey, DEVICE_KEY_PREFIX, SAL_N_ELEMENTS(DEVICE_KEY_PREFIX)-1) != 0) { SAL_WARN("vcl.opengl", "incorrect DeviceKey"); return; } // chop off DEVICE_KEY_PREFIX - maDeviceKey = o3tl::toU(displayDevice.DeviceKey) + ArrayLength(DEVICE_KEY_PREFIX)-1; + maDeviceKey = o3tl::toU(displayDevice.DeviceKey) + SAL_N_ELEMENTS(DEVICE_KEY_PREFIX)-1; maDeviceID = o3tl::toU(displayDevice.DeviceID); maDeviceString = o3tl::toU(displayDevice.DeviceString); @@ -816,69 +490,4 @@ void WinOpenGLDeviceInfo::GetData() } } -OUString WinOpenGLDeviceInfo::GetDeviceVendor(wgl::DeviceVendor id) -{ - assert(id >= 0 && id < wgl::DeviceVendorMax); - - if (mpDeviceVendors[id]) - return *mpDeviceVendors[id]; - - mpDeviceVendors[id] = new OUString(); - - switch (id) - { - case wgl::VendorAll: - *mpDeviceVendors[id] = ""; - break; - case wgl::VendorIntel: - *mpDeviceVendors[id] = "0x8086"; - break; - case wgl::VendorNVIDIA: - *mpDeviceVendors[id] = "0x10de"; - break; - case wgl::VendorAMD: - *mpDeviceVendors[id] = "0x1022"; - break; - case wgl::VendorATI: - *mpDeviceVendors[id] = "0x1002"; - break; - case wgl::VendorMicrosoft: - *mpDeviceVendors[id] = "0x1414"; - break; - case wgl::DeviceVendorMax: // Suppress a warning. - break; - } - - return *mpDeviceVendors[id]; -} - -namespace { - - -OUString getBlacklistFile() -{ - OUString url("$BRAND_BASE_DIR/" LIBO_SHARE_FOLDER); - rtl::Bootstrap::expandMacros(url); - - return url + "/opengl/opengl_blacklist_windows.xml"; -} - - -} - -void WinOpenGLDeviceInfo::FillBlacklist() -{ - OUString aURL = getBlacklistFile(); - WinBlocklistParser aParser(aURL, maDriverInfo); - try { - aParser.parse(); - } - catch (...) - { - SAL_WARN("vcl.opengl", "error parsing blacklist"); - maDriverInfo.clear(); - } -} - - /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/opengl/win/blocklist_parser.cxx b/vcl/opengl/win/blocklist_parser.cxx deleted file mode 100644 index 79e49f540028..000000000000 --- a/vcl/opengl/win/blocklist_parser.cxx +++ /dev/null @@ -1,351 +0,0 @@ -/* -*- 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 - -#include - -WinBlocklistParser::WinBlocklistParser(const OUString& rURL, - std::vector& rDriverList) - : meBlockType(BlockType::UNKNOWN) - , mrDriverList(rDriverList) - , maURL(rURL) -{ -} - -void WinBlocklistParser::parse() -{ - xmlreader::XmlReader aReader(maURL); - handleContent(aReader); -} - -namespace { - -wgl::OperatingSystem getOperatingSystem(const OString& rString) -{ - if (rString == "all") - { - return wgl::DRIVER_OS_ALL; - } - else if (rString == "7") - { - return wgl::DRIVER_OS_WINDOWS_7; - } - else if (rString == "8") - { - return wgl::DRIVER_OS_WINDOWS_8; - } - else if (rString == "8_1") - { - return wgl::DRIVER_OS_WINDOWS_8_1; - } - else if (rString == "10") - { - return wgl::DRIVER_OS_WINDOWS_10; - } - - return wgl::DRIVER_OS_UNKNOWN; -} - -wgl::VersionComparisonOp getComparison(const OString& rString) -{ - if (rString == "less") - { - return wgl::DRIVER_LESS_THAN; - } - else if (rString == "less_equal") - { - return wgl::DRIVER_LESS_THAN_OR_EQUAL; - } - else if (rString == "greater") - { - return wgl::DRIVER_GREATER_THAN; - } - else if (rString == "greater_equal") - { - return wgl::DRIVER_GREATER_THAN_OR_EQUAL; - } - else if (rString == "equal") - { - return wgl::DRIVER_EQUAL; - } - else if (rString == "not_equal") - { - return wgl::DRIVER_NOT_EQUAL; - } - else if (rString == "between_exclusive") - { - return wgl::DRIVER_BETWEEN_EXCLUSIVE; - } - else if (rString == "between_inclusive") - { - return wgl::DRIVER_BETWEEN_INCLUSIVE; - } - else if (rString == "between_inclusive_start") - { - return wgl::DRIVER_BETWEEN_INCLUSIVE_START; - } - - throw InvalidFileException(); -} - -OUString getVendor(const OString& rString) -{ - if (rString == "all") - { - return ""; - } - else if (rString == "intel") - { - return "0x8086"; - } - else if (rString == "nvidia") - { - return "0x10de"; - } - else if (rString == "amd") - { - return "0x1022"; - } - else if (rString == "ati") - { - return "0x1002"; - } - else if (rString == "microsoft") - { - return "0x1414"; - } - else - { - // Allow having simply the hex number as such there, too. After all, it's hex numbers that - // are output to opengl_device.log. - return OStringToOUString(rString, RTL_TEXTENCODING_UTF8); - } -} - -uint64_t getVersion(const OString& rString) -{ - OUString aString = OStringToOUString(rString, RTL_TEXTENCODING_UTF8); - uint64_t nVersion; - bool bResult = wgl::ParseDriverVersion(aString, nVersion); - - if (!bResult) - { - throw InvalidFileException(); - } - - return nVersion; -} - -void handleDevices(wgl::DriverInfo& rDriver, xmlreader::XmlReader& rReader) -{ - int nLevel = 1; - bool bInMsg = false; - - while(true) - { - xmlreader::Span name; - int nsId; - - xmlreader::XmlReader::Result res = rReader.nextItem( - xmlreader::XmlReader::Text::Normalized, &name, &nsId); - - if (res == xmlreader::XmlReader::Result::Begin) - { - ++nLevel; - if (nLevel > 2) - throw InvalidFileException(); - - if (name == "msg") - { - bInMsg = true; - } - else if (name == "device") - { - int nsIdDeveice; - while (rReader.nextAttribute(&nsIdDeveice, &name)) - { - if (name == "id") - { - name = rReader.getAttributeValue(false); - OString aDeviceId(name.begin, name.length); - rDriver.maDevices.push_back(OStringToOUString(aDeviceId, RTL_TEXTENCODING_UTF8)); - } - } - } - else - throw InvalidFileException(); - } - else if (res == xmlreader::XmlReader::Result::End) - { - --nLevel; - bInMsg = false; - if (!nLevel) - break; - } - else if (res == xmlreader::XmlReader::Result::Text) - { - if (bInMsg) - { - OString sMsg(name.begin, name.length); - rDriver.maMsg = OStringToOUString(sMsg, RTL_TEXTENCODING_UTF8); - } - } - } -} - -} - -void WinBlocklistParser::handleEntry(wgl::DriverInfo& rDriver, xmlreader::XmlReader& rReader) -{ - if (meBlockType == BlockType::WHITELIST) - { - rDriver.mbWhitelisted = true; - } - else if (meBlockType == BlockType::BLACKLIST) - { - rDriver.mbWhitelisted = false; - } - else if (meBlockType == BlockType::UNKNOWN) - { - throw InvalidFileException(); - } - - xmlreader::Span name; - int nsId; - - while (rReader.nextAttribute(&nsId, &name)) - { - if (name == "os") - { - name = rReader.getAttributeValue(false); - OString sOS(name.begin, name.length); - rDriver.meOperatingSystem = getOperatingSystem(sOS); - } - else if (name == "vendor") - { - name = rReader.getAttributeValue(false); - OString sVendor(name.begin, name.length); - rDriver.maAdapterVendor = getVendor(sVendor); - } - else if (name == "compare") - { - name = rReader.getAttributeValue(false); - OString sCompare(name.begin, name.length); - rDriver.meComparisonOp = getComparison(sCompare); - } - else if (name == "version") - { - name = rReader.getAttributeValue(false); - OString sVersion(name.begin, name.length); - rDriver.mnDriverVersion = getVersion(sVersion); - } - else if (name == "minVersion") - { - name = rReader.getAttributeValue(false); - OString sMinVersion(name.begin, name.length); - rDriver.mnDriverVersion = getVersion(sMinVersion); - } - else if (name == "maxVersion") - { - name = rReader.getAttributeValue(false); - OString sMaxVersion(name.begin, name.length); - rDriver.mnDriverVersionMax = getVersion(sMaxVersion); - } - else - { - OString aAttrName(name.begin, name.length); - SAL_WARN("vcl.opengl", "unsupported attribute: " << aAttrName); - } - } - - handleDevices(rDriver, rReader); -} - -void WinBlocklistParser::handleList(xmlreader::XmlReader& rReader) -{ - xmlreader::Span name; - int nsId; - - while (true) - { - xmlreader::XmlReader::Result res = rReader.nextItem( - xmlreader::XmlReader::Text::NONE, &name, &nsId); - - if (res == xmlreader::XmlReader::Result::Begin) - { - if (name == "entry") - { - wgl::DriverInfo aDriver; - handleEntry(aDriver, rReader); - mrDriverList.push_back(aDriver); - } - else if (name == "entryRange") - { - wgl::DriverInfo aDriver; - handleEntry(aDriver, rReader); - mrDriverList.push_back(aDriver); - } - else - { - throw InvalidFileException(); - } - } - else if (res == xmlreader::XmlReader::Result::End) - { - break; - } - } -} - -void WinBlocklistParser::handleContent(xmlreader::XmlReader& rReader) -{ - while (true) - { - xmlreader::Span name; - int nsId; - - xmlreader::XmlReader::Result res = rReader.nextItem( - xmlreader::XmlReader::Text::NONE, &name, &nsId); - - if (res == xmlreader::XmlReader::Result::Begin) - { - if (name == "whitelist") - { - meBlockType = BlockType::WHITELIST; - handleList(rReader); - } - else if (name == "blacklist") - { - meBlockType = BlockType::BLACKLIST; - handleList(rReader); - } - else if (name == "root") - { - } - else - { - throw InvalidFileException(); - } - } - else if (res == xmlreader::XmlReader::Result::End) - { - if (name == "whitelist" || name == "blacklist") - { - meBlockType = BlockType::UNKNOWN; - } - } - else if (res == xmlreader::XmlReader::Result::Done) - { - break; - } - } -} - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qa/cppunit/blocklistparsertest.cxx b/vcl/qa/cppunit/blocklistparsertest.cxx index 7d99e87f3750..1a22d61e3577 100644 --- a/vcl/qa/cppunit/blocklistparsertest.cxx +++ b/vcl/qa/cppunit/blocklistparsertest.cxx @@ -16,7 +16,9 @@ #include -#include +#include + +using namespace DriverBlocklist; namespace { @@ -34,9 +36,9 @@ class BlocklistParserTest : public test::BootstrapFixtureBase void BlocklistParserTest::testParse() { - std::vector aDriveInfos; + std::vector aDriveInfos; - WinBlocklistParser aBlocklistParser(m_directories.getURLFromSrc("vcl/qa/cppunit/") + "test_blocklist_parse.xml", aDriveInfos); + Parser aBlocklistParser(m_directories.getURLFromSrc("vcl/qa/cppunit/") + "test_blocklist_parse.xml", aDriveInfos); aBlocklistParser.parse(); size_t const n = aDriveInfos.size(); @@ -46,91 +48,87 @@ void BlocklistParserTest::testParse() for (bool bIsWhitelisted : {true, false}) { - wgl::DriverInfo& aDriveInfo = aDriveInfos[i++]; + DriverInfo& aDriveInfo = aDriveInfos[i++]; CPPUNIT_ASSERT_EQUAL(bIsWhitelisted, aDriveInfo.mbWhitelisted); - CPPUNIT_ASSERT_EQUAL(WinOpenGLDeviceInfo::GetDeviceVendor(wgl::VendorAll), aDriveInfo.maAdapterVendor); // "all" - CPPUNIT_ASSERT_EQUAL(wgl::VersionComparisonOp::DRIVER_LESS_THAN, aDriveInfo.meComparisonOp); - CPPUNIT_ASSERT_EQUAL(wgl::V(10,20,30,40), aDriveInfo.mnDriverVersion); + CPPUNIT_ASSERT_EQUAL(GetVendorId(VendorAll), aDriveInfo.maAdapterVendor); // "all" + CPPUNIT_ASSERT_EQUAL(VersionComparisonOp::DRIVER_LESS_THAN, aDriveInfo.meComparisonOp); + CPPUNIT_ASSERT_EQUAL(V(10,20,30,40), aDriveInfo.mnDriverVersion); aDriveInfo = aDriveInfos[i++]; CPPUNIT_ASSERT_EQUAL(bIsWhitelisted, aDriveInfo.mbWhitelisted); - CPPUNIT_ASSERT_EQUAL(WinOpenGLDeviceInfo::GetDeviceVendor(wgl::VendorNVIDIA), aDriveInfo.maAdapterVendor); - CPPUNIT_ASSERT_EQUAL(wgl::VersionComparisonOp::DRIVER_EQUAL, aDriveInfo.meComparisonOp); + CPPUNIT_ASSERT_EQUAL(GetVendorId(VendorNVIDIA), aDriveInfo.maAdapterVendor); + CPPUNIT_ASSERT_EQUAL(VersionComparisonOp::DRIVER_EQUAL, aDriveInfo.meComparisonOp); aDriveInfo = aDriveInfos[i++]; CPPUNIT_ASSERT_EQUAL(bIsWhitelisted, aDriveInfo.mbWhitelisted); - CPPUNIT_ASSERT_EQUAL(WinOpenGLDeviceInfo::GetDeviceVendor(wgl::VendorMicrosoft), aDriveInfo.maAdapterVendor); - CPPUNIT_ASSERT_EQUAL(wgl::VersionComparisonOp::DRIVER_NOT_EQUAL, aDriveInfo.meComparisonOp); + CPPUNIT_ASSERT_EQUAL(GetVendorId(VendorMicrosoft), aDriveInfo.maAdapterVendor); + CPPUNIT_ASSERT_EQUAL(VersionComparisonOp::DRIVER_NOT_EQUAL, aDriveInfo.meComparisonOp); aDriveInfo = aDriveInfos[i++]; CPPUNIT_ASSERT_EQUAL(bIsWhitelisted, aDriveInfo.mbWhitelisted); CPPUNIT_ASSERT_EQUAL(OUString("0xcafe"), aDriveInfo.maAdapterVendor); - CPPUNIT_ASSERT_EQUAL(wgl::VersionComparisonOp::DRIVER_NOT_EQUAL, aDriveInfo.meComparisonOp); + CPPUNIT_ASSERT_EQUAL(VersionComparisonOp::DRIVER_NOT_EQUAL, aDriveInfo.meComparisonOp); aDriveInfo = aDriveInfos[i++]; CPPUNIT_ASSERT_EQUAL(bIsWhitelisted, aDriveInfo.mbWhitelisted); - CPPUNIT_ASSERT_EQUAL(WinOpenGLDeviceInfo::GetDeviceVendor(wgl::VendorAll), aDriveInfo.maAdapterVendor); - CPPUNIT_ASSERT_EQUAL(wgl::VersionComparisonOp::DRIVER_BETWEEN_EXCLUSIVE, aDriveInfo.meComparisonOp); + CPPUNIT_ASSERT_EQUAL(GetVendorId(VendorAll), aDriveInfo.maAdapterVendor); + CPPUNIT_ASSERT_EQUAL(VersionComparisonOp::DRIVER_BETWEEN_EXCLUSIVE, aDriveInfo.meComparisonOp); aDriveInfo = aDriveInfos[i++]; CPPUNIT_ASSERT_EQUAL(bIsWhitelisted, aDriveInfo.mbWhitelisted); - CPPUNIT_ASSERT_EQUAL(WinOpenGLDeviceInfo::GetDeviceVendor(wgl::VendorAll), aDriveInfo.maAdapterVendor); - CPPUNIT_ASSERT_EQUAL(wgl::VersionComparisonOp::DRIVER_BETWEEN_INCLUSIVE, aDriveInfo.meComparisonOp); + CPPUNIT_ASSERT_EQUAL(GetVendorId(VendorAll), aDriveInfo.maAdapterVendor); + CPPUNIT_ASSERT_EQUAL(VersionComparisonOp::DRIVER_BETWEEN_INCLUSIVE, aDriveInfo.meComparisonOp); aDriveInfo = aDriveInfos[i++]; CPPUNIT_ASSERT_EQUAL(bIsWhitelisted, aDriveInfo.mbWhitelisted); - CPPUNIT_ASSERT_EQUAL(WinOpenGLDeviceInfo::GetDeviceVendor(wgl::VendorAll), aDriveInfo.maAdapterVendor); - CPPUNIT_ASSERT_EQUAL(wgl::VersionComparisonOp::DRIVER_BETWEEN_INCLUSIVE_START, aDriveInfo.meComparisonOp); + CPPUNIT_ASSERT_EQUAL(GetVendorId(VendorAll), aDriveInfo.maAdapterVendor); + CPPUNIT_ASSERT_EQUAL(VersionComparisonOp::DRIVER_BETWEEN_INCLUSIVE_START, aDriveInfo.meComparisonOp); aDriveInfo = aDriveInfos[i++]; CPPUNIT_ASSERT_EQUAL(bIsWhitelisted, aDriveInfo.mbWhitelisted); - CPPUNIT_ASSERT_EQUAL(WinOpenGLDeviceInfo::GetDeviceVendor(wgl::VendorAll), aDriveInfo.maAdapterVendor); - CPPUNIT_ASSERT_EQUAL(wgl::VersionComparisonOp::DRIVER_COMPARISON_IGNORED, aDriveInfo.meComparisonOp); + CPPUNIT_ASSERT_EQUAL(GetVendorId(VendorAll), aDriveInfo.maAdapterVendor); + CPPUNIT_ASSERT_EQUAL(VersionComparisonOp::DRIVER_COMPARISON_IGNORED, aDriveInfo.meComparisonOp); } } void BlocklistParserTest::testEvaluate() { - std::vector aDriveInfos; + std::vector aDriveInfos; - WinBlocklistParser aBlocklistParser(m_directories.getURLFromSrc("vcl/qa/cppunit/") + "test_blocklist_evaluate.xml", aDriveInfos); + Parser aBlocklistParser(m_directories.getURLFromSrc("vcl/qa/cppunit/") + "test_blocklist_evaluate.xml", aDriveInfos); aBlocklistParser.parse(); - OUString vendorAMD = WinOpenGLDeviceInfo::GetDeviceVendor(wgl::VendorAMD); - OUString vendorNVIDIA = WinOpenGLDeviceInfo::GetDeviceVendor(wgl::VendorNVIDIA); - OUString vendorIntel = WinOpenGLDeviceInfo::GetDeviceVendor(wgl::VendorIntel); - OUString vendorMicrosoft = WinOpenGLDeviceInfo::GetDeviceVendor(wgl::VendorMicrosoft); - - uint32_t const osWindows7 = 0x00060001; - uint32_t const osWindows8 = 0x00060002; - uint32_t const osWindows10 = 0x000A0000; + OUString vendorAMD = GetVendorId(VendorAMD); + OUString vendorNVIDIA = GetVendorId(VendorNVIDIA); + OUString vendorIntel = GetVendorId(VendorIntel); + OUString vendorMicrosoft = GetVendorId(VendorMicrosoft); // Check OS - CPPUNIT_ASSERT_EQUAL(false, WinOpenGLDeviceInfo::FindBlocklistedDeviceInList( - aDriveInfos, "10.20.30.40", vendorNVIDIA, "all", osWindows7)); - CPPUNIT_ASSERT_EQUAL(false, WinOpenGLDeviceInfo::FindBlocklistedDeviceInList( - aDriveInfos, "10.20.30.40", vendorNVIDIA, "all", osWindows8)); - CPPUNIT_ASSERT_EQUAL(false, WinOpenGLDeviceInfo::FindBlocklistedDeviceInList( - aDriveInfos, "10.20.30.40", vendorNVIDIA, "all", osWindows10)); + CPPUNIT_ASSERT_EQUAL(false, FindBlocklistedDeviceInList( + aDriveInfos, "10.20.30.40", vendorNVIDIA, "all", DRIVER_OS_WINDOWS_7)); + CPPUNIT_ASSERT_EQUAL(false, FindBlocklistedDeviceInList( + aDriveInfos, "10.20.30.40", vendorNVIDIA, "all", DRIVER_OS_WINDOWS_8)); + CPPUNIT_ASSERT_EQUAL(false, FindBlocklistedDeviceInList( + aDriveInfos, "10.20.30.40", vendorNVIDIA, "all", DRIVER_OS_WINDOWS_10)); // Check Vendors - CPPUNIT_ASSERT_EQUAL(true, WinOpenGLDeviceInfo::FindBlocklistedDeviceInList( - aDriveInfos, "10.20.30.40", vendorMicrosoft, "all", osWindows7)); - CPPUNIT_ASSERT_EQUAL(true, WinOpenGLDeviceInfo::FindBlocklistedDeviceInList( - aDriveInfos, "10.20.30.40", vendorMicrosoft, "all", osWindows10)); + CPPUNIT_ASSERT_EQUAL(true, FindBlocklistedDeviceInList( + aDriveInfos, "10.20.30.40", vendorMicrosoft, "all", DRIVER_OS_WINDOWS_7)); + CPPUNIT_ASSERT_EQUAL(true, FindBlocklistedDeviceInList( + aDriveInfos, "10.20.30.40", vendorMicrosoft, "all", DRIVER_OS_WINDOWS_10)); // Check Versions - CPPUNIT_ASSERT_EQUAL(true, WinOpenGLDeviceInfo::FindBlocklistedDeviceInList( - aDriveInfos, "10.20.30.39", vendorAMD, "all", osWindows7)); - CPPUNIT_ASSERT_EQUAL(false, WinOpenGLDeviceInfo::FindBlocklistedDeviceInList( - aDriveInfos, "10.20.30.40", vendorAMD, "all", osWindows7)); - CPPUNIT_ASSERT_EQUAL(false, WinOpenGLDeviceInfo::FindBlocklistedDeviceInList( - aDriveInfos, "10.20.30.41", vendorAMD, "all", osWindows7)); + CPPUNIT_ASSERT_EQUAL(true, FindBlocklistedDeviceInList( + aDriveInfos, "10.20.30.39", vendorAMD, "all", DRIVER_OS_WINDOWS_7)); + CPPUNIT_ASSERT_EQUAL(false, FindBlocklistedDeviceInList( + aDriveInfos, "10.20.30.40", vendorAMD, "all", DRIVER_OS_WINDOWS_7)); + CPPUNIT_ASSERT_EQUAL(false, FindBlocklistedDeviceInList( + aDriveInfos, "10.20.30.41", vendorAMD, "all", DRIVER_OS_WINDOWS_7)); // Check - CPPUNIT_ASSERT_EQUAL(true, WinOpenGLDeviceInfo::FindBlocklistedDeviceInList( - aDriveInfos, "9.17.10.4229", vendorIntel, "all", osWindows7)); + CPPUNIT_ASSERT_EQUAL(true, FindBlocklistedDeviceInList( + aDriveInfos, "9.17.10.4229", vendorIntel, "all", DRIVER_OS_WINDOWS_7)); } diff --git a/vcl/skia/SkiaHelper.cxx b/vcl/skia/SkiaHelper.cxx index 0404a52f98cc..c305c5275ea5 100644 --- a/vcl/skia/SkiaHelper.cxx +++ b/vcl/skia/SkiaHelper.cxx @@ -9,13 +9,6 @@ #include -#include -#include -#include -#include -#include -#include - #if !HAVE_FEATURE_SKIA namespace SkiaHelper @@ -26,7 +19,16 @@ bool isVCLSkiaEnabled() { return false; } #else +#include +#include +#include +#include +#include +#include +#include +#include #include +#include #include @@ -36,20 +38,31 @@ bool isVCLSkiaEnabled() { return false; } namespace SkiaHelper { +static OUString getBlacklistFile() +{ + OUString url("$BRAND_BASE_DIR/" LIBO_SHARE_FOLDER); + rtl::Bootstrap::expandMacros(url); + + return url + "/skia/skia_blacklist_vulkan.xml"; +} + static bool isVulkanBlacklisted(const VkPhysicalDeviceProperties& props) { static const char* const types[] = { "other", "integrated", "discrete", "virtual", "cpu", "??" }; // VkPhysicalDeviceType + OUString driverVersion = OUString::number(props.driverVersion >> 22) + "." + + OUString::number((props.driverVersion >> 12) & 0x3ff) + "." + + OUString::number(props.driverVersion & 0xfff); + OUString vendorId = "0x" + OUString::number(props.vendorID, 16); + OUString deviceId = "0x" + OUString::number(props.deviceID, 16); SAL_INFO("vcl.skia", "Vulkan API version: " << (props.apiVersion >> 22) << "." << ((props.apiVersion >> 12) & 0x3ff) << "." - << (props.apiVersion & 0xfff) << ", driver version: " - << (props.driverVersion >> 22) << "." << ((props.driverVersion >> 12) & 0x3ff) - << "." << (props.driverVersion & 0xfff) << std::hex << ", vendor: 0x" - << props.vendorID << ", device: 0x" << props.deviceID << std::dec - << ", type: " << types[std::min(props.deviceType, SAL_N_ELEMENTS(types))] + << (props.apiVersion & 0xfff) << ", driver version: " << driverVersion + << ", vendor: " << vendorId << ", device: " << deviceId << ", type: " + << types[std::min(props.deviceType, SAL_N_ELEMENTS(types) - 1)] << ", name: " << props.deviceName); - return false; + return DriverBlocklist::IsDeviceBlocked(getBlacklistFile(), driverVersion, vendorId, deviceId); } static void checkDeviceBlacklisted() diff --git a/vcl/skia/skia_blacklist_vulkan.xml b/vcl/skia/skia_blacklist_vulkan.xml new file mode 100644 index 000000000000..2c7714a38f8a --- /dev/null +++ b/vcl/skia/skia_blacklist_vulkan.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + diff --git a/vcl/source/helper/driverblocklist.cxx b/vcl/source/helper/driverblocklist.cxx new file mode 100644 index 000000000000..a63fdc00cd30 --- /dev/null +++ b/vcl/source/helper/driverblocklist.cxx @@ -0,0 +1,711 @@ +/* -*- 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 + +#include + +#include + +#ifdef _WIN32 +#if !defined WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include +#endif + +namespace DriverBlocklist +{ +static OperatingSystem getOperatingSystem(const OString& rString) +{ + if (rString == "all") + return DRIVER_OS_ALL; + else if (rString == "7") + return DRIVER_OS_WINDOWS_7; + else if (rString == "8") + return DRIVER_OS_WINDOWS_8; + else if (rString == "8_1") + return DRIVER_OS_WINDOWS_8_1; + else if (rString == "10") + return DRIVER_OS_WINDOWS_10; + else if (rString == "linux") + return DRIVER_OS_LINUX; + else if (rString == "osx_10_5") + return DRIVER_OS_OSX_10_5; + else if (rString == "osx_10_6") + return DRIVER_OS_OSX_10_6; + else if (rString == "osx_10_7") + return DRIVER_OS_OSX_10_7; + else if (rString == "osx_10_8") + return DRIVER_OS_OSX_10_8; + else if (rString == "android") + return DRIVER_OS_ANDROID; + return DRIVER_OS_UNKNOWN; +} + +static VersionComparisonOp getComparison(const OString& rString) +{ + if (rString == "less") + { + return DRIVER_LESS_THAN; + } + else if (rString == "less_equal") + { + return DRIVER_LESS_THAN_OR_EQUAL; + } + else if (rString == "greater") + { + return DRIVER_GREATER_THAN; + } + else if (rString == "greater_equal") + { + return DRIVER_GREATER_THAN_OR_EQUAL; + } + else if (rString == "equal") + { + return DRIVER_EQUAL; + } + else if (rString == "not_equal") + { + return DRIVER_NOT_EQUAL; + } + else if (rString == "between_exclusive") + { + return DRIVER_BETWEEN_EXCLUSIVE; + } + else if (rString == "between_inclusive") + { + return DRIVER_BETWEEN_INCLUSIVE; + } + else if (rString == "between_inclusive_start") + { + return DRIVER_BETWEEN_INCLUSIVE_START; + } + + throw InvalidFileException(); +} + +static OUString GetVendorId(const OString& rString) +{ + if (rString == "all") + { + return ""; + } + else if (rString == "intel") + { + return "0x8086"; + } + else if (rString == "nvidia") + { + return "0x10de"; + } + else if (rString == "amd") + { + return "0x1022"; + } + else if (rString == "ati") + { + return "0x1002"; + } + else if (rString == "microsoft") + { + return "0x1414"; + } + else + { + // Allow having simply the hex number as such there, too. + return OStringToOUString(rString, RTL_TEXTENCODING_UTF8); + } +} + +OUString GetVendorId(DeviceVendor id) +{ + assert(id >= 0 && id < DeviceVendorMax); + + switch (id) + { + case VendorAll: + return ""; + case VendorIntel: + return "0x8086"; + case VendorNVIDIA: + return "0x10de"; + case VendorAMD: + return "0x1022"; + case VendorATI: + return "0x1002"; + case VendorMicrosoft: + return "0x1414"; + } + abort(); +} + +Parser::Parser(const OUString& rURL, std::vector& rDriverList) + : meBlockType(BlockType::UNKNOWN) + , mrDriverList(rDriverList) + , maURL(rURL) +{ +} + +bool Parser::parse() +{ + try + { + xmlreader::XmlReader aReader(maURL); + handleContent(aReader); + } + catch (...) + { + mrDriverList.clear(); + return false; + } + return true; +} + +// 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. +static 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. +static 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 >= SAL_N_ELEMENTS(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; + + // Vulkan version numbers have only 3 fields. + if (destIdx == SAL_N_ELEMENTS(dest) - 2) + dest[destIdx++][0] = '\0'; + if (destIdx != SAL_N_ELEMENTS(dest) - 1) + { + return false; + } + return true; +} + +static bool ParseDriverVersion(const OUString& aVersion, uint64_t& rNumericVersion) +{ + rNumericVersion = 0; + + 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; + + rNumericVersion = GFX_DRIVER_VERSION(a, b, c, d); + return true; +} + +static uint64_t getVersion(const OString& rString) +{ + OUString aString = OStringToOUString(rString, RTL_TEXTENCODING_UTF8); + uint64_t nVersion; + bool bResult = ParseDriverVersion(aString, nVersion); + + if (!bResult) + { + throw InvalidFileException(); + } + + return nVersion; +} + +void Parser::handleDevices(DriverInfo& rDriver, xmlreader::XmlReader& rReader) +{ + int nLevel = 1; + bool bInMsg = false; + + while (true) + { + xmlreader::Span name; + int nsId; + + xmlreader::XmlReader::Result res + = rReader.nextItem(xmlreader::XmlReader::Text::Normalized, &name, &nsId); + + if (res == xmlreader::XmlReader::Result::Begin) + { + ++nLevel; + if (nLevel > 2) + throw InvalidFileException(); + + if (name == "msg") + { + bInMsg = true; + } + else if (name == "device") + { + int nsIdDeveice; + while (rReader.nextAttribute(&nsIdDeveice, &name)) + { + if (name == "id") + { + name = rReader.getAttributeValue(false); + OString aDeviceId(name.begin, name.length); + rDriver.maDevices.push_back( + OStringToOUString(aDeviceId, RTL_TEXTENCODING_UTF8)); + } + } + } + else + throw InvalidFileException(); + } + else if (res == xmlreader::XmlReader::Result::End) + { + --nLevel; + bInMsg = false; + if (!nLevel) + break; + } + else if (res == xmlreader::XmlReader::Result::Text) + { + if (bInMsg) + { + OString sMsg(name.begin, name.length); + rDriver.maMsg = OStringToOUString(sMsg, RTL_TEXTENCODING_UTF8); + } + } + } +} + +void Parser::handleEntry(DriverInfo& rDriver, xmlreader::XmlReader& rReader) +{ + if (meBlockType == BlockType::WHITELIST) + { + rDriver.mbWhitelisted = true; + } + else if (meBlockType == BlockType::BLACKLIST) + { + rDriver.mbWhitelisted = false; + } + else if (meBlockType == BlockType::UNKNOWN) + { + throw InvalidFileException(); + } + + xmlreader::Span name; + int nsId; + + while (rReader.nextAttribute(&nsId, &name)) + { + if (name == "os") + { + name = rReader.getAttributeValue(false); + OString sOS(name.begin, name.length); + rDriver.meOperatingSystem = getOperatingSystem(sOS); + } + else if (name == "vendor") + { + name = rReader.getAttributeValue(false); + OString sVendor(name.begin, name.length); + rDriver.maAdapterVendor = GetVendorId(sVendor); + } + else if (name == "compare") + { + name = rReader.getAttributeValue(false); + OString sCompare(name.begin, name.length); + rDriver.meComparisonOp = getComparison(sCompare); + } + else if (name == "version") + { + name = rReader.getAttributeValue(false); + OString sVersion(name.begin, name.length); + rDriver.mnDriverVersion = getVersion(sVersion); + } + else if (name == "minVersion") + { + name = rReader.getAttributeValue(false); + OString sMinVersion(name.begin, name.length); + rDriver.mnDriverVersion = getVersion(sMinVersion); + } + else if (name == "maxVersion") + { + name = rReader.getAttributeValue(false); + OString sMaxVersion(name.begin, name.length); + rDriver.mnDriverVersionMax = getVersion(sMaxVersion); + } + else + { + OString aAttrName(name.begin, name.length); + SAL_WARN("vcl.driver", "unsupported attribute: " << aAttrName); + } + } + + handleDevices(rDriver, rReader); +} + +void Parser::handleList(xmlreader::XmlReader& rReader) +{ + xmlreader::Span name; + int nsId; + + while (true) + { + xmlreader::XmlReader::Result res + = rReader.nextItem(xmlreader::XmlReader::Text::NONE, &name, &nsId); + + if (res == xmlreader::XmlReader::Result::Begin) + { + if (name == "entry") + { + DriverInfo aDriver; + handleEntry(aDriver, rReader); + mrDriverList.push_back(aDriver); + } + else if (name == "entryRange") + { + DriverInfo aDriver; + handleEntry(aDriver, rReader); + mrDriverList.push_back(aDriver); + } + else + { + throw InvalidFileException(); + } + } + else if (res == xmlreader::XmlReader::Result::End) + { + break; + } + } +} + +void Parser::handleContent(xmlreader::XmlReader& rReader) +{ + while (true) + { + xmlreader::Span name; + int nsId; + + xmlreader::XmlReader::Result res + = rReader.nextItem(xmlreader::XmlReader::Text::NONE, &name, &nsId); + + if (res == xmlreader::XmlReader::Result::Begin) + { + if (name == "whitelist") + { + meBlockType = BlockType::WHITELIST; + handleList(rReader); + } + else if (name == "blacklist") + { + meBlockType = BlockType::BLACKLIST; + handleList(rReader); + } + else if (name == "root") + { + } + else + { + throw InvalidFileException(); + } + } + else if (res == xmlreader::XmlReader::Result::End) + { + if (name == "whitelist" || name == "blacklist") + { + meBlockType = BlockType::UNKNOWN; + } + } + else if (res == xmlreader::XmlReader::Result::Done) + { + break; + } + } +} + +static OperatingSystem getOperatingSystem() +{ +#ifdef _WIN32 + // OS version in 16.16 major/minor form + // based on http://msdn.microsoft.com/en-us/library/ms724834(VS.85).aspx + switch (DriverBlocklist::GetWindowsVersion()) + { + case 0x00060001: + return DRIVER_OS_WINDOWS_7; + case 0x00060002: + return DRIVER_OS_WINDOWS_8; + case 0x00060003: + return DRIVER_OS_WINDOWS_8_1; + case 0x000A0000: // Major 10 Minor 0 + return DRIVER_OS_WINDOWS_10; + default: + return DRIVER_OS_UNKNOWN; + } +#elif defined LINUX + return DRIVER_OS_LINUX; +#else + return DRIVER_OS_UNKNOWN; +#endif +} + +namespace +{ +struct compareIgnoreAsciiCase +{ + explicit compareIgnoreAsciiCase(const OUString& rString) + : maString(rString) + { + } + + bool operator()(const OUString& rCompare) { return maString.equalsIgnoreAsciiCase(rCompare); } + +private: + OUString maString; +}; +} + +const uint64_t allDriverVersions = ~(uint64_t(0)); + +DriverInfo::DriverInfo() + : meOperatingSystem(DRIVER_OS_UNKNOWN) + , maAdapterVendor(GetVendorId(VendorAll)) + , mbWhitelisted(false) + , meComparisonOp(DRIVER_COMPARISON_IGNORED) + , mnDriverVersion(0) + , mnDriverVersionMax(0) +{ +} + +DriverInfo::DriverInfo(OperatingSystem os, const OUString& vendor, VersionComparisonOp op, + uint64_t driverVersion, bool bWhitelisted, + const char* suggestedVersion /* = nullptr */) + : meOperatingSystem(os) + , maAdapterVendor(vendor) + , mbWhitelisted(bWhitelisted) + , meComparisonOp(op) + , mnDriverVersion(driverVersion) + , mnDriverVersionMax(0) +{ + if (suggestedVersion) + maSuggestedVersion = OStringToOUString(OString(suggestedVersion), RTL_TEXTENCODING_UTF8); +} + +bool FindBlocklistedDeviceInList(std::vector& aDeviceInfos, + OUString const& sDriverVersion, OUString const& sAdapterVendorID, + OUString const& sAdapterDeviceID, OperatingSystem system, + const OUString& blocklistURL) +{ + uint64_t driverVersion; + ParseDriverVersion(sDriverVersion, driverVersion); + + bool match = false; + for (std::vector::size_type i = 0; i < aDeviceInfos.size(); i++) + { + if (aDeviceInfos[i].meOperatingSystem != DRIVER_OS_ALL + && aDeviceInfos[i].meOperatingSystem != system) + { + continue; + } + + if (!aDeviceInfos[i].maAdapterVendor.equalsIgnoreAsciiCase(GetVendorId(VendorAll)) + && !aDeviceInfos[i].maAdapterVendor.equalsIgnoreAsciiCase(sAdapterVendorID)) + { + continue; + } + + if (std::none_of(aDeviceInfos[i].maDevices.begin(), aDeviceInfos[i].maDevices.end(), + compareIgnoreAsciiCase("all")) + && std::none_of(aDeviceInfos[i].maDevices.begin(), aDeviceInfos[i].maDevices.end(), + compareIgnoreAsciiCase(sAdapterDeviceID))) + { + continue; + } + + switch (aDeviceInfos[i].meComparisonOp) + { + case DRIVER_LESS_THAN: + match = driverVersion < aDeviceInfos[i].mnDriverVersion; + break; + case DRIVER_LESS_THAN_OR_EQUAL: + match = driverVersion <= aDeviceInfos[i].mnDriverVersion; + break; + case DRIVER_GREATER_THAN: + match = driverVersion > aDeviceInfos[i].mnDriverVersion; + break; + case DRIVER_GREATER_THAN_OR_EQUAL: + match = driverVersion >= aDeviceInfos[i].mnDriverVersion; + break; + case DRIVER_EQUAL: + match = driverVersion == aDeviceInfos[i].mnDriverVersion; + break; + case DRIVER_NOT_EQUAL: + match = driverVersion != aDeviceInfos[i].mnDriverVersion; + break; + case DRIVER_BETWEEN_EXCLUSIVE: + match = driverVersion > aDeviceInfos[i].mnDriverVersion + && driverVersion < aDeviceInfos[i].mnDriverVersionMax; + break; + case DRIVER_BETWEEN_INCLUSIVE: + match = driverVersion >= aDeviceInfos[i].mnDriverVersion + && driverVersion <= aDeviceInfos[i].mnDriverVersionMax; + break; + case DRIVER_BETWEEN_INCLUSIVE_START: + match = driverVersion >= aDeviceInfos[i].mnDriverVersion + && driverVersion < aDeviceInfos[i].mnDriverVersionMax; + break; + case DRIVER_COMPARISON_IGNORED: + // We don't have a comparison op, so we match everything. + match = true; + break; + default: + SAL_WARN("vcl.driver", "Bogus op in " << blocklistURL); + break; + } + + if (match || aDeviceInfos[i].mnDriverVersion == allDriverVersions) + { + // white listed drivers + if (aDeviceInfos[i].mbWhitelisted) + { + SAL_INFO("vcl.driver", "whitelisted driver"); + return false; + } + + match = true; + if (!aDeviceInfos[i].maSuggestedVersion.isEmpty()) + { + SAL_WARN("vcl.driver", "use : " << aDeviceInfos[i].maSuggestedVersion); + } + break; + } + } + + SAL_INFO("vcl.driver", (match ? "blacklisted" : "not blacklisted") << " in " << blocklistURL); + return match; +} + +bool IsDeviceBlocked(const OUString& blocklistURL, const OUString& driverVersion, + const OUString& vendorId, const OUString& deviceId) +{ + std::vector driverList; + Parser parser(blocklistURL, driverList); + if (!parser.parse()) + { + SAL_WARN("vcl.driver", "error parsing blacklist " << blocklistURL); + return false; + } + return FindBlocklistedDeviceInList(driverList, driverVersion, vendorId, deviceId, + getOperatingSystem(), blocklistURL); +} + +#ifdef _WIN32 +int32_t GetWindowsVersion() +{ + static int32_t winVersion = [&]() { + // GetVersion(Ex) and VersionHelpers (based on VerifyVersionInfo) API are + // subject to manifest-based behavior since Windows 8.1, so give wrong results. + // Another approach would be to use NetWkstaGetInfo, but that has some small + // reported delays (some milliseconds), and might get slower in domains with + // poor network connections. + // So go with a solution described at https://msdn.microsoft.com/en-us/library/ms724429 + HINSTANCE hLibrary = LoadLibraryW(L"kernel32.dll"); + if (hLibrary != nullptr) + { + wchar_t szPath[MAX_PATH]; + DWORD dwCount = GetModuleFileNameW(hLibrary, szPath, SAL_N_ELEMENTS(szPath)); + FreeLibrary(hLibrary); + if (dwCount != 0 && dwCount < SAL_N_ELEMENTS(szPath)) + { + dwCount = GetFileVersionInfoSizeW(szPath, nullptr); + if (dwCount != 0) + { + std::unique_ptr ver(new char[dwCount]); + if (GetFileVersionInfoW(szPath, 0, dwCount, ver.get()) != FALSE) + { + void* pBlock = nullptr; + UINT dwBlockSz = 0; + if (VerQueryValueW(ver.get(), L"\\", &pBlock, &dwBlockSz) != FALSE + && dwBlockSz >= sizeof(VS_FIXEDFILEINFO)) + { + VS_FIXEDFILEINFO* vinfo = static_cast(pBlock); + return int32_t(vinfo->dwProductVersionMS); + } + } + } + } + } + return 0; + }(); + + return winVersion; +} +#endif + +} // namespace + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/opengl/OpenGLHelper.cxx b/vcl/source/opengl/OpenGLHelper.cxx index 081bf240cc8b..ece8e9d6c440 100644 --- a/vcl/source/opengl/OpenGLHelper.cxx +++ b/vcl/source/opengl/OpenGLHelper.cxx @@ -209,7 +209,7 @@ namespace return OUStringToOString(aInfo.GetAdapterVendorID(), RTL_TEXTENCODING_UTF8) + OUStringToOString(aInfo.GetAdapterDeviceID(), RTL_TEXTENCODING_UTF8) + OUStringToOString(aInfo.GetDriverVersion(), RTL_TEXTENCODING_UTF8) + - OString::number(aInfo.GetWindowsVersion()); + OString::number(DriverBlocklist::GetWindowsVersion()); #else return rtl::OStringView(reinterpret_cast(glGetString(GL_VENDOR))) + reinterpret_cast(glGetString(GL_RENDERER)) + @@ -767,7 +767,7 @@ bool OpenGLHelper::isDeviceBlacklisted() WinOpenGLDeviceInfo aInfo; bBlacklisted = aInfo.isDeviceBlocked(); - if (aInfo.GetWindowsVersion() == 0x00060001 && /* Windows 7 */ + if (DriverBlocklist::GetWindowsVersion() == 0x00060001 && /* Windows 7 */ (aInfo.GetAdapterVendorID() == "0x1002" || aInfo.GetAdapterVendorID() == "0x1022")) /* AMD */ { SAL_INFO("vcl.opengl", "Relaxing watchdog timings."); -- cgit