no bug - Import translations from android-l10n r=release a=l10n CLOSED TREE
[gecko.git] / widget / cocoa / GfxInfo.mm
blobf4477cef4a58b4088cde5271b0e262ccac0c637e
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/. */
6 #include <OpenGL/OpenGL.h>
7 #include <OpenGL/CGLRenderers.h>
9 #include "mozilla/ArrayUtils.h"
11 #include "GfxInfo.h"
12 #include "nsUnicharUtils.h"
13 #include "nsExceptionHandler.h"
14 #include "nsCocoaFeatures.h"
15 #include "nsCocoaUtils.h"
16 #include "mozilla/Preferences.h"
17 #include "js/PropertyAndElement.h"  // JS_SetElement, JS_SetProperty
19 #include <algorithm>
21 #import <Foundation/Foundation.h>
22 #import <IOKit/IOKitLib.h>
23 #import <Cocoa/Cocoa.h>
25 #include "jsapi.h"
27 using namespace mozilla;
28 using namespace mozilla::widget;
30 #ifdef DEBUG
31 NS_IMPL_ISUPPORTS_INHERITED(GfxInfo, GfxInfoBase, nsIGfxInfoDebug)
32 #endif
34 GfxInfo::GfxInfo() : mNumGPUsDetected(0), mOSXVersion{0} {
35   mAdapterRAM[0] = mAdapterRAM[1] = 0;
38 static OperatingSystem OSXVersionToOperatingSystem(uint32_t aOSXVersion) {
39   switch (nsCocoaFeatures::ExtractMajorVersion(aOSXVersion)) {
40     case 10:
41       switch (nsCocoaFeatures::ExtractMinorVersion(aOSXVersion)) {
42         case 6:
43           return OperatingSystem::OSX10_6;
44         case 7:
45           return OperatingSystem::OSX10_7;
46         case 8:
47           return OperatingSystem::OSX10_8;
48         case 9:
49           return OperatingSystem::OSX10_9;
50         case 10:
51           return OperatingSystem::OSX10_10;
52         case 11:
53           return OperatingSystem::OSX10_11;
54         case 12:
55           return OperatingSystem::OSX10_12;
56         case 13:
57           return OperatingSystem::OSX10_13;
58         case 14:
59           return OperatingSystem::OSX10_14;
60         case 15:
61           return OperatingSystem::OSX10_15;
62         case 16:
63           // Depending on the SDK version, we either get 10.16 or 11.0.
64           // Normalize this to 11.0.
65           return OperatingSystem::OSX11_0;
66         default:
67           break;
68       }
69       break;
70     case 11:
71       switch (nsCocoaFeatures::ExtractMinorVersion(aOSXVersion)) {
72         case 0:
73           return OperatingSystem::OSX11_0;
74         default:
75           break;
76       }
77       break;
78   }
80   return OperatingSystem::Unknown;
82 // The following three functions are derived from Chromium code
83 static CFTypeRef SearchPortForProperty(io_registry_entry_t dspPort,
84                                        CFStringRef propertyName) {
85   return IORegistryEntrySearchCFProperty(
86       dspPort, kIOServicePlane, propertyName, kCFAllocatorDefault,
87       kIORegistryIterateRecursively | kIORegistryIterateParents);
90 static uint32_t IntValueOfCFData(CFDataRef d) {
91   uint32_t value = 0;
93   if (d) {
94     const uint32_t* vp = reinterpret_cast<const uint32_t*>(CFDataGetBytePtr(d));
95     if (vp != NULL) value = *vp;
96   }
98   return value;
101 void GfxInfo::GetDeviceInfo() {
102   mNumGPUsDetected = 0;
104   CFMutableDictionaryRef pci_dev_dict = IOServiceMatching("IOPCIDevice");
105   io_iterator_t io_iter;
106   if (IOServiceGetMatchingServices(kIOMasterPortDefault, pci_dev_dict,
107                                    &io_iter) != kIOReturnSuccess) {
108     MOZ_DIAGNOSTIC_ASSERT(
109         false,
110         "Failed to detect any GPUs (couldn't enumerate IOPCIDevice services)");
111     return;
112   }
114   io_registry_entry_t entry = IO_OBJECT_NULL;
115   while ((entry = IOIteratorNext(io_iter)) != IO_OBJECT_NULL) {
116     constexpr uint32_t kClassCodeDisplayVGA = 0x30000;
117     CFTypeRef class_code_ref =
118         SearchPortForProperty(entry, CFSTR("class-code"));
119     if (class_code_ref) {
120       const uint32_t class_code = IntValueOfCFData((CFDataRef)class_code_ref);
121       CFRelease(class_code_ref);
123       if (class_code == kClassCodeDisplayVGA) {
124         CFTypeRef vendor_id_ref =
125             SearchPortForProperty(entry, CFSTR("vendor-id"));
126         if (vendor_id_ref) {
127           mAdapterVendorID[mNumGPUsDetected].AppendPrintf(
128               "0x%04x", IntValueOfCFData((CFDataRef)vendor_id_ref));
129           CFRelease(vendor_id_ref);
130         }
131         CFTypeRef device_id_ref =
132             SearchPortForProperty(entry, CFSTR("device-id"));
133         if (device_id_ref) {
134           mAdapterDeviceID[mNumGPUsDetected].AppendPrintf(
135               "0x%04x", IntValueOfCFData((CFDataRef)device_id_ref));
136           CFRelease(device_id_ref);
137         }
138         ++mNumGPUsDetected;
139       }
140     }
141     IOObjectRelease(entry);
142     if (mNumGPUsDetected == 2) {
143       break;
144     }
145   }
146   IOObjectRelease(io_iter);
148   // If we found IOPCI VGA devices, don't look for other devices
149   if (mNumGPUsDetected > 0) {
150     return;
151   }
153 #if defined(__aarch64__)
154   CFMutableDictionaryRef agx_dev_dict = IOServiceMatching("AGXAccelerator");
155   if (IOServiceGetMatchingServices(kIOMasterPortDefault, agx_dev_dict,
156                                    &io_iter) == kIOReturnSuccess) {
157     io_registry_entry_t entry = IO_OBJECT_NULL;
158     while ((entry = IOIteratorNext(io_iter)) != IO_OBJECT_NULL) {
159       CFTypeRef vendor_id_ref =
160           SearchPortForProperty(entry, CFSTR("vendor-id"));
161       if (vendor_id_ref) {
162         mAdapterVendorID[mNumGPUsDetected].AppendPrintf(
163             "0x%04x", IntValueOfCFData((CFDataRef)vendor_id_ref));
164         CFRelease(vendor_id_ref);
165         ++mNumGPUsDetected;
166       }
167       IOObjectRelease(entry);
168     }
170     IOObjectRelease(io_iter);
171   }
173   // If we found an AGXAccelerator, don't look for an AppleParavirtGPU
174   if (mNumGPUsDetected > 0) {
175     return;
176   }
177 #endif
179   CFMutableDictionaryRef apv_dev_dict = IOServiceMatching("AppleParavirtGPU");
180   if (IOServiceGetMatchingServices(kIOMasterPortDefault, apv_dev_dict,
181                                    &io_iter) == kIOReturnSuccess) {
182     io_registry_entry_t entry = IO_OBJECT_NULL;
183     while ((entry = IOIteratorNext(io_iter)) != IO_OBJECT_NULL) {
184       CFTypeRef vendor_id_ref =
185           SearchPortForProperty(entry, CFSTR("vendor-id"));
186       if (vendor_id_ref) {
187         mAdapterVendorID[mNumGPUsDetected].AppendPrintf(
188             "0x%04x", IntValueOfCFData((CFDataRef)vendor_id_ref));
189         CFRelease(vendor_id_ref);
190       }
192       CFTypeRef device_id_ref =
193           SearchPortForProperty(entry, CFSTR("device-id"));
194       if (device_id_ref) {
195         mAdapterDeviceID[mNumGPUsDetected].AppendPrintf(
196             "0x%04x", IntValueOfCFData((CFDataRef)device_id_ref));
197         CFRelease(device_id_ref);
198       }
199       ++mNumGPUsDetected;
200       IOObjectRelease(entry);
201     }
203     IOObjectRelease(io_iter);
204   }
206   MOZ_DIAGNOSTIC_ASSERT(mNumGPUsDetected > 0, "Failed to detect any GPUs");
209 nsresult GfxInfo::Init() {
210   nsresult rv = GfxInfoBase::Init();
212   // Calling CGLQueryRendererInfo causes us to switch to the discrete GPU
213   // even when we don't want to. We'll avoid doing so for now and just
214   // use the device ids.
216   GetDeviceInfo();
218   AddCrashReportAnnotations();
220   mOSXVersion = nsCocoaFeatures::macOSVersion();
222   return rv;
225 NS_IMETHODIMP
226 GfxInfo::GetD2DEnabled(bool* aEnabled) { return NS_ERROR_FAILURE; }
228 NS_IMETHODIMP
229 GfxInfo::GetDWriteEnabled(bool* aEnabled) { return NS_ERROR_FAILURE; }
231 /* readonly attribute bool HasBattery; */
232 NS_IMETHODIMP GfxInfo::GetHasBattery(bool* aHasBattery) {
233   return NS_ERROR_NOT_IMPLEMENTED;
236 /* readonly attribute DOMString DWriteVersion; */
237 NS_IMETHODIMP
238 GfxInfo::GetDWriteVersion(nsAString& aDwriteVersion) {
239   return NS_ERROR_FAILURE;
242 NS_IMETHODIMP
243 GfxInfo::GetEmbeddedInFirefoxReality(bool* aEmbeddedInFirefoxReality) {
244   return NS_ERROR_FAILURE;
247 /* readonly attribute DOMString cleartypeParameters; */
248 NS_IMETHODIMP
249 GfxInfo::GetCleartypeParameters(nsAString& aCleartypeParams) {
250   return NS_ERROR_FAILURE;
253 /* readonly attribute DOMString windowProtocol; */
254 NS_IMETHODIMP
255 GfxInfo::GetWindowProtocol(nsAString& aWindowProtocol) {
256   return NS_ERROR_NOT_IMPLEMENTED;
259 /* readonly attribute DOMString testType; */
260 NS_IMETHODIMP
261 GfxInfo::GetTestType(nsAString& aTestType) { return NS_ERROR_NOT_IMPLEMENTED; }
263 /* readonly attribute DOMString adapterDescription; */
264 NS_IMETHODIMP
265 GfxInfo::GetAdapterDescription(nsAString& aAdapterDescription) {
266   aAdapterDescription.AssignLiteral("");
267   return NS_OK;
270 /* readonly attribute DOMString adapterDescription2; */
271 NS_IMETHODIMP
272 GfxInfo::GetAdapterDescription2(nsAString& aAdapterDescription) {
273   if (mNumGPUsDetected < 2) {
274     return NS_ERROR_FAILURE;
275   }
276   aAdapterDescription.AssignLiteral("");
277   return NS_OK;
280 /* readonly attribute DOMString adapterRAM; */
281 NS_IMETHODIMP
282 GfxInfo::GetAdapterRAM(uint32_t* aAdapterRAM) {
283   *aAdapterRAM = mAdapterRAM[0];
284   return NS_OK;
287 /* readonly attribute DOMString adapterRAM2; */
288 NS_IMETHODIMP
289 GfxInfo::GetAdapterRAM2(uint32_t* aAdapterRAM) {
290   if (mNumGPUsDetected < 2) {
291     return NS_ERROR_FAILURE;
292   }
293   *aAdapterRAM = mAdapterRAM[1];
294   return NS_OK;
297 /* readonly attribute DOMString adapterDriver; */
298 NS_IMETHODIMP
299 GfxInfo::GetAdapterDriver(nsAString& aAdapterDriver) {
300   aAdapterDriver.AssignLiteral("");
301   return NS_OK;
304 /* readonly attribute DOMString adapterDriver2; */
305 NS_IMETHODIMP
306 GfxInfo::GetAdapterDriver2(nsAString& aAdapterDriver) {
307   if (mNumGPUsDetected < 2) {
308     return NS_ERROR_FAILURE;
309   }
310   aAdapterDriver.AssignLiteral("");
311   return NS_OK;
314 /* readonly attribute DOMString adapterDriverVendor; */
315 NS_IMETHODIMP
316 GfxInfo::GetAdapterDriverVendor(nsAString& aAdapterDriverVendor) {
317   aAdapterDriverVendor.AssignLiteral("");
318   return NS_OK;
321 /* readonly attribute DOMString adapterDriverVendor2; */
322 NS_IMETHODIMP
323 GfxInfo::GetAdapterDriverVendor2(nsAString& aAdapterDriverVendor) {
324   if (mNumGPUsDetected < 2) {
325     return NS_ERROR_FAILURE;
326   }
327   aAdapterDriverVendor.AssignLiteral("");
328   return NS_OK;
331 /* readonly attribute DOMString adapterDriverVersion; */
332 NS_IMETHODIMP
333 GfxInfo::GetAdapterDriverVersion(nsAString& aAdapterDriverVersion) {
334   aAdapterDriverVersion.AssignLiteral("");
335   return NS_OK;
338 /* readonly attribute DOMString adapterDriverVersion2; */
339 NS_IMETHODIMP
340 GfxInfo::GetAdapterDriverVersion2(nsAString& aAdapterDriverVersion) {
341   if (mNumGPUsDetected < 2) {
342     return NS_ERROR_FAILURE;
343   }
344   aAdapterDriverVersion.AssignLiteral("");
345   return NS_OK;
348 /* readonly attribute DOMString adapterDriverDate; */
349 NS_IMETHODIMP
350 GfxInfo::GetAdapterDriverDate(nsAString& aAdapterDriverDate) {
351   aAdapterDriverDate.AssignLiteral("");
352   return NS_OK;
355 /* readonly attribute DOMString adapterDriverDate2; */
356 NS_IMETHODIMP
357 GfxInfo::GetAdapterDriverDate2(nsAString& aAdapterDriverDate) {
358   if (mNumGPUsDetected < 2) {
359     return NS_ERROR_FAILURE;
360   }
361   aAdapterDriverDate.AssignLiteral("");
362   return NS_OK;
365 /* readonly attribute DOMString adapterVendorID; */
366 NS_IMETHODIMP
367 GfxInfo::GetAdapterVendorID(nsAString& aAdapterVendorID) {
368   aAdapterVendorID = mAdapterVendorID[0];
369   return NS_OK;
372 /* readonly attribute DOMString adapterVendorID2; */
373 NS_IMETHODIMP
374 GfxInfo::GetAdapterVendorID2(nsAString& aAdapterVendorID) {
375   if (mNumGPUsDetected < 2) {
376     return NS_ERROR_FAILURE;
377   }
378   aAdapterVendorID = mAdapterVendorID[1];
379   return NS_OK;
382 /* readonly attribute DOMString adapterDeviceID; */
383 NS_IMETHODIMP
384 GfxInfo::GetAdapterDeviceID(nsAString& aAdapterDeviceID) {
385   aAdapterDeviceID = mAdapterDeviceID[0];
386   return NS_OK;
389 /* readonly attribute DOMString adapterDeviceID2; */
390 NS_IMETHODIMP
391 GfxInfo::GetAdapterDeviceID2(nsAString& aAdapterDeviceID) {
392   if (mNumGPUsDetected < 2) {
393     return NS_ERROR_FAILURE;
394   }
395   aAdapterDeviceID = mAdapterDeviceID[1];
396   return NS_OK;
399 /* readonly attribute DOMString adapterSubsysID; */
400 NS_IMETHODIMP
401 GfxInfo::GetAdapterSubsysID(nsAString& aAdapterSubsysID) {
402   return NS_ERROR_FAILURE;
405 /* readonly attribute DOMString adapterSubsysID2; */
406 NS_IMETHODIMP
407 GfxInfo::GetAdapterSubsysID2(nsAString& aAdapterSubsysID) {
408   return NS_ERROR_FAILURE;
411 NS_IMETHODIMP
412 GfxInfo::GetDrmRenderDevice(nsACString& aDrmRenderDevice) {
413   return NS_ERROR_NOT_IMPLEMENTED;
416 /* readonly attribute boolean isGPU2Active; */
417 NS_IMETHODIMP
418 GfxInfo::GetIsGPU2Active(bool* aIsGPU2Active) { return NS_ERROR_FAILURE; }
420 void GfxInfo::AddCrashReportAnnotations() {
421   nsString deviceID, vendorID, driverVersion;
423   GetAdapterDeviceID(deviceID);
424   GetAdapterVendorID(vendorID);
425   GetAdapterDriverVersion(driverVersion);
427   CrashReporter::RecordAnnotationNSString(
428       CrashReporter::Annotation::AdapterVendorID, vendorID);
429   CrashReporter::RecordAnnotationNSString(
430       CrashReporter::Annotation::AdapterDeviceID, deviceID);
431   CrashReporter::RecordAnnotationNSString(
432       CrashReporter::Annotation::AdapterDriverVersion, driverVersion);
435 // We don't support checking driver versions on Mac.
436 #define IMPLEMENT_MAC_DRIVER_BLOCKLIST(os, device, features, blockOn, ruleId)  \
437   APPEND_TO_DRIVER_BLOCKLIST(os, device, features, blockOn,                    \
438                              DRIVER_COMPARISON_IGNORED, V(0, 0, 0, 0), ruleId, \
439                              "")
441 const nsTArray<GfxDriverInfo>& GfxInfo::GetGfxDriverInfo() {
442   if (!sDriverInfo->Length()) {
443     IMPLEMENT_MAC_DRIVER_BLOCKLIST(
444         OperatingSystem::OSX, DeviceFamily::RadeonX1000,
445         nsIGfxInfo::FEATURE_OPENGL_LAYERS, nsIGfxInfo::FEATURE_BLOCKED_DEVICE,
446         "FEATURE_FAILURE_MAC_RADEONX1000_NO_TEXTURE2D");
447     IMPLEMENT_MAC_DRIVER_BLOCKLIST(
448         OperatingSystem::OSX, DeviceFamily::Geforce7300GT,
449         nsIGfxInfo::FEATURE_WEBGL_OPENGL, nsIGfxInfo::FEATURE_BLOCKED_DEVICE,
450         "FEATURE_FAILURE_MAC_7300_NO_WEBGL");
451     IMPLEMENT_MAC_DRIVER_BLOCKLIST(
452         OperatingSystem::OSX, DeviceFamily::IntelHDGraphicsToIvyBridge,
453         nsIGfxInfo::FEATURE_GL_SWIZZLE, nsIGfxInfo::FEATURE_BLOCKED_DEVICE,
454         "FEATURE_FAILURE_MAC_INTELHD4000_NO_SWIZZLE");
455     // We block texture swizzling everwhere on mac because it's broken in some
456     // configurations and we want to support GPU switching.
457     IMPLEMENT_MAC_DRIVER_BLOCKLIST(
458         OperatingSystem::OSX, DeviceFamily::All, nsIGfxInfo::FEATURE_GL_SWIZZLE,
459         nsIGfxInfo::FEATURE_BLOCKED_DEVICE,
460         "FEATURE_FAILURE_MAC_GPU_SWITCHING_NO_SWIZZLE");
462     // Older generation Intel devices do not perform well with WebRender.
463     IMPLEMENT_MAC_DRIVER_BLOCKLIST(
464         OperatingSystem::OSX, DeviceFamily::IntelWebRenderBlocked,
465         nsIGfxInfo::FEATURE_WEBRENDER, nsIGfxInfo::FEATURE_BLOCKED_DEVICE,
466         "FEATURE_FAILURE_INTEL_GEN5_OR_OLDER");
468     // Intel HD3000 disabled due to bug 1661505
469     IMPLEMENT_MAC_DRIVER_BLOCKLIST(
470         OperatingSystem::OSX, DeviceFamily::IntelSandyBridge,
471         nsIGfxInfo::FEATURE_WEBRENDER, nsIGfxInfo::FEATURE_BLOCKED_DEVICE,
472         "FEATURE_FAILURE_INTEL_MAC_HD3000_NO_WEBRENDER");
474     // wgpu doesn't safely support OOB behavior on Metal yet.
475     IMPLEMENT_MAC_DRIVER_BLOCKLIST(
476         OperatingSystem::OSX, DeviceFamily::All, nsIGfxInfo::FEATURE_WEBGPU,
477         nsIGfxInfo::FEATURE_BLOCKED_DEVICE,
478         "FEATURE_FAILURE_MAC_WGPU_NO_METAL_BOUNDS_CHECKS");
479   }
480   return *sDriverInfo;
483 OperatingSystem GfxInfo::GetOperatingSystem() {
484   return OSXVersionToOperatingSystem(mOSXVersion);
487 nsresult GfxInfo::GetFeatureStatusImpl(
488     int32_t aFeature, int32_t* aStatus, nsAString& aSuggestedDriverVersion,
489     const nsTArray<GfxDriverInfo>& aDriverInfo, nsACString& aFailureId,
490     OperatingSystem* aOS /* = nullptr */) {
491   NS_ENSURE_ARG_POINTER(aStatus);
492   aSuggestedDriverVersion.SetIsVoid(true);
493   *aStatus = nsIGfxInfo::FEATURE_STATUS_UNKNOWN;
494   OperatingSystem os = OSXVersionToOperatingSystem(mOSXVersion);
495   if (aOS) *aOS = os;
497   if (sShutdownOccurred) {
498     return NS_OK;
499   }
501   // Don't evaluate special cases when we're evaluating the downloaded
502   // blocklist.
503   if (!aDriverInfo.Length()) {
504     if (aFeature == nsIGfxInfo::FEATURE_CANVAS2D_ACCELERATION) {
505       // See bug 1249659
506       switch (os) {
507         case OperatingSystem::OSX10_5:
508         case OperatingSystem::OSX10_6:
509         case OperatingSystem::OSX10_7:
510           *aStatus = nsIGfxInfo::FEATURE_BLOCKED_OS_VERSION;
511           aFailureId = "FEATURE_FAILURE_CANVAS_OSX_VERSION";
512           break;
513         default:
514           *aStatus = nsIGfxInfo::FEATURE_STATUS_OK;
515           break;
516       }
517       return NS_OK;
518     } else if (aFeature == nsIGfxInfo::FEATURE_WEBRENDER &&
519                nsCocoaFeatures::ProcessIsRosettaTranslated()) {
520       *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
521       aFailureId = "FEATURE_UNQUALIFIED_WEBRENDER_MAC_ROSETTA";
522       return NS_OK;
523     }
524   }
526   return GfxInfoBase::GetFeatureStatusImpl(
527       aFeature, aStatus, aSuggestedDriverVersion, aDriverInfo, aFailureId, &os);
530 #ifdef DEBUG
532 // Implement nsIGfxInfoDebug
534 /* void spoofVendorID (in DOMString aVendorID); */
535 NS_IMETHODIMP GfxInfo::SpoofVendorID(const nsAString& aVendorID) {
536   mAdapterVendorID[0] = aVendorID;
537   return NS_OK;
540 /* void spoofDeviceID (in unsigned long aDeviceID); */
541 NS_IMETHODIMP GfxInfo::SpoofDeviceID(const nsAString& aDeviceID) {
542   mAdapterDeviceID[0] = aDeviceID;
543   return NS_OK;
546 /* void spoofDriverVersion (in DOMString aDriverVersion); */
547 NS_IMETHODIMP GfxInfo::SpoofDriverVersion(const nsAString& aDriverVersion) {
548   mDriverVersion[0] = aDriverVersion;
549   return NS_OK;
552 /* void spoofOSVersion (in unsigned long aVersion); */
553 NS_IMETHODIMP GfxInfo::SpoofOSVersion(uint32_t aVersion) {
554   mOSXVersion = aVersion;
555   return NS_OK;
558 #endif