14# include <IOKit/IOKitLib.h>
22# define CYCLES_USE_TIER2D_BINDLESS
24string MetalInfo::get_device_name(id<MTLDevice> device)
26 string device_name = [device.name UTF8String];
29 int gpu_core_count = get_apple_gpu_core_count(device);
30 device_name +=
string_printf(gpu_core_count ?
" (GPU - %d cores)" :
" (GPU)", gpu_core_count);
35int MetalInfo::get_apple_gpu_core_count(id<MTLDevice> device)
38 if (@available(macos 12.0, *)) {
39 io_service_t gpu_service = IOServiceGetMatchingService(
40 kIOMainPortDefault, IORegistryEntryIDMatching(device.registryID));
41 if (CFNumberRef numberRef = (CFNumberRef)IORegistryEntryCreateCFProperty(
42 gpu_service, CFSTR(
"gpu-core-count"),
nullptr, 0))
44 if (CFGetTypeID(numberRef) == CFNumberGetTypeID()) {
45 CFNumberGetValue(numberRef, kCFNumberSInt32Type, &core_count);
53AppleGPUArchitecture MetalInfo::get_apple_gpu_architecture(id<MTLDevice> device)
55 const char *device_name = [device.name UTF8String];
56 if (strstr(device_name,
"M1")) {
59 if (strstr(device_name,
"M2")) {
60 return get_apple_gpu_core_count(device) <= 10 ? APPLE_M2 : APPLE_M2_BIG;
62 if (strstr(device_name,
"M3")) {
68int MetalInfo::optimal_sort_partition_elements()
70 if (
auto *
str = getenv(
"CYCLES_METAL_SORT_PARTITION_ELEMENTS")) {
84 static bool already_enumerated =
false;
86 if (already_enumerated) {
87 return usable_devices;
90 metal_printf(
"Usable Metal devices:");
91 for (id<MTLDevice> device
in MTLCopyAllDevices()) {
92 string device_name = get_device_name(device);
95 if (@available(macos 12.2, *)) {
96 const char *device_name_char = [device.name UTF8String];
97 if (!(strstr(device_name_char,
"Intel") || strstr(device_name_char,
"AMD")) &&
98 strstr(device_name_char,
"Apple"))
103 usable = [device hasUnifiedMemory];
108 metal_printf(
"- %s", device_name.c_str());
110 usable_devices.push_back(device);
113 metal_printf(
" (skipping \"%s\")", device_name.c_str());
116 if (usable_devices.empty()) {
117 metal_printf(
" No usable Metal devices found");
119 already_enumerated =
true;
121 return usable_devices;
124struct GPUAddressHelper {
125 id<MTLBuffer> resource_buffer = nil;
126 id<MTLArgumentEncoder> address_encoder = nil;
129 void init(id<MTLDevice> device)
131 if (resource_buffer) {
136# ifdef CYCLES_USE_TIER2D_BINDLESS
137 if (@available(macos 13.0, *)) {
144 resource_buffer = [device newBufferWithLength:8
options:MTLResourceStorageModeShared];
147 MTLArgumentDescriptor *encoder_params = [[MTLArgumentDescriptor alloc]
init];
148 encoder_params.arrayLength = 1;
149 encoder_params.access = MTLBindingAccessReadWrite;
150 encoder_params.dataType = MTLDataTypePointer;
151 address_encoder = [device newArgumentEncoderWithArguments:@[ encoder_params ]];
152 [address_encoder setArgumentBuffer:resource_buffer offset:0];
155 uint64_t gpuAddress(id<MTLBuffer> buffer)
157# ifdef CYCLES_USE_TIER2D_BINDLESS
158 if (@available(macos 13.0, *)) {
159 return buffer.gpuAddress;
162 [address_encoder setBuffer:buffer offset:0 atIndex:0];
163 return *(
uint64_t *)[resource_buffer contents];
168# ifdef CYCLES_USE_TIER2D_BINDLESS
169 if (@available(macos 13.0, *)) {
170 MTLResourceID resourceID =
texture.gpuResourceID;
174 [address_encoder setTexture:
texture atIndex:0];
175 return *(
uint64_t *)[resource_buffer contents];
178 uint64_t gpuResourceID(id<MTLAccelerationStructure> accel_struct)
180# ifdef CYCLES_USE_TIER2D_BINDLESS
181 if (@available(macos 13.0, *)) {
182 MTLResourceID resourceID = accel_struct.gpuResourceID;
186 [address_encoder setAccelerationStructure:accel_struct atIndex:0];
187 return *(
uint64_t *)[resource_buffer contents];
190 uint64_t gpuResourceID(id<MTLIntersectionFunctionTable> ift)
192# ifdef CYCLES_USE_TIER2D_BINDLESS
193 if (@available(macos 13.0, *)) {
194 MTLResourceID resourceID = ift.gpuResourceID;
198 [address_encoder setIntersectionFunctionTable:ift atIndex:0];
199 return *(
uint64_t *)[resource_buffer contents];
203GPUAddressHelper g_gpu_address_helper;
205void metal_gpu_address_helper_init(id<MTLDevice> device)
207 g_gpu_address_helper.init(device);
210uint64_t metal_gpuAddress(id<MTLBuffer> buffer)
212 return g_gpu_address_helper.gpuAddress(buffer);
217 return g_gpu_address_helper.gpuResourceID(
texture);
220uint64_t metal_gpuResourceID(id<MTLAccelerationStructure> accel_struct)
222 return g_gpu_address_helper.gpuResourceID(accel_struct);
225uint64_t metal_gpuResourceID(id<MTLIntersectionFunctionTable> ift)
227 return g_gpu_address_helper.gpuResourceID(ift);
unsigned long long int uint64_t
CCL_NAMESPACE_BEGIN struct Options options
#define CCL_NAMESPACE_END
TEX_TEMPLATE DataVec texture(T, FltCoord, float=0.0f) RET
CCL_NAMESPACE_BEGIN string string_printf(const char *format,...)