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