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"
12 #include "nsUnicharUtils.h"
13 #include "nsExceptionHandler.h"
14 #include "nsCocoaFeatures.h"
15 #include "nsCocoaUtils.h"
16 #include "mozilla/Preferences.h"
19 #import <Foundation/Foundation.h>
20 #import <IOKit/IOKitLib.h>
21 #import <Cocoa/Cocoa.h>
23 #define NS_CRASHREPORTER_CONTRACTID "@mozilla.org/toolkit/crash-reporter;1"
25 using namespace mozilla;
26 using namespace mozilla::widget;
29 NS_IMPL_ISUPPORTS_INHERITED(GfxInfo, GfxInfoBase, nsIGfxInfoDebug)
32 GfxInfo::GfxInfo() : mNumGPUsDetected(0), mOSXVersion{0} { mAdapterRAM[0] = mAdapterRAM[1] = 0; }
34 static OperatingSystem OSXVersionToOperatingSystem(uint32_t aOSXVersion) {
35 if (nsCocoaFeatures::ExtractMajorVersion(aOSXVersion) == 10) {
36 switch (nsCocoaFeatures::ExtractMinorVersion(aOSXVersion)) {
38 return OperatingSystem::OSX10_6;
40 return OperatingSystem::OSX10_7;
42 return OperatingSystem::OSX10_8;
44 return OperatingSystem::OSX10_9;
46 return OperatingSystem::OSX10_10;
48 return OperatingSystem::OSX10_11;
50 return OperatingSystem::OSX10_12;
52 return OperatingSystem::OSX10_13;
54 return OperatingSystem::OSX10_14;
56 return OperatingSystem::OSX10_15;
58 return OperatingSystem::OSX10_16;
62 return OperatingSystem::Unknown;
64 // The following three functions are derived from Chromium code
65 static CFTypeRef SearchPortForProperty(io_registry_entry_t dspPort, CFStringRef propertyName) {
66 return IORegistryEntrySearchCFProperty(dspPort, kIOServicePlane, propertyName,
68 kIORegistryIterateRecursively | kIORegistryIterateParents);
71 static uint32_t IntValueOfCFData(CFDataRef d) {
75 const uint32_t* vp = reinterpret_cast<const uint32_t*>(CFDataGetBytePtr(d));
76 if (vp != NULL) value = *vp;
82 void GfxInfo::GetDeviceInfo() {
85 CFMutableDictionaryRef pci_dev_dict = IOServiceMatching("IOPCIDevice");
86 io_iterator_t io_iter;
87 if (IOServiceGetMatchingServices(kIOMasterPortDefault, pci_dev_dict, &io_iter) !=
89 MOZ_DIAGNOSTIC_ASSERT(false,
90 "Failed to detect any GPUs (couldn't enumerate IOPCIDevice services)");
94 io_registry_entry_t entry = IO_OBJECT_NULL;
95 while ((entry = IOIteratorNext(io_iter)) != IO_OBJECT_NULL) {
96 constexpr uint32_t kClassCodeDisplayVGA = 0x30000;
97 CFTypeRef class_code_ref = SearchPortForProperty(entry, CFSTR("class-code"));
99 const uint32_t class_code = IntValueOfCFData((CFDataRef)class_code_ref);
100 CFRelease(class_code_ref);
102 if (class_code == kClassCodeDisplayVGA) {
103 CFTypeRef vendor_id_ref = SearchPortForProperty(entry, CFSTR("vendor-id"));
105 mAdapterVendorID[mNumGPUsDetected].AppendPrintf(
106 "0x%04x", IntValueOfCFData((CFDataRef)vendor_id_ref));
107 CFRelease(vendor_id_ref);
109 CFTypeRef device_id_ref = SearchPortForProperty(entry, CFSTR("device-id"));
111 mAdapterDeviceID[mNumGPUsDetected].AppendPrintf(
112 "0x%04x", IntValueOfCFData((CFDataRef)device_id_ref));
113 CFRelease(device_id_ref);
118 IOObjectRelease(entry);
119 if (mNumGPUsDetected == 2) {
123 IOObjectRelease(io_iter);
125 #if defined(__aarch64__)
126 // If we found IOPCI VGA devices, don't look for AGXAccelerator devices
127 if (mNumGPUsDetected > 0) {
131 CFMutableDictionaryRef agx_dev_dict = IOServiceMatching("AGXAccelerator");
132 if (IOServiceGetMatchingServices(kIOMasterPortDefault, agx_dev_dict, &io_iter) ==
135 io_registry_entry_t entry = IO_OBJECT_NULL;
136 while ((entry = IOIteratorNext(io_iter)) != IO_OBJECT_NULL) {
138 CFTypeRef vendor_id_ref = SearchPortForProperty(entry, CFSTR("vendor-id"));
140 mAdapterVendorID[mNumGPUsDetected].AppendPrintf(
141 "0x%04x", IntValueOfCFData((CFDataRef)vendor_id_ref));
142 CFRelease(vendor_id_ref);
145 IOObjectRelease(entry);
148 IOObjectRelease(io_iter);
152 MOZ_DIAGNOSTIC_ASSERT(mNumGPUsDetected > 0, "Failed to detect any GPUs");
155 nsresult GfxInfo::Init() {
156 nsresult rv = GfxInfoBase::Init();
158 // Calling CGLQueryRendererInfo causes us to switch to the discrete GPU
159 // even when we don't want to. We'll avoid doing so for now and just
160 // use the device ids.
164 AddCrashReportAnnotations();
166 mOSXVersion = nsCocoaFeatures::macOSVersion();
172 GfxInfo::GetD2DEnabled(bool* aEnabled) { return NS_ERROR_FAILURE; }
175 GfxInfo::GetDWriteEnabled(bool* aEnabled) { return NS_ERROR_FAILURE; }
177 /* readonly attribute bool HasBattery; */
178 NS_IMETHODIMP GfxInfo::GetHasBattery(bool* aHasBattery) { return NS_ERROR_NOT_IMPLEMENTED; }
180 /* readonly attribute DOMString DWriteVersion; */
182 GfxInfo::GetDWriteVersion(nsAString& aDwriteVersion) { return NS_ERROR_FAILURE; }
185 GfxInfo::GetEmbeddedInFirefoxReality(bool* aEmbeddedInFirefoxReality) { return NS_ERROR_FAILURE; }
187 /* readonly attribute DOMString cleartypeParameters; */
189 GfxInfo::GetCleartypeParameters(nsAString& aCleartypeParams) { return NS_ERROR_FAILURE; }
191 /* readonly attribute DOMString windowProtocol; */
193 GfxInfo::GetWindowProtocol(nsAString& aWindowProtocol) { return NS_ERROR_NOT_IMPLEMENTED; }
195 /* readonly attribute DOMString desktopEnvironment; */
197 GfxInfo::GetDesktopEnvironment(nsAString& aDesktopEnvironment) { return NS_ERROR_NOT_IMPLEMENTED; }
199 /* readonly attribute DOMString adapterDescription; */
201 GfxInfo::GetAdapterDescription(nsAString& aAdapterDescription) {
202 aAdapterDescription.AssignLiteral("");
206 /* readonly attribute DOMString adapterDescription2; */
208 GfxInfo::GetAdapterDescription2(nsAString& aAdapterDescription) {
209 if (mNumGPUsDetected < 2) {
210 return NS_ERROR_FAILURE;
212 aAdapterDescription.AssignLiteral("");
216 /* readonly attribute DOMString adapterRAM; */
218 GfxInfo::GetAdapterRAM(uint32_t* aAdapterRAM) {
219 *aAdapterRAM = mAdapterRAM[0];
223 /* readonly attribute DOMString adapterRAM2; */
225 GfxInfo::GetAdapterRAM2(uint32_t* aAdapterRAM) {
226 if (mNumGPUsDetected < 2) {
227 return NS_ERROR_FAILURE;
229 *aAdapterRAM = mAdapterRAM[1];
233 /* readonly attribute DOMString adapterDriver; */
235 GfxInfo::GetAdapterDriver(nsAString& aAdapterDriver) {
236 aAdapterDriver.AssignLiteral("");
240 /* readonly attribute DOMString adapterDriver2; */
242 GfxInfo::GetAdapterDriver2(nsAString& aAdapterDriver) {
243 if (mNumGPUsDetected < 2) {
244 return NS_ERROR_FAILURE;
246 aAdapterDriver.AssignLiteral("");
250 /* readonly attribute DOMString adapterDriverVendor; */
252 GfxInfo::GetAdapterDriverVendor(nsAString& aAdapterDriverVendor) {
253 aAdapterDriverVendor.AssignLiteral("");
257 /* readonly attribute DOMString adapterDriverVendor2; */
259 GfxInfo::GetAdapterDriverVendor2(nsAString& aAdapterDriverVendor) {
260 if (mNumGPUsDetected < 2) {
261 return NS_ERROR_FAILURE;
263 aAdapterDriverVendor.AssignLiteral("");
267 /* readonly attribute DOMString adapterDriverVersion; */
269 GfxInfo::GetAdapterDriverVersion(nsAString& aAdapterDriverVersion) {
270 aAdapterDriverVersion.AssignLiteral("");
274 /* readonly attribute DOMString adapterDriverVersion2; */
276 GfxInfo::GetAdapterDriverVersion2(nsAString& aAdapterDriverVersion) {
277 if (mNumGPUsDetected < 2) {
278 return NS_ERROR_FAILURE;
280 aAdapterDriverVersion.AssignLiteral("");
284 /* readonly attribute DOMString adapterDriverDate; */
286 GfxInfo::GetAdapterDriverDate(nsAString& aAdapterDriverDate) {
287 aAdapterDriverDate.AssignLiteral("");
291 /* readonly attribute DOMString adapterDriverDate2; */
293 GfxInfo::GetAdapterDriverDate2(nsAString& aAdapterDriverDate) {
294 if (mNumGPUsDetected < 2) {
295 return NS_ERROR_FAILURE;
297 aAdapterDriverDate.AssignLiteral("");
301 /* readonly attribute DOMString adapterVendorID; */
303 GfxInfo::GetAdapterVendorID(nsAString& aAdapterVendorID) {
304 aAdapterVendorID = mAdapterVendorID[0];
308 /* readonly attribute DOMString adapterVendorID2; */
310 GfxInfo::GetAdapterVendorID2(nsAString& aAdapterVendorID) {
311 if (mNumGPUsDetected < 2) {
312 return NS_ERROR_FAILURE;
314 aAdapterVendorID = mAdapterVendorID[1];
318 /* readonly attribute DOMString adapterDeviceID; */
320 GfxInfo::GetAdapterDeviceID(nsAString& aAdapterDeviceID) {
321 aAdapterDeviceID = mAdapterDeviceID[0];
325 /* readonly attribute DOMString adapterDeviceID2; */
327 GfxInfo::GetAdapterDeviceID2(nsAString& aAdapterDeviceID) {
328 if (mNumGPUsDetected < 2) {
329 return NS_ERROR_FAILURE;
331 aAdapterDeviceID = mAdapterDeviceID[1];
335 /* readonly attribute DOMString adapterSubsysID; */
337 GfxInfo::GetAdapterSubsysID(nsAString& aAdapterSubsysID) { return NS_ERROR_FAILURE; }
339 /* readonly attribute DOMString adapterSubsysID2; */
341 GfxInfo::GetAdapterSubsysID2(nsAString& aAdapterSubsysID) { return NS_ERROR_FAILURE; }
343 /* readonly attribute Array<DOMString> displayInfo; */
345 GfxInfo::GetDisplayInfo(nsTArray<nsString>& aDisplayInfo) {
346 for (NSScreen* screen in [NSScreen screens]) {
347 NSRect rect = [screen frame];
349 desc.AppendPrintf("%dx%d scale:%f", (int32_t)rect.size.width, (int32_t)rect.size.height,
350 nsCocoaUtils::GetBackingScaleFactor(screen));
351 aDisplayInfo.AppendElement(desc);
358 GfxInfo::GetDisplayWidth(nsTArray<uint32_t>& aDisplayWidth) {
359 for (NSScreen* screen in [NSScreen screens]) {
360 NSRect rect = [screen frame];
361 aDisplayWidth.AppendElement((uint32_t)rect.size.width);
367 GfxInfo::GetDisplayHeight(nsTArray<uint32_t>& aDisplayHeight) {
368 for (NSScreen* screen in [NSScreen screens]) {
369 NSRect rect = [screen frame];
370 aDisplayHeight.AppendElement((uint32_t)rect.size.height);
375 /* readonly attribute boolean isGPU2Active; */
377 GfxInfo::GetIsGPU2Active(bool* aIsGPU2Active) { return NS_ERROR_FAILURE; }
379 void GfxInfo::AddCrashReportAnnotations() {
380 nsString deviceID, vendorID, driverVersion;
381 nsAutoCString narrowDeviceID, narrowVendorID, narrowDriverVersion;
383 GetAdapterDeviceID(deviceID);
384 CopyUTF16toUTF8(deviceID, narrowDeviceID);
385 GetAdapterVendorID(vendorID);
386 CopyUTF16toUTF8(vendorID, narrowVendorID);
387 GetAdapterDriverVersion(driverVersion);
388 CopyUTF16toUTF8(driverVersion, narrowDriverVersion);
390 CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::AdapterVendorID, narrowVendorID);
391 CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::AdapterDeviceID, narrowDeviceID);
392 CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::AdapterDriverVersion,
393 narrowDriverVersion);
396 // We don't support checking driver versions on Mac.
397 #define IMPLEMENT_MAC_DRIVER_BLOCKLIST(os, device, features, blockOn, ruleId) \
398 APPEND_TO_DRIVER_BLOCKLIST(os, device, features, blockOn, DRIVER_COMPARISON_IGNORED, \
399 V(0, 0, 0, 0), ruleId, "")
401 const nsTArray<GfxDriverInfo>& GfxInfo::GetGfxDriverInfo() {
402 if (!sDriverInfo->Length()) {
403 IMPLEMENT_MAC_DRIVER_BLOCKLIST(
404 OperatingSystem::OSX, DeviceFamily::RadeonX1000, nsIGfxInfo::FEATURE_OPENGL_LAYERS,
405 nsIGfxInfo::FEATURE_BLOCKED_DEVICE, "FEATURE_FAILURE_MAC_RADEONX1000_NO_TEXTURE2D");
406 IMPLEMENT_MAC_DRIVER_BLOCKLIST(
407 OperatingSystem::OSX, DeviceFamily::Geforce7300GT, nsIGfxInfo::FEATURE_WEBGL_OPENGL,
408 nsIGfxInfo::FEATURE_BLOCKED_DEVICE, "FEATURE_FAILURE_MAC_7300_NO_WEBGL");
409 IMPLEMENT_MAC_DRIVER_BLOCKLIST(OperatingSystem::OSX, DeviceFamily::IntelHDGraphicsToIvyBridge,
410 nsIGfxInfo::FEATURE_GL_SWIZZLE,
411 nsIGfxInfo::FEATURE_BLOCKED_DEVICE,
412 "FEATURE_FAILURE_MAC_INTELHD4000_NO_SWIZZLE");
413 // We block texture swizzling everwhere on mac because it's broken in some configurations
414 // and we want to support GPU switching.
415 IMPLEMENT_MAC_DRIVER_BLOCKLIST(
416 OperatingSystem::OSX, DeviceFamily::All, nsIGfxInfo::FEATURE_GL_SWIZZLE,
417 nsIGfxInfo::FEATURE_BLOCKED_DEVICE, "FEATURE_FAILURE_MAC_GPU_SWITCHING_NO_SWIZZLE");
419 // FEATURE_WEBRENDER - ALLOWLIST
420 IMPLEMENT_MAC_DRIVER_BLOCKLIST(OperatingSystem::OSX, DeviceFamily::IntelRolloutWebRender,
421 nsIGfxInfo::FEATURE_WEBRENDER, nsIGfxInfo::FEATURE_ALLOW_ALWAYS,
422 "FEATURE_ROLLOUT_INTEL_MAC");
423 // Intel HD3000 disabled due to bug 1661505
424 IMPLEMENT_MAC_DRIVER_BLOCKLIST(
425 OperatingSystem::OSX, DeviceFamily::IntelHD3000, nsIGfxInfo::FEATURE_WEBRENDER,
426 nsIGfxInfo::FEATURE_BLOCKED_DEVICE, "FEATURE_FAILURE_INTEL_MAC_HD3000_NO_WEBRENDER");
427 IMPLEMENT_MAC_DRIVER_BLOCKLIST(OperatingSystem::OSX, DeviceFamily::AtiRolloutWebRender,
428 nsIGfxInfo::FEATURE_WEBRENDER, nsIGfxInfo::FEATURE_ALLOW_ALWAYS,
429 "FEATURE_ROLLOUT_AMD_MAC");
430 IMPLEMENT_MAC_DRIVER_BLOCKLIST(OperatingSystem::OSX, DeviceFamily::NvidiaRolloutWebRender,
431 nsIGfxInfo::FEATURE_WEBRENDER, nsIGfxInfo::FEATURE_ALLOW_ALWAYS,
432 "FEATURE_ROLLOUT_NVIDIA_MAC");
437 nsresult GfxInfo::GetFeatureStatusImpl(int32_t aFeature, int32_t* aStatus,
438 nsAString& aSuggestedDriverVersion,
439 const nsTArray<GfxDriverInfo>& aDriverInfo,
440 nsACString& aFailureId,
441 OperatingSystem* aOS /* = nullptr */) {
442 NS_ENSURE_ARG_POINTER(aStatus);
443 aSuggestedDriverVersion.SetIsVoid(true);
444 *aStatus = nsIGfxInfo::FEATURE_STATUS_UNKNOWN;
445 OperatingSystem os = OSXVersionToOperatingSystem(mOSXVersion);
448 if (sShutdownOccurred) {
452 // Don't evaluate special cases when we're evaluating the downloaded blocklist.
453 if (!aDriverInfo.Length()) {
454 if (aFeature == nsIGfxInfo::FEATURE_CANVAS2D_ACCELERATION) {
457 case OperatingSystem::OSX10_5:
458 case OperatingSystem::OSX10_6:
459 case OperatingSystem::OSX10_7:
460 *aStatus = nsIGfxInfo::FEATURE_BLOCKED_OS_VERSION;
461 aFailureId = "FEATURE_FAILURE_CANVAS_OSX_VERSION";
464 *aStatus = nsIGfxInfo::FEATURE_STATUS_OK;
468 } else if (aFeature == nsIGfxInfo::FEATURE_WEBRENDER &&
469 nsCocoaFeatures::ProcessIsRosettaTranslated()) {
470 *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
471 aFailureId = "FEATURE_UNQUALIFIED_WEBRENDER_MAC_ROSETTA";
474 #ifndef EARLY_BETA_OR_EARLIER
475 else if (aFeature == nsIGfxInfo::FEATURE_WEBRENDER && os == OperatingSystem::OSX10_16) {
476 *aStatus = nsIGfxInfo::FEATURE_BLOCKED_OS_VERSION;
477 aFailureId = "FEATURE_UNQUALIFIED_WEBRENDER_MAC";
483 return GfxInfoBase::GetFeatureStatusImpl(aFeature, aStatus, aSuggestedDriverVersion, aDriverInfo,
487 nsresult GfxInfo::FindMonitors(JSContext* aCx, JS::HandleObject aOutArray) {
488 // Getting the refresh rate is a little hard on OS X. We could use
489 // CVDisplayLinkGetNominalOutputVideoRefreshPeriod, but that's a little
490 // involved. Ideally we could query it from vsync. For now, we leave it out.
491 int32_t deviceCount = 0;
492 for (NSScreen* screen in [NSScreen screens]) {
493 NSRect rect = [screen frame];
495 JS::Rooted<JSObject*> obj(aCx, JS_NewPlainObject(aCx));
497 JS::Rooted<JS::Value> screenWidth(aCx, JS::Int32Value((int)rect.size.width));
498 JS_SetProperty(aCx, obj, "screenWidth", screenWidth);
500 JS::Rooted<JS::Value> screenHeight(aCx, JS::Int32Value((int)rect.size.height));
501 JS_SetProperty(aCx, obj, "screenHeight", screenHeight);
503 JS::Rooted<JS::Value> scale(aCx, JS::NumberValue(nsCocoaUtils::GetBackingScaleFactor(screen)));
504 JS_SetProperty(aCx, obj, "scale", scale);
506 JS::Rooted<JS::Value> element(aCx, JS::ObjectValue(*obj));
507 JS_SetElement(aCx, aOutArray, deviceCount++, element);
514 // Implement nsIGfxInfoDebug
516 /* void spoofVendorID (in DOMString aVendorID); */
517 NS_IMETHODIMP GfxInfo::SpoofVendorID(const nsAString& aVendorID) {
518 mAdapterVendorID[0] = aVendorID;
522 /* void spoofDeviceID (in unsigned long aDeviceID); */
523 NS_IMETHODIMP GfxInfo::SpoofDeviceID(const nsAString& aDeviceID) {
524 mAdapterDeviceID[0] = aDeviceID;
528 /* void spoofDriverVersion (in DOMString aDriverVersion); */
529 NS_IMETHODIMP GfxInfo::SpoofDriverVersion(const nsAString& aDriverVersion) {
530 mDriverVersion[0] = aDriverVersion;
534 /* void spoofOSVersion (in unsigned long aVersion); */
535 NS_IMETHODIMP GfxInfo::SpoofOSVersion(uint32_t aVersion) {
536 mOSXVersion = aVersion;
540 /* void fireTestProcess (); */
541 NS_IMETHODIMP GfxInfo::FireTestProcess() { return NS_OK; }