1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6 #ifndef __mozilla_widget_GfxDriverInfo_h__
7 #define __mozilla_widget_GfxDriverInfo_h__
8
9 #include "nsString.h"
10 #include "nsTArray.h"
11
12 // Macros for adding a blocklist item to the static list. _EXT variants
13 // allow one to specify all available parameters, including those available
14 // only on specific platforms (e.g. desktop environment and driver vendor
15 // for Linux.)
16
17 #define APPEND_TO_DRIVER_BLOCKLIST_EXT( \
18 os, screen, battery, desktopEnv, windowProtocol, driverVendor, devices, \
19 feature, featureStatus, driverComparator, driverVersion, ruleId, \
20 suggestedVersion) \
21 sDriverInfo->AppendElement(GfxDriverInfo( \
22 os, screen, battery, \
23 (nsAString&)GfxDriverInfo::GetDesktopEnvironment(desktopEnv), \
24 (nsAString&)GfxDriverInfo::GetWindowProtocol(windowProtocol), \
25 (nsAString&)GfxDriverInfo::GetDeviceVendor(devices), \
26 (nsAString&)GfxDriverInfo::GetDriverVendor(driverVendor), \
27 (GfxDeviceFamily*)GfxDriverInfo::GetDeviceFamily(devices), feature, \
28 featureStatus, driverComparator, driverVersion, ruleId, \
29 suggestedVersion))
30
31 #define APPEND_TO_DRIVER_BLOCKLIST(os, devices, feature, featureStatus, \
32 driverComparator, driverVersion, ruleId, \
33 suggestedVersion) \
34 APPEND_TO_DRIVER_BLOCKLIST_EXT( \
35 os, ScreenSizeStatus::All, BatteryStatus::All, DesktopEnvironment::All, \
36 WindowProtocol::All, DriverVendor::All, devices, feature, featureStatus, \
37 driverComparator, driverVersion, ruleId, suggestedVersion)
38
39 #define APPEND_TO_DRIVER_BLOCKLIST2_EXT( \
40 os, screen, battery, desktopEnv, windowProtocol, driverVendor, devices, \
41 feature, featureStatus, driverComparator, driverVersion, ruleId) \
42 sDriverInfo->AppendElement(GfxDriverInfo( \
43 os, screen, battery, \
44 (nsAString&)GfxDriverInfo::GetDesktopEnvironment(desktopEnv), \
45 (nsAString&)GfxDriverInfo::GetWindowProtocol(windowProtocol), \
46 (nsAString&)GfxDriverInfo::GetDeviceVendor(devices), \
47 (nsAString&)GfxDriverInfo::GetDriverVendor(driverVendor), \
48 (GfxDeviceFamily*)GfxDriverInfo::GetDeviceFamily(devices), feature, \
49 featureStatus, driverComparator, driverVersion, ruleId))
50
51 #define APPEND_TO_DRIVER_BLOCKLIST2(os, devices, feature, featureStatus, \
52 driverComparator, driverVersion, ruleId) \
53 APPEND_TO_DRIVER_BLOCKLIST2_EXT( \
54 os, ScreenSizeStatus::All, BatteryStatus::All, DesktopEnvironment::All, \
55 WindowProtocol::All, DriverVendor::All, devices, feature, featureStatus, \
56 driverComparator, driverVersion, ruleId)
57
58 #define APPEND_TO_DRIVER_BLOCKLIST_RANGE_EXT( \
59 os, screen, battery, desktopEnv, windowProtocol, driverVendor, devices, \
60 feature, featureStatus, driverComparator, driverVersion, driverVersionMax, \
61 ruleId, suggestedVersion) \
62 do { \
63 MOZ_ASSERT((driverComparator) == DRIVER_BETWEEN_EXCLUSIVE || \
64 (driverComparator) == DRIVER_BETWEEN_INCLUSIVE || \
65 (driverComparator) == DRIVER_BETWEEN_INCLUSIVE_START); \
66 GfxDriverInfo info( \
67 os, screen, battery, \
68 (nsAString&)GfxDriverInfo::GetDesktopEnvironment(desktopEnv), \
69 (nsAString&)GfxDriverInfo::GetWindowProtocol(windowProtocol), \
70 (nsAString&)GfxDriverInfo::GetDeviceVendor(devices), \
71 (nsAString&)GfxDriverInfo::GetDriverVendor(driverVendor), \
72 (GfxDeviceFamily*)GfxDriverInfo::GetDeviceFamily(devices), feature, \
73 featureStatus, driverComparator, driverVersion, ruleId, \
74 suggestedVersion); \
75 info.mDriverVersionMax = driverVersionMax; \
76 sDriverInfo->AppendElement(info); \
77 } while (false)
78
79 #define APPEND_TO_DRIVER_BLOCKLIST_RANGE( \
80 os, devices, feature, featureStatus, driverComparator, driverVersion, \
81 driverVersionMax, ruleId, suggestedVersion) \
82 APPEND_TO_DRIVER_BLOCKLIST_RANGE_EXT( \
83 os, ScreenSizeStatus::All, BatteryStatus::All, DesktopEnvironment::All, \
84 WindowProtocol::All, DriverVendor::All, devices, feature, featureStatus, \
85 driverComparator, driverVersion, driverVersionMax, ruleId, \
86 suggestedVersion)
87
88 #define APPEND_TO_DRIVER_BLOCKLIST_RANGE_GPU2_EXT( \
89 os, screen, battery, desktopEnv, windowProtocol, driverVendor, devices, \
90 feature, featureStatus, driverComparator, driverVersion, driverVersionMax, \
91 ruleId, suggestedVersion) \
92 do { \
93 MOZ_ASSERT((driverComparator) == DRIVER_BETWEEN_EXCLUSIVE || \
94 (driverComparator) == DRIVER_BETWEEN_INCLUSIVE || \
95 (driverComparator) == DRIVER_BETWEEN_INCLUSIVE_START); \
96 GfxDriverInfo info( \
97 os, screen, battery, \
98 (nsAString&)GfxDriverInfo::GetDesktopEnvironment(desktopEnv), \
99 (nsAString&)GfxDriverInfo::GetWindowProtocol(windowProtocol), \
100 (nsAString&)GfxDriverInfo::GetDeviceVendor(devices), \
101 (nsAString&)GfxDriverInfo::GetDriverVendor(driverVendor), \
102 (GfxDeviceFamily*)GfxDriverInfo::GetDeviceFamily(devices), feature, \
103 featureStatus, driverComparator, driverVersion, ruleId, \
104 suggestedVersion, false, true); \
105 info.mDriverVersionMax = driverVersionMax; \
106 sDriverInfo->AppendElement(info); \
107 } while (false)
108
109 #define APPEND_TO_DRIVER_BLOCKLIST_RANGE_GPU2( \
110 os, devices, feature, featureStatus, driverComparator, driverVersion, \
111 driverVersionMax, ruleId, suggestedVersion) \
112 APPEND_TO_DRIVER_BLOCKLIST_RANGE_GPU2_EXT( \
113 os, ScreenSizeStatus::All, BatteryStatus::All, DesktopEnvironment::All, \
114 WindowProtocol::All, DriverVendor::All, devices, feature, featureStatus, \
115 driverComparator, driverVersion, driverVersionMax, ruleId, \
116 suggestedVersion)
117
118 namespace mozilla {
119 namespace widget {
120
121 enum class OperatingSystem : uint8_t {
122 Unknown,
123 Windows,
124 WindowsXP,
125 WindowsServer2003,
126 WindowsVista,
127 Windows7,
128 Windows8,
129 Windows8_1,
130 Windows10,
131 RecentWindows10,
132 NotRecentWindows10,
133 Linux,
134 OSX,
135 OSX10_5,
136 OSX10_6,
137 OSX10_7,
138 OSX10_8,
139 OSX10_9,
140 OSX10_10,
141 OSX10_11,
142 OSX10_12,
143 OSX10_13,
144 OSX10_14,
145 OSX10_15,
146 OSX11_0,
147 Android,
148 Ios
149 };
150
151 enum VersionComparisonOp {
152 DRIVER_LESS_THAN, // driver < version
153 DRIVER_BUILD_ID_LESS_THAN, // driver build id < version
154 DRIVER_LESS_THAN_OR_EQUAL, // driver <= version
155 DRIVER_BUILD_ID_LESS_THAN_OR_EQUAL, // driver build id <= version
156 DRIVER_GREATER_THAN, // driver > version
157 DRIVER_GREATER_THAN_OR_EQUAL, // driver >= version
158 DRIVER_EQUAL, // driver == version
159 DRIVER_NOT_EQUAL, // driver != version
160 DRIVER_BETWEEN_EXCLUSIVE, // driver > version && driver < versionMax
161 DRIVER_BETWEEN_INCLUSIVE, // driver >= version && driver <= versionMax
162 DRIVER_BETWEEN_INCLUSIVE_START, // driver >= version && driver < versionMax
163 DRIVER_COMPARISON_IGNORED
164 };
165
166 enum class DeviceFamily : uint8_t {
167 All,
168 IntelAll,
169 NvidiaAll,
170 AtiAll,
171 MicrosoftAll,
172 ParallelsAll,
173 QualcommAll,
174 AppleAll,
175 AmazonAll,
176 IntelGMA500,
177 IntelGMA900,
178 IntelGMA950,
179 IntelGMA3150,
180 IntelGMAX3000,
181 IntelGMAX4500HD,
182 IntelHDGraphicsToIvyBridge,
183 IntelHDGraphicsToSandyBridge,
184 IntelHaswell,
185 IntelSandyBridge,
186 IntelGen7Baytrail,
187 IntelHD520,
188 IntelMobileHDGraphics,
189 NvidiaBlockD3D9Layers,
190 RadeonX1000,
191 RadeonCaicos,
192 Geforce7300GT,
193 Nvidia310M,
194 Nvidia8800GTS,
195 Bug1137716,
196 Bug1116812,
197 Bug1155608,
198 Bug1207665,
199 Bug1447141,
200 AmdR600,
201 NvidiaRolloutWebRender,
202 IntelRolloutWebRender,
203 IntelModernRolloutWebRender,
204 AtiRolloutWebRender,
205
206 Max
207 };
208
209 enum class DeviceVendor : uint8_t {
210 All, // There is an assumption that this is the first enum
211 Intel,
212 NVIDIA,
213 ATI,
214 Microsoft,
215 Parallels,
216 VMWare,
217 VirtualBox,
218 Qualcomm,
219 MicrosoftBasic,
220 MicrosoftHyperV,
221 Apple,
222 Amazon,
223
224 Max
225 };
226
227 enum DriverVendor : uint8_t {
228 All, // There is an assumption that this is the first enum
229 // Wildcard for all Mesa drivers.
230 MesaAll,
231 // Note that the following list of Mesa drivers is not comprehensive; we pull
232 // the DRI driver at runtime. These drivers are provided for convenience when
233 // populating the local blocklist.
234 MesaLLVMPipe,
235 MesaSoftPipe,
236 MesaSWRast,
237 // AMD
238 MesaR600,
239 // Nouveau: Open-source nvidia
240 MesaNouveau,
241 // A generic ID to be provided when we can't determine the DRI driver on Mesa.
242 MesaUnknown,
243 // Wildcard for all non-Mesa drivers.
244 NonMesaAll,
245 // Wildcard for all hardware Mesa drivers.
246 HardwareMesaAll,
247 // Wildcard for all software Mesa drivers.
248 SoftwareMesaAll,
249
250 Max
251 };
252
253 enum class DesktopEnvironment : uint8_t {
254 All, // There is an assumption that this is the first enum
255 GNOME,
256 KDE,
257 XFCE,
258 Cinnamon,
259 Enlightenment,
260 LXDE,
261 Openbox,
262 i3,
263 Mate,
264 Unity,
265 Pantheon,
266 LXQT,
267 Deepin,
268 Dwm,
269 Budgie,
270 Unknown,
271 Max
272 };
273
274 enum class WindowProtocol : uint8_t {
275 All, // There is an assumption that this is the first enum
276 X11,
277 XWayland,
278 Wayland,
279 WaylandDRM,
280 // Wildcard for all Wayland variants, excluding XWayland.
281 WaylandAll,
282 // Wildcard for all X11 variants, including XWayland.
283 X11All,
284 Max
285 };
286
287 enum class BatteryStatus : uint8_t { All, Present, None };
288
289 enum class ScreenSizeStatus : uint8_t {
290 All,
291 Small, // <= 1900x1200
292 SmallAndMedium, // <= 3440x1440
293 Medium, // <= 3440x1440 && > 1900x1200
294 MediumAndLarge, // >1900x1200
295 Large // > 3440x1440
296 };
297
298 /* Array of devices to match, or an empty array for all devices */
299 class GfxDeviceFamily final {
300 public:
301 GfxDeviceFamily() = default;
302
303 void Append(const nsAString& aDeviceId);
304 void AppendRange(int32_t aBeginDeviceId, int32_t aEndDeviceId);
305
IsEmpty()306 bool IsEmpty() const { return mIds.IsEmpty() && mRanges.IsEmpty(); }
307
308 nsresult Contains(nsAString& aDeviceId) const;
309
310 private:
311 struct DeviceRange {
312 int32_t mBegin;
313 int32_t mEnd;
314 };
315
316 CopyableTArray<nsString> mIds;
317 CopyableTArray<DeviceRange> mRanges;
318 };
319
320 struct GfxDriverInfo {
321 // If |ownDevices| is true, you are transferring ownership of the devices
322 // array, and it will be deleted when this GfxDriverInfo is destroyed.
323 GfxDriverInfo(OperatingSystem os, ScreenSizeStatus aScreen,
324 BatteryStatus aBattery, const nsAString& desktopEnv,
325 const nsAString& windowProtocol, const nsAString& vendor,
326 const nsAString& driverVendor, GfxDeviceFamily* devices,
327 int32_t feature, int32_t featureStatus, VersionComparisonOp op,
328 uint64_t driverVersion, const char* ruleId,
329 const char* suggestedVersion = nullptr, bool ownDevices = false,
330 bool gpu2 = false);
331
332 GfxDriverInfo();
333 GfxDriverInfo(const GfxDriverInfo&);
334 ~GfxDriverInfo();
335
336 OperatingSystem mOperatingSystem;
337 uint32_t mOperatingSystemVersion;
338 ScreenSizeStatus mScreen;
339 BatteryStatus mBattery;
340 nsString mDesktopEnvironment;
341 nsString mWindowProtocol;
342
343 nsString mAdapterVendor;
344 nsString mDriverVendor;
345
346 const GfxDeviceFamily* mDevices;
347
348 // Whether the mDevices array should be deleted when this structure is
349 // deallocated. False by default.
350 bool mDeleteDevices;
351
352 /* A feature from nsIGfxInfo, or all features */
353 int32_t mFeature;
354 static int32_t allFeatures;
355
356 /* A feature status from nsIGfxInfo */
357 int32_t mFeatureStatus;
358
359 VersionComparisonOp mComparisonOp;
360
361 /* versions are assumed to be A.B.C.D packed as 0xAAAABBBBCCCCDDDD */
362 uint64_t mDriverVersion;
363 uint64_t mDriverVersionMax;
364 static uint64_t allDriverVersions;
365
366 const char* mSuggestedVersion;
367 nsCString mRuleId;
368
369 static const GfxDeviceFamily* GetDeviceFamily(DeviceFamily id);
370 static GfxDeviceFamily*
371 sDeviceFamilies[static_cast<size_t>(DeviceFamily::Max)];
372
373 static const nsAString& GetDesktopEnvironment(DesktopEnvironment id);
374 static nsAString*
375 sDesktopEnvironment[static_cast<size_t>(DesktopEnvironment::Max)];
376
377 static const nsAString& GetWindowProtocol(WindowProtocol id);
378 static nsAString* sWindowProtocol[static_cast<size_t>(WindowProtocol::Max)];
379
380 static const nsAString& GetDeviceVendor(DeviceVendor id);
381 static const nsAString& GetDeviceVendor(DeviceFamily id);
382 static nsAString* sDeviceVendors[static_cast<size_t>(DeviceVendor::Max)];
383
384 static const nsAString& GetDriverVendor(DriverVendor id);
385 static nsAString* sDriverVendors[static_cast<size_t>(DriverVendor::Max)];
386
387 nsString mModel, mHardware, mProduct, mManufacturer;
388
389 bool mGpu2;
390 };
391
392 #define GFX_DRIVER_VERSION(a, b, c, d) \
393 ((uint64_t(a) << 48) | (uint64_t(b) << 32) | (uint64_t(c) << 16) | \
394 uint64_t(d))
395
V(uint32_t a,uint32_t b,uint32_t c,uint32_t d)396 inline uint64_t V(uint32_t a, uint32_t b, uint32_t c, uint32_t d) {
397 // We make sure every driver number is padded by 0s, this will allow us the
398 // easiest 'compare as if decimals' approach. See ParseDriverVersion for a
399 // more extensive explanation of this approach.
400 while (b > 0 && b < 1000) {
401 b *= 10;
402 }
403 while (c > 0 && c < 1000) {
404 c *= 10;
405 }
406 while (d > 0 && d < 1000) {
407 d *= 10;
408 }
409 return GFX_DRIVER_VERSION(a, b, c, d);
410 }
411
412 // All destination string storage needs to have at least 5 bytes available.
SplitDriverVersion(const char * aSource,char * aAStr,char * aBStr,char * aCStr,char * aDStr)413 inline bool SplitDriverVersion(const char* aSource, char* aAStr, char* aBStr,
414 char* aCStr, char* aDStr) {
415 // sscanf doesn't do what we want here to we parse this manually.
416 int len = strlen(aSource);
417
418 // This "4" is hardcoded in a few places, including once as a 3.
419 char* dest[4] = {aAStr, aBStr, aCStr, aDStr};
420 unsigned destIdx = 0;
421 unsigned destPos = 0;
422
423 for (int i = 0; i < len; i++) {
424 if (destIdx >= 4) {
425 // Invalid format found. Ensure we don't access dest beyond bounds.
426 return false;
427 }
428
429 if (aSource[i] == '.') {
430 MOZ_ASSERT(destIdx < 4 && destPos <= 4);
431 dest[destIdx++][destPos] = 0;
432 destPos = 0;
433 continue;
434 }
435
436 if (destPos > 3) {
437 // Ignore more than 4 chars. Ensure we never access dest[destIdx]
438 // beyond its bounds.
439 continue;
440 }
441
442 MOZ_ASSERT(destIdx < 4 && destPos < 4);
443 dest[destIdx][destPos++] = aSource[i];
444 }
445
446 // Take care of the trailing period
447 if (destIdx >= 4) {
448 return false;
449 }
450
451 // Add last terminator.
452 MOZ_ASSERT(destIdx < 4 && destPos <= 4);
453 dest[destIdx][destPos] = 0;
454
455 if (destIdx != 3) {
456 return false;
457 }
458 return true;
459 }
460
461 // This allows us to pad driver version 'substrings' with 0s, this
462 // effectively allows us to treat the version numbers as 'decimals'. This is
463 // a little strange but this method seems to do the right thing for all
464 // different vendor's driver strings. i.e. .98 will become 9800, which is
465 // larger than .978 which would become 9780.
PadDriverDecimal(char * aString)466 inline void PadDriverDecimal(char* aString) {
467 for (int i = 0; i < 4; i++) {
468 if (!aString[i]) {
469 for (int c = i; c < 4; c++) {
470 aString[c] = '0';
471 }
472 break;
473 }
474 }
475 aString[4] = 0;
476 }
477
ParseDriverVersion(const nsAString & aVersion,uint64_t * aNumericVersion)478 inline bool ParseDriverVersion(const nsAString& aVersion,
479 uint64_t* aNumericVersion) {
480 *aNumericVersion = 0;
481
482 #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)
483 int a, b, c, d;
484 char aStr[8], bStr[8], cStr[8], dStr[8];
485 /* honestly, why do I even bother */
486 if (!SplitDriverVersion(NS_LossyConvertUTF16toASCII(aVersion).get(), aStr,
487 bStr, cStr, dStr))
488 return false;
489
490 PadDriverDecimal(bStr);
491 PadDriverDecimal(cStr);
492 PadDriverDecimal(dStr);
493
494 a = atoi(aStr);
495 b = atoi(bStr);
496 c = atoi(cStr);
497 d = atoi(dStr);
498
499 if (a < 0 || a > 0xffff) return false;
500 if (b < 0 || b > 0xffff) return false;
501 if (c < 0 || c > 0xffff) return false;
502 if (d < 0 || d > 0xffff) return false;
503
504 *aNumericVersion = GFX_DRIVER_VERSION(a, b, c, d);
505 MOZ_ASSERT(*aNumericVersion != GfxDriverInfo::allDriverVersions);
506 return true;
507 #elif defined(ANDROID)
508 // Can't use aVersion.ToInteger() because that's not compiled into our code
509 // unless we have XPCOM_GLUE_AVOID_NSPR disabled.
510 *aNumericVersion = atoi(NS_LossyConvertUTF16toASCII(aVersion).get());
511 MOZ_ASSERT(*aNumericVersion != GfxDriverInfo::allDriverVersions);
512 return true;
513 #else
514 return false;
515 #endif
516 }
517
518 } // namespace widget
519 } // namespace mozilla
520
521 #endif /*__mozilla_widget_GfxDriverInfo_h__ */
522