diff options
Diffstat (limited to 'widget/GfxDriverInfo.h')
-rw-r--r-- | widget/GfxDriverInfo.h | 501 |
1 files changed, 501 insertions, 0 deletions
diff --git a/widget/GfxDriverInfo.h b/widget/GfxDriverInfo.h new file mode 100644 index 0000000000..a584c7ac3f --- /dev/null +++ b/widget/GfxDriverInfo.h @@ -0,0 +1,501 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef __mozilla_widget_GfxDriverInfo_h__ +#define __mozilla_widget_GfxDriverInfo_h__ + +#include "nsString.h" +#include "nsTArray.h" + +// Macros for adding a blocklist item to the static list. _EXT variants +// allow one to specify all available parameters, including those available +// only on specific platforms (e.g. desktop environment and driver vendor +// for Linux.) + +#define APPEND_TO_DRIVER_BLOCKLIST_EXT( \ + os, screen, battery, windowProtocol, driverVendor, devices, feature, \ + featureStatus, driverComparator, driverVersion, ruleId, suggestedVersion) \ + sDriverInfo->AppendElement(GfxDriverInfo( \ + os, screen, battery, \ + (nsAString&)GfxDriverInfo::GetWindowProtocol(windowProtocol), \ + (nsAString&)GfxDriverInfo::GetDeviceVendor(devices), \ + (nsAString&)GfxDriverInfo::GetDriverVendor(driverVendor), \ + (GfxDeviceFamily*)GfxDriverInfo::GetDeviceFamily(devices), feature, \ + featureStatus, driverComparator, driverVersion, ruleId, \ + suggestedVersion)) + +#define APPEND_TO_DRIVER_BLOCKLIST(os, devices, feature, featureStatus, \ + driverComparator, driverVersion, ruleId, \ + suggestedVersion) \ + APPEND_TO_DRIVER_BLOCKLIST_EXT( \ + os, ScreenSizeStatus::All, BatteryStatus::All, WindowProtocol::All, \ + DriverVendor::All, devices, feature, featureStatus, driverComparator, \ + driverVersion, ruleId, suggestedVersion) + +#define APPEND_TO_DRIVER_BLOCKLIST2_EXT( \ + os, screen, battery, windowProtocol, driverVendor, devices, feature, \ + featureStatus, driverComparator, driverVersion, ruleId) \ + sDriverInfo->AppendElement(GfxDriverInfo( \ + os, screen, battery, \ + (nsAString&)GfxDriverInfo::GetWindowProtocol(windowProtocol), \ + (nsAString&)GfxDriverInfo::GetDeviceVendor(devices), \ + (nsAString&)GfxDriverInfo::GetDriverVendor(driverVendor), \ + (GfxDeviceFamily*)GfxDriverInfo::GetDeviceFamily(devices), feature, \ + featureStatus, driverComparator, driverVersion, ruleId)) + +#define APPEND_TO_DRIVER_BLOCKLIST2(os, devices, feature, featureStatus, \ + driverComparator, driverVersion, ruleId) \ + APPEND_TO_DRIVER_BLOCKLIST2_EXT( \ + os, ScreenSizeStatus::All, BatteryStatus::All, WindowProtocol::All, \ + DriverVendor::All, devices, feature, featureStatus, driverComparator, \ + driverVersion, ruleId) + +#define APPEND_TO_DRIVER_BLOCKLIST_RANGE_EXT( \ + os, screen, battery, windowProtocol, driverVendor, devices, feature, \ + featureStatus, driverComparator, driverVersion, driverVersionMax, ruleId, \ + suggestedVersion) \ + do { \ + MOZ_ASSERT((driverComparator) == DRIVER_BETWEEN_EXCLUSIVE || \ + (driverComparator) == DRIVER_BETWEEN_INCLUSIVE || \ + (driverComparator) == DRIVER_BETWEEN_INCLUSIVE_START); \ + GfxDriverInfo info( \ + os, screen, battery, \ + (nsAString&)GfxDriverInfo::GetWindowProtocol(windowProtocol), \ + (nsAString&)GfxDriverInfo::GetDeviceVendor(devices), \ + (nsAString&)GfxDriverInfo::GetDriverVendor(driverVendor), \ + (GfxDeviceFamily*)GfxDriverInfo::GetDeviceFamily(devices), feature, \ + featureStatus, driverComparator, driverVersion, ruleId, \ + suggestedVersion); \ + info.mDriverVersionMax = driverVersionMax; \ + sDriverInfo->AppendElement(info); \ + } while (false) + +#define APPEND_TO_DRIVER_BLOCKLIST_RANGE( \ + os, devices, feature, featureStatus, driverComparator, driverVersion, \ + driverVersionMax, ruleId, suggestedVersion) \ + APPEND_TO_DRIVER_BLOCKLIST_RANGE_EXT( \ + os, ScreenSizeStatus::All, BatteryStatus::All, WindowProtocol::All, \ + DriverVendor::All, devices, feature, featureStatus, driverComparator, \ + driverVersion, driverVersionMax, ruleId, suggestedVersion) + +#define APPEND_TO_DRIVER_BLOCKLIST_RANGE_GPU2_EXT( \ + os, screen, battery, windowProtocol, driverVendor, devices, feature, \ + featureStatus, driverComparator, driverVersion, driverVersionMax, ruleId, \ + suggestedVersion) \ + do { \ + MOZ_ASSERT((driverComparator) == DRIVER_BETWEEN_EXCLUSIVE || \ + (driverComparator) == DRIVER_BETWEEN_INCLUSIVE || \ + (driverComparator) == DRIVER_BETWEEN_INCLUSIVE_START); \ + GfxDriverInfo info( \ + os, screen, battery, \ + (nsAString&)GfxDriverInfo::GetWindowProtocol(windowProtocol), \ + (nsAString&)GfxDriverInfo::GetDeviceVendor(devices), \ + (nsAString&)GfxDriverInfo::GetDriverVendor(driverVendor), \ + (GfxDeviceFamily*)GfxDriverInfo::GetDeviceFamily(devices), feature, \ + featureStatus, driverComparator, driverVersion, ruleId, \ + suggestedVersion, false, true); \ + info.mDriverVersionMax = driverVersionMax; \ + sDriverInfo->AppendElement(info); \ + } while (false) + +#define APPEND_TO_DRIVER_BLOCKLIST_RANGE_GPU2( \ + os, devices, feature, featureStatus, driverComparator, driverVersion, \ + driverVersionMax, ruleId, suggestedVersion) \ + APPEND_TO_DRIVER_BLOCKLIST_RANGE_GPU2_EXT( \ + os, ScreenSizeStatus::All, BatteryStatus::All, WindowProtocol::All, \ + DriverVendor::All, devices, feature, featureStatus, driverComparator, \ + driverVersion, driverVersionMax, ruleId, suggestedVersion) + +namespace mozilla { +namespace widget { + +enum class OperatingSystem : uint8_t { + Unknown, + Windows, + WindowsXP, + WindowsServer2003, + WindowsVista, + Windows7, + Windows8, + Windows8_1, + Windows10, + RecentWindows10, + NotRecentWindows10, + Linux, + OSX, + OSX10_5, + OSX10_6, + OSX10_7, + OSX10_8, + OSX10_9, + OSX10_10, + OSX10_11, + OSX10_12, + OSX10_13, + OSX10_14, + OSX10_15, + OSX11_0, + Android, + Ios +}; + +enum VersionComparisonOp { + DRIVER_LESS_THAN, // driver < version + DRIVER_BUILD_ID_LESS_THAN, // driver build id < version + DRIVER_LESS_THAN_OR_EQUAL, // driver <= version + DRIVER_BUILD_ID_LESS_THAN_OR_EQUAL, // driver build id <= 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 class DeviceFamily : uint8_t { + All, + IntelAll, + NvidiaAll, + AtiAll, + MicrosoftAll, + ParallelsAll, + QualcommAll, + AppleAll, + AmazonAll, + IntelGMA500, + IntelGMA900, + IntelGMA950, + IntelGMA3150, + IntelGMAX3000, + IntelGMAX4500HD, + IntelHDGraphicsToIvyBridge, + IntelHDGraphicsToSandyBridge, + IntelHaswell, + IntelSandyBridge, + IntelGen7Baytrail, + IntelSkylake, + IntelKabyLake, + IntelHD520, + IntelMobileHDGraphics, + NvidiaBlockD3D9Layers, + RadeonX1000, + RadeonCaicos, + RadeonBlockZeroVideoCopy, + Geforce7300GT, + Nvidia310M, + Nvidia8800GTS, + Bug1137716, + Bug1116812, + Bug1155608, + Bug1207665, + Bug1447141, + AmdR600, + IntelWebRenderBlocked, + NvidiaWebRenderBlocked, + + Max +}; + +enum class DeviceVendor : uint8_t { + All, // There is an assumption that this is the first enum + Intel, + NVIDIA, + ATI, + Microsoft, + Parallels, + VMWare, + VirtualBox, + Qualcomm, + MicrosoftBasic, + MicrosoftHyperV, + Apple, + Amazon, + + Max +}; + +enum DriverVendor : uint8_t { + All, // There is an assumption that this is the first enum + // Wildcard for all Mesa drivers. + MesaAll, + // Note that the following list of Mesa drivers is not comprehensive; we pull + // the DRI driver at runtime. These drivers are provided for convenience when + // populating the local blocklist. + MesaLLVMPipe, + MesaSoftPipe, + MesaSWRast, + MesaSWUnknown, + // AMD + MesaR600, + // Nouveau: Open-source nvidia + MesaNouveau, + // A generic ID to be provided when we can't determine the DRI driver on Mesa. + MesaUnknown, + // Wildcard for all non-Mesa drivers. + NonMesaAll, + // Wildcard for all hardware Mesa drivers. + HardwareMesaAll, + // Wildcard for all software Mesa drivers. + SoftwareMesaAll, + // Wildcard for all non-Intel/NVIDIA/ATI Mesa drivers. + MesaNonIntelNvidiaAtiAll, + // Running in VM. + MesaVM, + + Max +}; + +enum class WindowProtocol : uint8_t { + All, // There is an assumption that this is the first enum + X11, + XWayland, + Wayland, + WaylandDRM, + // Wildcard for all Wayland variants, excluding XWayland. + WaylandAll, + // Wildcard for all X11 variants, including XWayland. + X11All, + Max +}; + +enum class BatteryStatus : uint8_t { All, Present, None }; + +enum class ScreenSizeStatus : uint8_t { + All, + Small, // <= 1900x1200 + SmallAndMedium, // <= 3440x1440 + Medium, // <= 3440x1440 && > 1900x1200 + MediumAndLarge, // >1900x1200 + Large // > 3440x1440 +}; + +/* Array of devices to match, or an empty array for all devices */ +class GfxDeviceFamily final { + public: + GfxDeviceFamily() = default; + + void Append(const nsAString& aDeviceId); + void AppendRange(int32_t aBeginDeviceId, int32_t aEndDeviceId); + + bool IsEmpty() const { return mIds.IsEmpty() && mRanges.IsEmpty(); } + + nsresult Contains(nsAString& aDeviceId) const; + + private: + struct DeviceRange { + int32_t mBegin; + int32_t mEnd; + }; + + CopyableTArray<nsString> mIds; + CopyableTArray<DeviceRange> mRanges; +}; + +struct GfxDriverInfo { + // If |ownDevices| is true, you are transferring ownership of the devices + // array, and it will be deleted when this GfxDriverInfo is destroyed. + GfxDriverInfo(OperatingSystem os, ScreenSizeStatus aScreen, + BatteryStatus aBattery, const nsAString& windowProtocol, + const nsAString& vendor, const nsAString& driverVendor, + GfxDeviceFamily* devices, int32_t feature, + int32_t featureStatus, VersionComparisonOp op, + uint64_t driverVersion, const char* ruleId, + const char* suggestedVersion = nullptr, bool ownDevices = false, + bool gpu2 = false); + + GfxDriverInfo(); + GfxDriverInfo(const GfxDriverInfo&); + ~GfxDriverInfo(); + + OperatingSystem mOperatingSystem; + uint32_t mOperatingSystemVersion; + ScreenSizeStatus mScreen; + BatteryStatus mBattery; + nsString mWindowProtocol; + + nsString mAdapterVendor; + nsString mDriverVendor; + + const GfxDeviceFamily* mDevices; + + // Whether the mDevices array should be deleted when this structure is + // deallocated. False by default. + bool mDeleteDevices; + + /* A feature from nsIGfxInfo, or a wildcard set of features */ + int32_t mFeature; + /* Block all features */ + static constexpr int32_t allFeatures = -1; + /* Block all features not permitted by OnlyAllowFeatureOnKnownConfig */ + static constexpr int32_t optionalFeatures = -2; + + /* A feature status from nsIGfxInfo */ + int32_t mFeatureStatus; + + VersionComparisonOp mComparisonOp; + + /* versions are assumed to be A.B.C.D packed as 0xAAAABBBBCCCCDDDD */ + uint64_t mDriverVersion; + uint64_t mDriverVersionMax; + static constexpr uint64_t allDriverVersions = ~(uint64_t(0)); + + const char* mSuggestedVersion; + nsCString mRuleId; + + static const GfxDeviceFamily* GetDeviceFamily(DeviceFamily id); + static GfxDeviceFamily* + sDeviceFamilies[static_cast<size_t>(DeviceFamily::Max)]; + + static const nsAString& GetWindowProtocol(WindowProtocol id); + static nsString* sWindowProtocol[static_cast<size_t>(WindowProtocol::Max)]; + + static const nsAString& GetDeviceVendor(DeviceVendor id); + static const nsAString& GetDeviceVendor(DeviceFamily id); + static nsString* sDeviceVendors[static_cast<size_t>(DeviceVendor::Max)]; + + static const nsAString& GetDriverVendor(DriverVendor id); + static nsString* sDriverVendors[static_cast<size_t>(DriverVendor::Max)]; + + nsString mModel, mHardware, mProduct, mManufacturer; + + bool mGpu2; +}; + +inline uint64_t DriverVersion(uint32_t a, uint32_t b, uint32_t c, uint32_t d) { + return (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) { +#ifdef XP_WIN + // 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; + } +#endif + return DriverVersion(a, b, c, d); +} + +// All destination string storage needs to have at least 5 bytes available. +inline 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); + + // This "4" is hardcoded in a few places, including once as a 3. + char* dest[4] = {aAStr, aBStr, aCStr, aDStr}; + unsigned destIdx = 0; + unsigned destPos = 0; + + for (int i = 0; i < len; i++) { + if (destIdx >= 4) { + // Invalid format found. Ensure we don't access dest beyond bounds. + return false; + } + + if (aSource[i] == '.') { + MOZ_ASSERT(destIdx < 4 && destPos <= 4); + 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; + } + + MOZ_ASSERT(destIdx < 4 && destPos < 4); + dest[destIdx][destPos++] = aSource[i]; + } + + // Take care of the trailing period + if (destIdx >= 4) { + return false; + } + + // Add last terminator. + MOZ_ASSERT(destIdx < 4 && destPos <= 4); + dest[destIdx][destPos] = 0; + for (int unusedDestIdx = destIdx + 1; unusedDestIdx < 4; unusedDestIdx++) { + dest[unusedDestIdx][0] = 0; + } + + if (destIdx != 3) { + 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. +inline 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; +} + +inline bool ParseDriverVersion(const nsAString& aVersion, + uint64_t* aNumericVersion) { + *aNumericVersion = 0; + +#ifndef ANDROID + int a, b, c, d; + char aStr[8], bStr[8], cStr[8], dStr[8]; + /* honestly, why do I even bother */ + if (!SplitDriverVersion(NS_LossyConvertUTF16toASCII(aVersion).get(), aStr, + bStr, cStr, dStr)) + return false; + +# ifdef XP_WIN + PadDriverDecimal(bStr); + PadDriverDecimal(cStr); + PadDriverDecimal(dStr); +# endif + + a = atoi(aStr); + b = atoi(bStr); + c = atoi(cStr); + d = atoi(dStr); + + if (a < 0 || a > 0xffff) return false; + if (b < 0 || b > 0xffff) return false; + if (c < 0 || c > 0xffff) return false; + if (d < 0 || d > 0xffff) return false; + + *aNumericVersion = DriverVersion(a, b, c, d); +#else + // Can't use aVersion.ToInteger() because that's not compiled into our code + // unless we have XPCOM_GLUE_AVOID_NSPR disabled. + *aNumericVersion = atoi(NS_LossyConvertUTF16toASCII(aVersion).get()); +#endif + MOZ_ASSERT(*aNumericVersion != GfxDriverInfo::allDriverVersions); + return true; +} + +} // namespace widget +} // namespace mozilla + +#endif /*__mozilla_widget_GfxDriverInfo_h__ */ |