瀏覽代碼

Metal: Remove invalid assumption for image atomic operations

Fix image atomic checks, which require minimum OS version too.

Closes #108445
Stuart Carnie 2 周之前
父節點
當前提交
338816236b

+ 3 - 2
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 {

+ 5 - 3
drivers/metal/metal_device_properties.mm

@@ -122,10 +122,12 @@ void MetalDeviceProperties::init_features(id<MTLDevice> 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, *)) {

+ 6 - 35
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<bool>(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<MTLTexture> 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;
 	}