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