Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
f3ef296
feat(backend): add Intel XPU (torch.xpu) device support
Jul 31, 2026
97e1d83
test(backend): add XPU coverage for TorchDevice
Jul 31, 2026
cbf1cec
build: add [xpu] extra
Jul 31, 2026
db34e71
feat(backend): extend idle-GPU text encoder offload to XPU
Aug 1, 2026
1b1ad54
feat(ui): show the executing GPU for XPU sessions
Aug 1, 2026
7ba7b2f
fix(mm): gate Krea 2 fp8 encoder casting on fp8 storage support
Aug 1, 2026
55e37fd
chore: label XPU devices by index in load logs and fp8 help text
Aug 1, 2026
9bdd0c0
test: cover XPU config validation, progress device and fp8 probe
Aug 1, 2026
3488824
fix(nodes): recognise XPU out-of-memory errors in the Anima VAE retry
Aug 1, 2026
930e702
style: wrap long vram_usage_gb ternary for ruff
LexiconCode Aug 2, 2026
6ecaa8d
fix: drop CUDA-only wording from progress device description
LexiconCode Aug 2, 2026
b6bf7a3
docs: regenerate settings data for xpu device values
LexiconCode Aug 2, 2026
5d3baf0
fix: stop xpu VRAM probe from reporting an unknown total as zero
LexiconCode Aug 2, 2026
4e2fa56
fix: probe fp8 support on the target device, per device, without cach…
LexiconCode Aug 2, 2026
13025e8
fix: pin torch current device when borrowing an idle GPU
LexiconCode Aug 2, 2026
7e8245f
fix: keep idle-GPU borrows within one device type
LexiconCode Aug 2, 2026
6950ca8
feat: detect Intel integrated GPUs via Level Zero
LexiconCode Aug 2, 2026
21b7324
feat: add xpu torch index to pins.json
LexiconCode Aug 2, 2026
f603de5
fix: report VRAM diagnostics for the device in use
LexiconCode Aug 2, 2026
25e2b4e
docs: record why xpu takes the CUDA VAE constants and keeps the broad…
LexiconCode Aug 2, 2026
8c05cf5
fix: derive rand_device metadata from the backend's devices
LexiconCode Aug 2, 2026
99e8c71
docs: add Intel Arc install, driver and VRAM-reporting notes
LexiconCode Aug 2, 2026
506ef5b
fix: probe fp8 device support only when a model requests it
LexiconCode Aug 2, 2026
27c8b56
fix: query Level Zero Sysman for driver-global free VRAM on xpu
LexiconCode Aug 2, 2026
7ae8cd0
fix: make the fp8 probe mirror the runtime cast path
LexiconCode Aug 2, 2026
789180b
fix: degrade gracefully when a backend cannot name a device
LexiconCode Aug 2, 2026
3d3c86b
fix: resolve an index-less device in the Sysman VRAM query
LexiconCode Aug 2, 2026
4eb540b
fix: declare ctypes prototypes for the Level Zero calls
LexiconCode Aug 2, 2026
1fffa2a
fix: drop the ZES_ENABLE_SYSMAN mutation from the Sysman probe
LexiconCode Aug 2, 2026
a779812
refactor: tidy up the xpu additions after a cleanup review
LexiconCode Aug 2, 2026
82372a1
build: pin the xpu extra to torch 2.13.0
LexiconCode Aug 2, 2026
3700e37
test: stub Sysman in the unknown-total xpu probe test
LexiconCode Aug 9, 2026
7cc6de3
build: teach the pins check about the xpu index
LexiconCode Aug 9, 2026
0123ffa
fix: defer the xpu device pin like cuda's
LexiconCode Aug 9, 2026
0f5272b
docs: regenerate settings data on linux
LexiconCode Aug 9, 2026
77f2d07
fix(mm): handle shared memory on integrated GPUs
LexiconCode Aug 9, 2026
f779454
docs: note intel device selection and integrated-GPU memory
LexiconCode Aug 9, 2026
c5b83b6
chore(ui): typegen for the xpu device values
LexiconCode Aug 13, 2026
961c443
Merge branch 'main' into feat/intel-xpu-support
lstein Aug 15, 2026
0645f90
fix(mm): compare the integrated-GPU full-load guard against bytes sti…
lstein Aug 15, 2026
d04d443
test: run the integrated-GPU cache tests on CPU-only torch
lstein Aug 15, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions docs/src/content/docs/start-here/manual.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,12 @@ The following commands vary depending on the version of Invoke being installed a
--torch-backend=cu128
```
</TabItem>
<TabItem label="Intel Arc GPU">
Use:
```sh
--torch-backend=xpu
```
</TabItem>
<TabItem label="Other / no GPU">
Do not use a torch backend.
</TabItem>
Expand Down Expand Up @@ -142,6 +148,12 @@ The following commands vary depending on the version of Invoke being installed a
This workaround applies to the reported ROCm case only.
:::
</TabItem>
<TabItem label="Linux + Intel Arc GPU">
Use:
```sh
--torch-backend=xpu
```
</TabItem>
<TabItem label="All other cases">
Do not use a torch backend.
</TabItem>
Expand Down
32 changes: 31 additions & 1 deletion docs/src/content/docs/start-here/system-requirements.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ The requirements below are rough guidelines for best performance. GPUs with less

- All Apple Silicon (M1, M2, etc) Macs work, but 16GB+ memory is recommended.
- AMD GPUs are supported on Linux only. The VRAM requirements are the same as Nvidia GPUs.
- Intel Arc GPUs (Alchemist, Battlemage and newer) are supported on Windows and Linux `x86_64`. The VRAM requirements are the same as Nvidia GPUs.
- Linux ARM64 (`aarch64`) devices — e.g. Raspberry Pi 5, other SBCs, ARM servers — are supported in CPU-only mode. Local generation is slow without a GPU, but API-backed models (e.g. GPT Image, Gemini) work well.

### Windows/Linux
Expand Down Expand Up @@ -74,7 +75,34 @@ Check that your system has an up-to-date Python installed by running `python3 --

## Drivers

If you have an Nvidia or AMD GPU, you may need to manually install drivers or other support packages for things to work well or at all.
If you have an Nvidia, AMD or Intel GPU, you may need to manually install drivers or other support packages for things to work well or at all.

### Intel

Intel Arc support uses PyTorch's native XPU backend, so no separate oneAPI toolkit install is required — the runtime libraries come in with the `xpu` torch wheels. You do need an up-to-date **GPU driver**.

- **Windows:** install the latest [Intel Arc & Iris Xe Graphics driver]. Older drivers are a common cause of failures on Battlemage cards.
- **Linux:** install the client GPU driver packages by following the [Intel client GPU install guide]. Kernel 6.8+ (or the `xe`/`i915` backport packages) is required.

Verify the GPU is visible to PyTorch:

```sh
python -c "import torch; print(torch.xpu.is_available(), torch.xpu.device_count())"
```

:::note[Integrated GPUs]
Level Zero enumerates your CPU's integrated GPU alongside any discrete Arc card. Invoke excludes integrated GPUs from automatic device selection when a discrete GPU is present. To use one anyway, name it explicitly in the `generation_devices` setting.

An integrated GPU shares its memory with the CPU, so Invoke does not keep a second RAM copy of a model's weights there — that copy would double each model's footprint against the same memory. `keep_ram_copy_of_weights` is ignored on such a device, and a warning says so once. Partial loading still applies, so device residency stays bounded.
:::

:::note[Both an Nvidia and an Intel GPU?]
Automatic device selection prefers CUDA: if any Nvidia GPU is visible, `auto` enumerates only those and your Arc card is left unused. Name it explicitly to generate on it, e.g. `generation_devices: [xpu:0]`.
:::

:::caution[Free VRAM reporting]
Some driver and kernel combinations — notably GPU passthrough VMs and WSL2 — cannot report free VRAM to PyTorch. Invoke falls back to estimating it, which ignores memory used by *other* processes on the same GPU. If you share the GPU with other workloads and hit out-of-memory errors, set `max_cache_vram_gb` explicitly rather than relying on the estimate. A warning is logged once per device when this fallback is in use.
:::

### Nvidia

Expand Down Expand Up @@ -139,5 +167,7 @@ An alternative to installing ROCm locally is to use a [ROCm docker container] to
[CUDA Toolkit Downloads]: https://developer.nvidia.com/cuda-downloads
[Cuda Docs]: https://developer.nvidia.com/cudnn
[cuDNN support matrix]: https://docs.nvidia.com/deeplearning/cudnn/support-matrix/index.html
[Intel Arc & Iris Xe Graphics driver]: https://www.intel.com/content/www/us/en/download/785597/intel-arc-iris-xe-graphics-windows.html
[Intel client GPU install guide]: https://dgpu-docs.intel.com/driver/client/overview.html
[ROCm Documentation]: https://rocmdocs.amd.com
[ROCm docker container]: https://rocmdocs.amd.com/en/latest/Deep_learning/Deep_learning.html#docker-containers
4 changes: 2 additions & 2 deletions docs/src/generated/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -504,7 +504,7 @@
{
"category": "DEVICE",
"default": "auto",
"description": "Preferred execution device. `auto` will choose the device depending on the hardware platform and the installed torch capabilities.<br>Valid values: `auto`, `cpu`, `cuda`, `mps`, `cuda:N` (where N is a device number)",
"description": "Preferred execution device. `auto` will choose the device depending on the hardware platform and the installed torch capabilities.<br>Valid values: `auto`, `cpu`, `cuda`, `mps`, `xpu`, `cuda:N`, `xpu:N` (where N is a device number)",
"env_var": "INVOKEAI_DEVICE",
"literal_values": [],
"name": "device",
Expand All @@ -515,7 +515,7 @@
{
"category": "DEVICE",
"default": "auto",
"description": "Devices to use for parallel generation. `auto` (the default) uses every available GPU, running one generation session per GPU concurrently and distributing jobs fairly across users \u2014 unless the legacy `device` setting is pinned to a specific device, in which case `auto` uses only that device (preserving configs that pinned `device` before multi-GPU support existed). Provide an explicit list (e.g. `[cuda:0, cuda:1]`) to use specific devices regardless of `device`, or a single-device list (e.g. `[cuda:0]`) to run serially. On systems without a GPU, `auto` resolves to the single `cpu`/`mps` device.<br>Valid values: `auto`, or a list whose entries are each `cpu`, `cuda`, `mps`, or `cuda:N` (where N is a device number)",
"description": "Devices to use for parallel generation. `auto` (the default) uses every available GPU, running one generation session per GPU concurrently and distributing jobs fairly across users \u2014 unless the legacy `device` setting is pinned to a specific device, in which case `auto` uses only that device (preserving configs that pinned `device` before multi-GPU support existed). Provide an explicit list (e.g. `[cuda:0, cuda:1]`) to use specific devices regardless of `device`, or a single-device list (e.g. `[cuda:0]`) to run serially. On systems without a GPU, `auto` resolves to the single `cpu`/`mps` device.<br>Valid values: `auto`, or a list whose entries are each `cpu`, `cuda`, `mps`, `xpu`, `cuda:N`, or `xpu:N` (where N is a device number)",
"env_var": "INVOKEAI_GENERATION_DEVICES",
"literal_values": [],
"name": "generation_devices",
Expand Down
13 changes: 11 additions & 2 deletions invokeai/app/api/routers/app_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ def _remove_nullable_default_from_schema(schema: dict[str, Any]) -> None:
schema.update(non_null_schemas[0])


_GENERATION_DEVICE_PATTERN = re.compile(r"^(cpu|mps|cuda(:\d+)?)$")
_GENERATION_DEVICE_PATTERN = re.compile(r"^(cpu|mps|xpu(:\d+)?|cuda(:\d+)?)$")


class GenerationDeviceOption(BaseModel):
Expand Down Expand Up @@ -163,7 +163,8 @@ def validate_generation_devices(
for device in v:
if not _GENERATION_DEVICE_PATTERN.match(device):
raise ValueError(
f"Invalid generation device '{device}'. Valid values are 'auto', 'cpu', 'mps', 'cuda', or 'cuda:N'."
f"Invalid generation device '{device}'. Valid values are 'auto', 'cpu', 'mps', 'cuda', 'cuda:N', "
"'xpu', or 'xpu:N'."
)
return v

Expand Down Expand Up @@ -227,6 +228,14 @@ async def get_generation_device_options(current_user: CurrentUserOrDefault) -> l
except Exception:
name = device
options.append(GenerationDeviceOption(device=device, name=name))
elif hasattr(torch, "xpu") and torch.xpu.is_available():
for index in range(torch.xpu.device_count()):
device = f"xpu:{index}"
try:
name = torch.xpu.get_device_name(index)
except Exception:
name = device
options.append(GenerationDeviceOption(device=device, name=name))
elif torch.backends.mps.is_available():
options.append(GenerationDeviceOption(device="mps", name="Apple MPS"))
else:
Expand Down
30 changes: 24 additions & 6 deletions invokeai/app/invocations/anima_latents_to_image.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,16 +42,31 @@


def _is_oom_error(e: RuntimeError) -> bool:
"""Return True if the error indicates a CUDA out-of-memory condition.
"""Return True if the error indicates an out-of-memory condition.

The caching allocator raises torch.cuda.OutOfMemoryError, but an OOM surfaced from inside a
cuDNN/cuBLAS kernel (e.g. workspace allocation in the Wan VAE's convolutions) arrives as a
plain RuntimeError, which must be matched by message.
plain RuntimeError, which must be matched by message. XPU exhaustion likewise arrives as a
plain RuntimeError, naming the Level Zero/UR result code (`..._OUT_OF_DEVICE_MEMORY`) rather
than the words "out of memory" -- so it needs its own spelling to be matched here.

`out_of_host_memory` is knowingly over-broad: Level Zero returns it for driver-side resource
failures generally (kernel compilation, handle exhaustion), not only host allocation. Matching
it means a genuinely broken decode costs one wasted tiled retry before the error re-raises
unchanged. That is preferred over the alternative -- a real host-memory exhaustion that skips
the retry -- because the retry is bounded and non-destructive, while a missed OOM fails a
generation that would have succeeded tiled.
"""
if isinstance(e, torch.cuda.OutOfMemoryError):
return True
msg = str(e)
return "out of memory" in msg.lower() or "CUDNN_STATUS_ALLOC_FAILED" in msg or "CUBLAS_STATUS_ALLOC_FAILED" in msg
msg = str(e).lower()
return (
"out of memory" in msg
or "out_of_device_memory" in msg
or "out_of_host_memory" in msg
or "cudnn_status_alloc_failed" in msg
or "cublas_status_alloc_failed" in msg
)


@invocation(
Expand Down Expand Up @@ -83,9 +98,12 @@ def _use_tiled_decode(device: torch.device, full_decode_working_memory: int) ->
memory would consume most of the device, otherwise a single-pass decode is
faster (~0.65s vs ~1.05s at 1024x1024) and exact.
"""
if device.type != "cuda":
if device.type == "cuda":
total_vram = torch.cuda.get_device_properties(device).total_memory
elif device.type == "xpu":
total_vram = torch.xpu.get_device_properties(device).total_memory
else:
return False
total_vram = torch.cuda.get_device_properties(device).total_memory
return full_decode_working_memory > 0.7 * total_vram

@torch.no_grad()
Expand Down
2 changes: 1 addition & 1 deletion invokeai/app/invocations/blend_latents.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ def invoke(self, context: InvocationContext) -> LatentsOutput:

# https://discuss.huggingface.co/t/memory-usage-by-later-pipeline-stages/23699
blended_latents = blended_latents.to("cpu")
torch.cuda.empty_cache()
TorchDevice.empty_cache()

name = context.tensors.save(tensor=blended_latents)
return LatentsOutput.build(latents_name=name, latents=blended_latents)
3 changes: 2 additions & 1 deletion invokeai/app/invocations/qwen_image_text_encoder.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
ConditioningFieldData,
QwenImageConditioningInfo,
)
from invokeai.backend.util.devices import TorchDevice

# Prompt templates and drop indices for the two Qwen Image model modes.
# These are taken directly from the diffusers pipelines.
Expand Down Expand Up @@ -319,6 +320,6 @@ def cleanup():
nonlocal text_encoder
del text_encoder
gc.collect()
torch.cuda.empty_cache()
TorchDevice.empty_cache()

return text_encoder, device, cleanup
25 changes: 14 additions & 11 deletions invokeai/app/invocations/wan_latents_to_video.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,19 +132,22 @@ def invoke(self, context: InvocationContext) -> VideoOutput:
use_tiling = False
if not getattr(vae_info.config, "cpu_only", None):
exec_device = TorchDevice.choose_torch_device()
total_vram: int | None = None
if exec_device.type == "cuda":
total_vram = torch.cuda.get_device_properties(exec_device).total_memory
if estimated_working_memory > 0.9 * total_vram:
use_tiling = True
tile_size = int(getattr(vae_info.model, "tile_sample_min_height", 256))
estimated_working_memory = estimate_vae_working_memory_wan(
operation="decode",
vae=vae_info.model,
pixel_height=h_pixel,
pixel_width=w_pixel,
pixel_frames=t_pixel,
tile_size=tile_size,
)
elif exec_device.type == "xpu":
total_vram = torch.xpu.get_device_properties(exec_device).total_memory
if total_vram is not None and estimated_working_memory > 0.9 * total_vram:
use_tiling = True
tile_size = int(getattr(vae_info.model, "tile_sample_min_height", 256))
estimated_working_memory = estimate_vae_working_memory_wan(
operation="decode",
vae=vae_info.model,
pixel_height=h_pixel,
pixel_width=w_pixel,
pixel_frames=t_pixel,
tile_size=tile_size,
)

with vae_info.model_on_device(working_mem_bytes=estimated_working_memory) as (_, vae):
assert isinstance(vae, AutoencoderKLWan)
Expand Down
Loading
Loading