From 4efd36e84319b5f90ff370549aaa763e1402b262 Mon Sep 17 00:00:00 2001 From: Cristian Sfercoci Date: Sun, 17 May 2026 19:42:08 +0300 Subject: [PATCH] vulkan: fix flash attention garbage output on MoltenVK with AMD GPUs Scalar flash attention produces garbled output on macOS with AMD GPUs through MoltenVK. The issue was introduced in b8143 (PR #19625) which refactored the scalar FA shader to use subgroupShuffleXor for reductions instead of shared memory. MoltenVK reports subgroupShuffle as supported but the Metal translation of subgroupShuffleXor is broken, producing incorrect shuffle results. The shader already has a fallback path for SubGroupSize == 0 that uses shared memory XOR reductions (the pre-b8143 approach). This fix disables subgroup use for MoltenVK+AMD, forcing the shared memory path which produces correct results. Analogous to the existing Intel workaround in the same function which disables subgroups due to performance issues with subgroup sizes. Fixes #20029 --- ggml/src/ggml-vulkan/ggml-vulkan.cpp | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/ggml/src/ggml-vulkan/ggml-vulkan.cpp b/ggml/src/ggml-vulkan/ggml-vulkan.cpp index a296d0ab4467..8f48ded42d2a 100644 --- a/ggml/src/ggml-vulkan/ggml-vulkan.cpp +++ b/ggml/src/ggml-vulkan/ggml-vulkan.cpp @@ -2950,8 +2950,13 @@ static vk_fa_tuning_params get_fa_tuning_params_scalar(const vk_device& device, vk_fa_tuning_params result{}; result.path = FA_SCALAR; - if (device->vendor_id == VK_VENDOR_ID_INTEL) { - // Disable subgroup use due to performance issues when enforcing subgroup sizes + if (device->vendor_id == VK_VENDOR_ID_INTEL +#ifdef __APPLE__ + || (device->vendor_id == VK_VENDOR_ID_AMD && device->driver_id == vk::DriverId::eMoltenvk) +#endif + ) { + // Disable subgroup use — Intel has performance issues with subgroup sizes, + // MoltenVK/AMD has broken subgroupShuffleXor (Metal translation bug) result.subgroup_size = 32; result.disable_subgroups = true; } else if (device->vendor_id == VK_VENDOR_ID_AMD && device->architecture != AMD_GCN) { @@ -5240,23 +5245,22 @@ static vk_device ggml_vk_get_device(size_t idx) { (vk11_props.subgroupSupportedOperations & vk::SubgroupFeatureFlagBits::eBasic); device->subgroup_arithmetic = (vk11_props.subgroupSupportedStages & vk::ShaderStageFlagBits::eCompute) && (vk11_props.subgroupSupportedOperations & vk::SubgroupFeatureFlagBits::eArithmetic); -#ifdef __APPLE__ - // Workaround for subgroup arithmetic failing on MoltenVK with AMD GPUs (issue 15846) - if (device->vendor_id == VK_VENDOR_ID_AMD) { - device->subgroup_arithmetic = false; - } -#endif device->subgroup_shuffle = (vk11_props.subgroupSupportedStages & vk::ShaderStageFlagBits::eCompute) && (vk11_props.subgroupSupportedOperations & vk::SubgroupFeatureFlagBits::eShuffle); device->subgroup_clustered = (vk11_props.subgroupSupportedStages & vk::ShaderStageFlagBits::eCompute) && (vk11_props.subgroupSupportedOperations & vk::SubgroupFeatureFlagBits::eClustered); - device->subgroup_ballot = (vk11_props.subgroupSupportedStages & vk::ShaderStageFlagBits::eCompute) && (vk11_props.subgroupSupportedOperations & vk::SubgroupFeatureFlagBits::eBallot); - device->subgroup_vote = (vk11_props.subgroupSupportedStages & vk::ShaderStageFlagBits::eCompute) && (vk11_props.subgroupSupportedOperations & vk::SubgroupFeatureFlagBits::eVote); +#ifdef __APPLE__ + // Workaround for subgroup arithmetic failing on MoltenVK with AMD GPUs (issue 15846) + if (device->vendor_id == VK_VENDOR_ID_AMD) { + device->subgroup_arithmetic = false; + } +#endif + const bool force_disable_f16 = getenv("GGML_VK_DISABLE_F16") != nullptr; device->fp16 = !force_disable_f16 && fp16_storage && fp16_compute;