31#include <Cocoa/Cocoa.h>
32#include <Metal/Metal.h>
33#include <QuartzCore/QuartzCore.h>
34#include <sys/sysctl.h>
48 compiler_ = MEM_new<MTLShaderCompiler>(__func__);
62 return new MTLContext(ghost_window, ghost_context);
185void MTLBackend::platform_init(
MTLContext *ctx)
187 if (
GPG.initialized) {
197 id<MTLDevice> mtl_device = ctx->
device;
200 NSString *gpu_name = [mtl_device
name];
201 const char *vendor = [gpu_name UTF8String];
202 const char *renderer =
"Metal API";
203 const char *version =
"1.2";
205 printf(
"METAL API - DETECTED GPU: %s\n", vendor);
213 if (strstr(vendor,
"ATI") || strstr(vendor,
"AMD")) {
217 else if (strstr(vendor,
"NVIDIA")) {
221 else if (strstr(vendor,
"Intel")) {
226 else if (strstr(vendor,
"Apple") || strstr(vendor,
"APPLE")) {
231 else if (strstr(renderer,
"Apple Software Renderer")) {
235 else if (strstr(renderer,
"llvmpipe") || strstr(renderer,
"softpipe")) {
240 printf(
"Warning: Could not find a matching GPU name. Things may not behave as expected.\n");
241 printf(
"Detected configuration:\n");
242 printf(
"Vendor: %s\n", vendor);
243 printf(
"Renderer: %s\n", renderer);
265 const uint64_t luid = mtl_device.registryID;
273void MTLBackend::platform_exit()
293 NSString *gpu_name = [device
name];
295 const char *vendor = [gpu_name UTF8String];
298 bool supported_gpu = [device supportsFamily:MTLGPUFamilyMac2];
299 bool should_support_barycentrics =
false;
302 if (strstr(vendor,
"AMD") || strstr(vendor,
"Apple") || strstr(vendor,
"APPLE")) {
303 should_support_barycentrics =
true;
307 if ((strstr(vendor,
"Intel") || strstr(vendor,
"INTEL"))) {
308 should_support_barycentrics =
true;
310 return supported_gpu && should_support_barycentrics;
315 NSString *gpu_name = [device
name];
318 const char *vendor = [gpu_name UTF8String];
321 return (strstr(vendor,
"Apple") || strstr(vendor,
"APPLE"));
326 const int SYSCTL_BUF_LENGTH = 16;
327 int num_performance_cores = -1;
328 unsigned char sysctl_buffer[SYSCTL_BUF_LENGTH];
329 size_t sysctl_buffer_length = SYSCTL_BUF_LENGTH;
334 "hw.perflevel0.logicalcpu", &sysctl_buffer, &sysctl_buffer_length,
nullptr, 0) == 0)
336 num_performance_cores = sysctl_buffer[0];
341 if (sysctlbyname(
"hw.logicalcpu", &sysctl_buffer, &sysctl_buffer_length,
nullptr, 0) == 0) {
342 num_performance_cores = sysctl_buffer[0];
346 return num_performance_cores;
353 const int SYSCTL_BUF_LENGTH = 16;
354 int num_efficiency_cores = -1;
355 unsigned char sysctl_buffer[SYSCTL_BUF_LENGTH];
356 size_t sysctl_buffer_length = SYSCTL_BUF_LENGTH;
358 "hw.perflevel1.logicalcpu", &sysctl_buffer, &sysctl_buffer_length,
nullptr, 0) == 0)
360 num_efficiency_cores = sysctl_buffer[0];
364 return num_efficiency_cores;
374 NSOperatingSystemVersion version = [[NSProcessInfo processInfo] operatingSystemVersion];
377 bool supported_os_version = version.majorVersion >= 11 ||
378 (version.majorVersion == 10 ? version.minorVersion >= 15 :
false);
379 if (!supported_os_version) {
381 "OS Version too low to run minimum required metal version. Required at least 10.15, got "
383 (
long)version.majorVersion,
384 (
long)version.minorVersion);
388 id<MTLDevice> device = MTLCreateSystemDefaultDevice();
391 static const char *forceIntelStr = getenv(
"METAL_FORCE_INTEL");
392 bool forceIntel = forceIntelStr ? (atoi(forceIntelStr) != 0) :
false;
395 NSArray<id<MTLDevice>> *allDevices = MTLCopyAllDevices();
396 for (id<MTLDevice> _device
in allDevices) {
397 if (_device.lowPower) {
405 bool supports_argument_buffers_tier2 = ([device argumentBuffersSupport] ==
406 MTLArgumentBuffersTier2);
407 bool supports_barycentrics = [device supportsShaderBarycentricCoordinates] ||
409 bool supported_metal_version = [device supportsFamily:MTLGPUFamilyMac2];
411 bool result = supports_argument_buffers_tier2 && supports_barycentrics && supported_os_version &&
412 supported_metal_version;
415 if (!supports_argument_buffers_tier2) {
416 printf(
"[Metal] Device does not support argument buffers tier 2\n");
418 if (!supports_barycentrics) {
419 printf(
"[Metal] Device does not support barycentrics coordinates\n");
421 if (!supported_metal_version) {
422 printf(
"[Metal] Device does not support metal 2.2 or higher\n");
426 printf(
"Device with name %s supports metal minimum requirements\n",
427 [[device
name] UTF8String]);
434void MTLBackend::capabilities_init(
MTLContext *ctx)
437 id<MTLDevice> device = ctx->
device;
442 MTLArgumentBuffersTier2);
446 supportsFamily:MTLGPUFamilyMacCatalyst1];
448 supportsFamily:MTLGPUFamilyMacCatalyst2];
454 const char *gpu_name = [device.name UTF8String];
455 if (strstr(gpu_name,
"M1")) {
458 else if (strstr(gpu_name,
"M2")) {
461 else if (strstr(gpu_name,
"M3")) {
470#if defined(MAC_OS_VERSION_14_0)
471 if (@available(macOS 14.0, *)) {
478 if (is_tile_based_arch) {
500 (([device supportsFamily:MTLGPUFamilyApple4]) ? 96 : 31);
546 uint max_threads_per_threadgroup_per_dim = ([device supportsFamily:MTLGPUFamilyApple4] ||
@ G_DEBUG_GPU_FORCE_WORKAROUNDS
#define BLI_assert_msg(a, msg)
int BLI_system_thread_count(void)
unsigned long long int uint64_t
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
void reinitialize(const int64_t new_size)
ShaderCompiler * compiler_
void render_begin() override
QueryPool * querypool_alloc() override
void compute_dispatch_indirect(StorageBuf *indirect_buf) override
Context * context_alloc(void *ghost_window, void *ghost_context) override
bool is_inside_render_boundary()
PixelBuffer * pixelbuf_alloc(size_t size) override
FrameBuffer * framebuffer_alloc(const char *name) override
static bool metal_is_supported()
IndexBuf * indexbuf_alloc() override
StorageBuf * storagebuf_alloc(size_t size, GPUUsageType usage, const char *name) override
void render_end() override
void samplers_update() override
Batch * batch_alloc() override
Fence * fence_alloc() override
void init_resources() override
void compute_dispatch(int groups_x_len, int groups_y_len, int groups_z_len) override
static MTLCapabilities capabilities
UniformBuf * uniformbuf_alloc(size_t size, const char *name) override
VertBuf * vertbuf_alloc() override
void delete_resources() override
Texture * texture_alloc(const char *name) override
Shader * shader_alloc(const char *name) override
void render_step(bool force_resource_release=false) override
MTLSafeFreeList * get_current_safe_list()
void update_memory_pools()
void begin_new_safe_list()
static MTLContext * get()
void compute_dispatch_indirect(StorageBuf *indirect_buf)
void compute_dispatch(int groups_x_len, int groups_y_len, int groups_z_len)
static MTLBufferPool * get_global_memory_manager()
float length(VecOp< float, D >) RET
static const char * mtl_extensions_get_null(int)
static int get_num_performance_cpu_cores(id< MTLDevice > device)
NSAutoreleasePool * g_autoreleasepool
bool supports_barycentric_whitelist(id< MTLDevice > device)
static int get_num_efficiency_cpu_cores(id< MTLDevice > device)
int g_autoreleasepool_depth
bool is_apple_sillicon(id< MTLDevice > device)
static void init(bNodeTree *, bNode *node)
int max_shader_storage_buffer_bindings
int max_parallel_compilations
bool geometry_shader_support
int max_work_group_size[3]
size_t max_uniform_buffer_size
bool use_main_context_workaround
bool depth_blitting_workaround
bool hdr_viewport_support
int minimum_per_vertex_stride
uint32_t max_buffer_texture_size
int max_work_group_count[3]
const char *(* extension_get)(int)
int max_compute_shader_storage_blocks
size_t storage_buffer_alignment
bool stencil_export_support
size_t max_storage_buffer_size
bool supports_native_tile_inputs
bool supports_argument_buffers_tier2
int num_performance_cores
bool supports_texture_atomics
bool supports_texture_gather
bool supports_family_mac1