28#include <Cocoa/Cocoa.h>
29#include <Metal/Metal.h>
30#include <QuartzCore/QuartzCore.h>
31#include <sys/sysctl.h>
49 return new MTLContext(ghost_window, ghost_context);
172void MTLBackend::platform_init(
MTLContext *ctx)
184 id<MTLDevice> mtl_device = ctx->
device;
187 NSString *gpu_name = [mtl_device name];
188 const char *vendor = [gpu_name UTF8String];
189 const char *renderer =
"Metal API";
190 const char *version =
"1.2";
192 printf(
"METAL API - DETECTED GPU: %s\n", vendor);
200 if (strstr(vendor,
"ATI") || strstr(vendor,
"AMD")) {
204 else if (strstr(vendor,
"NVIDIA")) {
208 else if (strstr(vendor,
"Intel")) {
213 else if (strstr(vendor,
"Apple") || strstr(vendor,
"APPLE")) {
218 else if (strstr(renderer,
"Apple Software Renderer")) {
222 else if (strstr(renderer,
"llvmpipe") || strstr(renderer,
"softpipe")) {
227 printf(
"Warning: Could not find a matching GPU name. Things may not behave as expected.\n");
228 printf(
"Detected configuration:\n");
229 printf(
"Vendor: %s\n", vendor);
230 printf(
"Renderer: %s\n", renderer);
249void MTLBackend::platform_exit()
269 NSString *gpu_name = [device name];
271 const char *vendor = [gpu_name UTF8String];
274 bool supported_gpu = [device supportsFamily:MTLGPUFamilyMac2];
275 bool should_support_barycentrics =
false;
278 if (strstr(vendor,
"AMD") || strstr(vendor,
"Apple") || strstr(vendor,
"APPLE")) {
279 should_support_barycentrics =
true;
283 if ((strstr(vendor,
"Intel") || strstr(vendor,
"INTEL"))) {
284 should_support_barycentrics =
true;
286 return supported_gpu && should_support_barycentrics;
291 NSString *gpu_name = [device name];
294 const char *vendor = [gpu_name UTF8String];
297 return (strstr(vendor,
"Apple") || strstr(vendor,
"APPLE"));
302 const int SYSCTL_BUF_LENGTH = 16;
303 int num_performance_cores = -1;
304 unsigned char sysctl_buffer[SYSCTL_BUF_LENGTH];
305 size_t sysctl_buffer_length = SYSCTL_BUF_LENGTH;
309 if (sysctlbyname(
"hw.perflevel0.logicalcpu", &sysctl_buffer, &sysctl_buffer_length,
NULL, 0) ==
312 num_performance_cores = sysctl_buffer[0];
317 if (sysctlbyname(
"hw.logicalcpu", &sysctl_buffer, &sysctl_buffer_length,
NULL, 0) == 0) {
318 num_performance_cores = sysctl_buffer[0];
322 return num_performance_cores;
329 const int SYSCTL_BUF_LENGTH = 16;
330 int num_efficiency_cores = -1;
331 unsigned char sysctl_buffer[SYSCTL_BUF_LENGTH];
332 size_t sysctl_buffer_length = SYSCTL_BUF_LENGTH;
333 if (sysctlbyname(
"hw.perflevel1.logicalcpu", &sysctl_buffer, &sysctl_buffer_length,
NULL, 0) ==
336 num_efficiency_cores = sysctl_buffer[0];
340 return num_efficiency_cores;
352 NSOperatingSystemVersion version = [[NSProcessInfo processInfo] operatingSystemVersion];
355 bool supported_os_version = version.majorVersion >= 11 ||
356 (version.majorVersion == 10 ? version.minorVersion >= 15 :
false);
357 if (!supported_os_version) {
359 "OS Version too low to run minimum required metal version. Required at least 10.15, got "
361 (
long)version.majorVersion,
362 (
long)version.minorVersion);
366 id<MTLDevice> device = MTLCreateSystemDefaultDevice();
369 static const char *forceIntelStr = getenv(
"METAL_FORCE_INTEL");
370 bool forceIntel = forceIntelStr ? (atoi(forceIntelStr) != 0) :
false;
373 NSArray<id<MTLDevice>> *allDevices = MTLCopyAllDevices();
374 for (id<MTLDevice> _device in allDevices) {
375 if (_device.lowPower) {
383 bool supports_argument_buffers_tier2 = ([device argumentBuffersSupport] ==
384 MTLArgumentBuffersTier2);
385 bool supports_barycentrics = [device supportsShaderBarycentricCoordinates] ||
387 bool supported_metal_version = [device supportsFamily:MTLGPUFamilyMac2];
389 bool result = supports_argument_buffers_tier2 && supports_barycentrics && supported_os_version &&
390 supported_metal_version;
393 if (!supports_argument_buffers_tier2) {
394 printf(
"[Metal] Device does not support argument buffers tier 2\n");
396 if (!supports_barycentrics) {
397 printf(
"[Metal] Device does not support barycentrics coordinates\n");
399 if (!supported_metal_version) {
400 printf(
"[Metal] Device does not support metal 2.2 or higher\n");
404 printf(
"Device with name %s supports metal minimum requirements\n",
405 [[device name] UTF8String]);
412void MTLBackend::capabilities_init(
MTLContext *ctx)
415 id<MTLDevice> device = ctx->
device;
420 MTLArgumentBuffersTier2);
424 supportsFamily:MTLGPUFamilyMacCatalyst1];
426 supportsFamily:MTLGPUFamilyMacCatalyst2];
432 const char *gpu_name = [device.name UTF8String];
433 if (strstr(gpu_name,
"M1")) {
436 else if (strstr(gpu_name,
"M2")) {
439 else if (strstr(gpu_name,
"M3")) {
448#if defined(MAC_OS_VERSION_14_0)
449 if (@available(macOS 14.0, *)) {
467 (([device supportsFamily:MTLGPUFamilyApple4]) ? 96 : 31);
509 uint max_threads_per_threadgroup_per_dim = ([device supportsFamily:MTLGPUFamilyApple4] ||
#define BLI_assert_msg(a, msg)
void render_step() override
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 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
Texture * texture_alloc(const char *name) override
DrawList * drawlist_alloc(int list_length) override
Shader * shader_alloc(const char *name) 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()
static const char * mtl_extensions_get_null(int)
static int get_num_performance_cpu_cores(id< MTLDevice > device)
bool supports_barycentric_whitelist(id< MTLDevice > device)
static int get_num_efficiency_cpu_cores(id< MTLDevice > device)
thread_local int g_autoreleasepool_depth
bool is_apple_sillicon(id< MTLDevice > device)
thread_local NSAutoreleasePool * g_autoreleasepool
bool mip_render_workaround
int max_shader_storage_buffer_bindings
int max_parallel_compilations
bool geometry_shader_support
int max_work_group_size[3]
bool use_main_context_workaround
bool depth_blitting_workaround
bool hdr_viewport_support
int minimum_per_vertex_stride
int max_work_group_count[3]
const char *(* extension_get)(int)
bool shader_draw_parameters_support
bool transform_feedback_support
bool clear_viewport_workaround
bool stencil_export_support
size_t max_storage_buffer_size
bool supports_argument_buffers_tier2
int num_performance_cores
bool supports_family_mac2
bool supports_texture_atomics
bool supports_texture_gather
bool supports_family_mac1
bool supports_family_mac_catalyst2
bool supports_family_mac_catalyst1