Commit: 40fce61a6abe79508022d3e0cd3a29e187f18e74 Author: Michael Jones Date: Fri Feb 11 19:19:51 2022 +0100 Branches: blender-v3.1-release https://developer.blender.org/rB40fce61a6abe79508022d3e0cd3a29e187f18e74
Cycles: enable Metal on AMD GPUs, set macOS minimum versions * Apple Silicon support enabled on macOS 12.2+ * AMD support enabled on macOS 12.3+ This patch also fixes a device enumeration crash on certain AMD configs which was caused by over-release of MTLDevice objects. Differential Revision: https://developer.blender.org/D14090 =================================================================== M intern/cycles/device/metal/device.mm M intern/cycles/device/metal/device_impl.mm M intern/cycles/device/metal/util.h M intern/cycles/device/metal/util.mm =================================================================== diff --git a/intern/cycles/device/metal/device.mm b/intern/cycles/device/metal/device.mm index bc893adea17..ef592438980 100644 --- a/intern/cycles/device/metal/device.mm +++ b/intern/cycles/device/metal/device.mm @@ -39,33 +39,20 @@ bool device_metal_init() return true; } -static int device_metal_get_num_devices_safe(uint32_t *num_devices) -{ - *num_devices = MTLCopyAllDevices().count; - return 0; -} - void device_metal_info(vector<DeviceInfo> &devices) { - uint32_t num_devices = 0; - device_metal_get_num_devices_safe(&num_devices); - if (num_devices == 0) { - return; - } - - vector<MetalPlatformDevice> usable_devices; - MetalInfo::get_usable_devices(&usable_devices); + auto usable_devices = MetalInfo::get_usable_devices(); /* Devices are numbered consecutively across platforms. */ set<string> unique_ids; int device_index = 0; - for (MetalPlatformDevice &device : usable_devices) { + for (id<MTLDevice> &device : usable_devices) { /* Compute unique ID for persistent user preferences. */ - const string &device_name = device.device_name; + string device_name = [device.name UTF8String]; string id = string("METAL_") + device_name; /* Hardware ID might not be unique, add device number in that case. */ if (unique_ids.find(id) != unique_ids.end()) { - id += string_printf("_ID_%d", num_devices); + id += string_printf("_ID_%d", device_index); } unique_ids.insert(id); @@ -94,15 +81,13 @@ void device_metal_info(vector<DeviceInfo> &devices) string device_metal_capabilities() { string result = ""; - string error_msg = ""; - uint32_t num_devices = 0; - assert(device_metal_get_num_devices_safe(&num_devices)); + auto allDevices = MTLCopyAllDevices(); + uint32_t num_devices = allDevices.count; if (num_devices == 0) { return "No Metal devices found\n"; } result += string_printf("Number of devices: %u\n", num_devices); - NSArray<id<MTLDevice>> *allDevices = MTLCopyAllDevices(); for (id<MTLDevice> device in allDevices) { result += string_printf("\t\tDevice: %s\n", [device.name UTF8String]); } diff --git a/intern/cycles/device/metal/device_impl.mm b/intern/cycles/device/metal/device_impl.mm index cdaafc60ab0..8ced0210e30 100644 --- a/intern/cycles/device/metal/device_impl.mm +++ b/intern/cycles/device/metal/device_impl.mm @@ -53,16 +53,10 @@ MetalDevice::MetalDevice(const DeviceInfo &info, Stats &stats, Profiler &profile mtlDevId = info.num; /* select chosen device */ - vector<MetalPlatformDevice> usable_devices; - MetalInfo::get_usable_devices(&usable_devices); - if (usable_devices.size() == 0) { - set_error("Metal: no devices found."); - return; - } + auto usable_devices = MetalInfo::get_usable_devices(); assert(mtlDevId < usable_devices.size()); - MetalPlatformDevice &platform_device = usable_devices[mtlDevId]; - mtlDevice = platform_device.device_id; - device_name = platform_device.device_name; + mtlDevice = usable_devices[mtlDevId]; + device_name = [mtlDevice.name UTF8String]; device_vendor = MetalInfo::get_vendor_from_device_name(device_name); assert(device_vendor != METAL_GPU_UNKNOWN); metal_printf("Creating new Cycles device for Metal: %s\n", device_name.c_str()); @@ -458,7 +452,8 @@ MetalDevice::MetalMem *MetalDevice::generic_alloc(device_memory &mem) id<MTLBuffer> metal_buffer = nil; MTLResourceOptions options = default_storage_mode; - /* Workaround for "bake" unit tests which fail if RenderBuffers is allocated with MTLResourceStorageModeShared. */ + /* Workaround for "bake" unit tests which fail if RenderBuffers is allocated with + * MTLResourceStorageModeShared. */ if (strstr(mem.name, "RenderBuffers")) { options = MTLResourceStorageModeManaged; } @@ -769,9 +764,11 @@ void MetalDevice::tex_alloc(device_texture &mem) /* Check that dimensions fit within maximum allowable size. See https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf */ - if (mem.data_width > 16384 || - mem.data_height > 16384) { - set_error(string_printf("Texture exceeds maximum allowed size of 16384 x 16384 (requested: %zu x %zu)", mem.data_width, mem.data_height)); + if (mem.data_width > 16384 || mem.data_height > 16384) { + set_error(string_printf( + "Texture exceeds maximum allowed size of 16384 x 16384 (requested: %zu x %zu)", + mem.data_width, + mem.data_height)); return; } diff --git a/intern/cycles/device/metal/util.h b/intern/cycles/device/metal/util.h index dbeb3a5d064..084ba626370 100644 --- a/intern/cycles/device/metal/util.h +++ b/intern/cycles/device/metal/util.h @@ -36,33 +36,10 @@ enum MetalGPUVendor { METAL_GPU_INTEL = 3, }; -/* Retains a named MTLDevice for device enumeration. */ -struct MetalPlatformDevice { - MetalPlatformDevice(id<MTLDevice> device, const string &device_name) - : device_id(device), device_name(device_name) - { - [device_id retain]; - } - ~MetalPlatformDevice() - { - [device_id release]; - } - id<MTLDevice> device_id; - string device_name; -}; - /* Contains static Metal helper functions. */ struct MetalInfo { - static bool device_version_check(id<MTLDevice> device); - static void get_usable_devices(vector<MetalPlatformDevice> *usable_devices); + static vector<id<MTLDevice>> const &get_usable_devices(); static MetalGPUVendor get_vendor_from_device_name(string const &device_name); - - /* Platform information. */ - static bool get_num_devices(uint32_t *num_platforms); - static uint32_t get_num_devices(); - - static bool get_device_name(id<MTLDevice> device_id, string *device_name); - static string get_device_name(id<MTLDevice> device_id); }; /* Pool of MTLBuffers whose lifetime is linked to a single MTLCommandBuffer */ diff --git a/intern/cycles/device/metal/util.mm b/intern/cycles/device/metal/util.mm index 763a37cb503..f0eb22e57f3 100644 --- a/intern/cycles/device/metal/util.mm +++ b/intern/cycles/device/metal/util.mm @@ -43,83 +43,45 @@ MetalGPUVendor MetalInfo::get_vendor_from_device_name(string const &device_name) return METAL_GPU_UNKNOWN; } -bool MetalInfo::device_version_check(id<MTLDevice> device) +vector<id<MTLDevice>> const &MetalInfo::get_usable_devices() { - /* Metal Cycles doesn't work correctly on macOS versions older than 12.0 */ - if (@available(macos 12.0, *)) { - MetalGPUVendor vendor = get_vendor_from_device_name([[device name] UTF8String]); + static vector<id<MTLDevice>> usable_devices; + static bool already_enumerated = false; - /* Metal Cycles works on Apple Silicon GPUs at present */ - return (vendor == METAL_GPU_APPLE); + if (already_enumerated) { + return usable_devices; } - return false; -} + metal_printf("Usable Metal devices:\n"); + for (id<MTLDevice> device in MTLCopyAllDevices()) { + const char *device_name = [device.name UTF8String]; -void MetalInfo::get_usable_devices(vector<MetalPlatformDevice> *usable_devices) -{ - static bool first_time = true; -# define FIRST_VLOG(severity) \ - if (first_time) \ - VLOG(severity) - - usable_devices->clear(); - - NSArray<id<MTLDevice>> *allDevices = MTLCopyAllDevices(); - for (id<MTLDevice> device in allDevices) { - string device_name; - if (!get_device_name(device, &device_name)) { - FIRST_VLOG(2) << "Failed to get device name, ignoring."; - continue; + MetalGPUVendor vendor = get_vendor_from_device_name(device_name); + bool usable = false; + + if (@available(macos 12.2, *)) { + usable |= (vendor == METAL_GPU_APPLE); } - static const char *forceIntelStr = getenv("CYCLES_METAL_FORCE_INTEL"); - bool forceIntel = forceIntelStr ? (atoi(forceIntelStr) != 0) : false; - if (forceIntel && device_name.find("Intel") == string::npos) { - FIRST_VLOG(2) << "CYCLES_METAL_FORCE_INTEL causing non-Intel device " << device_name - << " to be ignored."; - continue; + if (@available(macos 12.3, *)) { + usable |= (vendor == METAL_GPU_AMD); } - if (!device_version_check(device)) { - FIRST_VLOG(2) << "Ignoring device " << device_name << " due to too old compiler version."; - continue; + if (usable) { + metal_printf("- %s\n", device_name); + [device retain]; + usable_devices.push_back(device); + } + else { + metal_printf(" (skipping \"%s\")\n", device_name); } - FIRST_VLOG(2) << "Adding new device " << device_name << "."; - string hardware_id; - usable_devices->push_back(MetalPlatformDevice(device, device_name)); } - first_time = false; -} - -bool MetalInfo::get_num_devices(uint32_t *num_devices) -{ - *num_devices = MTLCopyAllDevices().count; - return true; -} - -uint32_t MetalInfo::get_num_devices() -{ - uint32_t num_devices; - if (!get_num_devices(&num_devices)) { - return 0; + if (usable_devices.empty()) { + metal_printf(" No usable Metal devices found\n"); } - return num_devices; -} - -bool MetalInfo::get_device_name(id<MTLDevice> device, string *platform_name) -{ - *platform_name = [device.name UTF8String]; - return true; -} + already_enumerated = true; -string MetalInfo::get_device_name(id<MTLDevice> device) -{ - string platform_name; - if (!get_device_name(device, &platform_name)) { - return ""; - } - return platform_name; + return usable_devices; } id<MTLBuffer> MetalBufferPool::get_buffer(id<MTLDevice> device, _______________________________________________ Bf-blender-cvs mailing list Bf-blender-cvs@blender.org List details, subscription details or unsubscribe: https://lists.blender.org/mailman/listinfo/bf-blender-cvs