From 813bfbd061128113dd7b4c7c80321b536597c362 Mon Sep 17 00:00:00 2001 From: Li Hao Date: Thu, 29 Nov 2018 10:54:03 +0000 Subject: [PATCH] Collect device information on Metal Becuase CGDisplayIOServicePort is deprecated in OSX >= 10.9, we create an alternative function which manually finding a service port with matching vendor and product IDs. BUG=dawn:10 TEST=dawn_end2end_tests Change-Id: I94ff65911e159c2b7075209d8902c1551560ed47 Reviewed-on: https://dawn-review.googlesource.com/c/2541 Commit-Queue: Corentin Wallez Reviewed-by: Corentin Wallez Reviewed-by: Kai Ninomiya --- BUILD.gn | 1 + src/dawn_native/metal/DeviceMTL.mm | 95 +++++++++++++++++++++++++- src/tests/end2end/TextureViewTests.cpp | 4 +- 3 files changed, 97 insertions(+), 3 deletions(-) diff --git a/BUILD.gn b/BUILD.gn index 2408412611..1a4922ff97 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -478,6 +478,7 @@ source_set("libdawn_native_sources") { libs += [ "Metal.framework", "Cocoa.framework", + "IOKit.framework", ] sources += [ "src/dawn_native/metal/BlendStateMTL.h", diff --git a/src/dawn_native/metal/DeviceMTL.mm b/src/dawn_native/metal/DeviceMTL.mm index 4d62e5d124..a01ab6a83e 100644 --- a/src/dawn_native/metal/DeviceMTL.mm +++ b/src/dawn_native/metal/DeviceMTL.mm @@ -33,10 +33,96 @@ #include "dawn_native/metal/SwapChainMTL.h" #include "dawn_native/metal/TextureMTL.h" +#include #include namespace dawn_native { namespace metal { + namespace { + // Since CGDisplayIOServicePort was deprecated in macOS 10.9, we need create + // an alternative function for getting I/O service port from current display. + io_service_t GetDisplayIOServicePort() { + // The matching service port (or 0 if none can be found) + io_service_t servicePort = 0; + + // Create matching dictionary for display service + CFMutableDictionaryRef matchingDict = IOServiceMatching("IODisplayConnect"); + if (matchingDict == nullptr) { + return 0; + } + + io_iterator_t iter; + // IOServiceGetMatchingServices look up the default master ports that match a + // matching dictionary, and will consume the reference on the matching dictionary, + // so we don't need to release the dictionary, but the iterator handle should + // be released when its iteration is finished. + if (IOServiceGetMatchingServices(kIOMasterPortDefault, matchingDict, &iter) != + kIOReturnSuccess) { + return 0; + } + + // Vendor number and product number of current main display + const uint32_t displayVendorNumber = CGDisplayVendorNumber(kCGDirectMainDisplay); + const uint32_t displayProductNumber = CGDisplayModelNumber(kCGDirectMainDisplay); + + io_service_t serv; + while ((serv = IOIteratorNext(iter)) != IO_OBJECT_NULL) { + CFDictionaryRef displayInfo = + IODisplayCreateInfoDictionary(serv, kIODisplayOnlyPreferredName); + + CFNumberRef vendorIDRef, productIDRef; + Boolean success; + // The ownership of CF object follows the 'Get Rule', we don't need to + // release these values + success = CFDictionaryGetValueIfPresent(displayInfo, CFSTR(kDisplayVendorID), + (const void**)&vendorIDRef); + success &= CFDictionaryGetValueIfPresent(displayInfo, CFSTR(kDisplayProductID), + (const void**)&productIDRef); + if (success) { + CFIndex vendorID = 0, productID = 0; + CFNumberGetValue(vendorIDRef, kCFNumberSInt32Type, &vendorID); + CFNumberGetValue(productIDRef, kCFNumberSInt32Type, &productID); + + if (vendorID == displayVendorNumber && productID == displayProductNumber) { + // Check if vendor id and product id match with current display's + // If it does, we find the desired service port + servicePort = serv; + CFRelease(displayInfo); + break; + } + } + + CFRelease(displayInfo); + IOObjectRelease(serv); + } + IOObjectRelease(iter); + return servicePort; + } + + // Get integer property from registry entry. + uint32_t GetEntryProperty(io_registry_entry_t entry, CFStringRef name) { + uint32_t value = 0; + + // Recursively search registry entry and its parents for property name + // The data should release with CFRelease + CFDataRef data = static_cast(IORegistryEntrySearchCFProperty( + entry, kIOServicePlane, name, kCFAllocatorDefault, + kIORegistryIterateRecursively | kIORegistryIterateParents)); + + if (data != nullptr) { + const uint32_t* valuePtr = + reinterpret_cast(CFDataGetBytePtr(data)); + if (valuePtr) { + value = *valuePtr; + } + + CFRelease(data); + } + + return value; + } + } // anonymous namespace + dawnDevice CreateDevice(id metalDevice) { return reinterpret_cast(new Device(metalDevice)); } @@ -200,8 +286,15 @@ namespace dawn_native { namespace metal { return mResourceUploader.get(); } - // TODO(jiawei.shao@intel.com): collect device information on Metal void Device::CollectPCIInfo() { + io_registry_entry_t entry = GetDisplayIOServicePort(); + if (entry != IO_OBJECT_NULL) { + mPCIInfo.vendorId = GetEntryProperty(entry, CFSTR("vendor-id")); + mPCIInfo.deviceId = GetEntryProperty(entry, CFSTR("device-id")); + IOObjectRelease(entry); + } + + mPCIInfo.name = std::string([mMtlDevice.name UTF8String]); } }} // namespace dawn_native::metal diff --git a/src/tests/end2end/TextureViewTests.cpp b/src/tests/end2end/TextureViewTests.cpp index a0ee5adf2a..acccc23982 100644 --- a/src/tests/end2end/TextureViewTests.cpp +++ b/src/tests/end2end/TextureViewTests.cpp @@ -365,7 +365,7 @@ TEST_P(TextureViewTest, Texture2DViewOn2DArrayTexture) { // Test sampling from a 2D array texture view created on a 2D array texture. TEST_P(TextureViewTest, Texture2DArrayViewOn2DArrayTexture) { - DAWN_SKIP_TEST_IF(IsMetal()); + DAWN_SKIP_TEST_IF(IsMetal() && IsIntel()); Texture2DArrayViewTest(6, 1, 2, 0); } @@ -381,7 +381,7 @@ TEST_P(TextureViewTest, Texture2DViewOnOneLevelOf2DArrayTexture) { // Test sampling from a 2D array texture view created on a mipmap level of a 2D array texture. TEST_P(TextureViewTest, Texture2DArrayViewOnOneLevelOf2DArrayTexture) { - DAWN_SKIP_TEST_IF(IsMetal()); + DAWN_SKIP_TEST_IF(IsMetal() && IsIntel()); Texture2DArrayViewTest(6, 6, 2, 4); }