aboutsummaryrefslogtreecommitdiffstats

imggen

Local SDXL image generation on an Intel Arc B580 (12GB) under Slackware, via a container that carries the Intel Level Zero runtime the host distro does not package. Prompt in, PNG on the host out.

Why this exists (and its limits)

The Arc B580 runs SDXL's compute fast (~31 UNet it/s warm), but its memory is tight. Stock SDXL fp16 OOMs at VAE decode on 12GB because diffusers upcasts the VAE to fp32. Swapping in the fp16-fix VAE removes that upcast and the whole pipeline fits, at roughly 6.3s per warm 1024x1024 image, 25 steps.

Measured peak VRAM for the working config is 9.07 GB on a 12GB card, so there is roughly 2.5-3 GB of real headroom, not zero.

Known to work:

  • SDXL base, single image, 1024x1024, ~25 steps. ~6.3s warm.

Plausibly fits in the remaining headroom (UNTESTED, try before assuming):

  • A second batched image, or modest resolution bumps above 1024.
  • Light img2img.

Probably does NOT fit (a second resident model exceeds ~3GB):

  • SDXL refiner co-resident with base.

Does NOT fit:

  • Flux (any variant). Far heavier than the available margin.

If you want the refiner or Flux, that is the signal to move that tier of work to a RunPod serverless endpoint rather than fighting 12GB. Local covers the light case comfortably and may stretch a little past it; it does not reach the heavy tier.

Build

The Dockerfile is PINNED to the exact versions captured from the known-good test container (torch 2.12.1+xpu, diffusers 0.39.0, transformers 5.13.0, etc., on oneAPI 2025.3.2 / Ubuntu 24.04.4). These produced ~6.3s warm SDXL-base images with 9.07 GB peak VRAM on an Arc B580.

Build:

docker build -t imggen:local .

If the base image tag intel/oneapi-basekit:2025.3.2-0-devel-ubuntu24.04 is not available on Docker Hub, substitute the closest 2025.3.x tag and record what you used. Do not fall back to :latest.

Install the wrapper

cp imggen ~/bin/imggen      # or anywhere on your PATH
chmod +x ~/bin/imggen

Usage

imggen "a red bicycle against a stone wall"
imggen "a foggy harbour at dawn" --steps 30 --seed 42
imggen "portrait of a fox" -o fox.png -n "blurry, low quality"

Output lands in ~/imggen-out by default. Models cache in ~/.cache/imggen-models so the ~7.5GB download happens once.

Override paths with env vars:

IMGGEN_OUT=/srv/blog/img IMGGEN_CACHE=/mnt/models imggen "a lighthouse"

First run

The first invocation downloads SDXL base + the fp16-fix VAE (~7.5GB) into the cache volume. That run is network-bound and slow. Subsequent runs skip the download. The first generation in any fresh container is also slower (~7.3s) due to one-time kernel compilation; warm runs settle to ~6.3s.

Upgrading

Treat upgrades as deliberate, tested events. Do not pip install -U casually. This working state depends on a specific torch-XPU build, a specific diffusers version, and the fp16-fix VAE. If you rebuild with newer versions, keep the old pinned Dockerfile in git so you can revert when something breaks.

Trial

This is a time-boxed experiment. Run it against real blog work for a few weeks. If it sticks, keep it. If it does not, the fallback is a RunPod serverless ComfyUI endpoint wrapped in the same imggen CLI shape, which trades local privacy for the ability to run heavier models (Flux, refiner, batching) on-demand at zero idle cost.