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).
This commit is contained in:
Julian Pscheid
2026-09-10 03:42:23 -07:00
committed by GitHub
parent 8c322d5bc4
commit 3ff67eb43d
+5 -1
View File
@@ -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);