Backed out changeset b4a0f8afc02e (bug 1857946) for causing bc failures at browser...
[gecko.git] / widget / cocoa / GfxInfo.mm
blobff75a539498a5c92e6c43e7597bfb7afd1ae5520
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 defined(__aarch64__)
149   // If we found IOPCI VGA devices, don't look for AGXAccelerator devices
150   if (mNumGPUsDetected > 0) {
151     return;
152   }
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   }
172 #endif
174   MOZ_DIAGNOSTIC_ASSERT(mNumGPUsDetected > 0, "Failed to detect any GPUs");
177 nsresult GfxInfo::Init() {
178   nsresult rv = GfxInfoBase::Init();
180   // Calling CGLQueryRendererInfo causes us to switch to the discrete GPU
181   // even when we don't want to. We'll avoid doing so for now and just
182   // use the device ids.
184   GetDeviceInfo();
186   AddCrashReportAnnotations();
188   mOSXVersion = nsCocoaFeatures::macOSVersion();
190   return rv;
193 NS_IMETHODIMP
194 GfxInfo::GetD2DEnabled(bool* aEnabled) { return NS_ERROR_FAILURE; }
196 NS_IMETHODIMP
197 GfxInfo::GetDWriteEnabled(bool* aEnabled) { return NS_ERROR_FAILURE; }
199 /* readonly attribute bool HasBattery; */
200 NS_IMETHODIMP GfxInfo::GetHasBattery(bool* aHasBattery) {
201   return NS_ERROR_NOT_IMPLEMENTED;
204 /* readonly attribute DOMString DWriteVersion; */
205 NS_IMETHODIMP
206 GfxInfo::GetDWriteVersion(nsAString& aDwriteVersion) {
207   return NS_ERROR_FAILURE;
210 NS_IMETHODIMP
211 GfxInfo::GetEmbeddedInFirefoxReality(bool* aEmbeddedInFirefoxReality) {
212   return NS_ERROR_FAILURE;
215 /* readonly attribute DOMString cleartypeParameters; */
216 NS_IMETHODIMP
217 GfxInfo::GetCleartypeParameters(nsAString& aCleartypeParams) {
218   return NS_ERROR_FAILURE;
221 /* readonly attribute DOMString windowProtocol; */
222 NS_IMETHODIMP
223 GfxInfo::GetWindowProtocol(nsAString& aWindowProtocol) {
224   return NS_ERROR_NOT_IMPLEMENTED;
227 /* readonly attribute DOMString testType; */
228 NS_IMETHODIMP
229 GfxInfo::GetTestType(nsAString& aTestType) { return NS_ERROR_NOT_IMPLEMENTED; }
231 /* readonly attribute DOMString adapterDescription; */
232 NS_IMETHODIMP
233 GfxInfo::GetAdapterDescription(nsAString& aAdapterDescription) {
234   aAdapterDescription.AssignLiteral("");
235   return NS_OK;
238 /* readonly attribute DOMString adapterDescription2; */
239 NS_IMETHODIMP
240 GfxInfo::GetAdapterDescription2(nsAString& aAdapterDescription) {
241   if (mNumGPUsDetected < 2) {
242     return NS_ERROR_FAILURE;
243   }
244   aAdapterDescription.AssignLiteral("");
245   return NS_OK;
248 /* readonly attribute DOMString adapterRAM; */
249 NS_IMETHODIMP
250 GfxInfo::GetAdapterRAM(uint32_t* aAdapterRAM) {
251   *aAdapterRAM = mAdapterRAM[0];
252   return NS_OK;
255 /* readonly attribute DOMString adapterRAM2; */
256 NS_IMETHODIMP
257 GfxInfo::GetAdapterRAM2(uint32_t* aAdapterRAM) {
258   if (mNumGPUsDetected < 2) {
259     return NS_ERROR_FAILURE;
260   }
261   *aAdapterRAM = mAdapterRAM[1];
262   return NS_OK;
265 /* readonly attribute DOMString adapterDriver; */
266 NS_IMETHODIMP
267 GfxInfo::GetAdapterDriver(nsAString& aAdapterDriver) {
268   aAdapterDriver.AssignLiteral("");
269   return NS_OK;
272 /* readonly attribute DOMString adapterDriver2; */
273 NS_IMETHODIMP
274 GfxInfo::GetAdapterDriver2(nsAString& aAdapterDriver) {
275   if (mNumGPUsDetected < 2) {
276     return NS_ERROR_FAILURE;
277   }
278   aAdapterDriver.AssignLiteral("");
279   return NS_OK;
282 /* readonly attribute DOMString adapterDriverVendor; */
283 NS_IMETHODIMP
284 GfxInfo::GetAdapterDriverVendor(nsAString& aAdapterDriverVendor) {
285   aAdapterDriverVendor.AssignLiteral("");
286   return NS_OK;
289 /* readonly attribute DOMString adapterDriverVendor2; */
290 NS_IMETHODIMP
291 GfxInfo::GetAdapterDriverVendor2(nsAString& aAdapterDriverVendor) {
292   if (mNumGPUsDetected < 2) {
293     return NS_ERROR_FAILURE;
294   }
295   aAdapterDriverVendor.AssignLiteral("");
296   return NS_OK;
299 /* readonly attribute DOMString adapterDriverVersion; */
300 NS_IMETHODIMP
301 GfxInfo::GetAdapterDriverVersion(nsAString& aAdapterDriverVersion) {
302   aAdapterDriverVersion.AssignLiteral("");
303   return NS_OK;
306 /* readonly attribute DOMString adapterDriverVersion2; */
307 NS_IMETHODIMP
308 GfxInfo::GetAdapterDriverVersion2(nsAString& aAdapterDriverVersion) {
309   if (mNumGPUsDetected < 2) {
310     return NS_ERROR_FAILURE;
311   }
312   aAdapterDriverVersion.AssignLiteral("");
313   return NS_OK;
316 /* readonly attribute DOMString adapterDriverDate; */
317 NS_IMETHODIMP
318 GfxInfo::GetAdapterDriverDate(nsAString& aAdapterDriverDate) {
319   aAdapterDriverDate.AssignLiteral("");
320   return NS_OK;
323 /* readonly attribute DOMString adapterDriverDate2; */
324 NS_IMETHODIMP
325 GfxInfo::GetAdapterDriverDate2(nsAString& aAdapterDriverDate) {
326   if (mNumGPUsDetected < 2) {
327     return NS_ERROR_FAILURE;
328   }
329   aAdapterDriverDate.AssignLiteral("");
330   return NS_OK;
333 /* readonly attribute DOMString adapterVendorID; */
334 NS_IMETHODIMP
335 GfxInfo::GetAdapterVendorID(nsAString& aAdapterVendorID) {
336   aAdapterVendorID = mAdapterVendorID[0];
337   return NS_OK;
340 /* readonly attribute DOMString adapterVendorID2; */
341 NS_IMETHODIMP
342 GfxInfo::GetAdapterVendorID2(nsAString& aAdapterVendorID) {
343   if (mNumGPUsDetected < 2) {
344     return NS_ERROR_FAILURE;
345   }
346   aAdapterVendorID = mAdapterVendorID[1];
347   return NS_OK;
350 /* readonly attribute DOMString adapterDeviceID; */
351 NS_IMETHODIMP
352 GfxInfo::GetAdapterDeviceID(nsAString& aAdapterDeviceID) {
353   aAdapterDeviceID = mAdapterDeviceID[0];
354   return NS_OK;
357 /* readonly attribute DOMString adapterDeviceID2; */
358 NS_IMETHODIMP
359 GfxInfo::GetAdapterDeviceID2(nsAString& aAdapterDeviceID) {
360   if (mNumGPUsDetected < 2) {
361     return NS_ERROR_FAILURE;
362   }
363   aAdapterDeviceID = mAdapterDeviceID[1];
364   return NS_OK;
367 /* readonly attribute DOMString adapterSubsysID; */
368 NS_IMETHODIMP
369 GfxInfo::GetAdapterSubsysID(nsAString& aAdapterSubsysID) {
370   return NS_ERROR_FAILURE;
373 /* readonly attribute DOMString adapterSubsysID2; */
374 NS_IMETHODIMP
375 GfxInfo::GetAdapterSubsysID2(nsAString& aAdapterSubsysID) {
376   return NS_ERROR_FAILURE;
379 NS_IMETHODIMP
380 GfxInfo::GetDrmRenderDevice(nsACString& aDrmRenderDevice) {
381   return NS_ERROR_NOT_IMPLEMENTED;
384 /* readonly attribute boolean isGPU2Active; */
385 NS_IMETHODIMP
386 GfxInfo::GetIsGPU2Active(bool* aIsGPU2Active) { return NS_ERROR_FAILURE; }
388 void GfxInfo::AddCrashReportAnnotations() {
389   nsString deviceID, vendorID, driverVersion;
390   nsAutoCString narrowDeviceID, narrowVendorID, narrowDriverVersion;
392   GetAdapterDeviceID(deviceID);
393   CopyUTF16toUTF8(deviceID, narrowDeviceID);
394   GetAdapterVendorID(vendorID);
395   CopyUTF16toUTF8(vendorID, narrowVendorID);
396   GetAdapterDriverVersion(driverVersion);
397   CopyUTF16toUTF8(driverVersion, narrowDriverVersion);
399   CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::AdapterVendorID,
400                                      narrowVendorID);
401   CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::AdapterDeviceID,
402                                      narrowDeviceID);
403   CrashReporter::AnnotateCrashReport(
404       CrashReporter::Annotation::AdapterDriverVersion, narrowDriverVersion);
407 // We don't support checking driver versions on Mac.
408 #define IMPLEMENT_MAC_DRIVER_BLOCKLIST(os, device, features, blockOn, ruleId)  \
409   APPEND_TO_DRIVER_BLOCKLIST(os, device, features, blockOn,                    \
410                              DRIVER_COMPARISON_IGNORED, V(0, 0, 0, 0), ruleId, \
411                              "")
413 const nsTArray<GfxDriverInfo>& GfxInfo::GetGfxDriverInfo() {
414   if (!sDriverInfo->Length()) {
415     IMPLEMENT_MAC_DRIVER_BLOCKLIST(
416         OperatingSystem::OSX, DeviceFamily::RadeonX1000,
417         nsIGfxInfo::FEATURE_OPENGL_LAYERS, nsIGfxInfo::FEATURE_BLOCKED_DEVICE,
418         "FEATURE_FAILURE_MAC_RADEONX1000_NO_TEXTURE2D");
419     IMPLEMENT_MAC_DRIVER_BLOCKLIST(
420         OperatingSystem::OSX, DeviceFamily::Geforce7300GT,
421         nsIGfxInfo::FEATURE_WEBGL_OPENGL, nsIGfxInfo::FEATURE_BLOCKED_DEVICE,
422         "FEATURE_FAILURE_MAC_7300_NO_WEBGL");
423     IMPLEMENT_MAC_DRIVER_BLOCKLIST(
424         OperatingSystem::OSX, DeviceFamily::IntelHDGraphicsToIvyBridge,
425         nsIGfxInfo::FEATURE_GL_SWIZZLE, nsIGfxInfo::FEATURE_BLOCKED_DEVICE,
426         "FEATURE_FAILURE_MAC_INTELHD4000_NO_SWIZZLE");
427     // We block texture swizzling everwhere on mac because it's broken in some
428     // configurations and we want to support GPU switching.
429     IMPLEMENT_MAC_DRIVER_BLOCKLIST(
430         OperatingSystem::OSX, DeviceFamily::All, nsIGfxInfo::FEATURE_GL_SWIZZLE,
431         nsIGfxInfo::FEATURE_BLOCKED_DEVICE,
432         "FEATURE_FAILURE_MAC_GPU_SWITCHING_NO_SWIZZLE");
434     // Older generation Intel devices do not perform well with WebRender.
435     IMPLEMENT_MAC_DRIVER_BLOCKLIST(
436         OperatingSystem::OSX, DeviceFamily::IntelWebRenderBlocked,
437         nsIGfxInfo::FEATURE_WEBRENDER, nsIGfxInfo::FEATURE_BLOCKED_DEVICE,
438         "FEATURE_FAILURE_INTEL_GEN5_OR_OLDER");
440     // Intel HD3000 disabled due to bug 1661505
441     IMPLEMENT_MAC_DRIVER_BLOCKLIST(
442         OperatingSystem::OSX, DeviceFamily::IntelSandyBridge,
443         nsIGfxInfo::FEATURE_WEBRENDER, nsIGfxInfo::FEATURE_BLOCKED_DEVICE,
444         "FEATURE_FAILURE_INTEL_MAC_HD3000_NO_WEBRENDER");
446     // wgpu doesn't safely support OOB behavior on Metal yet.
447     IMPLEMENT_MAC_DRIVER_BLOCKLIST(
448         OperatingSystem::OSX, DeviceFamily::All, nsIGfxInfo::FEATURE_WEBGPU,
449         nsIGfxInfo::FEATURE_BLOCKED_DEVICE,
450         "FEATURE_FAILURE_MAC_WGPU_NO_METAL_BOUNDS_CHECKS");
451   }
452   return *sDriverInfo;
455 OperatingSystem GfxInfo::GetOperatingSystem() {
456   return OSXVersionToOperatingSystem(mOSXVersion);
459 nsresult GfxInfo::GetFeatureStatusImpl(
460     int32_t aFeature, int32_t* aStatus, nsAString& aSuggestedDriverVersion,
461     const nsTArray<GfxDriverInfo>& aDriverInfo, nsACString& aFailureId,
462     OperatingSystem* aOS /* = nullptr */) {
463   NS_ENSURE_ARG_POINTER(aStatus);
464   aSuggestedDriverVersion.SetIsVoid(true);
465   *aStatus = nsIGfxInfo::FEATURE_STATUS_UNKNOWN;
466   OperatingSystem os = OSXVersionToOperatingSystem(mOSXVersion);
467   if (aOS) *aOS = os;
469   if (sShutdownOccurred) {
470     return NS_OK;
471   }
473   // Don't evaluate special cases when we're evaluating the downloaded
474   // blocklist.
475   if (!aDriverInfo.Length()) {
476     if (aFeature == nsIGfxInfo::FEATURE_CANVAS2D_ACCELERATION) {
477       // See bug 1249659
478       switch (os) {
479         case OperatingSystem::OSX10_5:
480         case OperatingSystem::OSX10_6:
481         case OperatingSystem::OSX10_7:
482           *aStatus = nsIGfxInfo::FEATURE_BLOCKED_OS_VERSION;
483           aFailureId = "FEATURE_FAILURE_CANVAS_OSX_VERSION";
484           break;
485         default:
486           *aStatus = nsIGfxInfo::FEATURE_STATUS_OK;
487           break;
488       }
489       return NS_OK;
490     } else if (aFeature == nsIGfxInfo::FEATURE_WEBRENDER &&
491                nsCocoaFeatures::ProcessIsRosettaTranslated()) {
492       *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
493       aFailureId = "FEATURE_UNQUALIFIED_WEBRENDER_MAC_ROSETTA";
494       return NS_OK;
495     }
496   }
498   return GfxInfoBase::GetFeatureStatusImpl(
499       aFeature, aStatus, aSuggestedDriverVersion, aDriverInfo, aFailureId, &os);
502 #ifdef DEBUG
504 // Implement nsIGfxInfoDebug
506 /* void spoofVendorID (in DOMString aVendorID); */
507 NS_IMETHODIMP GfxInfo::SpoofVendorID(const nsAString& aVendorID) {
508   mAdapterVendorID[0] = aVendorID;
509   return NS_OK;
512 /* void spoofDeviceID (in unsigned long aDeviceID); */
513 NS_IMETHODIMP GfxInfo::SpoofDeviceID(const nsAString& aDeviceID) {
514   mAdapterDeviceID[0] = aDeviceID;
515   return NS_OK;
518 /* void spoofDriverVersion (in DOMString aDriverVersion); */
519 NS_IMETHODIMP GfxInfo::SpoofDriverVersion(const nsAString& aDriverVersion) {
520   mDriverVersion[0] = aDriverVersion;
521   return NS_OK;
524 /* void spoofOSVersion (in unsigned long aVersion); */
525 NS_IMETHODIMP GfxInfo::SpoofOSVersion(uint32_t aVersion) {
526   mOSXVersion = aVersion;
527   return NS_OK;
530 #endif