Skip to content

Vulkan/RADV: --offload-to-cpu pins past the amdgpu GTT budget and loses the device; the VAE tiling retry then runs against a dead device #2015

Description

@linxuhao

Reporting this here because the reproduction lives in sd.cpp, and because one part of it is sd.cpp's to fix.

Setup

  • Radeon RX 7900 XTX, RADV (Mesa 25.2.8), kernel 7.0.0-31, 30 GiB system RAM
  • mem_info_gtt_total = 15591 MiB (amdgpu defaults GTT to about half of system RAM)
  • sd.cpp at c678dfe, built with -DSD_VULKAN=ON
  • Qwen-Image-2.1 Q8_0 + Qwen3-VL-8B-Instruct Q8_0 + qwen_image_2.1_vae_bf16
sd-cli --diffusion-model qwen_image_2.1-Q8_0.gguf \
       --vae qwen_image_2.1_vae_bf16.safetensors \
       --llm Qwen3VL-8B-Instruct-Q8_0.gguf \
       --backend vulkan0 --fa --offload-to-cpu \
       --steps 20 --cfg-scale 6.0 --sampling-method euler -H 1024 -W 1024 -p "..."
radv/amdgpu: Not enough memory for command submission.
[ERROR] ggml_vulkan: device lost on Vulkan0
[ERROR] wan_vae graph execution failed on Vulkan0: vk::Queue::submit: ErrorDeviceLost
[WARN ] backend_fit.cpp:501 - VAE decode failed (likely out of memory); retrying with spatial tiling

This is not VRAM exhaustion — the card has 24 GiB and peak usage was ~8 GiB. --offload-to-cpu pins about 16.7 GiB of weights as host-visible Vulkan buffers, and amdgpu's GTT budget is 15.23 GiB. I filed the ggml side as ggml-org/llama.cpp#29213 with the measurements; it should reach this repo when the ggml submodule is next synced.

The part that is sd.cpp's

backend_fit.cpp:501 retries the VAE decode with spatial tiling after the device has been lost, so the retry cannot succeed — the whole context is gone. It would be worth checking whether the device is still alive before retrying, and failing with the original error if it is not; right now the log reads as if tiling was tried and did not help, when in fact tiling was never really attempted.

Starting with --vae-tiling from the outset does work on the same machine: the decode compute buffer drops from 11322 MB to 2556 MB and the decode takes 4.6 s.

Two smaller things

--vae-tile-size is in latent units, not pixels, and the help text does not say so. At 1024×1024 the latent is 128×128, so --vae-tile-size 256x256 yields num tiles : 1, 1 — tiling silently does nothing. I lost a while to this while assuming tiling could not help.

--fa vs --diffusion-fa for Qwen-Image-2.1. The LLM text encoder path uses ctx->flash_attn_enabled, which --diffusion-fa does not set, so a command line carried over from a FLUX setup leaves flash attention off for the text encoder without any indication. Possibly worth a note in docs/qwen_image_2.1.md.

For reference, what works on this machine

--backend vulkan0 --fa --vae-tiling with no --offload-to-cpu: the weights (16.7 GiB) go straight to VRAM, GTT is not involved at all, and 1024×1024 takes 139 s (text encode 18 s, sampling 116 s, VAE 4.5 s), peak 17.74 GiB. With a reference image, 272 s and peak 18.93 GiB.

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