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 Android,
147 Ios
148 };
149
150 enum VersionComparisonOp {
151 DRIVER_LESS_THAN, // driver < version
152 DRIVER_BUILD_ID_LESS_THAN, // driver build id < version
153 DRIVER_LESS_THAN_OR_EQUAL, // driver <= version
154 DRIVER_BUILD_ID_LESS_THAN_OR_EQUAL, // driver build id <= version
155 DRIVER_GREATER_THAN, // driver > version
156 DRIVER_GREATER_THAN_OR_EQUAL, // driver >= version
157 DRIVER_EQUAL, // driver == version
158 DRIVER_NOT_EQUAL, // driver != version
159 DRIVER_BETWEEN_EXCLUSIVE, // driver > version && driver < versionMax
160 DRIVER_BETWEEN_INCLUSIVE, // driver >= version && driver <= versionMax
161 DRIVER_BETWEEN_INCLUSIVE_START, // driver >= version && driver < versionMax
162 DRIVER_COMPARISON_IGNORED
163 };
164
165 enum class DeviceFamily : uint8_t {
166 All,
167 IntelAll,
168 NvidiaAll,
169 AtiAll,
170 MicrosoftAll,
171 ParallelsAll,
172 QualcommAll,
173 IntelGMA500,
174 IntelGMA900,
175 IntelGMA950,
176 IntelGMA3150,
177 IntelGMAX3000,
178 IntelGMAX4500HD,
179 IntelHDGraphicsToIvyBridge,
180 IntelHDGraphicsToSandyBridge,
181 IntelHDGraphicsToHaswell,
182 IntelHD3000,
183 IntelHD520,
184 IntelMobileHDGraphics,
185 NvidiaBlockD3D9Layers,
186 RadeonX1000,
187 RadeonCaicos,
188 Geforce7300GT,
189 Nvidia310M,
190 Nvidia8800GTS,
191 Bug1137716,
192 Bug1116812,
193 Bug1155608,
194 Bug1207665,
195 Bug1447141,
196 NvidiaBlockWebRender,
197 NvidiaRolloutWebRender,
198 IntelRolloutWebRender,
199 IntelModernRolloutWebRender,
200 AtiRolloutWebRender,
201
202 Max
203 };
204
205 enum class DeviceVendor : uint8_t {
206 All, // There is an assumption that this is the first enum
207 Intel,
208 NVIDIA,
209 ATI,
210 Microsoft,
211 Parallels,
212 Qualcomm,
213
214 Max
215 };
216
217 enum DriverVendor : uint8_t {
218 All, // There is an assumption that this is the first enum
219 // Wildcard for all Mesa drivers.
220 MesaAll,
221 // Note that the following list of Mesa drivers is not comprehensive; we pull
222 // the DRI driver at runtime. These drivers are provided for convenience when
223 // populating the local blocklist.
224 MesaLLVMPipe,
225 MesaSoftPipe,
226 MesaSWRast,
227 // A generic ID to be provided when we can't determine the DRI driver on Mesa.
228 MesaUnknown,
229 // Wildcard for all non-Mesa drivers.
230 NonMesaAll,
231
232 Max
233 };
234
235 enum class DesktopEnvironment : uint8_t {
236 All, // There is an assumption that this is the first enum
237 GNOME,
238 KDE,
239 XFCE,
240 Cinnamon,
241 Enlightenment,
242 LXDE,
243 Openbox,
244 i3,
245 Mate,
246 Unity,
247 Pantheon,
248 LXQT,
249 Deepin,
250 Unknown,
251 Max
252 };
253
254 enum class WindowProtocol : uint8_t {
255 All, // There is an assumption that this is the first enum
256 X11,
257 Wayland,
258 WaylandDRM,
259 // Wildcard for all Wayland variants.
260 WaylandAll,
261 Max
262 };
263
264 enum class BatteryStatus : uint8_t { All, Present, None };
265
266 enum class ScreenSizeStatus : uint8_t {
267 All,
268 Small, // <= 1900x1200
269 SmallAndMedium, // <= 3440x1440
270 Medium, // <= 3440x1440 && > 1900x1200
271 MediumAndLarge, // >1900x1200
272 Large // > 3440x1440
273 };
274
275 /* Array of devices to match, or an empty array for all devices */
276 class GfxDeviceFamily final {
277 public:
278 GfxDeviceFamily() = default;
279
280 void Append(const nsAString& aDeviceId);
281 void AppendRange(int32_t aBeginDeviceId, int32_t aEndDeviceId);
282
IsEmpty()283 bool IsEmpty() const { return mIds.IsEmpty() && mRanges.IsEmpty(); }
284
285 nsresult Contains(nsAString& aDeviceId) const;
286
287 private:
288 struct DeviceRange {
289 int32_t mBegin;
290 int32_t mEnd;
291 };
292
293 CopyableTArray<nsString> mIds;
294 CopyableTArray<DeviceRange> mRanges;
295 };
296
297 struct GfxDriverInfo {
298 // If |ownDevices| is true, you are transferring ownership of the devices
299 // array, and it will be deleted when this GfxDriverInfo is destroyed.
300 GfxDriverInfo(OperatingSystem os, ScreenSizeStatus aScreen,
301 BatteryStatus aBattery, const nsAString& desktopEnv,
302 const nsAString& windowProtocol, const nsAString& vendor,
303 const nsAString& driverVendor, GfxDeviceFamily* devices,
304 int32_t feature, int32_t featureStatus, VersionComparisonOp op,
305 uint64_t driverVersion, const char* ruleId,
306 const char* suggestedVersion = nullptr, bool ownDevices = false,
307 bool gpu2 = false);
308
309 GfxDriverInfo();
310 GfxDriverInfo(const GfxDriverInfo&);
311 ~GfxDriverInfo();
312
313 OperatingSystem mOperatingSystem;
314 uint32_t mOperatingSystemVersion;
315 ScreenSizeStatus mScreen;
316 BatteryStatus mBattery;
317 nsString mDesktopEnvironment;
318 nsString mWindowProtocol;
319
320 nsString mAdapterVendor;
321 nsString mDriverVendor;
322
323 const GfxDeviceFamily* mDevices;
324
325 // Whether the mDevices array should be deleted when this structure is
326 // deallocated. False by default.
327 bool mDeleteDevices;
328
329 /* A feature from nsIGfxInfo, or all features */
330 int32_t mFeature;
331 static int32_t allFeatures;
332
333 /* A feature status from nsIGfxInfo */
334 int32_t mFeatureStatus;
335
336 VersionComparisonOp mComparisonOp;
337
338 /* versions are assumed to be A.B.C.D packed as 0xAAAABBBBCCCCDDDD */
339 uint64_t mDriverVersion;
340 uint64_t mDriverVersionMax;
341 static uint64_t allDriverVersions;
342
343 const char* mSuggestedVersion;
344 nsCString mRuleId;
345
346 static const GfxDeviceFamily* GetDeviceFamily(DeviceFamily id);
347 static GfxDeviceFamily*
348 sDeviceFamilies[static_cast<size_t>(DeviceFamily::Max)];
349
350 static const nsAString& GetDesktopEnvironment(DesktopEnvironment id);
351 static nsAString*
352 sDesktopEnvironment[static_cast<size_t>(DesktopEnvironment::Max)];
353
354 static const nsAString& GetWindowProtocol(WindowProtocol id);
355 static nsAString* sWindowProtocol[static_cast<size_t>(WindowProtocol::Max)];
356
357 static const nsAString& GetDeviceVendor(DeviceVendor id);
358 static const nsAString& GetDeviceVendor(DeviceFamily id);
359 static nsAString* sDeviceVendors[static_cast<size_t>(DeviceVendor::Max)];
360
361 static const nsAString& GetDriverVendor(DriverVendor id);
362 static nsAString* sDriverVendors[static_cast<size_t>(DriverVendor::Max)];
363
364 nsString mModel, mHardware, mProduct, mManufacturer;
365
366 bool mGpu2;
367 };
368
369 #define GFX_DRIVER_VERSION(a, b, c, d) \
370 ((uint64_t(a) << 48) | (uint64_t(b) << 32) | (uint64_t(c) << 16) | \
371 uint64_t(d))
372
V(uint32_t a,uint32_t b,uint32_t c,uint32_t d)373 inline uint64_t V(uint32_t a, uint32_t b, uint32_t c, uint32_t d) {
374 // We make sure every driver number is padded by 0s, this will allow us the
375 // easiest 'compare as if decimals' approach. See ParseDriverVersion for a
376 // more extensive explanation of this approach.
377 while (b > 0 && b < 1000) {
378 b *= 10;
379 }
380 while (c > 0 && c < 1000) {
381 c *= 10;
382 }
383 while (d > 0 && d < 1000) {
384 d *= 10;
385 }
386 return GFX_DRIVER_VERSION(a, b, c, d);
387 }
388
389 // All destination string storage needs to have at least 5 bytes available.
SplitDriverVersion(const char * aSource,char * aAStr,char * aBStr,char * aCStr,char * aDStr)390 inline bool SplitDriverVersion(const char* aSource, char* aAStr, char* aBStr,
391 char* aCStr, char* aDStr) {
392 // sscanf doesn't do what we want here to we parse this manually.
393 int len = strlen(aSource);
394
395 // This "4" is hardcoded in a few places, including once as a 3.
396 char* dest[4] = {aAStr, aBStr, aCStr, aDStr};
397 unsigned destIdx = 0;
398 unsigned destPos = 0;
399
400 for (int i = 0; i < len; i++) {
401 if (destIdx >= 4) {
402 // Invalid format found. Ensure we don't access dest beyond bounds.
403 return false;
404 }
405
406 if (aSource[i] == '.') {
407 MOZ_ASSERT(destIdx < 4 && destPos <= 4);
408 dest[destIdx++][destPos] = 0;
409 destPos = 0;
410 continue;
411 }
412
413 if (destPos > 3) {
414 // Ignore more than 4 chars. Ensure we never access dest[destIdx]
415 // beyond its bounds.
416 continue;
417 }
418
419 MOZ_ASSERT(destIdx < 4 && destPos < 4);
420 dest[destIdx][destPos++] = aSource[i];
421 }
422
423 // Take care of the trailing period
424 if (destIdx >= 4) {
425 return false;
426 }
427
428 // Add last terminator.
429 MOZ_ASSERT(destIdx < 4 && destPos <= 4);
430 dest[destIdx][destPos] = 0;
431
432 if (destIdx != 3) {
433 return false;
434 }
435 return true;
436 }
437
438 // This allows us to pad driver version 'substrings' with 0s, this
439 // effectively allows us to treat the version numbers as 'decimals'. This is
440 // a little strange but this method seems to do the right thing for all
441 // different vendor's driver strings. i.e. .98 will become 9800, which is
442 // larger than .978 which would become 9780.
PadDriverDecimal(char * aString)443 inline void PadDriverDecimal(char* aString) {
444 for (int i = 0; i < 4; i++) {
445 if (!aString[i]) {
446 for (int c = i; c < 4; c++) {
447 aString[c] = '0';
448 }
449 break;
450 }
451 }
452 aString[4] = 0;
453 }
454
ParseDriverVersion(const nsAString & aVersion,uint64_t * aNumericVersion)455 inline bool ParseDriverVersion(const nsAString& aVersion,
456 uint64_t* aNumericVersion) {
457 *aNumericVersion = 0;
458
459 #if defined(XP_WIN) || defined(MOZ_X11)
460 int a, b, c, d;
461 char aStr[8], bStr[8], cStr[8], dStr[8];
462 /* honestly, why do I even bother */
463 if (!SplitDriverVersion(NS_LossyConvertUTF16toASCII(aVersion).get(), aStr,
464 bStr, cStr, dStr))
465 return false;
466
467 PadDriverDecimal(bStr);
468 PadDriverDecimal(cStr);
469 PadDriverDecimal(dStr);
470
471 a = atoi(aStr);
472 b = atoi(bStr);
473 c = atoi(cStr);
474 d = atoi(dStr);
475
476 if (a < 0 || a > 0xffff) return false;
477 if (b < 0 || b > 0xffff) return false;
478 if (c < 0 || c > 0xffff) return false;
479 if (d < 0 || d > 0xffff) return false;
480
481 *aNumericVersion = GFX_DRIVER_VERSION(a, b, c, d);
482 MOZ_ASSERT(*aNumericVersion != GfxDriverInfo::allDriverVersions);
483 return true;
484 #elif defined(ANDROID)
485 // Can't use aVersion.ToInteger() because that's not compiled into our code
486 // unless we have XPCOM_GLUE_AVOID_NSPR disabled.
487 *aNumericVersion = atoi(NS_LossyConvertUTF16toASCII(aVersion).get());
488 MOZ_ASSERT(*aNumericVersion != GfxDriverInfo::allDriverVersions);
489 return true;
490 #else
491 return false;
492 #endif
493 }
494
495 } // namespace widget
496 } // namespace mozilla
497
498 #endif /*__mozilla_widget_GfxDriverInfo_h__ */
499