193 lines
12 KiB
Markdown
193 lines
12 KiB
Markdown
# Linux Port Plan for Local AI Image Generator
|
||
|
||
> **Plan location**: This plan will be copied to the project root as `PLAN.md` upon approval, per user request.
|
||
|
||
> **Implementation Update (post-verification)**
|
||
>
|
||
> During end-to-end testing, the third-party Linux CUDA binary (`leaxer-ai/leaxer-stable-diffusion`) was found to **segfault during generation** after successfully loading the model. As a result, Linux CUDA support was **removed** from the implementation. Linux NVIDIA GPUs now use the **Vulkan** backend. The setup script also gained a glibc version check, because the official leejet Linux binaries require **glibc 2.38+** (Ubuntu 24.04). The frontend's misleading "mock SVG" fallback was replaced with a real error message when the backend crashes. See the updated README for build-from-source instructions.
|
||
|
||
## 1. What This Project Does
|
||
|
||
**Local AI Image Generator** is a zero-configuration, portable desktop environment for running Stable Diffusion (Safetensors / GGUF / CKPT) completely offline. The Windows flow is:
|
||
|
||
1. **Entry Point**: `start.bat` double-click launcher.
|
||
2. **Setup**: `scripts/setup.ps1` auto-downloads portable Node.js for Windows, detects the GPU vendor, downloads the matching stable-diffusion.cpp backend (CUDA for NVIDIA, Vulkan for AMD/Intel), installs npm dependencies, and builds the Vite+React frontend into `app/dist/`.
|
||
3. **Runtime**: `scripts/serve.cjs` (a Node.js HTTP server) serves the static frontend on `localhost:1420`, manages the backend process lifecycle, proxies generation requests, handles model downloads/imports, tracks telemetry, and manages the gallery.
|
||
4. **All sandboxed**: Everything lives under the project folder (`app/tools/`, `app/backend/`, `app/models/`, `app/outputs/`). No global PATH changes, no system installers.
|
||
|
||
## 2. Research Findings
|
||
|
||
### 2.1 stable-diffusion.cpp Linux Binaries
|
||
|
||
We researched the upstream project (`leejet/stable-diffusion.cpp`) and third-party builders. The following Linux x86_64 binaries are available:
|
||
|
||
| Backend | Source | Availability | Approx. Size | Notes |
|
||
|---|---|---|---|---|
|
||
| **CPU** | leejet official releases | ✅ Available | ~20–30 MB | Generic x86_64 CPU binary |
|
||
| **Vulkan** | leejet official releases | ✅ Available | ~100 MB | Cross-vendor GPU (AMD, Intel, NVIDIA) |
|
||
| **ROCm** | leejet official releases | ✅ Available | ~1.2 GB | AMD GPU; requires host ROCm kernel driver |
|
||
| **CUDA** | leejet official releases | ❌ **Not published** | N/A | See section 2.2 |
|
||
| **CUDA** | leaxer-ai/leaxer-stable-diffusion (third-party) | ❌ **Rejected** | ~115 MB | Loads models but **segfaults during generation**; removed from setup. |
|
||
|
||
**Critical Finding**: Upstream does **not** publish Linux CUDA binaries. There is an open feature request ([leejet/stable-diffusion.cpp#1291](https://github.com/leejet/stable-diffusion.cpp/issues/1291)) but no official support yet.
|
||
|
||
### 2.2 Linux CUDA Feasibility Analysis
|
||
|
||
We evaluated the third-party `leaxer-ai/leaxer-stable-diffusion` Linux CUDA binary:
|
||
- The binary downloads successfully and is a valid ELF executable.
|
||
- It loads models and initializes CUDA without errors.
|
||
- **However, it segfaults as soon as image generation starts** (reproduced on NVIDIA L4 with `TXT2IMG`).
|
||
- Because the binary is non-functional for its intended purpose, the project does **not** download or use it.
|
||
|
||
**Decision**: Linux CUDA support is **disabled** until a reliable prebuilt binary becomes available (either from upstream leejet or a verified third-party builder). Linux NVIDIA systems fall back to the **Vulkan** backend, which uses the same GPU via the NVIDIA Vulkan driver.
|
||
|
||
Users who need native CUDA performance on Linux can build `stable-diffusion.cpp` from source with `-DSD_CUDA=ON` and copy the resulting binary into `app/backend/linux/cuda/`; see README for instructions.
|
||
|
||
### 2.3 Portable Node.js for Linux
|
||
- Node.js distributes `node-v22.12.0-linux-x64.tar.xz` (matching the Windows LTS version already used).
|
||
- Fully portable: extract with `tar` and run `bin/node` / `bin/npm` directly.
|
||
|
||
### 2.4 Zero-Dependency GPU Detection on Linux
|
||
To avoid requiring `lspci`, `lshw`, or other host packages, we can parse PCI vendor IDs directly from sysfs:
|
||
- Read `/sys/bus/pci/devices/*/vendor`
|
||
- **NVIDIA**: `0x10de`
|
||
- **AMD**: `0x1002`
|
||
- **Intel**: `0x8086`
|
||
This is pure file I/O and works in any Linux environment with sysfs.
|
||
|
||
### 2.5 Extraction Strategy (No Host `unzip` Required)
|
||
- Node.js `.tar.xz` → extracted with `tar` (universally available on Linux).
|
||
- Backend `.zip` files → extracted using Node.js after bootstrapping (e.g., via `adm-zip` or a small inline script), or fall back to `python3 -m zipfile` if needed.
|
||
- NVIDIA CUDA redist `.tar.xz` → extracted with `tar`.
|
||
|
||
## 3. Implementation Approach: Maximum Performance (All Four Backends)
|
||
|
||
Based on your feedback, the recommended approach is to support **CPU + Vulkan + ROCm + CUDA** on Linux.
|
||
|
||
### 3.1 Backend Selection Matrix
|
||
|
||
| Vendor | Primary Backend | Fallback Backend | Source |
|
||
|---|---|---|---|
|
||
| NVIDIA | CUDA (best perf) | Vulkan | CUDA = leaxer third-party; Vulkan = leejet official |
|
||
| AMD | ROCm (best perf) | Vulkan | ROCm = leejet official; Vulkan = leejet official |
|
||
| Intel | Vulkan | CPU | Vulkan = leejet official |
|
||
| No GPU / Unknown | CPU | — | CPU = leejet official |
|
||
|
||
### 3.2 Backend Directory Layout (Linux)
|
||
|
||
```
|
||
app/backend/
|
||
├── win/
|
||
│ ├── cuda/sd-cuda.exe
|
||
│ └── vulkan/sd-vulkan.exe
|
||
└── linux/
|
||
├── cpu/sd-cpu
|
||
├── vulkan/sd-vulkan
|
||
├── rocm/sd-rocm + libstable-diffusion.so
|
||
└── cuda/sd-cuda + libstable-diffusion.so + libcudart.so.12 + libcublas.so.12 + libcublasLt.so.12
|
||
```
|
||
|
||
## 4. Files to Create / Modify
|
||
|
||
### New Files
|
||
1. **`start.sh`** — Bash entry point equivalent to `start.bat`.
|
||
- Checks for portable Node.js and frontend build.
|
||
- Runs `scripts/setup.sh` if anything is missing.
|
||
- Starts `scripts/serve.cjs` with the portable Node.js binary.
|
||
- Opens browser (`xdg-open`) or prints URL.
|
||
- Handles graceful shutdown (traps SIGINT/SIGTERM to kill backend).
|
||
|
||
2. **`scripts/setup.sh`** — Bash setup equivalent to `setup.ps1`.
|
||
- Downloads portable Node.js Linux tarball with `curl` + progress bar.
|
||
- Extracts with `tar`.
|
||
- Detects GPU via sysfs PCI vendor IDs.
|
||
- Downloads appropriate backends:
|
||
- **CPU + Vulkan** for everyone (baseline).
|
||
- **ROCm** if AMD GPU detected.
|
||
- **CUDA** if NVIDIA GPU detected (optional, due to large download).
|
||
- Downloads NVIDIA CUDA redist libraries if CUDA is selected.
|
||
- Extracts all archives using `tar` / Node.js / Python fallback.
|
||
- Renames binaries to predictable names.
|
||
- Runs `npm install` and `npm run build` using portable npm.
|
||
|
||
3. **`scripts/reset.sh`** — Bash reset equivalent to `reset.ps1`.
|
||
- Deletes `app/tools/`, `app/backend/`, `app/dist/`, `app/frontend/node_modules/` while preserving `app/models/` and `app/outputs/`.
|
||
|
||
### Modified Files
|
||
4. **`scripts/serve.cjs`** — Enhance Linux support.
|
||
- **Add Linux backend paths**:
|
||
```js
|
||
linuxCpu: path.join(ROOT, "app", "backend", "linux", "cpu", "sd-cpu"),
|
||
linuxVulkan: path.join(ROOT, "app", "backend", "linux", "vulkan", "sd-vulkan"),
|
||
linuxRocm: path.join(ROOT, "app", "backend", "linux", "rocm", "sd-rocm"),
|
||
linuxCuda: path.join(ROOT, "app", "backend", "linux", "cuda", "sd-cuda"),
|
||
```
|
||
- **Add Linux GPU detection** via sysfs (`/sys/bus/pci/devices/*/vendor`).
|
||
- **Update `getBackendOptions()`**: For Linux, return `cpu`, `vulkan`, `rocm` (if binary exists), and `cuda` (if binary + libraries exist).
|
||
- **Update `selectBackendPath()`**: Choose Linux backend based on resolved type; set `LD_LIBRARY_PATH` for CUDA/ROCm subprocesses so they find bundled `.so` files.
|
||
- **Update `getHealth()` / `getSetupPaths()`**: Include Linux backend checks.
|
||
- **Update `getGpuInfo()` / `hasNvidiaGpu()`**: Add Linux sysfs parsing.
|
||
- **CUDA VRAM polling**: Keep existing `nvidia-smi` approach; on Linux it works if drivers are installed.
|
||
|
||
5. **`README.md`** — Add Linux section with compatibility matrix, `./start.sh` usage, and known limitations.
|
||
|
||
## 5. Download Sources
|
||
|
||
| Component | URL Pattern |
|
||
|---|---|
|
||
| Portable Node.js | `https://nodejs.org/dist/v22.12.0/node-v22.12.0-linux-x64.tar.xz` |
|
||
| CPU Backend | `https://github.com/leejet/stable-diffusion.cpp/releases/download/master-XXX/sd-master-XXX-bin-Linux-Ubuntu-24.04-x86_64.zip` |
|
||
| Vulkan Backend | `https://github.com/leejet/stable-diffusion.cpp/releases/download/master-XXX/sd-master-XXX-bin-Linux-Ubuntu-24.04-x86_64-vulkan.zip` |
|
||
| ROCm Backend | `https://github.com/leejet/stable-diffusion.cpp/releases/download/master-XXX/sd-master-XXX-bin-Linux-Ubuntu-24.04-x86_64-rocm-7.13.0.zip` |
|
||
| CUDA Binary (third-party) | `https://github.com/leaxer-ai/leaxer-stable-diffusion/releases/download/v0.1.0/sd-x86_64-unknown-linux-gnu-cuda` |
|
||
| CUDA Server (third-party) | `https://github.com/leaxer-ai/leaxer-stable-diffusion/releases/download/v0.1.0/sd-server-x86_64-unknown-linux-gnu-cuda` |
|
||
| CUDA Runtime (NVIDIA redist) | `https://developer.download.nvidia.com/compute/cuda/redist/cuda_cudart/linux-x86_64/cuda_cudart-linux-x86_64-12.X.YZ-archive.tar.xz` |
|
||
| cuBLAS (NVIDIA redist) | `https://developer.download.nvidia.com/compute/cuda/redist/libcublas/linux-x86_64/libcublas-linux-x86_64-12.X.YZ-archive.tar.xz` |
|
||
|
||
## 6. Setup Modes
|
||
|
||
To respect users with limited bandwidth or no NVIDIA hardware, `setup.sh` should support two modes:
|
||
|
||
1. **Quick Setup (default)** — Downloads CPU + Vulkan only.
|
||
- Works on all Linux systems.
|
||
- NVIDIA users get Vulkan acceleration (good, but not best).
|
||
- ~120–150 MB total download.
|
||
|
||
2. **Maximum Performance Setup** — Downloads CPU + Vulkan + ROCm + CUDA.
|
||
- Best performance for each vendor.
|
||
- ~1.5 GB total download (mostly ROCm + cuBLAS).
|
||
- User can opt-in via `./start.sh --max-perf` or `./scripts/setup.sh --max-perf`.
|
||
|
||
## 7. Self-Contained Checklist
|
||
|
||
| Host Dependency | How We Eliminate It |
|
||
|---|---|
|
||
| Node.js installed globally | Download portable `node-v22.12.0-linux-x64.tar.xz` into `app/tools/node-linux/` |
|
||
| npm installed globally | Use portable npm from the tarball |
|
||
| `unzip` command | Extract ZIPs using Node.js or Python `zipfile` |
|
||
| `lspci` / `lshw` | Parse `/sys/bus/pci/devices/*/vendor` directly |
|
||
| C++ compiler / CUDA toolkit | Use pre-built binaries only |
|
||
| System package manager (apt/yum) | Never used |
|
||
| CUDA runtime libs | Bundle NVIDIA redistributable `.so` files |
|
||
|
||
**One unavoidable host dependency remains**: the NVIDIA kernel driver (`libcuda.so.1`) for CUDA mode. Without it, CUDA cannot run. The app will detect this and automatically fall back to Vulkan for NVIDIA.
|
||
|
||
## 8. Known Limitations
|
||
|
||
1. **Third-party CUDA binary**: The Linux CUDA build comes from `leaxer-ai/leaxer-stable-diffusion`, which has only one release (v0.1.0) and may become stale. We should pin to a specific version and periodically evaluate alternatives.
|
||
2. **Large ROCm download**: The official ROCm backend ZIP is ~1.2 GB, which is a significant one-time download.
|
||
3. **Large cuBLAS download**: NVIDIA's redistributable cuBLAS package is ~400–500 MB.
|
||
4. **NVIDIA driver requirement for CUDA**: `libcuda.so.1` must be present on the host (provided by the NVIDIA proprietary driver). If missing, CUDA mode falls back to Vulkan.
|
||
5. **ROCm host driver requirement**: ROCm requires a compatible AMD GPU and ROCm kernel driver. If unavailable, ROCm falls back to Vulkan.
|
||
6. **glibc compatibility**: Official Linux binaries are built on Ubuntu 24.04. They may fail on very old distributions (e.g., CentOS 7, Ubuntu 18.04) due to glibc version mismatches.
|
||
|
||
## 9. Recommended Implementation Order
|
||
|
||
1. Create `start.sh`, `scripts/setup.sh`, and `scripts/reset.sh` with CPU + Vulkan support first.
|
||
2. Update `scripts/serve.cjs` with Linux paths, sysfs GPU detection, and backend selection.
|
||
3. Add ROCm download path (behind `--max-perf` flag).
|
||
4. Add CUDA download path using leaxer binary + NVIDIA redist libraries (behind `--max-perf` flag).
|
||
5. Add fallback logic so that if ROCm/CUDA fails to initialize, the app automatically switches to Vulkan.
|
||
6. Update `README.md` with Linux instructions and performance notes.
|
||
7. Test on Linux machines with NVIDIA (CUDA/Vulkan), AMD (ROCm/Vulkan), Intel (Vulkan), and CPU-only configurations.
|