Studio diffusion (Phase 16): route no-GPU loads to the native sd.cpp engine

When no CUDA/ROCm/XPU GPU is available, route diffusion load/generate to the
native stable-diffusion.cpp engine instead of diffusers, with diffusers as the
guaranteed fallback. On CPU sd.cpp is 1.4-2.8x faster and uses 1.5-2.2x less RAM.

- diffusion_engine_router: centralised engine selection (built on the existing
  select_diffusion_engine), env opt-outs, MPS gating, recorded fallback reason.
- sd_cpp_backend (SdCppDiffusionBackend): the diffusers backend method surface
  backed by sd-cli, with lazy binary install, registry-driven asset fetch,
  step-progress parsing, and cancellation.
- diffusion_families: per-family single-file VAE + text-encoder asset mapping.
- sd_cpp_engine: cancellation support (process-group kill + SdCppCancelled).
- routes/inference + gpu_arbiter: drive the active engine via the router; the
  API now reports the active engine and any fallback reason.
- tests for the backend, router, route selection, and cancellation.
This commit is contained in:
Daniel Han 2026-06-28 04:30:21 +00:00
commit 7f3c206fa1
11 changed files with 1241 additions and 27 deletions

View file

@ -78,7 +78,10 @@ def test_find_returns_none_when_absent(tmp_path, monkeypatch):
# ── availability / version ──────────────────────────────────────────────────
def test_engine_unavailable_when_no_binary():
def test_engine_unavailable_when_no_binary(monkeypatch):
# Force the "no binary anywhere" condition so the test is hermetic even on a host
# that happens to have sd-cli installed.
monkeypatch.setattr(eng, "find_sd_cpp_binary", lambda: None)
e = SdCppEngine(binary = None)
assert e.is_available() is False
assert e.version() is None
@ -350,12 +353,13 @@ def test_upscale_runs_and_returns_path(tmp_path, monkeypatch):
assert "--upscale-model" in _FakePopen.captured_cmd
def test_upscale_raises_when_binary_missing():
def test_upscale_raises_when_binary_missing(monkeypatch, tmp_path):
monkeypatch.setattr(eng, "find_sd_cpp_binary", lambda: None)
e = SdCppEngine(binary = None)
with pytest.raises(RuntimeError, match = "not found"):
e.upscale(
SdCppUpscaleParams(input_image = "/i.png", upscale_model = "/m/e.pth"),
output_path = "/tmp/x.png",
output_path = str(tmp_path / "x.png"),
)