diff --git a/drivers/metal/metal_device_properties.h b/drivers/metal/metal_device_properties.h index 24a1a4cdf99..5cc8a1217f0 100644 --- a/drivers/metal/metal_device_properties.h +++ b/drivers/metal/metal_device_properties.h @@ -94,8 +94,9 @@ struct API_AVAILABLE(macos(11.0), ios(14.0), tvos(14.0)) MetalFeatures { bool metal_fx_spatial = false; /**< If true, Metal FX spatial functions are supported. */ bool metal_fx_temporal = false; /**< If true, Metal FX temporal functions are supported. */ bool supports_gpu_address = false; /**< If true, referencing a GPU address in a shader is supported. */ - bool supports_image_atomic_32_bit = false; /**< If true, 32-bit atomic operations on images are supported. */ - bool supports_image_atomic_64_bit = false; /**< If true, 64-bit atomic operations on images are supported. */ + bool supports_image_atomic_32_bit = false; /**< If true, 32-bit atomic operations on images are supported by the GPU. */ + bool supports_image_atomic_64_bit = false; /**< If true, 64-bit atomic operations on images are supported by the GPU. */ + bool supports_native_image_atomics = false; /**< If true, native image atomic operations are supported by the OS. */ }; struct MetalLimits { diff --git a/drivers/metal/metal_device_properties.mm b/drivers/metal/metal_device_properties.mm index 4b06e24ad39..473cda8dbe9 100644 --- a/drivers/metal/metal_device_properties.mm +++ b/drivers/metal/metal_device_properties.mm @@ -122,10 +122,12 @@ void MetalDeviceProperties::init_features(id p_device) { features.simdReduction = [p_device supportsFamily:MTLGPUFamilyApple7]; features.argument_buffers_tier = p_device.argumentBuffersSupport; features.supports_image_atomic_32_bit = [p_device supportsFamily:MTLGPUFamilyApple6]; - features.supports_image_atomic_64_bit = [p_device supportsFamily:MTLGPUFamilyApple8]; + features.supports_image_atomic_64_bit = [p_device supportsFamily:MTLGPUFamilyApple9] || ([p_device supportsFamily:MTLGPUFamilyApple8] && [p_device supportsFamily:MTLGPUFamilyMac2]); + if (@available(macOS 14.0, iOS 17.0, tvOS 17.0, visionOS 1.0, *)) { + features.supports_native_image_atomics = true; + } if (OS::get_singleton()->get_environment("GODOT_MTL_DISABLE_IMAGE_ATOMICS") == "1") { - features.supports_image_atomic_32_bit = false; - features.supports_image_atomic_64_bit = false; + features.supports_native_image_atomics = false; } if (@available(macOS 13.0, iOS 16.0, tvOS 16.0, *)) { diff --git a/drivers/metal/rendering_device_driver_metal.mm b/drivers/metal/rendering_device_driver_metal.mm index e099e28a39b..3bdc7a8a425 100644 --- a/drivers/metal/rendering_device_driver_metal.mm +++ b/drivers/metal/rendering_device_driver_metal.mm @@ -330,14 +330,11 @@ RDD::TextureID RenderingDeviceDriverMetal::texture_create(const TextureFormat &p } if (p_format.usage_bits & TEXTURE_USAGE_STORAGE_ATOMIC_BIT) { + ERR_FAIL_COND_V_MSG((format_caps & kMTLFmtCapsAtomic) == 0, RDD::TextureID(), "Atomic operations on this texture format are not supported."); + ERR_FAIL_COND_V_MSG(!device_properties->features.supports_native_image_atomics, RDD::TextureID(), "Atomic operations on textures are not supported on this OS version. Check SUPPORTS_IMAGE_ATOMIC_32_BIT."); + // If supports_native_image_atomics is true, this condition should always succeed, as it is set the same. if (@available(macOS 14.0, iOS 17.0, tvOS 17.0, *)) { - if (format_caps & kMTLFmtCapsAtomic) { - desc.usage |= MTLTextureUsageShaderAtomic; - } else { - ERR_FAIL_V_MSG(RDD::TextureID(), "Atomic operations on this texture format are not supported."); - } - } else { - ERR_FAIL_V_MSG(RDD::TextureID(), "Atomic texture operations not supported on this OS version."); + desc.usage |= MTLTextureUsageShaderAtomic; } } @@ -368,34 +365,8 @@ RDD::TextureID RenderingDeviceDriverMetal::texture_create(const TextureFormat &p is_linear = std::get(is_linear_or_err); } - // Check if it is a linear format for atomic operations and therefore needs a buffer, - // as generally Metal does not support atomic operations on textures. - bool needs_buffer = is_linear; - - // Check for atomic requirements. - if (flags::any(p_format.usage_bits, TEXTURE_USAGE_STORAGE_BIT) && p_format.array_layers == 1 && p_format.mipmaps == 1 && p_format.texture_type == TEXTURE_TYPE_2D) { - switch (p_format.format) { - case RenderingDeviceCommons::DATA_FORMAT_R32_SINT: - case RenderingDeviceCommons::DATA_FORMAT_R32_UINT: { - if (!device_properties->features.supports_image_atomic_32_bit) { - // We can emulate 32-bit atomic operations on textures. - needs_buffer = true; - } - } break; - case RenderingDeviceCommons::DATA_FORMAT_R32G32_SINT: - case RenderingDeviceCommons::DATA_FORMAT_R32G32_UINT: { - if (!device_properties->features.supports_image_atomic_64_bit) { - // No emulation for 64-bit atomics. - ERR_FAIL_V_MSG(TextureID(), "64-bit atomic operations are not supported."); - } - } break; - default: - break; - } - } - id obj = nil; - if (needs_buffer) { + if (is_linear) { // Linear textures are restricted to 2D textures, a single mipmap level and a single array layer. MTLPixelFormat pixel_format = desc.pixelFormat; size_t row_alignment = get_texel_buffer_alignment_for_format(p_format.format); @@ -2771,7 +2742,7 @@ bool RenderingDeviceDriverMetal::has_feature(Features p_feature) { case SUPPORTS_METALFX_TEMPORAL: return device_properties->features.metal_fx_temporal; case SUPPORTS_IMAGE_ATOMIC_32_BIT: - return device_properties->features.supports_image_atomic_32_bit; + return device_properties->features.supports_native_image_atomics; default: return false; }