13 # include <IOKit/IOKitLib.h>
20 string MetalInfo::get_device_name(id<MTLDevice> device)
22 string device_name = [device.name UTF8String];
23 if (get_device_vendor(device) == METAL_GPU_APPLE) {
25 int gpu_core_count = get_apple_gpu_core_count(device);
26 device_name +=
string_printf(gpu_core_count ?
" (GPU - %d cores)" :
" (GPU)", gpu_core_count);
31 int MetalInfo::get_apple_gpu_core_count(id<MTLDevice> device)
34 if (@available(macos 12.0, *)) {
35 io_service_t gpu_service = IOServiceGetMatchingService(
36 kIOMainPortDefault, IORegistryEntryIDMatching(device.registryID));
37 if (CFNumberRef numberRef = (CFNumberRef)IORegistryEntryCreateCFProperty(
38 gpu_service, CFSTR(
"gpu-core-count"), 0, 0)) {
39 if (CFGetTypeID(numberRef) == CFNumberGetTypeID()) {
40 CFNumberGetValue(numberRef, kCFNumberSInt32Type, &core_count);
48 AppleGPUArchitecture MetalInfo::get_apple_gpu_architecture(id<MTLDevice> device)
50 const char *device_name = [device.name UTF8String];
51 if (strstr(device_name,
"M1")) {
54 else if (strstr(device_name,
"M2")) {
60 MetalGPUVendor MetalInfo::get_device_vendor(id<MTLDevice> device)
62 const char *device_name = [device.name UTF8String];
63 if (strstr(device_name,
"Intel")) {
64 return METAL_GPU_INTEL;
66 else if (strstr(device_name,
"AMD")) {
69 else if (strstr(device_name,
"Apple")) {
70 return METAL_GPU_APPLE;
72 return METAL_GPU_UNKNOWN;
75 int MetalInfo::optimal_sort_partition_elements(id<MTLDevice> device)
77 if (
auto str = getenv(
"CYCLES_METAL_SORT_PARTITION_ELEMENTS")) {
84 if (get_device_vendor(device) == METAL_GPU_APPLE) {
93 static bool already_enumerated =
false;
95 if (already_enumerated) {
96 return usable_devices;
99 metal_printf(
"Usable Metal devices:\n");
100 for (id<MTLDevice> device in MTLCopyAllDevices()) {
101 string device_name = get_device_name(device);
102 MetalGPUVendor vendor = get_device_vendor(device);
105 if (@available(macos 12.2, *)) {
106 usable |= (vendor == METAL_GPU_APPLE);
109 if (@available(macos 12.3, *)) {
110 usable |= (vendor == METAL_GPU_AMD);
113 # if defined(MAC_OS_VERSION_13_0)
114 if (@available(macos 13.0, *)) {
115 usable |= (vendor == METAL_GPU_INTEL);
120 metal_printf(
"- %s\n", device_name.c_str());
122 usable_devices.push_back(device);
125 metal_printf(
" (skipping \"%s\")\n", device_name.c_str());
128 if (usable_devices.empty()) {
129 metal_printf(
" No usable Metal devices found\n");
131 already_enumerated =
true;
133 return usable_devices;
136 id<MTLBuffer> MetalBufferPool::get_buffer(id<MTLDevice> device,
137 id<MTLCommandBuffer> command_buffer,
145 MTLStorageMode storageMode = MTLStorageMode((
options & MTLResourceStorageModeMask) >>
146 MTLResourceStorageModeShift);
147 MTLCPUCacheMode cpuCacheMode = MTLCPUCacheMode((
options & MTLResourceCPUCacheModeMask) >>
148 MTLResourceCPUCacheModeShift);
151 for (
auto entry = buffer_free_list.begin(); entry != buffer_free_list.end(); entry++) {
152 MetalBufferListEntry bufferEntry = *entry;
155 if (bufferEntry.buffer.length ==
length && storageMode == bufferEntry.buffer.storageMode &&
156 cpuCacheMode == bufferEntry.buffer.cpuCacheMode) {
157 buffer = bufferEntry.buffer;
158 buffer_free_list.erase(entry);
159 bufferEntry.command_buffer = command_buffer;
160 buffer_in_use_list.push_back(bufferEntry);
161 buffer_mutex.unlock();
166 if (bufferEntry.buffer.storageMode == MTLStorageModeManaged) {
182 MetalBufferListEntry buffer_entry(
buffer, command_buffer);
186 total_temp_mem_size +=
buffer.allocatedSize;
187 buffer_in_use_list.push_back(buffer_entry);
188 buffer_mutex.unlock();
193 void MetalBufferPool::process_command_buffer_completion(id<MTLCommandBuffer> command_buffer)
195 assert(command_buffer);
198 for (
auto entry = buffer_in_use_list.begin(); entry != buffer_in_use_list.end();) {
199 MetalBufferListEntry buffer_entry = *entry;
200 if (buffer_entry.command_buffer == command_buffer) {
201 entry = buffer_in_use_list.erase(entry);
202 buffer_entry.command_buffer = nil;
203 buffer_free_list.push_back(buffer_entry);
211 MetalBufferPool::~MetalBufferPool()
215 for (
auto entry = buffer_free_list.begin(); entry != buffer_free_list.end();) {
216 MetalBufferListEntry buffer_entry = *entry;
218 id<MTLBuffer>
buffer = buffer_entry.buffer;
221 total_temp_mem_size -=
buffer.allocatedSize;
223 entry = buffer_free_list.erase(entry);
void mem_alloc(size_t size)
#define CCL_NAMESPACE_END
CCL_NAMESPACE_BEGIN struct Options options
ccl_global float * buffer
T length(const vec_base< T, Size > &a)
CCL_NAMESPACE_BEGIN string string_printf(const char *format,...)
std::unique_lock< std::mutex > thread_scoped_lock