From 3ff67eb43d362b6720a4f1fc745931fd3e8a78d6 Mon Sep 17 00:00:00 2001 From: Julian Pscheid Date: Thu, 10 Sep 2026 03:42:23 -0700 Subject: [PATCH] vulkan: fall back to shared-memory reduction for dmmv on PowerVR (#28341) The Imagination proprietary Vulkan compiler returns VK_ERROR_UNKNOWN from vkCreateComputePipelines for every dequant mul_mat_vec shader built with the subgroup-only reduction that requires a subgroup size >= 16. That covers the k-quants, the i-quants, TQ2_0, MXFP4 and NVFP4. ggml rethrows, so the first generated token of any such model kills the process. Reproduced on a Pixel 11 Pro (PowerVR C-Series CXTP-48-1536 MC1, driver 1.662.3024, subgroup size 128, min 32, max 128). The failure is independent of subgroup size: 32, 64 and 128 all fail, as does dropping the full-subgroups flag and the required-subgroup-size pNext. The legacy quants, which use the plain subgroup reduction, compile and run fine. The shared-memory reduction variant compiles and matches the CPU reference for q2_K, q3_K, q4_K, q5_K and q6_K. The hybrid variant also compiles but costs 27% of token throughput (3.78 vs 5.20 t/s on Qwen3.5-2B-Q4_K_M). --- ggml/src/ggml-vulkan/ggml-vulkan.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ggml/src/ggml-vulkan/ggml-vulkan.cpp b/ggml/src/ggml-vulkan/ggml-vulkan.cpp index cefe186fee..870fa11558 100644 --- a/ggml/src/ggml-vulkan/ggml-vulkan.cpp +++ b/ggml/src/ggml-vulkan/ggml-vulkan.cpp @@ -5480,8 +5480,12 @@ static void ggml_vk_load_shaders(vk_device& device, vk_pipeline requested) { uint32_t rm_iq = 2 * rm_kq; const bool use_subgroups = device->subgroup_arithmetic; + // The Imagination proprietary compiler rejects the subgroup-only dequant mul_mat_vec + // shaders that require a subgroup size >= 16; fall back to shared-memory reduction. + const bool is_imagination_proprietary = + device->driver_id == vk::DriverId::eImaginationProprietary; // Ensure a subgroup size >= 16 is available - const bool use_subgroups16 = use_subgroups && subgroup_min_size_16; + const bool use_subgroups16 = use_subgroups && subgroup_min_size_16 && !is_imagination_proprietary; const uint32_t subgroup_size = (device->vendor_id == VK_VENDOR_ID_INTEL && device->subgroup_size_control && device->subgroup_min_size <= 16 && device->subgroup_max_size >= 16) ? 16 : device->subgroup_size; const uint32_t subgroup_size16 = std::max(subgroup_size, 16u);