Skip to content

Vulkan: vkCreateDevice fails with ErrorExtensionNotPresent on a device reporting bf16: 0 #62

Description

@jkkma

Every model fails to load on the Vulkan backend on an AMD Radeon 880M (RDNA 3.5 integrated).
The backend enumerates the device, reports bf16: 0, and then requests a bfloat16 device extension
the driver does not expose, so vkCreateDevice fails and no model can be loaded at all.

Setting GGML_VK_DISABLE_BFLOAT16=1 fixes it completely, with cooperative matrices still enabled.

Environment

parakeet.cpp v0.5.0, prebuilt parakeet-v0.5.0-bin-win-vulkan-x64.zip
sha256 717c416fab299755e8140137e3a0115121ce1acb6379d13c60f2f0613f6c13a3
OS Windows 11 (10.0.26200), x64
GPU AMD Radeon 880M (integrated, RDNA 3.5), driver 32.0.13022.3006
Vulkan API 1.3.302, driverVersion 2.0.331
Model tdt-0.6b-v3-f16.gguf (also reproduced with tdt-0.6b-v3-q4_k.gguf)

Reproduction

Using only the prebuilt CLI from the release:

parakeet-cli transcribe --model tdt-0.6b-v3-f16.gguf --input short.wav

Output:

ggml_vulkan: Found 1 Vulkan devices:
ggml_vulkan: 0 = AMD Radeon(TM) 880M Graphics (AMD proprietary driver) | uma: 1 | fp16: 1 | bf16: 0 |
             warp size: 64 | shared memory: 32768 | int dot: 1 | matrix cores: KHR_coopmat
transcribe failed: vk::PhysicalDevice::createDevice: ErrorExtensionNotPresent
ERROR:             vkDestroyFence: Invalid device [VUID-vkDestroyFence-device-parameter]

The process then exits with 0xC0000409 (STATUS_STACK_BUFFER_OVERRUN) rather than a clean error
exit — the vkDestroyFence line is teardown running against the device that was never created.

Any 10-second 16 kHz mono PCM WAV reproduces it; the failure is at device creation, before the audio
is used.

Note that parakeet-cli info <model.gguf> succeeds on this machine. It reads GGUF metadata and
never creates a backend, so it is not a useful check for this.

The cause

VK_ERROR_EXTENSION_NOT_PRESENT from vkCreateDevice means a requested device extension is not
available. vulkaninfo on this device shows:

  • VK_KHR_cooperative_matrixpresent, extension revision 2
  • no bfloat16 extension of any kind — absent

The backend has already worked this out: it prints bf16: 0. It then requests a bfloat16 device
extension anyway, which cannot succeed. The capability check and the extension request appear to
disagree.

Workarounds, both confirmed

Setting Result Device line
(none) ErrorExtensionNotPresent matrix cores: KHR_coopmat
GGML_VK_DISABLE_BFLOAT16=1 works matrix cores: KHR_coopmat
GGML_VK_DISABLE_COOPMAT=1 works matrix cores: none

GGML_VK_DISABLE_BFLOAT16=1 is the better of the two — it keeps cooperative matrices enabled and is
about 1.36x faster than disabling coopmat wholesale (measured over a 600 s file, 3 runs each,
mean real-time factor 0.0349 against 0.0473, run-to-run range 3.2% and 5.3%).

That GGML_VK_DISABLE_COOPMAT=1 also avoids it suggests the bfloat16 extension is requested from
the cooperative-matrix path rather than independently.

Ruled out

  • Not the model or its size. f16 (1.34 GiB) and q4_k (644 MiB) fail identically. Both load
    and decode correctly on the cpu backend on the same machine, from the same files.
  • Not memory. maxMemoryAllocationSize and maxBufferSize are both 2 GiB, against a 7.75 GiB
    device-local heap with 7.36 GiB budget.
  • Not these, all of which still fail: GGML_VK_DISABLE_F16,
    GGML_VK_DISABLE_INTEGER_DOT_PRODUCT, GGML_VK_PREFER_HOST_MEMORY,
    GGML_VK_ALLOW_SYSMEM_FALLBACK, GGML_VK_DISABLE_HOST_VISIBLE_VIDMEM.

Once it loads, it works correctly

With the workaround, Vulkan output matches the CPU backend closely on a 600 s file: all 106 segment
boundaries identical, 1,605 words against 1,606 on CPU, first divergence a punctuation difference.
So this is purely a device-creation problem, not a correctness one.

Suggested fix

Do not request the bfloat16 device extension when the device does not advertise it — the same
condition that already produces bf16: 0 in the device line. A device that lacks it currently cannot
create a Vulkan device at all, which makes the backend unusable rather than degraded.

Two smaller points that would have saved a lot of time here:

  1. The C API (parakeet_capi_load) returns NULL with no message on this path, so anything using
    the shared library instead of the CLI sees a bare load failure with no cause. Surfacing the
    underlying error through parakeet_capi_last_error would make it diagnosable.
  2. Exiting via STATUS_STACK_BUFFER_OVERRUN in teardown after a failed device creation looks like
    memory corruption and sends you down the wrong path; guarding teardown on a device that was never
    created would fail cleanly.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions