14# include <IOKit/IOKitLib.h>
21string MetalInfo::get_device_name(id<MTLDevice> device)
23 string device_name = [device.name UTF8String];
26 int gpu_core_count = get_apple_gpu_core_count(device);
27 device_name +=
string_printf(gpu_core_count ?
" (GPU - %d cores)" :
" (GPU)", gpu_core_count);
32int MetalInfo::get_apple_gpu_core_count(id<MTLDevice> device)
35 if (@available(macos 12.0, *)) {
36 io_service_t gpu_service = IOServiceGetMatchingService(
37 kIOMainPortDefault, IORegistryEntryIDMatching(device.registryID));
38 if (CFNumberRef numberRef = (CFNumberRef)IORegistryEntryCreateCFProperty(
39 gpu_service, CFSTR(
"gpu-core-count"), 0, 0))
41 if (CFGetTypeID(numberRef) == CFNumberGetTypeID()) {
42 CFNumberGetValue(numberRef, kCFNumberSInt32Type, &core_count);
50AppleGPUArchitecture MetalInfo::get_apple_gpu_architecture(id<MTLDevice> device)
52 const char *device_name = [device.name UTF8String];
53 if (strstr(device_name,
"M1")) {
56 else if (strstr(device_name,
"M2")) {
57 return get_apple_gpu_core_count(device) <= 10 ? APPLE_M2 : APPLE_M2_BIG;
59 else if (strstr(device_name,
"M3")) {
65int MetalInfo::optimal_sort_partition_elements()
67 if (
auto str = getenv(
"CYCLES_METAL_SORT_PARTITION_ELEMENTS")) {
81 static bool already_enumerated =
false;
83 if (already_enumerated) {
84 return usable_devices;
87 metal_printf(
"Usable Metal devices:\n");
88 for (id<MTLDevice> device in MTLCopyAllDevices()) {
89 string device_name = get_device_name(device);
92 if (@available(macos 12.2, *)) {
93 const char *device_name_char = [device.name UTF8String];
94 if (!(strstr(device_name_char,
"Intel") || strstr(device_name_char,
"AMD")) &&
95 strstr(device_name_char,
"Apple"))
103 metal_printf(
"- %s\n", device_name.c_str());
105 usable_devices.push_back(device);
108 metal_printf(
" (skipping \"%s\")\n", device_name.c_str());
111 if (usable_devices.empty()) {
112 metal_printf(
" No usable Metal devices found\n");
114 already_enumerated =
true;
116 return usable_devices;
119id<MTLBuffer> MetalBufferPool::get_buffer(id<MTLDevice> device,
120 id<MTLCommandBuffer> command_buffer,
126 id<MTLBuffer> buffer = nil;
128 MTLStorageMode storageMode = MTLStorageMode((
options & MTLResourceStorageModeMask) >>
129 MTLResourceStorageModeShift);
130 MTLCPUCacheMode cpuCacheMode = MTLCPUCacheMode((
options & MTLResourceCPUCacheModeMask) >>
131 MTLResourceCPUCacheModeShift);
136 for (MetalBufferListEntry &bufferEntry : temp_buffers) {
137 if (bufferEntry.buffer.length == length && storageMode == bufferEntry.buffer.storageMode &&
138 cpuCacheMode == bufferEntry.buffer.cpuCacheMode && bufferEntry.command_buffer == nil)
140 buffer = bufferEntry.buffer;
141 bufferEntry.command_buffer = command_buffer;
150 total_temp_mem_size += buffer.allocatedSize;
151 temp_buffers.push_back(MetalBufferListEntry{buffer, command_buffer});
157 memcpy(buffer.contents, pointer, length);
158 if (buffer.storageMode == MTLStorageModeManaged) {
159 [buffer didModifyRange:NSMakeRange(0, length)];
166void MetalBufferPool::process_command_buffer_completion(id<MTLCommandBuffer> command_buffer)
168 assert(command_buffer);
171 for (MetalBufferListEntry &buffer_entry : temp_buffers) {
172 if (buffer_entry.command_buffer == command_buffer) {
173 buffer_entry.command_buffer = nil;
178MetalBufferPool::~MetalBufferPool()
182 for (MetalBufferListEntry &buffer_entry : temp_buffers) {
183 total_temp_mem_size -= buffer_entry.buffer.allocatedSize;
184 [buffer_entry.buffer release];
185 buffer_entry.buffer = nil;
187 temp_buffers.clear();
void mem_alloc(size_t size)
CCL_NAMESPACE_BEGIN struct Options options
#define CCL_NAMESPACE_END
CCL_NAMESPACE_BEGIN string string_printf(const char *format,...)
std::unique_lock< std::mutex > thread_scoped_lock