diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000000..3814594766 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +/start-server.sh text eol=lf +/start-server.bat text eol=crlf diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 06485ca16c..35418c280a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -26,6 +26,8 @@ on: "ggml", "examples/server/frontend", "examples/server/frontend/**", + "start-server.sh", + "start-server.bat", ] pull_request: types: [opened, synchronize, reopened] @@ -44,6 +46,8 @@ on: "ggml", "examples/server/frontend", "examples/server/frontend/**", + "start-server.sh", + "start-server.bat", ] env: @@ -107,7 +111,8 @@ jobs: run: | cp ggml/LICENSE ./build/bin/ggml.txt cp LICENSE ./build/bin/stable-diffusion.cpp.txt - zip -j sd-${{ env.BRANCH_NAME }}-${{ steps.commit.outputs.short }}-bin-${{ steps.system-info.outputs.OS_TYPE }}-${{ steps.system-info.outputs.OS_NAME }}-${{ steps.system-info.outputs.OS_VERSION }}-${{ steps.system-info.outputs.CPU_ARCH }}.zip ./build/bin/* + chmod +x start-server.sh + zip -j sd-${{ env.BRANCH_NAME }}-${{ steps.commit.outputs.short }}-bin-${{ steps.system-info.outputs.OS_TYPE }}-${{ steps.system-info.outputs.OS_NAME }}-${{ steps.system-info.outputs.OS_VERSION }}-${{ steps.system-info.outputs.CPU_ARCH }}.zip ./build/bin/* ./start-server.sh ./start-server.bat - name: Upload artifacts if: ${{ ( github.event_name == 'push' && github.ref == 'refs/heads/master' ) || github.event.inputs.create_release == 'true' }} @@ -171,7 +176,8 @@ jobs: run: | cp ggml/LICENSE ./build/bin/ggml.txt cp LICENSE ./build/bin/stable-diffusion.cpp.txt - zip -j sd-${{ env.BRANCH_NAME }}-${{ steps.commit.outputs.short }}-bin-${{ steps.system-info.outputs.OS_TYPE }}-${{ steps.system-info.outputs.OS_NAME }}-${{ steps.system-info.outputs.OS_VERSION }}-${{ steps.system-info.outputs.CPU_ARCH }}-vulkan.zip ./build/bin/* + chmod +x start-server.sh + zip -j sd-${{ env.BRANCH_NAME }}-${{ steps.commit.outputs.short }}-bin-${{ steps.system-info.outputs.OS_TYPE }}-${{ steps.system-info.outputs.OS_NAME }}-${{ steps.system-info.outputs.OS_VERSION }}-${{ steps.system-info.outputs.CPU_ARCH }}-vulkan.zip ./build/bin/* ./start-server.sh ./start-server.bat - name: Upload artifacts if: ${{ ( github.event_name == 'push' && github.ref == 'refs/heads/master' ) || github.event.inputs.create_release == 'true' }} @@ -326,7 +332,8 @@ jobs: run: | cp ggml/LICENSE ./build/bin/ggml.txt cp LICENSE ./build/bin/stable-diffusion.cpp.txt - zip -j sd-${{ env.BRANCH_NAME }}-${{ steps.commit.outputs.short }}-bin-${{ steps.system-info.outputs.OS_TYPE }}-${{ steps.system-info.outputs.OS_NAME }}-${{ steps.system-info.outputs.OS_VERSION }}-${{ steps.system-info.outputs.CPU_ARCH }}.zip ./build/bin/* + chmod +x start-server.sh + zip -j sd-${{ env.BRANCH_NAME }}-${{ steps.commit.outputs.short }}-bin-${{ steps.system-info.outputs.OS_TYPE }}-${{ steps.system-info.outputs.OS_NAME }}-${{ steps.system-info.outputs.OS_VERSION }}-${{ steps.system-info.outputs.CPU_ARCH }}.zip ./build/bin/* ./start-server.sh ./start-server.bat - name: Upload artifacts if: ${{ ( github.event_name == 'push' && github.ref == 'refs/heads/master' ) || github.event.inputs.create_release == 'true' }} @@ -418,7 +425,7 @@ jobs: ls .\build\bin throw "Can't find stable-diffusion.dll" } - 7z a sd-${{ env.BRANCH_NAME }}-${{ steps.commit.outputs.short }}-bin-win-${{ matrix.build }}-x64.zip $filePath + 7z a sd-${{ env.BRANCH_NAME }}-${{ steps.commit.outputs.short }}-bin-win-${{ matrix.build }}-x64.zip $filePath .\start-server.sh .\start-server.bat - name: Copy and pack Cuda runtime id: pack_cuda_runtime @@ -450,7 +457,7 @@ jobs: runs-on: windows-2022 env: - ROCM_VERSION: "7.14.0" + ROCM_VERSION: "10.1.0" GPU_TARGETS: "gfx1010;gfx1011;gfx1012;gfx1030;gfx1031;gfx1032;gfx1033;gfx1034;gfx1035;gfx1036;gfx1100;gfx1101;gfx1102;gfx1103;gfx1150;gfx1151;gfx1152;gfx1153;gfx1200;gfx1201" # rocm-sdk re-expands clang from the wheel every run, so its mtime always # differs and the default compiler_check=mtime misses every object. @@ -502,7 +509,7 @@ jobs: write-host "Installing ROCm wheels for multi-arch support" # Install ROCm wheels for multi-arch support (this may take several minutes) - python -m pip install --index-url https://repo.amd.com/rocm/whl-multi-arch/ "rocm[libraries,devel]==${{env.ROCM_VERSION}}" + python -m pip install --index-url https://stable.repo.amd.com/rocm/whl-next/ "rocm[libraries,devel]==${{env.ROCM_VERSION}}" # Pre-expand the devel tree so it is included in the cache write-host "Initializing ROCm devel tree" @@ -564,10 +571,22 @@ jobs: if: ${{ ( github.event_name == 'push' && github.ref == 'refs/heads/master' ) || github.event.inputs.create_release == 'true' }} uses: pr-mpt/actions-commit-hash@01d19a83c242e1851c9aa6cf9625092ecd095d09 # v2 + - name: Bundle HIP runtime libraries + if: ${{ ( github.event_name == 'push' && github.ref == 'refs/heads/master' ) || github.event.inputs.create_release == 'true' }} + run: | + $ErrorActionPreference = "Stop" + $binPath = (rocm-sdk path --bin).Trim() + if (-not $binPath) { throw "rocm-sdk path --bin returned empty" } + foreach ($dll in @("amdhip64_7.dll", "rocm_kpack.dll", "amd_comgr.dll")) { + $f = Get-ChildItem -Path $binPath -Filter $dll -ErrorAction SilentlyContinue + if (-not $f) { throw "no match for $dll in $binPath" } + Copy-Item $f.FullName -Destination .\build\bin\ -Force + } + - name: Pack artifacts if: ${{ ( github.event_name == 'push' && github.ref == 'refs/heads/master' ) || github.event.inputs.create_release == 'true' }} run: | - 7z a sd-${{ env.BRANCH_NAME }}-${{ steps.commit.outputs.short }}-bin-win-rocm-${{ env.ROCM_VERSION }}-x64.zip .\build\bin\* + 7z a sd-${{ env.BRANCH_NAME }}-${{ steps.commit.outputs.short }}-bin-win-rocm-${{ env.ROCM_VERSION }}-x64.zip .\build\bin\* .\start-server.sh .\start-server.bat - name: Upload artifacts if: ${{ ( github.event_name == 'push' && github.ref == 'refs/heads/master' ) || github.event.inputs.create_release == 'true' }} @@ -587,9 +606,9 @@ jobs: strategy: matrix: include: - - ROCM_VERSION: "7.14.0" + - ROCM_VERSION: "10.1.0" gpu_targets: "gfx900;gfx906;gfx908;gfx90a;gfx90c;gfx942;gfx950;gfx1010;gfx1011;gfx1012;gfx1030;gfx1031;gfx1032;gfx1033;gfx1034;gfx1035;gfx1036;gfx1100;gfx1101;gfx1102;gfx1103;gfx1150;gfx1151;gfx1152;gfx1153;gfx1200;gfx1201" - build: x64 + build: 'x64' steps: - name: Clone @@ -606,6 +625,15 @@ jobs: # Plateaus at the 500M default (88.19% full, 142 misses/run). max-size: 2G + - name: Tune ccache for reinstalled ROCm toolchain + run: | + # ROCm is pip-installed fresh each run, so the clang binary's mtime + # changes every time. With the default compiler_check=mtime that + # invalidates the cache; hash compiler contents instead so warm + # builds hit. + ccache --set-config=compiler_check=content + ccache --set-config=sloppiness=time_macros,include_file_mtime,include_file_ctime + - name: Dependencies id: depends run: | @@ -641,7 +669,7 @@ jobs: # libraries = HIP runtime and CMake configs needed for linking # devel = compilers, headers, static libs python -m pip install --upgrade pip - python -m pip install --index-url https://repo.amd.com/rocm/whl-multi-arch/ "rocm[libraries,devel]==${{matrix.ROCM_VERSION}}" + python -m pip install --index-url https://stable.repo.amd.com/rocm/whl-next/ "rocm[libraries,devel]==${{matrix.ROCM_VERSION}}" # Get ROCm installation paths using the rocm-sdk CLI tool ROCM_PATH=$(rocm-sdk path --root) @@ -722,7 +750,8 @@ jobs: run: | cp ggml/LICENSE ./build/bin/ggml.txt cp LICENSE ./build/bin/stable-diffusion.cpp.txt - zip -y -r sd-${{ env.BRANCH_NAME }}-${{ steps.commit.outputs.short }}-bin-${{ steps.system-info.outputs.OS_TYPE }}-Ubuntu-${{ env.UBUNTU_VERSION }}-${{ steps.system-info.outputs.CPU_ARCH }}-rocm-${{ matrix.ROCM_VERSION }}.zip ./build/bin + chmod +x start-server.sh + zip -y -r sd-${{ env.BRANCH_NAME }}-${{ steps.commit.outputs.short }}-bin-${{ steps.system-info.outputs.OS_TYPE }}-Ubuntu-${{ env.UBUNTU_VERSION }}-${{ steps.system-info.outputs.CPU_ARCH }}-rocm-${{ matrix.ROCM_VERSION }}.zip ./build/bin ./start-server.sh ./start-server.bat - name: Upload artifacts if: ${{ ( github.event_name == 'push' && github.ref == 'refs/heads/master' ) || github.event.inputs.create_release == 'true' }} diff --git a/.github/workflows/unsloth-sd-prebuilt.yml b/.github/workflows/unsloth-sd-prebuilt.yml index cd981b98f4..e6f582e329 100644 --- a/.github/workflows/unsloth-sd-prebuilt.yml +++ b/.github/workflows/unsloth-sd-prebuilt.yml @@ -1,26 +1,29 @@ # SPDX-License-Identifier: MIT # Copyright 2026-present the Unsloth AI Inc. team. -name: Unsloth SD prebuilt (CPU/Apple/CUDA/Vulkan) +name: Unsloth SD prebuilt (CPU/Apple/CUDA/Vulkan/ROCm) # Build and publish our stable-diffusion.cpp (sd-cli + sd-server) prebuilts for -# CPU, Apple, CUDA, and Vulkan. MiniMax-H3 uses the native engine on GPU hosts too. +# CPU, Apple, CUDA, Vulkan, and ROCm. MiniMax-H3 uses the native engine on GPU hosts too. # Vulkan must carry the same H3 and graph-segment fixes as the other backends, # rather than sending AMD hosts to an older upstream fallback binary. # # Shape mirrors unslothai/llama.cpp's prebuilt pipeline, simplified for a 7-way -# CPU/Apple/Vulkan matrix plus one best-effort CUDA leg: +# CPU/Apple/Vulkan matrix plus best-effort CUDA and ROCm legs: # resolve -- take THIS repository at the requested ref, merge the pinned PR set # in scripts/unsloth/pr-set.json, stamp a source tarball, name it # after the upstream release the tree descends from (supply-chain # aged), decide if our release already exists. # build-unix -- macOS arm64 (Metal) + x64, Linux x64 + arm64, Linux Vulkan. # build-windows-- Windows x64 CPU + Vulkan (MSVC + Ninja). -# build-linux-cuda -- Linux x64, CUDA 12.8, best effort (continue-on-error). +# build-linux-cuda / build-windows-cuda -- x64, CUDA 12.8 and 13.3, best effort +# (continue-on-error); the CUDA runtime is not bundled, see build-linux-cuda. +# build-linux-rocm -- Linux x64, ROCm 7.14.0 with its userspace bundled, best effort +# like CUDA. Without it AMD Linux hosts fall back to upstream or CPU (unsloth#8814). # assemble -- fingerprint gate, sha256 + manifest, coverage gate, atomic # draft->publish. If any CPU/Apple/Vulkan leg fails, assemble # is skipped and nothing is published (the Studio needs the full -# asset set). The CUDA leg is exempt: it ships when it built and is +# asset set). The CUDA and ROCm legs are exempt: each ships when it built and is # absent when it did not, so it can never hold back the fallbacks. # # Asset names match the Studio installer's resolve_release_asset. @@ -220,6 +223,12 @@ jobs: # (we build with SD_SERVER_BUILD_FRONTEND / SD_WEBP / SD_WEBM off), so fetch only # ggml to keep the source tarball small and the build self-contained. git submodule update --init --recursive --depth 1 ggml + # ggml changes we carry on top of the pinned submodule commit (the submodule points at + # leejet/ggml, which we do not push to). A patch that no longer applies fails the build. + for p in scripts/unsloth/ggml-patches/*.patch; do + [ -e "$p" ] || continue + git -C ggml apply --verbose "../$p" + done COMMIT="$(git rev-parse HEAD)" SRC_ARTIFACT="sd-source-${TAG}" if [ "$EXISTS" != "true" ] || [ "${{ github.event_name }}" = "workflow_dispatch" ]; then @@ -259,23 +268,29 @@ jobs: - label: Darwin-macOS-arm64 runner: macos-14 arch: arm64 - defines: "-DSD_METAL=ON -DGGML_METAL_EMBED_LIBRARY=ON -DCMAKE_OSX_DEPLOYMENT_TARGET=14.0" + # Static: apple_m1 variant drops FP16_VA (~40% slower). BLAS explicit: sd.cpp routes big matmuls to it. + defines: "-DSD_METAL=ON -DGGML_METAL_EMBED_LIBRARY=ON -DGGML_BLAS=ON -DGGML_BLAS_VENDOR=Apple -DCMAKE_OSX_DEPLOYMENT_TARGET=14.0" gate: "true" - label: Darwin-macOS-x86_64 runner: macos-15-intel arch: x86_64 - defines: "-DSD_METAL=OFF -DCMAKE_OSX_DEPLOYMENT_TARGET=13.3" + # BLAS off: its matmul path was only measured on Apple Silicon. + defines: "-DSD_METAL=OFF -DGGML_BLAS=OFF -DCMAKE_OSX_DEPLOYMENT_TARGET=13.3" gate: "true" + cpu_floor: x64 - label: Linux-Ubuntu-22.04-x86_64 runner: ubuntu-22.04 arch: x86_64 defines: "" gate: "false" + cpu_floor: x64 - label: Linux-Ubuntu-24.04-aarch64 runner: ubuntu-24.04-arm arch: aarch64 - defines: "" + # GCC 13 (the image default) rejects +sme, which the Armv9.2 variants need. + defines: "-DCMAKE_C_COMPILER=gcc-14 -DCMAKE_CXX_COMPILER=g++-14" gate: "false" + cpu_floor: armv8.0_1 - label: Linux-Ubuntu-22.04-x86_64-vulkan runner: ubuntu-22.04 arch: x86_64 @@ -321,20 +336,38 @@ jobs: echo "VULKAN_SDK=$sdk_root/x86_64" >> "$GITHUB_ENV" echo "$sdk_root/x86_64/bin" >> "$GITHUB_PATH" + # CPU bundles ship all ggml CPU variants, picked per host at startup; -DGGML_NATIVE=OFF alone + # pins AVX2 (SIGILL on older x86) or plain Armv8.0. Metal/Vulkan stay static. - name: Build sd-cli + sd-server working-directory: src run: | set -euo pipefail + CPU_VARIANTS="" + if [ -n "${{ matrix.cpu_floor }}" ]; then + CPU_VARIANTS="-DSD_BUILD_SHARED_GGML_LIB=ON -DBUILD_SHARED_LIBS=ON -DGGML_BACKEND_DL=ON -DGGML_CPU_ALL_VARIANTS=ON" + # macOS: @loader_path only, never an absolute rpath into the build tree. + if [ "$(uname -s)" = "Darwin" ]; then + CPU_VARIANTS="$CPU_VARIANTS -DCMAKE_BUILD_WITH_INSTALL_RPATH=ON -DCMAKE_INSTALL_RPATH=@loader_path" + fi + fi cmake -B build \ -DCMAKE_BUILD_TYPE=Release \ -DSD_BUILD_EXAMPLES=ON \ -DSD_SERVER_BUILD_FRONTEND=OFF \ -DSD_WEBP=OFF -DSD_WEBM=OFF \ -DGGML_NATIVE=OFF \ + $CPU_VARIANTS \ ${{ matrix.defines }} if [ "$(uname -s)" = "Darwin" ]; then J="$(sysctl -n hw.logicalcpu)"; else J="$(nproc)"; fi cmake --build build --config Release -j "$J" --target sd-cli sd-server + - name: Pin the bundle's own ggml (CPU variants) + if: ${{ matrix.cpu_floor != '' && runner.os == 'Linux' }} + run: | + set -euo pipefail + sudo apt-get update -qq && sudo apt-get install -y -qq patchelf + bash tooling/scripts/unsloth/cpu_variants_gate.sh pin src/build/bin + - name: macOS load gate if: ${{ matrix.gate == 'true' }} run: | @@ -354,6 +387,10 @@ jobs: LICENSE_FILE: ${{ github.workspace }}/src/LICENSE run: python3 tooling/scripts/unsloth/package_bundle.py + - name: CPU variants gate + if: ${{ matrix.cpu_floor != '' }} + run: bash tooling/scripts/unsloth/cpu_variants_gate.sh check "dist/sd-${{ needs.resolve.outputs.tag }}-bin-${{ matrix.label }}.zip" "${{ matrix.cpu_floor }}" + - name: Upload bundle uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: @@ -368,21 +405,38 @@ jobs: # against 21.5 s/step at 960x544 from a CUDA build. That is the difference between a render # taking four hours and taking eleven minutes. # + # One bundle per CUDA major, and no CUDA runtime in any of them. Studio always installs + # unslothai/llama.cpp, whose CUDA build links the same cudart / cublas / cublasLt and already + # resolves them on every CUDA host (the venv's torch and nvidia-* wheels, CUDA_PATH, the paired + # cudart archive on Windows). Studio picks the bundle whose major matches that llama.cpp build + # and hands sd-cli the same directories, so the toolkits here match llama.cpp's cuda12 / cuda13 + # lines. ggml is a shared library so sd-cli and sd-server share one copy of the CUDA kernels. + # # continue-on-error, and deliberately so. The CPU and Apple assets are what Studio falls back # to, and a CUDA toolchain failure must never stop them publishing. assemble collects bundles # by the sd-*-bin-* pattern, so this asset appears when it built and is simply absent when it # did not; the coverage gate requires CPU/Apple/Vulkan assets but leaves CUDA optional. build-linux-cuda: - name: Linux-Ubuntu-22.04-x86_64-cuda12 + name: Linux-Ubuntu-22.04-x86_64-${{ matrix.line }} needs: resolve continue-on-error: true if: ${{ needs.resolve.outputs.exists != 'true' || github.event_name == 'workflow_dispatch' }} runs-on: ubuntu-22.04 - # One source of truth for both: the ccache key has to track whatever changes - # the objects, and these two do. + strategy: + fail-fast: false + matrix: + include: + - line: cuda12 + cuda: "12.8.0" + archs: "70;75;80;86;89;90;100;120" + # CUDA 13 dropped Volta. + - line: cuda13 + cuda: "13.3" + archs: "75;80;86;89;90;100;120" + # The ccache key tracks both, since both change the objects. env: - CUDA_VERSION: "12.8.1" - CUDA_ARCHS: "70;75;80;86;89;90;100;120" + CUDA_VERSION: ${{ matrix.cuda }} + CUDA_ARCHS: ${{ matrix.archs }} steps: - name: Checkout mirror (tooling) uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 @@ -409,18 +463,36 @@ jobs: mkdir -p src tar -xzf "srcpkg/sd-source-${{ needs.resolve.outputs.tag }}.tar.gz" -C src - - name: Install CUDA toolkit - id: cuda-toolkit - uses: Jimver/cuda-toolkit@95b5a29a2823ef87666dcd45ec236fc4f82498d0 # v0.2.22 - with: - cuda: ${{ env.CUDA_VERSION }} - method: "network" - # sub-packages are installed as cuda--12-8. cuBLAS is not under that - # prefix (it ships as libcublas / libcublas-dev), so it has to go in the - # other list or apt cannot find it. cudart-dev is what carries the headers; - # cudart alone is the runtime and does not compile anything. - sub-packages: '["nvcc", "cudart", "cudart-dev", "thrust"]' - non-cuda-sub-packages: '["libcublas", "libcublas-dev"]' + # Component tables copied from unslothai/llama.cpp's unsloth-cuda-linux-setup, so both projects + # link the sonames Studio already resolves for llama-server. nvrtc: cudnn-frontend's headers + # include nvrtc.h (it dlopens libnvrtc itself, so nothing links it). + - name: Install CUDA toolkit ${{ env.CUDA_VERSION }} (NVIDIA redist) + run: | + set -eux + case "$CUDA_VERSION" in + 12.8.0) COMPONENTS="cuda_cudart:12.8.90 cuda_nvcc:12.8.93 cuda_nvrtc:12.8.93 libcublas:12.8.4.1 cuda_nvtx:12.8.90 cuda_profiler_api:12.8.90 cuda_cccl:12.8.90" ;; + 13.3) COMPONENTS="cuda_crt:13.3.33 cuda_cudart:13.3.29 cuda_nvcc:13.3.33 cuda_nvrtc:13.3.33 libcublas:13.5.1.27 libnvvm:13.3.33 cuda_nvtx:13.3.29 cuda_profiler_api:13.3.27 cccl:13.3.3.3.1" ;; + *) echo "no redist component table for CUDA $CUDA_VERSION" >&2; exit 1 ;; + esac + PREFIX="$HOME/cuda-$CUDA_VERSION" + mkdir -p "$PREFIX" + BASE="https://developer.download.nvidia.com/compute/cuda/redist" + for cv in $COMPONENTS; do + comp="${cv%:*}"; ver="${cv#*:}" + name="${comp}-linux-x86_64-${ver}-archive" + curl -fsSL --retry 3 -o comp.tar.xz "$BASE/${comp}/linux-x86_64/${name}.tar.xz" + tar -xf comp.tar.xz + cp -a "${name}/." "$PREFIX"/ + rm -rf comp.tar.xz "${name}" + done + ln -sfn lib "$PREFIX/lib64" + { + echo "CUDA_PATH=$PREFIX" + echo "CUDA_HOME=$PREFIX" + echo "LD_LIBRARY_PATH=$PREFIX/lib:${LD_LIBRARY_PATH:-}" + } >> "$GITHUB_ENV" + echo "$PREFIX/bin" >> "$GITHUB_PATH" + "$PREFIX/bin/nvcc" --version # This leg rebuilt every object on every run: 3903 s of the 4121 s job on # 2026-08-09, and 4942 s on the run before it, with no speedup between the @@ -450,17 +522,40 @@ jobs: # keeps what it compiled. save: false + - name: cuDNN headers (build time only) + run: | + set -euo pipefail + # ggml-cuda's cuDNN attention path (GGML_CUDA_CUDNN) compiles against cudnn.h, but the + # library itself is opened with dlopen when the first attention op runs and is NOT + # bundled: a host without a loadable libcudnn.so.9 keeps the ggml attention kernels. + # Only the headers package is fetched (80 KB), pinned by version and checksum. + deb=libcudnn9-headers-cuda-12_9.27.0.42-1_amd64.deb + curl -fsSL --retry 3 -o "$RUNNER_TEMP/$deb" \ + "https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2204/x86_64/$deb" + echo "68243ab04422da565e0bafec00f64ac08cfd82d805c8015c0c503af7ab4dd1d6 $RUNNER_TEMP/$deb" | sha256sum -c - + dpkg -x "$RUNNER_TEMP/$deb" "$RUNNER_TEMP/cudnn-deb" + # The package ships cudnn*_v9.h; the unversioned names normally come from the -dev + # package's alternatives, so link them here. + inc="$RUNNER_TEMP/cudnn-include" + mkdir -p "$inc" + for f in "$RUNNER_TEMP"/cudnn-deb/usr/include/x86_64-linux-gnu/cudnn*_v9.h; do + b="$(basename "$f")" + ln -s "$f" "$inc/${b%_v9.h}.h" + done + test -e "$inc/cudnn.h" + echo "CUDNN_INCLUDE_DIR=$inc" >> "$GITHUB_ENV" + - name: Build sd-cli + sd-server (CUDA) working-directory: src run: | set -euo pipefail - # Volta through Blackwell. V100 can run H3 with quantized weights and CPU offload, - # but a device probe succeeds even when the binary has no sm_70 kernels. Include - # sm_70 so generation does not fail at the first CUDA kernel launch. + # cuda12 covers Volta through Blackwell. V100 can run H3 with quantized weights and CPU + # offload, but a device probe succeeds even when the binary has no sm_70 kernels, so + # sm_70 stays in the list. # - # The CUDA launcher matters more than the other two here: Jimver installs nvcc outside - # the default search, and nvcc is nearly the whole build, so caching only C/CXX would - # leave the expensive half uncached. + # The CUDA launcher matters more than the other two here: nvcc lives outside the default + # search, and nvcc is nearly the whole build, so caching only C/CXX would leave the + # expensive half uncached. cmake -B build \ -DCMAKE_BUILD_TYPE=Release \ -DSD_BUILD_EXAMPLES=ON \ @@ -468,6 +563,11 @@ jobs: -DSD_WEBP=OFF -DSD_WEBM=OFF \ -DGGML_NATIVE=OFF \ -DSD_CUDA=ON \ + -DSD_BUILD_SHARED_GGML_LIB=ON \ + -DBUILD_SHARED_LIBS=ON \ + -DCMAKE_CUDA_COMPILER="$CUDA_PATH/bin/nvcc" \ + -DGGML_CUDA_CUDNN=ON \ + -DGGML_CUDA_CUDNN_INCLUDE_DIR="$CUDNN_INCLUDE_DIR" \ -DCMAKE_CUDA_ARCHITECTURES="$CUDA_ARCHS" \ -DCMAKE_C_COMPILER_LAUNCHER=ccache \ -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \ @@ -476,43 +576,66 @@ jobs: # Diagnostic only, under set -e: never fail a good build over stats. ccache --show-stats || true - - name: Bundle the CUDA runtime beside the binaries + - name: Pin the bundle's own ggml; leave the CUDA runtime to the host run: | set -euo pipefail - # A Studio host has an NVIDIA driver but not necessarily a CUDA runtime, and Studio's - # torch install keeps its own copies somewhere we must not depend on. Ship ours and - # point the binaries at their own directory, or sd-cli dies on a missing libcublas. BIN="${GITHUB_WORKSPACE}/src/build/bin" - CUDA_ROOT="${{ steps.cuda-toolkit.outputs.CUDA_PATH }}" + MAJOR="${CUDA_VERSION%%.*}" sudo apt-get update -qq && sudo apt-get install -y -qq patchelf - # cudart lands under the toolkit root; the libcublas debs land in the system - # multiarch dir. Search both rather than guess which is which. - for so in libcudart.so.12 libcublas.so.12 libcublasLt.so.12; do - src="$(find "$CUDA_ROOT" /usr/lib/x86_64-linux-gnu -name "${so}*" -type f 2>/dev/null | sort | tail -1)" - [ -n "$src" ] || { echo "ERROR: $so not found under $CUDA_ROOT or /usr/lib/x86_64-linux-gnu" >&2; exit 1; } - cp -L "$src" "$BIN/$so" + # DT_RPATH, not RUNPATH: it is searched before LD_LIBRARY_PATH and covers the whole + # dependency chain, so this bundle's libggml*.so win over llama.cpp's same-named ones + # when Studio puts both directories on the loader path. + for f in "$BIN"/sd-cli "$BIN"/sd-server "$BIN"/libggml*.so* "$BIN"/libstable-diffusion*.so*; do + [ -f "$f" ] && [ ! -L "$f" ] || continue + patchelf --force-rpath --set-rpath '$ORIGIN' "$f" done - for exe in sd-cli sd-server; do - patchelf --set-rpath '$ORIGIN' "$BIN/$exe" + ls -la "$BIN" + if ls "$BIN" | grep -qE '^lib(cudart|cublas|cublasLt)\.so'; then + echo "ERROR: a CUDA runtime library is in the bundle; the host provides it" >&2 + exit 1 + fi + cuda_lib="$(ls "$BIN"/libggml-cuda.so* | head -1)" + for so in "libcudart.so.${MAJOR}" "libcublas.so.${MAJOR}"; do + readelf -d "$cuda_lib" | grep -qF "[${so}]" \ + || { echo "ERROR: $(basename "$cuda_lib") does not link ${so}" >&2; exit 1; } + done + # The host supplies exactly what llama.cpp's build of this major links. cuDNN and NVRTC are + # run-time dlopens only; linking them would stop the binaries loading on hosts without them. + allowed=" libcuda.so.1 libcudart.so.${MAJOR} libcublas.so.${MAJOR} libcublasLt.so.${MAJOR} " + for f in "$BIN"/sd-cli "$BIN"/sd-server "$BIN"/libggml*.so* "$BIN"/libstable-diffusion*.so*; do + [ -f "$f" ] && [ ! -L "$f" ] || continue + for so in $(readelf -d "$f" | sed -n 's/.*(NEEDED).*\[\(lib\(cu\|nv\)[^]]*\)\].*/\1/p'); do + case "$allowed" in + *" $so "*) ;; + *) echo "ERROR: $(basename "$f") links $so; only ${allowed} may come from the host" >&2; exit 1 ;; + esac + done done - ldd "$BIN/sd-cli" | sed -n '1,40p' - name: Package bundle env: BIN_DIR: ${{ github.workspace }}/src/build/bin OUT_DIR: ${{ github.workspace }}/dist TAG: ${{ needs.resolve.outputs.tag }} - LABEL: Linux-Ubuntu-22.04-x86_64-cuda12 + LABEL: Linux-Ubuntu-22.04-x86_64-${{ matrix.line }} COMMIT: ${{ needs.resolve.outputs.commit }} SOURCE_REPO: ${{ github.repository }} - LICENSE_FILE: ${{ github.workspace }}/src/LICENSE - run: python3 tooling/scripts/unsloth/package_bundle.py + LICENSE_FILE: ${{ runner.temp }}/LICENSE + run: | + set -euo pipefail + # The binaries compile in cudnn-frontend's header-only templates, so its MIT notice ships too. + { + cat src/LICENSE + printf '\n\n---- cudnn-frontend (https://github.com/NVIDIA/cudnn-frontend) ----\n\n' + cat src/build/_deps/ggml_cudnn_frontend-src/LICENSE.txt + } > "$LICENSE_FILE" + python3 tooling/scripts/unsloth/package_bundle.py - name: Upload bundle uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: - name: sd-${{ needs.resolve.outputs.tag }}-bin-Linux-Ubuntu-22.04-x86_64-cuda12 - path: dist/sd-${{ needs.resolve.outputs.tag }}-bin-Linux-Ubuntu-22.04-x86_64-cuda12.zip + name: sd-${{ needs.resolve.outputs.tag }}-bin-Linux-Ubuntu-22.04-x86_64-${{ matrix.line }} + path: dist/sd-${{ needs.resolve.outputs.tag }}-bin-Linux-Ubuntu-22.04-x86_64-${{ matrix.line }}.zip if-no-files-found: error retention-days: 7 @@ -538,6 +661,200 @@ jobs: # restored from, so the save is never a no-op against itself. key: ccache-sd-cuda-${{ env.CUDA_VERSION }}-${{ steps.cckey.outputs.archs }}-${{ needs.resolve.outputs.tag }}- + # Windows CUDA, same runtime policy as build-linux-cuda: the ggml*.dll ship beside the executables + # (Windows searches the executable's own directory first, so llama.cpp's same-named DLLs elsewhere + # on PATH never win), and cudart64 / cublas64 / cublasLt64 come from the host exactly as they do + # for unslothai/llama.cpp's Windows CUDA build. No cuDNN attention path: the ggml kernels serve. + build-windows-cuda: + name: win-${{ matrix.line }}-x64 + needs: resolve + continue-on-error: true + if: ${{ needs.resolve.outputs.exists != 'true' || github.event_name == 'workflow_dispatch' }} + runs-on: windows-2022 + timeout-minutes: 300 + environment: release-signing + strategy: + fail-fast: false + matrix: + include: + - line: cuda12 + cuda: "12.8.0" + archs: "70;75;80;86;89;90;100;120" + - line: cuda13 + cuda: "13.3" + archs: "75;80;86;89;90;100;120" + defaults: + run: + shell: pwsh + steps: + - name: Checkout mirror (tooling) + uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 + with: + path: tooling + fetch-depth: 1 + + - name: Download source @ ${{ needs.resolve.outputs.tag }} + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 + with: + name: ${{ needs.resolve.outputs.source_artifact }} + path: srcpkg + + - name: Extract source + shell: bash + run: | + set -eux + mkdir -p src + tar -xzf "srcpkg/sd-source-${{ needs.resolve.outputs.tag }}.tar.gz" -C src + + - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 + with: + python-version: "3.11" + - name: Setup MSVC + uses: ilammy/msvc-dev-cmd@0b201ec74fa43914dc39ae48a89fd1d8cb592756 # v1.13.0 + + # Component tables copied from unslothai/llama.cpp's unsloth-cuda-windows-setup. + - name: Install CUDA toolkit ${{ matrix.cuda }} (NVIDIA redist) + run: | + $ErrorActionPreference = 'Stop' + switch ("${{ matrix.cuda }}") { + '12.8.0' { $components = @('cuda_cudart:12.8.57', 'cuda_nvcc:12.8.61', 'cuda_nvrtc:12.8.61', 'libcublas:12.8.3.14', 'cuda_nvtx:12.8.55', 'cuda_profiler_api:12.8.55', 'cuda_cccl:12.8.55', 'visual_studio_integration:12.8.55') } + '13.3' { $components = @('cuda_crt:13.3.33', 'cuda_cudart:13.3.29', 'cuda_nvcc:13.3.33', 'cuda_nvrtc:13.3.33', 'libcublas:13.5.1.27', 'libnvvm:13.3.33', 'cuda_nvtx:13.3.29', 'cuda_profiler_api:13.3.27', 'cccl:13.3.3.3.1', 'visual_studio_integration:13.3.27') } + default { throw "no redist component table for CUDA ${{ matrix.cuda }}" } + } + $line = "${{ matrix.cuda }}" -replace '^(\d+\.\d+).*$', '$1' + $prefix = "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v$line" + $stage = Join-Path $env:RUNNER_TEMP 'cuda-redist' + New-Item -ItemType Directory -Force -Path $prefix, $stage | Out-Null + foreach ($cv in $components) { + $comp, $ver = $cv.Split(':') + $name = "$comp-windows-x86_64-$ver-archive" + $zip = Join-Path $stage "$name.zip" + curl.exe -fsSL --retry 3 -o $zip "https://developer.download.nvidia.com/compute/cuda/redist/$comp/windows-x86_64/$name.zip" + if ($LASTEXITCODE -ne 0) { throw "download failed: $name" } + tar.exe -xf $zip -C $stage + if ($LASTEXITCODE -ne 0) { throw "extract failed: $name" } + robocopy (Join-Path $stage $name) $prefix /E /NFL /NDL /NJH /NJS /NP | Out-Null + if ($LASTEXITCODE -ge 8) { throw "copy failed: $name ($LASTEXITCODE)" } + Remove-Item -Recurse -Force $zip, (Join-Path $stage $name) + } + "$prefix\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append + "CUDA_PATH=$prefix" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append + "CUDA_HOME=$prefix" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append + "CUDA_PATH_V$($line.Replace('.', '_'))=$prefix" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append + exit 0 + + - name: ccache key + id: cckey + shell: bash + run: echo "archs=$(echo '${{ matrix.archs }}' | tr ';' '-')" >> "$GITHUB_OUTPUT" + + - name: ccache + uses: hendrikmuhs/ccache-action@d62db5f07c26379fc4b4e0916f098a92573c3b03 # v1.2.23 + with: + key: sd-cuda-${{ matrix.cuda }}-windows-${{ steps.cckey.outputs.archs }}-${{ needs.resolve.outputs.tag }} + restore-keys: | + sd-cuda-${{ matrix.cuda }}-windows-${{ steps.cckey.outputs.archs }} + append-timestamp: false + variant: ccache + max-size: 3G + save: false + + - name: Build sd-cli + sd-server (CUDA) + working-directory: src + run: | + nvcc --version + cmake -S . -B build -G Ninja ` + -DCMAKE_BUILD_TYPE=Release ` + -DCMAKE_CXX_FLAGS='/bigobj' ` + -DSD_BUILD_EXAMPLES=ON ` + -DSD_SERVER_BUILD_FRONTEND=OFF ` + -DSD_WEBP=OFF -DSD_WEBM=OFF ` + -DGGML_NATIVE=OFF ` + -DSD_CUDA=ON ` + -DSD_BUILD_SHARED_GGML_LIB=ON ` + -DBUILD_SHARED_LIBS=ON ` + -DCMAKE_CUDA_ARCHITECTURES='${{ matrix.archs }}' ` + -DCMAKE_C_COMPILER_LAUNCHER=ccache ` + -DCMAKE_CXX_COMPILER_LAUNCHER=ccache ` + -DCMAKE_CUDA_COMPILER_LAUNCHER=ccache + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + # -j 3: a multi-arch nvcc TU peaks near 3 GB RSS on the 16 GB hosted runner. + cmake --build build --config Release -j 3 --target sd-cli sd-server + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + ccache -s + exit 0 + + - name: Leave the CUDA runtime to the host + run: | + $ErrorActionPreference = 'Stop' + $bin = Join-Path $env:GITHUB_WORKSPACE 'src/build/bin' + $major = "${{ matrix.cuda }}".Split('.')[0] + Get-ChildItem $bin | Format-Table Name, Length + $bundled = @(Get-ChildItem $bin -Filter *.dll | Where-Object { $_.Name -match '^(cudart|cublas|cublasLt)64_' }) + if ($bundled.Count -gt 0) { throw "CUDA runtime DLLs in the bundle: $($bundled.Name -join ', ')" } + $cuda = Join-Path $bin 'ggml-cuda.dll' + if (-not (Test-Path $cuda)) { throw 'ggml-cuda.dll was not built' } + $imports = (& dumpbin /dependents $cuda) -join "`n" + $imports + # cublas is always the host's. cudart is too on CUDA 12; CUDA 13 links it statically, as in + # unslothai/llama.cpp's cuda13 build, which imports cublas64_13.dll alone. + if ($imports -notmatch [regex]::Escape("cublas64_$major.dll")) { throw "ggml-cuda.dll does not import cublas64_$major.dll" } + # Anything else CUDA-shaped (another major, nvrtc, cudnn) would not be on the host. + $allowed = @('nvcuda.dll', "cudart64_$major.dll", "cublas64_$major.dll", "cublasLt64_$major.dll") + foreach ($pe in Get-ChildItem $bin -Include *.dll, *.exe -Recurse) { + $deps = [regex]::Matches(((& dumpbin /dependents $pe.FullName) -join "`n"), '(?im)^\s*((?:cu|nv)\S*\.dll)\s*$') | ForEach-Object { $_.Groups[1].Value } + $extra = @($deps | Where-Object { $allowed -notcontains $_ }) + if ($extra.Count -gt 0) { throw "$($pe.Name) imports $($extra -join ', '); only $($allowed -join ', ') may come from the host" } + } + + - name: Sign Windows binaries + uses: ./tooling/.github/actions/sign-windows + with: + path: src/build/bin + azure-client-id: ${{ secrets.AZURE_CLIENT_ID }} + azure-client-secret: ${{ secrets.AZURE_CLIENT_SECRET }} + azure-tenant-id: ${{ secrets.AZURE_TENANT_ID }} + azure-account: ${{ secrets.AZURE_TRUSTED_SIGNING_ACCOUNT_NAME }} + azure-certificate-profile: ${{ secrets.AZURE_CERTIFICATE_PROFILE_NAME }} + + - name: Package bundle + env: + BIN_DIR: ${{ github.workspace }}/src/build/bin + OUT_DIR: ${{ github.workspace }}/dist + TAG: ${{ needs.resolve.outputs.tag }} + LABEL: win-${{ matrix.line }}-x64 + COMMIT: ${{ needs.resolve.outputs.commit }} + SOURCE_REPO: ${{ github.repository }} + LICENSE_FILE: ${{ github.workspace }}/src/LICENSE + run: python tooling/scripts/unsloth/package_bundle.py + + - name: Verify every PE in the bundle is signed + run: | + $ErrorActionPreference = 'Continue' + $zips = @(Get-ChildItem dist -Filter *.zip -ErrorAction SilentlyContinue | ForEach-Object { $_.FullName }) + if ($zips.Count -eq 0) { + Write-Host '::error::no bundle in dist/; packaging produced nothing to verify' + exit 1 + } + & tooling/.github/scripts/assert-windows-bundle-signed.ps1 -Path $zips + exit $LASTEXITCODE + + - name: Upload bundle + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + with: + name: sd-${{ needs.resolve.outputs.tag }}-bin-win-${{ matrix.line }}-x64 + path: dist/sd-${{ needs.resolve.outputs.tag }}-bin-win-${{ matrix.line }}-x64.zip + if-no-files-found: error + retention-days: 7 + + - name: Save ccache + # always(): a job killed by the cap takes the cancellation path, the most expensive case to lose. + if: ${{ always() }} + uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 + with: + path: ${{ github.workspace }}\.ccache + key: ccache-sd-cuda-${{ matrix.cuda }}-windows-${{ steps.cckey.outputs.archs }}-${{ needs.resolve.outputs.tag }}- + build-windows: name: ${{ matrix.label }} needs: resolve @@ -549,6 +866,7 @@ jobs: include: - label: win-cpu-x64 vulkan: "OFF" + cpu_floor: x64 - label: win-vulkan-x64 vulkan: "ON" env: @@ -608,6 +926,10 @@ jobs: shell: pwsh working-directory: src run: | + $cpuVariants = @() + if ('${{ matrix.cpu_floor }}' -ne '') { + $cpuVariants = @('-DSD_BUILD_SHARED_GGML_LIB=ON', '-DBUILD_SHARED_LIBS=ON', '-DGGML_BACKEND_DL=ON', '-DGGML_CPU_ALL_VARIANTS=ON') + } cmake -S . -B build -G Ninja ` -DCMAKE_BUILD_TYPE=Release ` -DCMAKE_CXX_FLAGS='/bigobj' ` @@ -615,7 +937,9 @@ jobs: -DSD_SERVER_BUILD_FRONTEND=OFF ` -DSD_WEBP=OFF -DSD_WEBM=OFF ` -DSD_VULKAN=${{ matrix.vulkan }} ` - -DGGML_NATIVE=OFF + -DGGML_NATIVE=OFF ` + @cpuVariants + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } cmake --build build --config Release -j 3 --target sd-cli sd-server # Before packaging, so every PE the bundle carries is signed. Windows @@ -661,6 +985,44 @@ jobs: & tooling/.github/scripts/assert-windows-bundle-signed.ps1 -Path $zips exit $LASTEXITCODE + - name: CPU variants gate + if: ${{ matrix.cpu_floor != '' }} + shell: pwsh + run: | + $ErrorActionPreference = 'Stop' + $zip = (Get-ChildItem dist -Filter *.zip | Select-Object -First 1).FullName + $work = Join-Path $env:RUNNER_TEMP 'cpu-variants' + $empty = Join-Path $env:RUNNER_TEMP 'cpu-variants-cwd' + Remove-Item -Recurse -Force $work, $empty -ErrorAction SilentlyContinue + New-Item -ItemType Directory -Force $work, $empty | Out-Null + Expand-Archive -Path $zip -DestinationPath $work + $cli = Get-ChildItem $work -Recurse -Filter sd-cli.exe | Select-Object -First 1 + $dir = $cli.DirectoryName + $variants = @(Get-ChildItem $dir -Filter 'ggml-cpu-*.dll' | ForEach-Object { $_.BaseName -replace '^ggml-cpu-', '' }) + Write-Host "variants: $($variants -join ' ')" + if ($variants -notcontains '${{ matrix.cpu_floor }}') { + Write-Host "::error::floor variant ${{ matrix.cpu_floor }} missing from the bundle" + exit 1 + } + Push-Location $empty + $ErrorActionPreference = 'Continue' + $out = (& $cli.FullName -m (Join-Path $empty 'none.gguf') -p x -v 2>&1 | Out-String) + Pop-Location + $m = [regex]::Match($out, 'loaded CPU backend from (.+?\.dll)') + if (-not $m.Success) { + Write-Host $out + Write-Host '::error::sd-cli loaded no CPU backend variant' + exit 1 + } + $loaded = $m.Groups[1].Value.Trim() + Write-Host "loaded: $loaded" + if ((Split-Path -Parent ([IO.Path]::GetFullPath($loaded))) -ne [IO.Path]::GetFullPath($dir)) { + Write-Host "::error::variant came from outside the bundle: $loaded" + exit 1 + } + # sd-cli itself exits 1 at the missing model; that is the expected stop, not the verdict. + exit 0 + - name: Upload bundle uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: @@ -669,9 +1031,185 @@ jobs: if-no-files-found: error retention-days: 7 + # Linux ROCm from TheRock wheels like upstream's build.yml, but the linked ROCm userspace ships + # in the bundle with rpath $ORIGIN: upstream's zip dies on a host whose ROCm differs or is + # absent (unsloth#8814). Only the kernel driver comes from the host. + build-linux-rocm: + name: Linux-Ubuntu-24.04-x86_64-rocm-7.14.0 + needs: resolve + continue-on-error: true + if: ${{ needs.resolve.outputs.exists != 'true' || github.event_name == 'workflow_dispatch' }} + runs-on: ubuntu-24.04 + env: + ROCM_VERSION: "7.14.0" + # Consumer parts, upstream's Windows list. CDNA hosts run diffusers and never reach this. + GPU_TARGETS: "gfx1010;gfx1011;gfx1012;gfx1030;gfx1031;gfx1032;gfx1033;gfx1034;gfx1035;gfx1036;gfx1100;gfx1101;gfx1102;gfx1103;gfx1150;gfx1151;gfx1152;gfx1153;gfx1200;gfx1201" + # rocm-sdk re-expands clang from the wheel every run, so its mtime always differs and + # the default compiler_check=mtime misses every object. + CCACHE_COMPILERCHECK: content + steps: + - name: Checkout mirror (tooling) + uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 + with: + path: tooling + fetch-depth: 1 + + - name: Free disk for the ROCm wheels + run: | + set -eux + sudo rm -rf /usr/local/lib/android /usr/share/dotnet /opt/ghc /usr/local/.ghcup \ + /usr/local/share/boost /usr/share/swift /opt/hostedtoolcache + docker system prune -af || true + df -h / + + - name: Download source @ ${{ needs.resolve.outputs.tag }} + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 + with: + name: ${{ needs.resolve.outputs.source_artifact }} + path: srcpkg + - name: Extract source + run: | + set -eux + mkdir -p src + tar -xzf "srcpkg/sd-source-${{ needs.resolve.outputs.tag }}.tar.gz" -C src + + - name: Install ROCm (TheRock wheels) + run: | + set -euo pipefail + sudo apt-get update -qq && sudo apt-get install -y -qq ninja-build patchelf + python3 -m venv .rocm + . .rocm/bin/activate + python -m pip install -q --upgrade pip + # libraries/devel carry no GPU code: rocBLAS/hipBLASLt kernels and kpack archives come + # from one rocm-sdk-device- wheel per target, linked into the devel tree by + # `rocm-sdk path`. + DEVICE="$(echo "$GPU_TARGETS" | sed 's/;/,device-/g; s/^/device-/')" + python -m pip install -q --no-cache-dir --index-url https://repo.amd.com/rocm/whl-multi-arch/ \ + "rocm[libraries,devel,${DEVICE}]==${ROCM_VERSION}" + ROCM_PATH="$(rocm-sdk path --root)" + { + echo "ROCM_PATH=$ROCM_PATH" + echo "HIP_PATH=$ROCM_PATH" + echo "CMAKE_PREFIX_PATH=$(rocm-sdk path --cmake)" + echo "LD_LIBRARY_PATH=$ROCM_PATH/lib:${LD_LIBRARY_PATH:-}" + } >> "$GITHUB_ENV" + echo "$(rocm-sdk path --bin)" >> "$GITHUB_PATH" + echo "$(pwd)/.rocm/bin" >> "$GITHUB_PATH" + + - name: ccache key + id: cckey + run: echo "archs=$(echo "$GPU_TARGETS" | sha256sum | cut -c1-8)" >> "$GITHUB_OUTPUT" + + - name: ccache + uses: hendrikmuhs/ccache-action@d62db5f07c26379fc4b4e0916f098a92573c3b03 # v1.2.23 + with: + key: sd-rocm-${{ env.ROCM_VERSION }}-${{ steps.cckey.outputs.archs }}-${{ needs.resolve.outputs.tag }} + restore-keys: | + sd-rocm-${{ env.ROCM_VERSION }}-${{ steps.cckey.outputs.archs }} + append-timestamp: false + variant: ccache + max-size: 2G + save: false + + - name: Build sd-cli + sd-server (ROCm) + working-directory: src + run: | + set -euo pipefail + cmake -B build -G Ninja \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_HIP_COMPILER="$(hipconfig -l)/clang" \ + -DCMAKE_HIP_FLAGS="-mllvm --amdgpu-unroll-threshold-local=600" \ + -DSD_BUILD_EXAMPLES=ON \ + -DSD_SERVER_BUILD_FRONTEND=OFF \ + -DSD_WEBP=OFF -DSD_WEBM=OFF \ + -DGGML_NATIVE=OFF \ + -DSD_HIPBLAS=ON \ + -DHIP_PLATFORM=amd \ + -DGPU_TARGETS="$GPU_TARGETS" \ + -DCMAKE_C_COMPILER_LAUNCHER=ccache \ + -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \ + -DCMAKE_HIP_COMPILER_LAUNCHER=ccache + cmake --build build --config Release -j "$(nproc)" --target sd-cli sd-server + ccache --show-stats || true + + - name: Stage the bundle with the ROCm runtime + run: | + set -euo pipefail + BIN="${GITHUB_WORKSPACE}/src/build/bin" + STAGE="${GITHUB_WORKSPACE}/rocm-bundle" + rm -rf "$STAGE" && mkdir -p "$STAGE/lib" "$STAGE/.kpack" + cp "$BIN/sd-cli" "$BIN/sd-server" "$STAGE/" + # ldd walks the closure and ggml is static here, so the two binaries are the whole list. + ldd "$STAGE/sd-cli" "$STAGE/sd-server" \ + | awk -v r="$ROCM_PATH/" 'index($3, r) == 1 { print $3 }' | sort -u > "$RUNNER_TEMP/rocm-libs.txt" + if [ ! -s "$RUNNER_TEMP/rocm-libs.txt" ]; then + echo "ERROR: nothing resolved from $ROCM_PATH; is this a HIP build?" >&2 + exit 1 + fi + while read -r so; do cp -L "$so" "$STAGE/lib/"; done < "$RUNNER_TEMP/rocm-libs.txt" + # rocBLAS and hipBLASLt load kernels from //library. + for t in rocblas hipblaslt; do + compgen -G "$STAGE/lib/lib$t.so*" > /dev/null || continue + mkdir -p "$STAGE/lib/$t" + cp -rL "$ROCM_PATH/lib/$t/library" "$STAGE/lib/$t/" + done + # kpack-split libraries name their GPU code in .rocm_kpack_ref as + # ../.kpack/_@GFXARCH@.kpack, relative to the library, so lib/ and .kpack/ must + # stay siblings in the bundle. + for so in "$STAGE"/lib/*.so*; do + objcopy -O binary --only-section=.rocm_kpack_ref "$so" "$RUNNER_TEMP/kpack_ref.bin" + for name in $(strings "$RUNNER_TEMP/kpack_ref.bin" | grep -o '\.kpack/[A-Za-z0-9_]*_@GFXARCH@' \ + | sed 's#^\.kpack/##; s#_@GFXARCH@$##' | sort -u); do + for gfx in ${GPU_TARGETS//;/ }; do + cp -L "$ROCM_PATH/.kpack/${name}_${gfx}.kpack" "$STAGE/.kpack/" + done + done + done + patchelf --set-rpath '$ORIGIN/lib' "$STAGE/sd-cli" "$STAGE/sd-server" + for f in "$STAGE"/lib/*.so*; do patchelf --set-rpath '$ORIGIN' "$f"; done + echo "bundled $(wc -l < "$RUNNER_TEMP/rocm-libs.txt") ROCm libraries, $(ls "$STAGE/.kpack" | wc -l) kpack archives" + du -sh "$STAGE" + # The proof the bundle stands alone: resolve with the wheel tree hidden. + if LD_LIBRARY_PATH= ldd "$STAGE/sd-cli" "$STAGE/sd-server" | grep -i 'not found'; then + echo "ERROR: unresolved libraries after bundling" >&2 + exit 1 + fi + + - name: Package bundle + env: + BIN_DIR: ${{ github.workspace }}/rocm-bundle + KEEP_LAYOUT: "1" + OUT_DIR: ${{ github.workspace }}/dist + TAG: ${{ needs.resolve.outputs.tag }} + LABEL: Linux-Ubuntu-24.04-x86_64-rocm-7.14.0 + COMMIT: ${{ needs.resolve.outputs.commit }} + SOURCE_REPO: ${{ github.repository }} + LICENSE_FILE: ${{ github.workspace }}/src/LICENSE + run: python3 tooling/scripts/unsloth/package_bundle.py + + - name: Upload bundle + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + with: + name: sd-${{ needs.resolve.outputs.tag }}-bin-Linux-Ubuntu-24.04-x86_64-rocm-7.14.0 + path: dist/sd-${{ needs.resolve.outputs.tag }}-bin-Linux-Ubuntu-24.04-x86_64-rocm-7.14.0.zip + if-no-files-found: error + retention-days: 7 + + - name: Evict stale ccache files + if: ${{ !cancelled() }} + continue-on-error: true + run: ccache --evict-older-than 14d + + - name: Save ccache + if: ${{ always() }} + uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 + with: + path: ${{ github.workspace }}/.ccache + key: ccache-sd-rocm-${{ env.ROCM_VERSION }}-${{ steps.cckey.outputs.archs }}-${{ needs.resolve.outputs.tag }}- + assemble: name: Assemble + publish - needs: [resolve, build-unix, build-windows, build-linux-cuda] + needs: [resolve, build-unix, build-windows, build-linux-cuda, build-windows-cuda, build-linux-rocm] # Consumed by `reclaim` to tell "these bundles are now release assets" from # "nothing will ever read these". Set only after draft=false lands. outputs: @@ -727,6 +1265,7 @@ jobs: # Vulkan is required: the pinned upstream fallback lacks our H3 fixes. # Blocking publication on a Vulkan failure prevents promoting an incomplete fix. + # CUDA and ROCm are best effort and are not listed here. - name: Coverage gate (all 7 CPU/Apple/Vulkan assets present) run: | set -eu @@ -776,7 +1315,7 @@ jobs: AHEAD='${{ needs.resolve.outputs.ahead }}' COMMIT='${{ needs.resolve.outputs.commit }}' REPO="$GITHUB_REPOSITORY" - NOTES="Automated Unsloth stable-diffusion.cpp prebuild (sd-cli + sd-server), built from [\`${COMMIT}\`](https://github.com/${REPO}/commit/${COMMIT}) in this repository. Includes CPU, Apple Metal, and Linux/Windows Vulkan builds, plus Linux CUDA when its build succeeds." + NOTES="Automated Unsloth stable-diffusion.cpp prebuild (sd-cli + sd-server), built from [\`${COMMIT}\`](https://github.com/${REPO}/commit/${COMMIT}) in this repository. Includes CPU, Apple Metal, and Linux/Windows Vulkan builds, plus Linux/Windows CUDA 12 and 13 and Linux ROCm when those builds succeed. The CUDA bundles carry no CUDA runtime: Studio supplies the one its llama.cpp build already uses." PINS='${{ needs.resolve.outputs.pins }}' if [ "${AHEAD:-0}" -gt 0 ]; then NOTES="${NOTES}"$'\n\n'"Not a stock build: the tree is ${AHEAD} commits past the ${UPSTREAM_TAG} release it descends from, which is what the \`-u\` suffix on the tag marks. \`sd-prebuilt-manifest.json\` records the commit." diff --git a/.gitignore b/.gitignore index 80599b3f81..b55ea0f81b 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,10 @@ tests/ .cache/ *.swp *.bat +!/start-server.bat +/start-server.local.sh +/start-server.local.bat +/start-server.local.ps1 *.bin *.exe *.gguf diff --git a/AGENTS.md b/AGENTS.md index 4953e2278b..a48040869d 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -83,6 +83,8 @@ documentation. and debugging. * `examples/common/` - shared example support code. * `examples/server/` - server application built on top of the library. + Before modifying built-in recipes, read and follow + [the built-in recipe policy](examples/server/recipes/README.md). * `examples/server/frontend/` - git submodule containing independent frontend code. Avoid modifying it unless explicitly requested. diff --git a/CMakeLists.txt b/CMakeLists.txt index 134719ca47..d7bfda5999 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -225,6 +225,8 @@ file(GLOB SD_LIB_SOURCES CONFIGURE_DEPENDS "src/core/*.h" "src/core/*.cpp" "src/core/*.hpp" + "src/core/probe/*.h" + "src/core/probe/*.cpp" "src/extensions/*.h" "src/extensions/*.cpp" "src/extensions/*.hpp" @@ -342,9 +344,17 @@ if (SD_CUDA) target_link_libraries(${SD_LIB} PUBLIC CUDA::cuda_driver) set_property(SOURCE src/core/ggml_extend_backend.cpp APPEND PROPERTY COMPILE_DEFINITIONS SD_USE_CUDA) endif() -target_include_directories(${SD_LIB} PUBLIC . src include) -target_include_directories(${SD_LIB} PRIVATE src/core) -target_include_directories(${SD_LIB} PUBLIC . thirdparty) +if (SD_HIPBLAS) + find_package(hip REQUIRED CONFIG HINTS "$ENV{ROCM_PATH}" /opt/rocm) + target_link_libraries(${SD_LIB} PRIVATE hip::host) + set_property(SOURCE src/core/ggml_extend_backend.cpp APPEND PROPERTY COMPILE_DEFINITIONS SD_USE_HIP) + if (GGML_HIP_MMQ_MFMA) + set_property(SOURCE src/core/ggml_extend_backend.cpp APPEND PROPERTY COMPILE_DEFINITIONS SD_HIP_MFMA) + endif() +endif() +target_include_directories(${SD_LIB} PUBLIC include) +target_include_directories(${SD_LIB} PRIVATE src src/core) +target_include_directories(${SD_LIB} PUBLIC thirdparty) target_compile_features(${SD_LIB} PUBLIC c_std_11 cxx_std_17) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d9975cf60d..ca64ad1981 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -12,6 +12,10 @@ If you want to update a third-party dependency, please open an issue first inste ## Pull Requests +When contributing from a fork, use a fork under your personal GitHub account and enable **Allow edits from maintainers**. This lets maintainers make follow-up fixes directly on the PR branch. + +PRs from organization-owned forks are automatically closed when opened or reopened because GitHub does not support this maintainer-edit option for those forks. Submit the changes from a personal fork instead. See [GitHub's documentation](https://docs.github.com/en/pull-requests/how-tos/work-with-forks/allowing-changes-to-a-pull-request-branch-created-from-a-fork). + Keep each PR focused on one clear change. Large or overly complex PRs are harder to review and may not be merged. Do not include test code or test scripts in commits or PRs. Keep them local and report verification results in the PR description. @@ -25,6 +29,21 @@ PRs should include: - Linked issue/PR context when applicable. - Screenshots or sample outputs for UI/visual behavior changes. +## README UI Listings + +The [UIs list in the README](README.md#uis) only includes open-source projects that use `stable-diffusion.cpp` as a backend. Do not submit PRs to add closed-source UIs. + +## Server Recipes + +Before adding or changing a built-in server recipe, read and follow the +[built-in recipe policy](examples/server/recipes/README.md). The policy governs +native editing, community editing LoRAs, distinct task checkpoints, external +adapters, native components and layer-count variants. Do not add recipes solely +for style or acceleration LoRAs, separately stored native components, or added +or removed model layers. Explain the task, component compatibility or capability +difference that justifies a new recipe, and verify its required components, +feature declarations and embedded API representation. + ## Code Style Format code according to the repository style before submitting changes. diff --git a/README.md b/README.md index f184c51b0f..b4ab2f5ab2 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,8 @@ API and command-line option may change frequently.*** ## 🔥Important News +* **2026/10/16** 🚀 stable-diffusion.cpp adds **Day-0 support for MOSS-Image-Base / MOSS-Image-SFT** +* **2026/10/16** 🚀 stable-diffusion.cpp adds **Day-0 support for FLUX.3 Image Klein / Klein Base** * **2026/09/20** 🚀 stable-diffusion.cpp adds **Day-0 support for Qwen-Image-2.1** * **2026/08/20** 🚀 stable-diffusion.cpp now supports **LTX-2.5** * **2026/08/04** 🚀 stable-diffusion.cpp adds **Day-1 support for MiniMax-H3** @@ -44,6 +46,8 @@ API and command-line option may change frequently.*** - [SD3/SD3.5](./docs/sd3.md) - [FLUX.1-dev/FLUX.1-schnell](./docs/flux.md) - [FLUX.2-dev/FLUX.2-klein](./docs/flux2.md) + - [FLUX.3 Image Klein / Klein Base](./docs/flux3.md) + - [MOSS-Image-Base / MOSS-Image-SFT](./docs/moss_image.md) - [Lens](./docs/lens.md) - [Chroma](./docs/chroma.md) - [Chroma1-Radiance](./docs/chroma_radiance.md) @@ -52,6 +56,7 @@ API and command-line option may change frequently.*** - [PiD](./docs/pid.md) - [LongCat Image](./docs/longcat_image.md) - [Z-Image](./docs/z_image.md) + - [Z-Image L2P](./docs/z_image_l2p.md) - [MiniT2I](./docs/minit2i.md) - [SenseNova U1.5](./docs/sensenova_u1.md) - [Ovis-Image](./docs/ovis_image.md) @@ -64,6 +69,9 @@ API and command-line option may change frequently.*** - [HiDream-O1-Image](./docs/hidream_o1_image.md) - [Ideogram4](./docs/ideogram4.md) - [LLaDA-Image](./docs/llada_image.md) + - [Ming-Image Design](./docs/ming_image.md) + - [PixArt](./docs/pixart.md) + - [Iris-3B](./docs/iris.md) - [Image Edit Models](./docs/edit.md) - [FLUX.1-Kontext-dev](./docs/kontext.md) - [Qwen Image Edit series](./docs/qwen_image_edit.md) @@ -179,7 +187,6 @@ These projects wrap `stable-diffusion.cpp` for easier use in other languages/fra These projects use `stable-diffusion.cpp` as a backend for their image generation. - [GIMP Plugins](https://github.com/themanyone/gimp-plugins) -- [Jellybox](https://jellybox.com) - [Stable Diffusion GUI](https://github.com/fszontagh/sd.cpp.gui.wx) - [Stable Diffusion CLI-GUI](https://github.com/piallai/stable-diffusion.cpp) - [Local Diffusion](https://github.com/rmatif/Local-Diffusion) @@ -187,6 +194,7 @@ These projects use `stable-diffusion.cpp` as a backend for their image generatio - [LocalAI](https://github.com/mudler/LocalAI) - [Neural-Pixel](https://github.com/Luiz-Alcantara/Neural-Pixel) - [KoboldCpp](https://github.com/LostRuins/koboldcpp) +- [Kokon](https://github.com/GabrieleLozupone/kokon) ## Contributors diff --git a/assets/flux3/flux3-image-klein-base.png b/assets/flux3/flux3-image-klein-base.png new file mode 100644 index 0000000000..411502269a Binary files /dev/null and b/assets/flux3/flux3-image-klein-base.png differ diff --git a/assets/flux3/flux3-image-klein-edit.png b/assets/flux3/flux3-image-klein-edit.png new file mode 100644 index 0000000000..f392eb86d2 Binary files /dev/null and b/assets/flux3/flux3-image-klein-edit.png differ diff --git a/assets/flux3/flux3-image-klein.png b/assets/flux3/flux3-image-klein.png new file mode 100644 index 0000000000..7d45f34720 Binary files /dev/null and b/assets/flux3/flux3-image-klein.png differ diff --git a/assets/iris/example.png b/assets/iris/example.png new file mode 100644 index 0000000000..af3a4fd75b Binary files /dev/null and b/assets/iris/example.png differ diff --git a/assets/moss/sft.png b/assets/moss/sft.png new file mode 100644 index 0000000000..ede42d1f78 Binary files /dev/null and b/assets/moss/sft.png differ diff --git a/assets/qwen/qwen-image-2.1-alpha-in1.png b/assets/qwen/qwen-image-2.1-alpha-in1.png new file mode 100644 index 0000000000..e65fcf0719 Binary files /dev/null and b/assets/qwen/qwen-image-2.1-alpha-in1.png differ diff --git a/assets/qwen/qwen-image-2.1-alpha-out1.png b/assets/qwen/qwen-image-2.1-alpha-out1.png new file mode 100644 index 0000000000..6841b7f787 Binary files /dev/null and b/assets/qwen/qwen-image-2.1-alpha-out1.png differ diff --git a/assets/qwen/qwen-image-2.1-alpha-out2.png b/assets/qwen/qwen-image-2.1-alpha-out2.png new file mode 100644 index 0000000000..8bef08a213 Binary files /dev/null and b/assets/qwen/qwen-image-2.1-alpha-out2.png differ diff --git a/assets/wan/Wan2.2_A14B_vace_r2v.mp4 b/assets/wan/Wan2.2_A14B_vace_r2v.mp4 new file mode 100644 index 0000000000..caf19c2151 Binary files /dev/null and b/assets/wan/Wan2.2_A14B_vace_r2v.mp4 differ diff --git a/cmake/ggml.cmake b/cmake/ggml.cmake index 39d77eae35..d3e952dca4 100644 --- a/cmake/ggml.cmake +++ b/cmake/ggml.cmake @@ -21,6 +21,28 @@ endif() target_include_directories(${SD_LIB} PRIVATE "${sd_ggml_private_include}") set_property(TARGET ${SD_LIB} PROPERTY SD_GGML_PRIVATE_INCLUDE_DIR "${sd_ggml_private_include}") +# The fused DiT ops come from scripts/unsloth/ggml-patches/0004; an unpatched ggml keeps the unfused H3 graph. +set(sd_ggml_header "${sd_ggml_private_include}/../include/ggml.h") +if(EXISTS "${sd_ggml_header}") + set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${sd_ggml_header}") + file(STRINGS "${sd_ggml_header}" sd_ggml_h3_fused_ops REGEX "ggml_rope_pe_permute\\(") + file(STRINGS "${sd_ggml_header}" sd_ggml_h3_fused_qk_norm REGEX "ggml_rope_pe_permute_rms\\(") + file(STRINGS "${sd_ggml_header}" sd_ggml_rope_pe_interleaved REGEX "ggml_rope_pe_permute_set_interleaved\\(") +endif() +if(sd_ggml_h3_fused_ops) + target_compile_definitions(${SD_LIB} PUBLIC SD_GGML_H3_FUSED_OPS) +else() + message(STATUS "ggml lacks the fused DiT ops patch: MiniMax-H3 uses the unfused graph") +endif() +# The fused q/k RMS norm comes from patch 0005. +if(sd_ggml_h3_fused_qk_norm) + target_compile_definitions(${SD_LIB} PUBLIC SD_GGML_H3_FUSED_QK_NORM) +endif() +# Interleaved pairing for the fused RoPE op (patch 0007): the shared DiT attention (Rope::attention) uses it. +if(sd_ggml_h3_fused_ops AND sd_ggml_rope_pe_interleaved) + target_compile_definitions(${SD_LIB} PUBLIC SD_GGML_FUSED_ROPE_ATTN) +endif() + if(SD_USE_UPSTREAM_GGML) target_compile_definitions(${SD_LIB} PUBLIC SD_USE_UPSTREAM_GGML) message(WARNING "Using upstream GGML: INT8 tensorwise/convrot is disabled and FP8 weights are converted to F16 at load time. Some operators may be unsupported and performance may be lower than with patched GGML.") diff --git a/docker/Dockerfile b/docker/Dockerfile index 0ef3d56acc..3a80ae9bf8 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -40,4 +40,6 @@ RUN printf '#!/bin/sh\nexec /sd.cpp/bin/sd-cli "$@"\n' > /sd-cli && \ printf '#!/bin/sh\nexec /sd.cpp/bin/sd-server "$@"\n' > /sd-server && \ chmod +x /sd-cli /sd-server +WORKDIR /sd.cpp + ENTRYPOINT [ "/sd-cli" ] diff --git a/docker/Dockerfile.cuda b/docker/Dockerfile.cuda index 3e51bda60c..625dc60e70 100644 --- a/docker/Dockerfile.cuda +++ b/docker/Dockerfile.cuda @@ -57,4 +57,6 @@ RUN printf '#!/bin/sh\nexec /sd.cpp/bin/sd-cli "$@"\n' > /sd-cli && \ printf '#!/bin/sh\nexec /sd.cpp/bin/sd-server "$@"\n' > /sd-server && \ chmod +x /sd-cli /sd-server +WORKDIR /sd.cpp + ENTRYPOINT [ "/sd-cli" ] diff --git a/docker/Dockerfile.musa b/docker/Dockerfile.musa index 1c1d4d28c3..08d6f1d43d 100644 --- a/docker/Dockerfile.musa +++ b/docker/Dockerfile.musa @@ -1,7 +1,6 @@ -ARG MUSA_VERSION=rc4.2.0 -ARG UBUNTU_VERSION=22.04 +ARG MUSA_IMAGE=registry.mthreads.com/mcconline/inference/pytorch:2.9.1.post1-py3.10-musa5.2.0-mp31-devel-ubuntu22.04-amd64 -FROM mthreads/musa:${MUSA_VERSION}-devel-ubuntu${UBUNTU_VERSION}-amd64 as build +FROM ${MUSA_IMAGE} AS build # sd-server embeds the web UI at build time, so the build image needs Node/pnpm. RUN apt-get update && apt-get install -y --no-install-recommends ccache cmake git ca-certificates curl gnupg && \ @@ -22,9 +21,8 @@ COPY . . RUN mkdir build && cd build && \ cmake .. -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ \ - -DCMAKE_C_FLAGS="${CMAKE_C_FLAGS} -fopenmp -I/usr/lib/llvm-14/lib/clang/14.0.0/include -L/usr/lib/llvm-14/lib" \ - -DCMAKE_CXX_FLAGS="${CMAKE_CXX_FLAGS} -fopenmp -I/usr/lib/llvm-14/lib/clang/14.0.0/include -L/usr/lib/llvm-14/lib" \ -DSD_MUSA=ON \ + -DMUSA_ARCHITECTURES=31 \ -DSD_BUILD_SHARED_LIBS=ON \ -DGGML_NATIVE=OFF \ -DSD_BUILD_SHARED_GGML_LIB=ON \ @@ -35,11 +33,14 @@ RUN mkdir build && cd build && \ -DCMAKE_BUILD_TYPE=Release && \ cmake --build . --config Release -FROM mthreads/musa:${MUSA_VERSION}-runtime-ubuntu${UBUNTU_VERSION}-amd64 as runtime +FROM ${MUSA_IMAGE} AS runtime COPY --from=build /sd.cpp/build/bin /sd.cpp/bin RUN printf '#!/bin/sh\nexec /sd.cpp/bin/sd-cli "$@"\n' > /sd-cli && \ printf '#!/bin/sh\nexec /sd.cpp/bin/sd-server "$@"\n' > /sd-server && \ chmod +x /sd-cli /sd-server +WORKDIR /sd.cpp + ENTRYPOINT [ "/sd-cli" ] +CMD [] diff --git a/docker/Dockerfile.rocm b/docker/Dockerfile.rocm new file mode 100644 index 0000000000..fe8a9b15e1 --- /dev/null +++ b/docker/Dockerfile.rocm @@ -0,0 +1,50 @@ +FROM rocm/dev-ubuntu-24.04 AS build + +# sd-server embeds the web UI at build time, so the build image needs Node/pnpm. +RUN apt-get update && apt-get install -y --no-install-recommends \ + build-essential git cmake ninja-build ccache ca-certificates curl gnupg && \ + mkdir -p /etc/apt/keyrings && \ + curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key -o /tmp/nodesource-repo.gpg.key && \ + gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg /tmp/nodesource-repo.gpg.key && \ + rm /tmp/nodesource-repo.gpg.key && \ + echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_20.x nodistro main" > /etc/apt/sources.list.d/nodesource.list && \ + apt-get update && apt-get install -y --no-install-recommends nodejs && \ + npm install -g pnpm@10.15.1 && \ + apt-get clean && rm -rf /var/lib/apt/lists/* + +WORKDIR /sd.cpp + +# ROCm's clang is not on PATH in Docker RUN shells (profile scripts are not loaded). +ENV PATH="/opt/rocm/llvm/bin:$PATH" + +COPY . . + +ARG AMDGPU_TARGETS="" + +RUN cmake . -B ./build -G Ninja \ + -DCMAKE_C_COMPILER=clang \ + -DCMAKE_CXX_COMPILER=clang++ \ + -DSD_HIPBLAS=ON \ + -DGGML_NATIVE=OFF \ + -DAMDGPU_TARGETS="${AMDGPU_TARGETS}" \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_BUILD_WITH_INSTALL_RPATH=ON \ + -DCMAKE_POSITION_INDEPENDENT_CODE=ON +RUN cmake --build ./build --config Release --parallel + +FROM rocm/dev-ubuntu-24.04 AS runtime + +# ROCm clang links against its own OpenMP runtime in /opt/rocm/llvm/lib, +# and the ROCm runtime libs (hipblas, rocblas, amdhip64) live in /opt/rocm/lib. +ENV LD_LIBRARY_PATH="/opt/rocm/llvm/lib:/opt/rocm/lib:$LD_LIBRARY_PATH" + +RUN apt-get update && \ + apt-get install --yes --no-install-recommends libgomp1 && \ + apt-get clean && rm -rf /var/lib/apt/lists/* + +COPY --from=build /sd.cpp/build/bin /sd.cpp/bin +RUN printf '#!/bin/sh\nexec /sd.cpp/bin/sd-cli "$@"\n' > /sd-cli && \ + printf '#!/bin/sh\nexec /sd.cpp/bin/sd-server "$@"\n' > /sd-server && \ + chmod +x /sd-cli /sd-server + +ENTRYPOINT [ "/sd-cli" ] diff --git a/docker/Dockerfile.sycl b/docker/Dockerfile.sycl index 9927ae7e58..9225e6eb2f 100644 --- a/docker/Dockerfile.sycl +++ b/docker/Dockerfile.sycl @@ -29,4 +29,6 @@ FROM intel/oneapi-basekit:${SYCL_VERSION}-devel-ubuntu24.04 AS runtime COPY --from=build /sd.cpp/build/bin/sd-cli /sd-cli COPY --from=build /sd.cpp/build/bin/sd-server /sd-server +WORKDIR /sd.cpp + ENTRYPOINT [ "/sd-cli" ] \ No newline at end of file diff --git a/docker/Dockerfile.vulkan b/docker/Dockerfile.vulkan index 2c40c21a77..c7810a1fa5 100644 --- a/docker/Dockerfile.vulkan +++ b/docker/Dockerfile.vulkan @@ -41,4 +41,6 @@ RUN printf '#!/bin/sh\nexec /sd.cpp/bin/sd-cli "$@"\n' > /sd-cli && \ printf '#!/bin/sh\nexec /sd.cpp/bin/sd-server "$@"\n' > /sd-server && \ chmod +x /sd-cli /sd-server +WORKDIR /sd.cpp + ENTRYPOINT [ "/sd-cli" ] diff --git a/docs/anima.md b/docs/anima.md index b852358fdd..18b94952b6 100644 --- a/docs/anima.md +++ b/docs/anima.md @@ -15,7 +15,7 @@ ## Examples ```sh -.\bin\Release\sd-cli.exe --diffusion-model ..\models\diffusion_models\anima-preview.safetensors --vae ..\models\vae\qwen_image_vae.safetensors --llm ..\models\text_encoders\qwen_3_06b_base.safetensors -p "a lovely cat holding a sign says 'anima.cpp'" --cfg-scale 6.0 --sampling-method euler -v --offload-to-cpu --diffusion-fa +.\bin\Release\sd-cli.exe --diffusion-model ..\models\diffusion_models\anima-preview.safetensors --vae ..\models\vae\qwen_image_vae.safetensors --llm ..\models\text_encoders\qwen_3_06b_base.safetensors -p "a lovely cat holding a sign says 'anima.cpp'" --cfg-scale 6.0 --sampling-method euler -v --offload-to-cpu ``` anima image example diff --git a/docs/animatediff.md b/docs/animatediff.md index 2e923b0bf3..80c46ae64f 100644 --- a/docs/animatediff.md +++ b/docs/animatediff.md @@ -51,7 +51,7 @@ SD 1.5 defaults (euler_a, low CFG) produces noise-like output. .\bin\Release\sd-cli.exe -M vid_gen \ --model ..\models\checkpoints\realisticVisionV60B1.safetensors \ --motion-module ..\models\animatediff\mm_sd15_v3.safetensors \ - --offload-to-cpu --diffusion-fa \ + --offload-to-cpu \ -p "a red apple on a wooden table" \ --cfg-scale 8.0 --sampling-method euler --scheduler discrete \ -H 512 -W 512 --video-frames 8 --fps 8 --steps 20 -s 42 \ @@ -66,7 +66,7 @@ use layer streaming: .\bin\Release\sd-cli.exe -M vid_gen \ --model ..\models\checkpoints\realisticVisionV60B1.safetensors \ --motion-module ..\models\animatediff\mm_sd15_v3.safetensors \ - --offload-to-cpu --diffusion-fa \ + --offload-to-cpu \ -p "photo of coastline, rocks, storm weather, wind, waves, lightning" \ --cfg-scale 8.0 --sampling-method euler --scheduler discrete \ -H 384 -W 384 --video-frames 16 --fps 8 --steps 20 -s 42 \ @@ -79,7 +79,7 @@ Low-VRAM streaming (verified with a 2 GiB cap on RTX 3060): .\bin\Release\sd-cli.exe -M vid_gen \ --model ..\models\checkpoints\realisticVisionV60B1.safetensors \ --motion-module ..\models\animatediff\mm_sd15_v3.safetensors \ - --max-vram 2.0 --diffusion-fa \ + --max-vram 2.0 \ -p "photo of coastline, rocks, storm weather, wind, waves, lightning" \ --cfg-scale 8.0 --sampling-method euler --scheduler discrete \ -H 384 -W 384 --video-frames 8 --fps 8 --steps 20 -s 42 \ diff --git a/docs/backend.md b/docs/backend.md index 846aafb858..057d3f20ef 100644 --- a/docs/backend.md +++ b/docs/backend.md @@ -65,8 +65,12 @@ sd-cli -m model.safetensors -p "a cat" --backend "diffusion=cuda0&cuda1" ``` The module's transformer blocks are then distributed across the listed devices -in contiguous ranges sized proportionally to each device's free memory (minus a -compute-buffer headroom of about 2 GiB per device), and the +in contiguous ranges sized proportionally to each device's weight capacity: its +free memory or its `--max-vram` budget, whichever is lower, minus a +compute-buffer headroom of about 2 GiB. Every device therefore keeps the same +fraction of its budget for the compute buffers of the blocks it runs. If the +proportional ranges do not fit (very uneven block sizes), each device is filled +in turn up to its capacity instead. The module's graphs are executed with a `ggml_backend_sched` that runs each block on the device holding its weights, copying the residual stream at the range boundaries. The first device in the list is the module's main device: it also @@ -156,8 +160,14 @@ the runner's graph-cut capacity checks. Runtime capacity checks also leave 512 MiB of currently free device memory for backend scratch buffers and pipelines, including with explicit backend assignments. -They cap stale free-memory reports by the device's total memory minus tracked -resident allocations and reject reports that exceed the device's total memory. +They cap free-memory reports by the device's total memory minus tracked +resident allocations. Vulkan reports exceeding total memory are rejected because +its heap-budget subtraction can underflow. Other backends use the cap instead of +treating such reports as zero free memory. Failed checks log the reported free and +total memory alongside tracked weight and runtime allocations. +With `--mmap`, device-backed mappings count toward these budgets at their full +mapped-file size, once per device buffer even when multiple parameter blocks +share it. Mappings retained in the loader cache continue to count. Components are considered in `diffusion`, `te`, `vae` order so that repeatedly used diffusion weights have priority. Each component's weights use the first @@ -209,6 +219,123 @@ If a VAE decode fails, decoding retries with spatial tiling even when `--auto-fi is off; supported video decoders try temporal tiling first and can then add spatial tiling. Spatial retries use half-size tiles along each latent dimension. +## Direct convolution (`--conv-direct on|off|auto`) + +`--conv-direct` defaults to `auto` and accepts module assignments for +`diffusion`, `vae` (including preview VAE), and `controlnet`, using the same +aliases and precedence rules as `--flash-attn`: + +```shell +sd-cli -m model.safetensors -p "a cat" --conv-direct auto,vae=off +sd-cli -m model.safetensors -p "a cat" --conv-direct off,diffusion=on +``` + +- `on` requests direct 2D and 3D convolution. +- `off` uses the existing im2col-based convolution paths. +- `auto` first checks support for a representative F16-weight/F32-input direct + convolution graph. Vulkan then benchmarks direct convolution against im2col + using two small shapes per dimension, with warmup, output validation, and five + interleaved measurements per shape. Direct convolution must improve the sum of + median times by at least 5%; a failed probe defaults to `off`. + Other backends retain their implicit GEMM checks without benchmarking: + CUDA 2D requires a compiled Turing-or-newer MMA architecture; HIP 2D requires + the supported CDNA MFMA or RDNA WMMA architectures described below for flash + attention. MUSA 2D has a SIMT implementation. CUDA, HIP, and MUSA 3D also have + a SIMT implementation, so they do not require MMA. Other backends default to + `off`. Results and decision logs are cached per compute backend and dimension + in the context, as with flash attention. Each dimension is selected independently, + and all compute devices in a module must qualify. Parameter-storage devices do + not affect this choice. + +These are backend-level defaults. GGML still chooses the actual kernel based on +weight type, shape, and hardware; enabling direct convolution does not guarantee +that every operation uses implicit GEMM. The CUDA-family implicit GEMM paths +require F16 weights and can use ordinary direct kernels for other cases. +This option does not change the separately created image upscaler context. + +Repeating `--conv-direct` replaces the previous assignment string. Existing +`--diffusion-conv-direct` (diffusion and ControlNet) and `--vae-conv-direct` +flags are deprecated and emit a warning, but remain supported when +`--conv-direct` is omitted. Use `--conv-direct auto,diffusion=on,controlnet=on` +and `--conv-direct auto,vae=on`, respectively. An explicit +`--conv-direct` takes precedence over both legacy flags regardless of order. +Library callers can set the appended `sd_ctx_params_t::conv_direct_mode` field +to the same string; null or empty selects `auto` while honoring legacy true +flags. The context copies the string. + +## Flash attention (`--flash-attn on|off|auto`) + +`--flash-attn` defaults to `auto`. Selection happens while creating the model +context, before inference, and is cached once per compute backend in that context. +Parameter-storage backends are not benchmarked. + +The option also accepts module assignments, using the same module aliases as +`--backend`: + +```shell +sd-cli -m model.safetensors -p "a cat" --flash-attn auto,te=off,vae=on +sd-cli -m model.safetensors -p "a cat" --flash-attn off,diffusion=auto +``` + +Supported modules are `diffusion`, `te`, `clip_vision`, `vae`, `controlnet`, and +`audio_encoder`. Modules without an assignment use the default (`auto` if no +default is supplied). A bare mode or `all=`, `default=`, or `*=` sets the default; +module-specific settings take precedence regardless of their position. Within +one assignment string, the last setting for the same module or default wins. +Repeating `--flash-attn` replaces the entire previous string. + +Only modules set to `auto` need backend probing. An explicit `on` or `off` for +one module does not change another module's decision, even when they share a +backend. Modules without configurable attention are rejected instead of silently +ignoring their settings. + +- `on` requests flash attention for all models. Unsupported attention operations + still fall back to ordinary attention. +- `off` disables flash attention, including the flash-attention fallback from + SageAttention. SageAttention itself remains controlled by `--sage-attn`. +- `auto` enables CPU and supported CUDA MMA configurations without timing a + benchmark. CUDA uses both the device's capability and the compiled GGML + architectures. HIP also skips timing on known CDNA MFMA architectures + (`gfx908`, `gfx90a`, `gfx940`/`gfx941`/`gfx942`, `gfx950`) and RDNA 3/3.5/4 + WMMA architectures (`gfx11xx`/`gfx12xx`). The CDNA shortcut requires + `GGML_HIP_MMQ_MFMA` to be enabled at build time. All shortcuts still check + support for the FA probe graph. Vulkan devices whose description identifies + NVIDIA RTX hardware (GeForce RTX, TITAN RTX, Quadro RTX and professional RTX) + also skip timing. This is a device-name heuristic and needs no CUDA runtime. + Unsupported graphs are disabled; other configurations, including older or + unknown HIP architectures and other Vulkan devices, are benchmarked. + +The probe compares ordinary and flash attention through the same attention +builder used by models, including layout conversion and F16 conversion. It uses +two small self-attention graphs (512 tokens with head size 64, and 1024 tokens +with head size 128, both with four heads), checks their outputs, warms up each +path, then alternates five synchronized measurements. Flash attention is enabled +when the sum of its median times is at least 5% lower. These representative +shapes are a startup heuristic, not a guarantee for every model or resolution. +Allocation/execution failures and inconclusive probes select `off`. Timing stops +starting new measurement pairs after one second of measured computation; +backend initialization, warmup and an in-flight pair can take longer. + +Different modules can select different results. A multi-device model enables +flash attention only if all of its compute devices select `on`, preserving the +model's existing single boolean setting. This conservative rule also covers +row-split configurations, which can fall back to layer split during initialization. + +`--fa` and `--diffusion-fa` are deprecated and emit a warning when used. +Use `--flash-attn on` and `--flash-attn off,diffusion=on`, respectively. +Both aliases write the same mode string as `--flash-attn`; the last occurrence +of any of these options wins. Library callers +can set `sd_ctx_params_t::flash_attn_mode` to the same string, including +`"on"`, `"off"`, `"auto"`, or `"auto,te=off,vae=on"`. +A null or empty string uses automatic selection unless a +legacy `flash_attn` or `diffusion_flash_attn` boolean is set. The context copies +the string; no new enum is required. + +```shell +sd-cli -m model.safetensors -p "a cat" --flash-attn auto +sd-cli -m model.safetensors -p "a cat" --flash-attn off +``` + ## Modules | Module | Purpose | Accepted names | diff --git a/docs/backend_probe.md b/docs/backend_probe.md new file mode 100644 index 0000000000..c420326d4c --- /dev/null +++ b/docs/backend_probe.md @@ -0,0 +1,50 @@ +# Adding backend performance probes + +`src/core/probe/backend_probe.h` provides the shared measurement machinery. Operator +policy stays separate: `src/core/probe/flash_attn.cpp`, for example, defines attention +shapes and its CPU/CUDA/HIP/Vulkan shortcuts, then calls `sd_run_backend_probe` for unknown +configurations. `src/core/probe/conv_direct.cpp` uses metadata-only probe graphs +to check direct 2D/3D convolution support, then enables known implicit GEMM +paths on non-Vulkan backends. Vulkan compares direct convolution with im2col +using the shared measurement machinery. + +For each representative shape, create a `BackendProbeCase`: + +- `build(graph, candidate)` creates inputs and either the reference or candidate + graph in `graph.ctx`, registers input tensors in `graph.inputs`, and assigns + `graph.output`. Leave the output null if the requested implementation is + unavailable; do not silently benchmark its fallback as the candidate. +- By default, inputs receive deterministic F32 data, with the same seed for both + variants. Supply `initialize` for F16 convolution weights, integer inputs, or + operator-specific values. It runs after allocation, outside timed execution. + Both variants must receive equivalent logical inputs. +- Default output validation requires matching shapes and contiguous F32 outputs, + checks finiteness, and applies absolute and relative tolerances. Supply + `compare` for other output types or validation rules. + +Graphs must be safe to execute repeatedly without modifying their inputs. +`BackendProbeGraph` owns its GGML context and buffer, so all return paths release +probe resources. Constructors allocate metadata only; `supported()` can also be +used before a known-architecture shortcut, without allocating device tensors. + +`BackendProbeOptions` controls graph metadata capacity, warmup count, measurement +count, measured-time budget, minimum free device memory, comparison tolerances, +and minimum improvement. Warmup and allocation are excluded from timing. The +runner alternates the two variants, synchronizes the backend around execution, +and compares sums of per-case medians. The time budget is checked before each +measurement pair; it cannot interrupt an in-flight backend operation. + +Only use `candidate_faster` when `completed` is true. On incomplete probes, +`error` reports why comparison failed and the timing totals may be partial. +The caller handles logging, known architecture rules, fallback policy, and +context-lifetime caching. Keep caches separate by operation (or key a shared +cache by both operation and backend); an attention result must not select a +convolution implementation. If shapes or settings vary within one context, +include them in the corresponding cache key as well. + +Convolution results are cached separately for 2D and 3D, once per compute backend +in the context, just like attention results. Each probe logs its backend, decision, +and reason; mixed-device modules log when their compute devices disagree. + +Module assignment parsing remains in `src/core/ggml_extend_backend.cpp`, next +to backend assignment parsing. The probe directory does not parse CLI/API options. diff --git a/docs/boogu_image.md b/docs/boogu_image.md index 2744aae57a..c5ad97dd85 100644 --- a/docs/boogu_image.md +++ b/docs/boogu_image.md @@ -17,7 +17,7 @@ Boogu Image uses a Boogu diffusion transformer, the FLUX VAE, and Qwen3-VL as th ### Boogu Image Base ``` -.\bin\Release\sd-cli.exe --diffusion-model ..\models\diffusion_models\boogu_image_base_bf16.safetensors --llm ..\models\text_encoders\Qwen3VL-8B-Instruct-Q4_K_M.gguf --vae ..\models\vae\ae.sft -p "a lovely cat" --diffusion-fa -v --offload-to-cpu +.\bin\Release\sd-cli.exe --diffusion-model ..\models\diffusion_models\boogu_image_base_bf16.safetensors --llm ..\models\text_encoders\Qwen3VL-8B-Instruct-Q4_K_M.gguf --vae ..\models\vae\ae.sft -p "a lovely cat" -v --offload-to-cpu ``` Boogu Image Base example @@ -25,7 +25,7 @@ Boogu Image uses a Boogu diffusion transformer, the FLUX VAE, and Qwen3-VL as th ### Boogu Image Edit ``` -.\bin\Release\sd-cli.exe --diffusion-model ..\models\diffusion_models\boogu_image_edit_bf16.safetensors --llm ..\models\text_encoders\Qwen3VL-8B-Instruct-Q4_K_M.gguf --llm_vision ..\models\text_encoders\mmproj-Qwen3VL-8B-Instruct-F16.gguf --vae ..\models\vae\ae.sft --diffusion-fa -v --offload-to-cpu -r ..\assets\flux\flux1-dev-q8_0.png -p "change 'flux.cpp' to 'boogu.cpp'" +.\bin\Release\sd-cli.exe --diffusion-model ..\models\diffusion_models\boogu_image_edit_bf16.safetensors --llm ..\models\text_encoders\Qwen3VL-8B-Instruct-Q4_K_M.gguf --llm_vision ..\models\text_encoders\mmproj-Qwen3VL-8B-Instruct-F16.gguf --vae ..\models\vae\ae.sft -v --offload-to-cpu -r ..\assets\flux\flux1-dev-q8_0.png -p "change 'flux.cpp' to 'boogu.cpp'" ``` Boogu Image Edit example \ No newline at end of file diff --git a/docs/build.md b/docs/build.md index 9daaa219b4..6ec0e40f0a 100644 --- a/docs/build.md +++ b/docs/build.md @@ -119,14 +119,16 @@ cmake --build . --config Release ## Build with MUSA -This provides GPU acceleration using Moore Threads GPU. Make sure to have the MUSA toolkit installed. +This provides GPU acceleration using Moore Threads GPUs. The configuration below follows upstream validation with MUSA SDK 5.2.0 and MTT S5000 (PH1, `mp_31`). Install that toolkit before building. Older SDKs such as 4.2 may lack the CUB headers required by the current backend. ```shell mkdir build && cd build -cmake .. -DCMAKE_C_COMPILER=/usr/local/musa/bin/clang -DCMAKE_CXX_COMPILER=/usr/local/musa/bin/clang++ -DSD_MUSA=ON -DCMAKE_BUILD_TYPE=Release +cmake .. -DCMAKE_C_COMPILER=/usr/local/musa/bin/clang -DCMAKE_CXX_COMPILER=/usr/local/musa/bin/clang++ -DSD_MUSA=ON -DMUSA_ARCHITECTURES=31 -DCMAKE_BUILD_TYPE=Release cmake --build . --config Release ``` +The MUSA Docker image uses the same SDK 5.2.0 development image as upstream for both build and runtime stages, and targets `mp_31` only. It includes the development tools and PyTorch from that base image, so it is larger than a minimal runtime image. Other GPU architectures require separate validation. + ## Build with Metal Using Metal makes the computation run on the GPU. Currently, there are some issues with Metal when performing operations on very large matrices, making it highly inefficient at the moment. Performance improvements are expected in the near future. diff --git a/docs/caching.md b/docs/caching.md index 01f0197443..f69cfbeca8 100644 --- a/docs/caching.md +++ b/docs/caching.md @@ -2,6 +2,16 @@ Caching methods accelerate diffusion inference by reusing intermediate computations when changes between steps are small. +### Conditioning Cache + +Conditioning results are cached per model context using an LRU cache. The default +capacity is **0 (disabled) for `sd-cli`** and **4 entries for `sd-server` and the C +API**. Set `--conditioning-cache-size N` to change the limit; `0` disables caching. +For example, `sd-cli -m model.safetensors -p "a cat" --conditioning-cache-size 4` +enables the cache in the CLI. The C API option is +`sd_ctx_params_t::conditioning_cache_size`, initialized by `sd_ctx_params_init()`. +This cache is independent of the diffusion-step `--cache-mode` options below. + ### Cache Modes | Mode | Target | Description | diff --git a/docs/docker.md b/docs/docker.md index 5bacdd2d4b..28e9ab5dfa 100644 --- a/docs/docker.md +++ b/docs/docker.md @@ -24,12 +24,25 @@ docker build -f docker/Dockerfile -t sd . ## Building variants using Docker -Vulkan: +### Vulkan: ```shell docker build -f docker/Dockerfile.vulkan -t sd . ``` +### ROCm (AMD GPU): + +Defining one or multiple targets with `--build-arg AMDGPU_TARGETS` is strongly recommended. +Building the image will otherwise likely fail or build for a target that does not fit your +hardware. + +```shell +# Build for one target +docker build -f docker/Dockerfile.rocm --build-arg "AMDGPU_TARGETS=gfx1100" -t sd . +# Build for multiple targets +docker build -f docker/Dockerfile.rocm --build-arg "AMDGPU_TARGETS=gfx1030;gfx1100" -t sd . +``` + ## Run locally built image's CLI ```shell @@ -37,3 +50,21 @@ docker run --rm -v /path/to/models:/models -v /path/to/output/:/output sd [args. # For example # docker run --rm -v ./models:/models -v ./build:/output sd -m /models/sd-v1-4.ckpt -p "a lovely cat" -v -o /output/output.png ``` + +### ROCm (AMD GPU) + +The user that executes this command needs to be in the `video` group and have read and write +access to `/dev/dri` and `/dev/kfd`. + +`--device` and `--group-add` allow the container access to the GPU. + +```shell +docker run --rm --device=/dev/dri --device=/dev/kfd --group-add video \ + -v /path/to/models:/models -v /path/to/output/:/output \ + sd [args...] +# For example +# docker run --rm --device=/dev/dri --device=/dev/kfd --group-add video \ +# -v ./models:/models -v ./build:/output \ +# sd -m /models/sd-v1-4.ckpt -v -o /output/output.png \ +# -p "a lovely cat" +``` \ No newline at end of file diff --git a/docs/edit.md b/docs/edit.md index 9f8a9c3f3b..62ecff2af5 100644 --- a/docs/edit.md +++ b/docs/edit.md @@ -14,6 +14,7 @@ Depending on the architecture, different models handle reference images differen | [**Qwen Image Edit**](./qwen_image_edit.md) | `qwen` | | **Qwen Image LAYERED** | `qwen_layered` | | [**Flux.2 [Dev] / Flux.2 [Klein]**](./flux2.md) | `flux2` | +| [**FLUX.3 Image Klein / Klein Base**](./flux3.md) | `flux2` | | [**Boogu Image Edit**](./boogu_image.md) | `z_image_omni` | | **Krea2 (Community Edit LoRAs)** | `krea2_ostris_edit` | | [**Mage-Flow-Edit**](./mage_flow.md#image-editing) | `mage_flow` | @@ -26,6 +27,9 @@ Stable-diffusion.spp also supports basic Unet-based editing models like instruct ## Configuring Reference Modes (`--ref-image-args`) +For a one-time input transform before reference presets and model processing, +including cropping, padding, and resizing algorithms, see [Image preprocessing](./image_preprocessing.md). + Different DiT-based editing models require different configurations to process reference images correctly (e.g., whether to use a Vision Language Model (VLM) encoder or pass VAE-encoded images directly to the DiT). To simplify this, we provide **Presets**. By default, the system automatically selects the best preset based on the model architecture. However, you can override this using the `--ref-image-args` argument. diff --git a/docs/ernie_image.md b/docs/ernie_image.md index 99f942211e..3b1fc124cb 100644 --- a/docs/ernie_image.md +++ b/docs/ernie_image.md @@ -21,7 +21,7 @@ You can run ERNIE-Image with stable-diffusion.cpp on GPUs with 4GB of VRAM — o ### ERNIE-Image-Turbo ``` -.\bin\Release\sd-cli.exe --diffusion-model ..\models\diffusion_models\ernie-image-turbo.safetensors --vae ..\models\vae\flux2_ae.safetensors --llm ..\models\text_encoders\ministral-3-3b.safetensors -p "a lovely cat" --cfg-scale 1.0 --steps 8 -v --offload-to-cpu --diffusion-fa +.\bin\Release\sd-cli.exe --diffusion-model ..\models\diffusion_models\ernie-image-turbo.safetensors --vae ..\models\vae\flux2_ae.safetensors --llm ..\models\text_encoders\ministral-3-3b.safetensors -p "a lovely cat" --cfg-scale 1.0 --steps 8 -v --offload-to-cpu ``` ERNIE-Image Turbo example @@ -29,7 +29,7 @@ You can run ERNIE-Image with stable-diffusion.cpp on GPUs with 4GB of VRAM — o ### ERNIE-Image ``` -.\bin\Release\sd-cli.exe --diffusion-model ..\models\diffusion_models\ernie-image-UD-Q4_K_M.gguf --vae ..\models\vae\flux2_ae.safetensors --llm ..\models\text_encoders\ministral-3-3b.safetensors -p "a lovely cat" --cfg-scale 5.0 -v --offload-to-cpu --diffusion-fa +.\bin\Release\sd-cli.exe --diffusion-model ..\models\diffusion_models\ernie-image-UD-Q4_K_M.gguf --vae ..\models\vae\flux2_ae.safetensors --llm ..\models\text_encoders\ministral-3-3b.safetensors -p "a lovely cat" --cfg-scale 5.0 -v --offload-to-cpu ``` ERNIE-Image example diff --git a/docs/esrgan.md b/docs/esrgan.md index 39a9760502..4068ef11c7 100644 --- a/docs/esrgan.md +++ b/docs/esrgan.md @@ -2,6 +2,10 @@ You can use ESRGAN—such as the model [RealESRGAN_x4plus_anime_6B.pth](https://github.com/xinntao/Real-ESRGAN/releases/download/v0.2.2.4/RealESRGAN_x4plus_anime_6B.pth)—to upscale the generated images and improve their overall resolution and clarity. +MoSR models with the PixelShuffle upsampler, such as [4xNomos2_hq_mosr.pth](https://github.com/Phhofm/models/releases/download/4xNomos2_hq_mosr/4xNomos2_hq_mosr.pth), are also supported. The architecture is detected from the weights, so they are used the same way as ESRGAN models. + +RGBA images, including Qwen Image 2.1 output, keep their alpha channel during model upscaling and hires fix. The upscaler processes the RGB channels; the alpha channel is resized with bilinear interpolation and recombined with the upscaled image. + - Specify the model path using the `--upscale-model PATH` parameter. example: ```bash diff --git a/docs/flux2.md b/docs/flux2.md index d3b2eff1f0..53fc8be5cf 100644 --- a/docs/flux2.md +++ b/docs/flux2.md @@ -16,7 +16,7 @@ ### Examples ``` -.\bin\Release\sd-cli.exe --diffusion-model ..\models\diffusion_models\flux2-dev-Q4_K_S.gguf --vae ..\models\vae\flux2_ae.safetensors --llm ..\models\text_encoders\Mistral-Small-3.2-24B-Instruct-2506-Q4_K_M.gguf -r .\kontext_input.png -p "change 'flux.cpp' to 'flux2-dev.cpp'" --cfg-scale 1.0 --sampling-method euler -v --diffusion-fa --offload-to-cpu +.\bin\Release\sd-cli.exe --diffusion-model ..\models\diffusion_models\flux2-dev-Q4_K_S.gguf --vae ..\models\vae\flux2_ae.safetensors --llm ..\models\text_encoders\Mistral-Small-3.2-24B-Instruct-2506-Q4_K_M.gguf -r .\kontext_input.png -p "change 'flux.cpp' to 'flux2-dev.cpp'" --cfg-scale 1.0 --sampling-method euler -v --offload-to-cpu ``` flux2 example @@ -42,19 +42,19 @@ ### Examples ``` -.\bin\Release\sd-cli.exe --diffusion-model ..\models\diffusion_models\flux-2-klein-4b.safetensors --vae ..\models\vae\flux2_ae.safetensors --llm ..\models\text_encoders\qwen_3_4b.safetensors -p "a lovely cat" --cfg-scale 1.0 --steps 4 -v --offload-to-cpu --diffusion-fa +.\bin\Release\sd-cli.exe --diffusion-model ..\models\diffusion_models\flux-2-klein-4b.safetensors --vae ..\models\vae\flux2_ae.safetensors --llm ..\models\text_encoders\qwen_3_4b.safetensors -p "a lovely cat" --cfg-scale 1.0 --steps 4 -v --offload-to-cpu ``` flux2-klein-4b ``` -.\bin\Release\sd-cli.exe --diffusion-model ..\models\diffusion_models\flux-2-klein-4b.safetensors --vae ..\models\vae\flux2_ae.safetensors --llm ..\models\text_encoders\qwen_3_4b.safetensors -r .\kontext_input.png -p "change 'flux.cpp' to 'klein.cpp'" --cfg-scale 1.0 --sampling-method euler -v --diffusion-fa --offload-to-cpu --steps 4 +.\bin\Release\sd-cli.exe --diffusion-model ..\models\diffusion_models\flux-2-klein-4b.safetensors --vae ..\models\vae\flux2_ae.safetensors --llm ..\models\text_encoders\qwen_3_4b.safetensors -r .\kontext_input.png -p "change 'flux.cpp' to 'klein.cpp'" --cfg-scale 1.0 --sampling-method euler -v --offload-to-cpu --steps 4 ``` flux2-klein-4b-edit ``` -.\bin\Release\sd-cli.exe --diffusion-model ..\models\diffusion_models\flux-2-klein-base-4b.safetensors --vae ..\models\vae\flux2_ae.safetensors --llm ..\models\text_encoders\qwen_3_4b.safetensors -p "a lovely cat" --cfg-scale 4.0 --steps 20 -v --offload-to-cpu --diffusion-fa +.\bin\Release\sd-cli.exe --diffusion-model ..\models\diffusion_models\flux-2-klein-base-4b.safetensors --vae ..\models\vae\flux2_ae.safetensors --llm ..\models\text_encoders\qwen_3_4b.safetensors -p "a lovely cat" --cfg-scale 4.0 --steps 20 -v --offload-to-cpu ``` flux2-klein-base-4b @@ -78,19 +78,19 @@ ### Examples ``` -.\bin\Release\sd-cli.exe --diffusion-model ..\models\diffusion_models\flux-2-klein-9b.safetensors --vae ..\models\vae\flux2_ae.safetensors --llm ..\models\text_encoders\qwen_3_8b.safetensors -p "a lovely cat" --cfg-scale 1.0 --steps 4 -v --offload-to-cpu --diffusion-fa +.\bin\Release\sd-cli.exe --diffusion-model ..\models\diffusion_models\flux-2-klein-9b.safetensors --vae ..\models\vae\flux2_ae.safetensors --llm ..\models\text_encoders\qwen_3_8b.safetensors -p "a lovely cat" --cfg-scale 1.0 --steps 4 -v --offload-to-cpu ``` flux2-klein-9b ``` -.\bin\Release\sd-cli.exe --diffusion-model ..\models\diffusion_models\flux-2-klein-9b.safetensors --vae ..\models\vae\flux2_ae.safetensors --llm ..\models\text_encoders\qwen_3_8b.safetensors -r .\kontext_input.png -p "change 'flux.cpp' to 'klein.cpp'" --cfg-scale 1.0 --sampling-method euler -v --diffusion-fa --offload-to-cpu --steps 4 +.\bin\Release\sd-cli.exe --diffusion-model ..\models\diffusion_models\flux-2-klein-9b.safetensors --vae ..\models\vae\flux2_ae.safetensors --llm ..\models\text_encoders\qwen_3_8b.safetensors -r .\kontext_input.png -p "change 'flux.cpp' to 'klein.cpp'" --cfg-scale 1.0 --sampling-method euler -v --offload-to-cpu --steps 4 ``` flux2-klein-9b-edit ``` -.\bin\Release\sd-cli.exe --diffusion-model ..\models\diffusion_models\flux-2-klein-base-9b.safetensors --vae ..\models\vae\flux2_ae.safetensors --llm ..\models\text_encoders\qwen_3_8b.safetensors -p "a lovely cat" --cfg-scale 4.0 --steps 20 -v --offload-to-cpu --diffusion-fa +.\bin\Release\sd-cli.exe --diffusion-model ..\models\diffusion_models\flux-2-klein-base-9b.safetensors --vae ..\models\vae\flux2_ae.safetensors --llm ..\models\text_encoders\qwen_3_8b.safetensors -p "a lovely cat" --cfg-scale 4.0 --steps 20 -v --offload-to-cpu ``` flux2-klein-base-9b \ No newline at end of file diff --git a/docs/flux3.md b/docs/flux3.md new file mode 100644 index 0000000000..8bc0b2ec29 --- /dev/null +++ b/docs/flux3.md @@ -0,0 +1,50 @@ +# How to Use + +FLUX.3 Image Klein uses a FLUX.3 diffusion transformer, the FLUX.2 VAE, and Qwen3-VL 4B as the LLM text encoder. + +## Download weights + +- Download FLUX.3 Image Klein + - safetensors: https://huggingface.co/black-forest-labs/flux-3-image-klein/tree/main + - gguf: https://huggingface.co/leejet/flux-3-image-klein-GGUF/tree/main +- Download FLUX.3 Image Klein Base + - safetensors: https://huggingface.co/black-forest-labs/flux-3-image-klein-base/tree/main + - gguf: https://huggingface.co/leejet/flux-3-image-klein-base-GGUF/tree/main +- Download vae + - safetensors: https://huggingface.co/black-forest-labs/FLUX.2-dev/tree/main + - The `ae.safetensors` included with FLUX.3 can also be used. +- Download Qwen3-VL 4B + - safetensors: https://huggingface.co/Comfy-Org/Krea-2/tree/main/text_encoders + - gguf: https://huggingface.co/Qwen/Qwen3-VL-4B-Instruct-GGUF/tree/main + +Use the root `model.safetensors` for the diffusion model. + +## Examples + +### FLUX.3 Image Klein + +The distilled model uses 16 steps and CFG 1.0. + +``` +.\bin\Release\sd-cli.exe --diffusion-model ..\models\diffusion_models\flux-3-image-klein.safetensors --llm ..\models\text_encoders\Qwen3-VL-4B-Instruct-Q4_K_M.gguf --vae ..\models\vae\flux2_ae.safetensors -p "a lovely cat holding a sign says 'flux3.cpp'" --cfg-scale 1.0 --steps 16 --sampling-method euler -v --offload-to-cpu +``` + + + +``` +.\bin\Release\sd-cli.exe --diffusion-model ..\models\diffusion_models\flux-3-image-klein.safetensors --vae ..\models\vae\flux2_ae.safetensors --llm ..\models\text_encoders\Qwen3-VL-4B-Instruct-Q4_K_M.gguf -r ..\assets\flux\flux1-dev-q8_0.png -p "change 'flux.cpp' to 'flux3-image-klein.cpp'" --cfg-scale 1.0 --sampling-method euler -v --offload-to-cpu --steps 16 +``` + + + +Repeat `-r` to use multiple reference images, up to 10. See [Image Editing](./edit.md) for reference-image preprocessing options. + +### FLUX.3 Image Klein Base + +``` +.\bin\Release\sd-cli.exe --diffusion-model ..\models\diffusion_models\flux-3-image-klein-base.safetensors --llm ..\models\text_encoders\Qwen3-VL-4B-Instruct-Q4_K_M.gguf --vae ..\models\vae\flux2_ae.safetensors -p "a lovely cat holding a sign says 'flux3.cpp'" --cfg-scale 3.5 --steps 20 --sampling-method euler -v --offload-to-cpu +``` + + + +The default discrete scheduler uses the upstream time shift of 6.93 for both models. Use `--flow-shift` to override it. diff --git a/docs/hunyuan_video.md b/docs/hunyuan_video.md index 2b05e0f718..fadb884ef4 100644 --- a/docs/hunyuan_video.md +++ b/docs/hunyuan_video.md @@ -18,7 +18,7 @@ and ByT5 Small GlyphXL for glyph-aware text conditioning. ## Text-to-video example ```shell -.\bin\Release\sd-cli.exe -M vid_gen --diffusion-model ..\models\diffusion_models\hunyuanvideo1.5_720p_t2v_fp16.safetensors --vae ..\models\vae\hunyuanvideo15_vae_fp16.safetensors --llm ..\models\text_encoders\qwen_2.5_vl_7b.safetensors --t5xxl ..\models\text_encoders\byt5_small_glyphxl_fp16.safetensors -p "a lovely cat" --cfg-scale 6.0 --sampling-method euler -v -W 1280 -H 720 --offload-to-cpu --diffusion-fa --video-frames 33 --vae-tiling +.\bin\Release\sd-cli.exe -M vid_gen --diffusion-model ..\models\diffusion_models\hunyuanvideo1.5_720p_t2v_fp16.safetensors --vae ..\models\vae\hunyuanvideo15_vae_fp16.safetensors --llm ..\models\text_encoders\qwen_2.5_vl_7b.safetensors --t5xxl ..\models\text_encoders\byt5_small_glyphxl_fp16.safetensors -p "a lovely cat" --cfg-scale 6.0 --sampling-method euler -v -W 1280 -H 720 --offload-to-cpu --video-frames 33 --vae-tiling ``` \ No newline at end of file diff --git a/docs/ideogram4.md b/docs/ideogram4.md index 003a02d594..f0f1dd2500 100644 --- a/docs/ideogram4.md +++ b/docs/ideogram4.md @@ -49,7 +49,7 @@ If you want lower VRAM usage, you can change the quantization from q8_0 to a low ## Examples ```sh -.\bin\Release\sd-cli.exe --diffusion-model ideogram4-Q8_0.gguf --uncond-diffusion-model ideogram4_uncond-Q8_0.gguf --llm ..\models\text_encoders\Qwen3VL-8B-Instruct-Q4_K_M.gguf --vae ..\models\vae\flux2_ae.safetensors -p '{"high_level_description":"A square 1024 x 1024 luxury fashion magazine cover featuring exactly one short chubby fluffy cat as the main model. The cat sits on a soft ivory studio floor, facing the viewer with a stylish calm expression, wearing tiny black sunglasses, a red silk scarf, and a small gold collar charm. In front of the cat on the floor is a wide horizontal luxury nameplate that clearly reads ideogram4.cpp. The whole design feels premium, fashionable, clean, and editorial.","style_description":{"aesthetics":"luxury fashion magazine cover, high-end pet couture campaign, minimalist editorial design, elegant studio photography, soft paper texture, refined typography, fashionable and polished","lighting":"Soft diffused studio lighting, gentle spotlight on the cat, subtle floor shadow, warm ivory highlights, clean separation between subject and background","photo":"high-resolution fashion editorial photography look, front-facing cat portrait, crisp fur details, glossy sunglasses, clear readable nameplate text, shallow depth of field","medium":"mixed media fashion photography and premium editorial graphic design","color_palette":["#F4EFE7","#111111","#D8B56D","#B73A3A","#FFFFFF","#8A7A6A"]},"compositional_deconstruction":{"canvas":"Square 1024 x 1024 canvas with a normal upright orientation. Do not rotate the poster or any text. Use a clean fashion magazine cover layout.","background":"Warm ivory studio backdrop with subtle paper grain, a soft spotlight gradient, faint floor shadow, and a few minimal gold editorial lines. The background is spacious, premium, and uncluttered.","layout":"Top center has a small elegant headline. Center area features one cat as the main fashion model. Lower foreground has a wide horizontal luxury nameplate placed on the floor in front of the cat. Bottom center has a small footer. All text is horizontal, upright, and readable left to right.","elements":[{"type":"text","desc":"Top center headline reading LOOK WHAT I FOUND in a refined high-fashion serif font. The headline is horizontal, centered, elegant, and secondary to the nameplate text."},{"type":"obj","desc":"Exactly one short chubby fluffy cat sitting in the center like a luxury fashion model. The cat has a large round head, compact body, short legs, soft detailed fur, expressive eyes, and a calm confident pose. The cat is cute and rounded, not tall, not stretched, not duplicated."},{"type":"obj","desc":"Tiny glossy black sunglasses worn naturally by the cat, slightly oversized but still showing the cat face clearly. The sunglasses add a chic fashion-editorial attitude."},{"type":"obj","desc":"A red silk scarf tied neatly around the cat neck, with soft folds and a couture feeling. The scarf must not cover the cat face or the nameplate."},{"type":"obj","desc":"A small gold collar charm or fashion accessory under the scarf, subtle and premium, adding a luxury campaign detail."},{"type":"obj","desc":"In the lower foreground, place a wide horizontal luxury nameplate on the floor in front of the cat. The nameplate is low, flat, landscape-oriented, much wider than tall, like a fashion show seat card or premium display plaque. It is centered, front-facing, level, and fully visible. It must not become vertical, tall, standing, rotated, or side-facing."},{"type":"text","desc":"Print the exact text ideogram4.cpp only on the wide horizontal nameplate. Use clean bold black lettering, perfectly spelled, lowercase, with the number 4 and .cpp extension. The text must fit completely inside the nameplate, stay horizontal, and be readable from left to right."},{"type":"obj","desc":"Add sparse premium editorial accents around the edges: thin gold lines, small code brackets, tiny cursor marks, subtle dots, and minimal geometric details. No extra cats, no stickers, no animal faces, no busy decorations."},{"type":"text","desc":"Bottom center footer reading tiny paws, big compile energy in a small refined monospace or editorial font. The footer is horizontal, centered, understated, and much smaller than the nameplate text."}]}}' --diffusion-fa -v --offload-to-cpu -H 1024 -W 1024 +.\bin\Release\sd-cli.exe --diffusion-model ideogram4-Q8_0.gguf --uncond-diffusion-model ideogram4_uncond-Q8_0.gguf --llm ..\models\text_encoders\Qwen3VL-8B-Instruct-Q4_K_M.gguf --vae ..\models\vae\flux2_ae.safetensors -p '{"high_level_description":"A square 1024 x 1024 luxury fashion magazine cover featuring exactly one short chubby fluffy cat as the main model. The cat sits on a soft ivory studio floor, facing the viewer with a stylish calm expression, wearing tiny black sunglasses, a red silk scarf, and a small gold collar charm. In front of the cat on the floor is a wide horizontal luxury nameplate that clearly reads ideogram4.cpp. The whole design feels premium, fashionable, clean, and editorial.","style_description":{"aesthetics":"luxury fashion magazine cover, high-end pet couture campaign, minimalist editorial design, elegant studio photography, soft paper texture, refined typography, fashionable and polished","lighting":"Soft diffused studio lighting, gentle spotlight on the cat, subtle floor shadow, warm ivory highlights, clean separation between subject and background","photo":"high-resolution fashion editorial photography look, front-facing cat portrait, crisp fur details, glossy sunglasses, clear readable nameplate text, shallow depth of field","medium":"mixed media fashion photography and premium editorial graphic design","color_palette":["#F4EFE7","#111111","#D8B56D","#B73A3A","#FFFFFF","#8A7A6A"]},"compositional_deconstruction":{"canvas":"Square 1024 x 1024 canvas with a normal upright orientation. Do not rotate the poster or any text. Use a clean fashion magazine cover layout.","background":"Warm ivory studio backdrop with subtle paper grain, a soft spotlight gradient, faint floor shadow, and a few minimal gold editorial lines. The background is spacious, premium, and uncluttered.","layout":"Top center has a small elegant headline. Center area features one cat as the main fashion model. Lower foreground has a wide horizontal luxury nameplate placed on the floor in front of the cat. Bottom center has a small footer. All text is horizontal, upright, and readable left to right.","elements":[{"type":"text","desc":"Top center headline reading LOOK WHAT I FOUND in a refined high-fashion serif font. The headline is horizontal, centered, elegant, and secondary to the nameplate text."},{"type":"obj","desc":"Exactly one short chubby fluffy cat sitting in the center like a luxury fashion model. The cat has a large round head, compact body, short legs, soft detailed fur, expressive eyes, and a calm confident pose. The cat is cute and rounded, not tall, not stretched, not duplicated."},{"type":"obj","desc":"Tiny glossy black sunglasses worn naturally by the cat, slightly oversized but still showing the cat face clearly. The sunglasses add a chic fashion-editorial attitude."},{"type":"obj","desc":"A red silk scarf tied neatly around the cat neck, with soft folds and a couture feeling. The scarf must not cover the cat face or the nameplate."},{"type":"obj","desc":"A small gold collar charm or fashion accessory under the scarf, subtle and premium, adding a luxury campaign detail."},{"type":"obj","desc":"In the lower foreground, place a wide horizontal luxury nameplate on the floor in front of the cat. The nameplate is low, flat, landscape-oriented, much wider than tall, like a fashion show seat card or premium display plaque. It is centered, front-facing, level, and fully visible. It must not become vertical, tall, standing, rotated, or side-facing."},{"type":"text","desc":"Print the exact text ideogram4.cpp only on the wide horizontal nameplate. Use clean bold black lettering, perfectly spelled, lowercase, with the number 4 and .cpp extension. The text must fit completely inside the nameplate, stay horizontal, and be readable from left to right."},{"type":"obj","desc":"Add sparse premium editorial accents around the edges: thin gold lines, small code brackets, tiny cursor marks, subtle dots, and minimal geometric details. No extra cats, no stickers, no animal faces, no busy decorations."},{"type":"text","desc":"Bottom center footer reading tiny paws, big compile energy in a small refined monospace or editorial font. The footer is horizontal, centered, understated, and much smaller than the nameplate text."}]}}' -v --offload-to-cpu -H 1024 -W 1024 ``` ideogram4 image example diff --git a/docs/image_preprocessing.md b/docs/image_preprocessing.md new file mode 100644 index 0000000000..719781750e --- /dev/null +++ b/docs/image_preprocessing.md @@ -0,0 +1,173 @@ +# Image preprocessing + +Use `--image-preprocess` to transform each image input once, before generation: + +```sh +sd-cli ... \ + --image-preprocess "target=init,mode=crop-resize,filter=lanczos,antialias=true" \ + --image-preprocess "target=mask,filter=nearest-exact" \ + --image-preprocess "target=ref,index=0,mode=fit-pad,width=768,height=768,filter=bicubic" +``` + +CLI and server image loaders decode at the original resolution. The generation +entry point merges input defaults with user rules and prepares one transformed +image per input. The original pipeline then consumes those images, including +its mandatory canvas adaptation, reference resizing, and encoder preprocessing. + +```text +native-resolution image + -> input defaults + user overrides + -> one input transform + -> original generation pipeline and model-specific processing +``` + +These rules do not override internal VAE, CLIP/VLM, ControlNet, or pixel-patch preprocessing. +`--ref-image-args` retains its existing meaning and runs after this input transform. + +## Inputs and defaults + +| `target` | Input | Default geometry | Indexed? | +| --- | --- | --- | --- | +| `init` | img2img image or video first frame | Center crop to the generation aspect ratio, then resize | No | +| `end` | Video last frame | Center crop, then resize | No | +| `mask` | Inpainting mask | Inherit init geometry; otherwise center crop, then resize | No | +| `control` | Control image | Center crop, then resize | No | +| `ref` | Reference images | Preserve source dimensions | Yes | +| `ip-adapter` | IP-Adapter image | Preserve source dimensions | No | +| `id` | PhotoMaker identity images | Preserve source dimensions | Yes | +| `control-frame` | Control video frames | Center crop, then resize | Yes | + +Canvas defaults use the aligned generation dimensions. Reference, IP-Adapter, +and identity inputs use their original dimensions unless overridden. Default +resampling is nearest for images and nearest-exact for masks. + +These defaults are shared by CLI, server, and C API. Moving geometry out of +the loaders replaces the previous CLI/server BOX/sRGB resizing, so default +pixels are not guaranteed to match earlier builds. + +Reference video and audio preprocessing are outside these image rules. +Preprocessing options apply to `img_gen` and `vid_gen`, not standalone upscale +or ADetailer mode. ADetailer clears the user's rules for its internal crops. + +## Rules + +Rules are comma-separated `key=value` lists. Repeat the CLI option or separate +rules with semicolons. Every rule requires a `target` and at least one option. +Rule syntax and input compatibility are checked when image/video generation +starts. Unknown keys, invalid values, duplicate keys in a rule, missing images, +and out-of-range indices cause generation to fail with an error log. + +Omit `index` to configure every image of that type; otherwise use a zero-based +index. CLI directory inputs follow filename order. Indexed rules override +type-wide rules field by field, regardless of order. At equal specificity, +the last value for a field wins. `auto` selects the input preset. + +| `mode` | Input transform | +| --- | --- | +| `auto` | Use the input's default geometry | +| `none` | Keep source dimensions without resizing, cropping, or padding | +| `stretch` | Resize to the target dimensions | +| `crop` | Crop a target-sized rectangle without resizing; fail if the source is too small | +| `crop-resize` | Crop to the target aspect ratio, then resize | +| `fit-pad` | Fit the entire image inside the target dimensions, preserving aspect ratio, then pad | + +`width` and `height` must be specified together as positive integers. They +override the input transform's dimensions, not the generation or encoder size. +For a native-size preset, specifying dimensions without a mode selects stretch. +`mode=none` with explicit dimensions different from the source is contradictory +and is rejected. + +`anchor=center|top|bottom|left|right` selects crop/padding placement. +`pad_color=#RRGGBB` or `#RRGGBBAA` selects padding, defaulting to opaque black. +A grayscale mask uses the first color component. + +`filter=auto|nearest|nearest-exact|bilinear|bicubic|lanczos` selects resampling. +`antialias=auto|true|false` enables antialiasing automatically for filtered +downscaling; explicit true requires bilinear, bicubic, or Lanczos. +Filtered RGBA resizing uses premultiplied alpha. + +`canny=true|false` enables edge detection for any supported image target, +defaulting to `false`. It runs once after geometry, before the original +generation pipeline, including with `mode=none`. Grayscale, grayscale-alpha, +RGB, and RGBA inputs are supported; alpha is preserved. + +Each input has its own Canny setting. Indexed rules can enable or disable it +for individual references, identity images, or video control frames. + +```sh +--image-preprocess "target=init,mode=fit-pad,canny=true" +--image-preprocess "target=ref,index=0,mode=none,canny=true" +--image-preprocess "target=control-frame,index=2,canny=true" +``` + +Init and mask sources must have the same dimensions. The mask inherits the +init crop, resize, and padding coordinates, while retaining its own filter, +padding value, and Canny setting. Conflicting mask geometry is rejected. An +omitted mask remains absent until the original pipeline creates its default mask. + +## Downstream behavior + +`mode=none` only skips the input geometry transform. For example: + +```sh +--image-preprocess "target=init,mode=none" \ +--image-preprocess "target=ref,mode=none" +``` + +The init image is still adapted to the generation canvas by the original +pipeline. Reference images still follow `--ref-image-args` and model-specific +resizing. CLIP retains its fixed input dimensions and normalization. HiDream-O1 +retains its original pixel-reference and visual preprocessing. + +Existing sharing between consumers is preserved: for example, Wan img2video +uses the same adapted first frame for VAE conditioning and CLIP. High-resolution +passes reuse the prepared images and apply their original size adaptation; +they do not apply the user's crop a second time. + +To disable reference resizing before VAE encoding, use +`--ref-image-args "resize_before_vae=false"` or the server field +`"ref_image_args": "resize_before_vae=false"`. This is separate from +`target=ref,mode=none`, which only skips input geometry. Model constraints +still apply. + +## Server requests + +Native image/video requests and SDAPI accept `image_preprocess` as a string or +an array of rule strings: + +```json +{ + "image_preprocess": [ + "target=init,mode=fit-pad,filter=bicubic", + "target=mask,filter=nearest-exact", + "target=ref,index=0,mode=none" + ] +} +``` + +OpenAI-compatible requests accept it through +`{...}` in the prompt. +Request rules replace server-default rules. Generation metadata records the +user rules; image encodings and channel conventions are unchanged. + +## C API + +Set `image_preprocess` on the existing image/video generation parameters. +The `generate_image()` and `generate_video()` signatures are unchanged: + +```c +sd_img_gen_params_t params; +sd_img_gen_params_init(¶ms); +/* Set prompt, original-resolution input images, and generation options. */ +params.image_preprocess.rules = "target=init,mode=crop-resize,filter=lanczos;" + "target=mask,filter=nearest-exact"; +bool ok = generate_image(ctx, ¶ms, &images, &count); +``` + +Both generation parameter initializers set `image_preprocess.rules` to `NULL`, +selecting input presets. Rule strings are borrowed for the synchronous call. +The library owns temporary transformed pixels; caller images and arrays are +not modified. Add `canny=true` to the desired target's rule in +`image_preprocess.rules` to enable Canny. + +The parameter structs have grown; applications and bindings must be rebuilt. diff --git a/docs/int8_convrot.md b/docs/int8_convrot.md index 3b65113d2d..04d9c4f73c 100644 --- a/docs/int8_convrot.md +++ b/docs/int8_convrot.md @@ -84,22 +84,23 @@ The floating-point output is reconstructed as Y[r, o] ~= A[r, o] * s_x[r] * s_w[o] + b[o] ``` -The packed runtime activation tensor contains the I8 activation rows and their floating-point row scales. Linear layers that share the same input and convrot group size reuse this packed tensor, avoiding repeated rotation and activation quantization within the graph. +The packed runtime activation tensor contains the I8 activation rows and their floating-point row scales. Linear layers with an input scale of `1` that share the same input and convrot group size reuse this packed tensor, avoiding repeated rotation and activation quantization within the graph. For other input scales, activations are scaled before explicit convrot quantization, and the linear output is unscaled before adding bias. ## Backend support - CPU provides the portable regular Hadamard, activation quantization, INT8 matrix multiplication, and scale restoration implementations. - NVIDIA CUDA devices with compute capability 7.5 or newer use the native accelerated path. For H256, CUDA fuses the rotation, row-wise maximum reduction, and activation quantization. It uses cuBLAS for I8 x I8 to I32 GEMM and a CUDA kernel for scale restoration and bias addition. -- Vulkan and other GPU backends do not currently have dedicated INT8 convrot kernels. They use the backend scheduler to fall back to CPU, which is expected to be substantially slower than the CUDA path. +- AMD HIP devices in the CDNA, RDNA3 (including RDNA3.5), and RDNA4 families use the same INT8/H256 kernels with hipBLAS for I8 x I8 to I32 GEMM. Other AMD architectures fall back to CPU for INT8 matrix multiplication. +- Vulkan provides native H256 activation quantization and INT8 matrix multiplication when the build and device support accelerated packed INT8 dot products. Unsupported configurations and GPU backends without these kernels use the backend scheduler to fall back to CPU. LoRA adapters are applied at runtime without modifying the INT8 weights. The INT8 convrot path computes the base linear output, while LoRA, LoHa, LoKr, and raw weight-difference adapters compute their output corrections from the original, unrotated activation and add them to the base output. `--lora-apply-mode auto` selects this path for models containing INT8 tensorwise weights. If `immediately` is requested, sd.cpp falls back to runtime application because merging an adapter would require dequantizing and rotating its weight update, then recalculating the per-row scales and requantizing the result. -The dedicated CUDA convrot activation path currently requires a group size of `256`; other supported group sizes use CPU execution. +The dedicated CUDA and HIP convrot activation paths currently require a group size of `256`; other supported group sizes use CPU execution. ## Example ComfyUI INT8 convrot safetensors can be passed to `--diffusion-model` without conversion: ```powershell -.\bin\Release\sd-cli.exe --diffusion-model ..\models\diffusion_models\krea2_turbo_int8_convrot.safetensors --llm ..\models\text_encoders\Qwen3-VL-4B-Instruct-Q4_K_M.gguf --vae ..\models\vae\wan_2.1_vae.safetensors -p "a lovely cat holding a sign says 'krea2.cpp'" --steps 8 --cfg-scale 1 --diffusion-fa -v --offload-to-cpu +.\bin\Release\sd-cli.exe --diffusion-model ..\models\diffusion_models\krea2_turbo_int8_convrot.safetensors --llm ..\models\text_encoders\Qwen3-VL-4B-Instruct-Q4_K_M.gguf --vae ..\models\vae\wan_2.1_vae.safetensors -p "a lovely cat holding a sign says 'krea2.cpp'" --steps 8 --cfg-scale 1 -v --offload-to-cpu ``` diff --git a/docs/ip_adapter.md b/docs/ip_adapter.md index 76a651011b..27f9ae6896 100644 --- a/docs/ip_adapter.md +++ b/docs/ip_adapter.md @@ -48,7 +48,7 @@ sd-cli -m ..\models\sd_v1.5.safetensors --clip_vision ..\models\clip_vision_h.sa ## Example (SDXL) ``` -sd-cli -m ..\models\sdxl.safetensors --clip_vision ..\models\clip_vision_h.safetensors --ip-adapter ..\models\ip-adapter_sdxl_vit-h.safetensors --ip-adapter-image ..\assets\reference.png --ip-adapter-strength 0.8 -p "a woman, best quality" -n "lowres, bad anatomy" --cfg-scale 6 --steps 25 --sampling-method dpm++2m --scheduler karras -W 1024 -H 1024 --diffusion-fa --vae-tiling +sd-cli -m ..\models\sdxl.safetensors --clip_vision ..\models\clip_vision_h.safetensors --ip-adapter ..\models\ip-adapter_sdxl_vit-h.safetensors --ip-adapter-image ..\assets\reference.png --ip-adapter-strength 0.8 -p "a woman, best quality" -n "lowres, bad anatomy" --cfg-scale 6 --steps 25 --sampling-method dpm++2m --scheduler karras -W 1024 -H 1024 --vae-tiling ``` The SDXL VAE decode at 1024x1024 is memory heavy; add `--vae-tiling` (and @@ -83,5 +83,5 @@ Add the usual Control Net options to keep the reference appearance while controlling the pose: ``` -sd-cli -m ..\models\sdxl.safetensors --clip_vision ..\models\clip_vision_h.safetensors --ip-adapter ..\models\ip-adapter_sdxl_vit-h.safetensors --ip-adapter-image ..\assets\character.png --ip-adapter-strength 0.9 --control-net ..\models\OpenPoseXL2.safetensors --control-image ..\assets\pose.png --control-strength 0.8 -p "a character, side view" --cfg-scale 6 --steps 25 -W 1024 -H 1024 --diffusion-fa --vae-tiling +sd-cli -m ..\models\sdxl.safetensors --clip_vision ..\models\clip_vision_h.safetensors --ip-adapter ..\models\ip-adapter_sdxl_vit-h.safetensors --ip-adapter-image ..\assets\character.png --ip-adapter-strength 0.9 --control-net ..\models\OpenPoseXL2.safetensors --control-image ..\assets\pose.png --control-strength 0.8 -p "a character, side view" --cfg-scale 6 --steps 25 -W 1024 -H 1024 --vae-tiling ``` diff --git a/docs/iris.md b/docs/iris.md new file mode 100644 index 0000000000..322a3da1a4 --- /dev/null +++ b/docs/iris.md @@ -0,0 +1,24 @@ +# How to Use + +Iris-3B generates images directly in pixel space and uses Qwen3-VL-4B-Instruct as the text encoder. No VAE is required. + +## Download weights + +- Download Iris-3B + - safetensors: https://huggingface.co/speridlabs/iris-3b/tree/main (`model.safetensors` in the root directory) +- Download Qwen3-VL-4B-Instruct + - safetensors: https://huggingface.co/Comfy-Org/Krea-2/tree/main/text_encoders + - gguf: https://huggingface.co/Qwen/Qwen3-VL-4B-Instruct-GGUF/tree/main + +## Examples + +``` +.\bin\Release\sd-cli.exe --diffusion-model ..\models\diffusion_models\iris-3b.safetensors --llm ..\models\text_encoders\Qwen3-VL-4B-Instruct-Q4_K_M.gguf -p "a lovely cat" --cfg-scale 3 -H 1024 -W 1024 +``` + +iris-3b example + +## Notes + +- Width and height must be multiples of 16. Do not pass `--vae`. +- Captions are limited to 300 tokens including the assistant-turn suffix. Positive and negative prompts use the same template. diff --git a/docs/krea2.md b/docs/krea2.md index 10f8eab80e..67fad023ed 100644 --- a/docs/krea2.md +++ b/docs/krea2.md @@ -21,7 +21,7 @@ Krea2 uses a Krea2 diffusion transformer, the Wan2.1 VAE, and Qwen3-VL 4B as the ### Krea2 ``` -.\bin\Release\sd-cli.exe --diffusion-model ..\models\diffusion_models\Krea-2-Raw-Q8_0.gguf --llm ..\models\text_encoders\Qwen3-VL-4B-Instruct-Q4_K_M.gguf --vae ..\models\vae\wan_2.1_vae.safetensors -p "a lovely cat holding a sign says 'krea2.cpp'" --diffusion-fa -v --offload-to-cpu +.\bin\Release\sd-cli.exe --diffusion-model ..\models\diffusion_models\Krea-2-Raw-Q8_0.gguf --llm ..\models\text_encoders\Qwen3-VL-4B-Instruct-Q4_K_M.gguf --vae ..\models\vae\wan_2.1_vae.safetensors -p "a lovely cat holding a sign says 'krea2.cpp'" -v --offload-to-cpu ``` Krea2 Raw example diff --git a/docs/lens.md b/docs/lens.md index 64dc594c47..09e9575ac9 100644 --- a/docs/lens.md +++ b/docs/lens.md @@ -22,7 +22,7 @@ Lens and Lens Turbo require an external GPT-OSS `tokenizer.json` matching the te ### Lens ``` -.\bin\Release\sd-cli.exe --diffusion-model ..\models\diffusion_models\lens_bf16.safetensors --llm "..\models\text_encoders\gpt-oss-20b-UD-Q8_K_XL.gguf" --tokenizer ..\models\tokenizers\tokenizer_gpt_oss.json --vae ..\models\vae\flux2_ae.safetensors --cfg-scale 5.0 -p "A crystal dragon soaring through an aurora borealis sky, its entire body made of transparent faceted crystal refracting the green and purple aurora light into rainbow spectra, ice particles trailing from its wings, high fantasy digital art" --diffusion-fa -v +.\bin\Release\sd-cli.exe --diffusion-model ..\models\diffusion_models\lens_bf16.safetensors --llm "..\models\text_encoders\gpt-oss-20b-UD-Q8_K_XL.gguf" --tokenizer ..\models\tokenizers\tokenizer_gpt_oss.json --vae ..\models\vae\flux2_ae.safetensors --cfg-scale 5.0 -p "A crystal dragon soaring through an aurora borealis sky, its entire body made of transparent faceted crystal refracting the green and purple aurora light into rainbow spectra, ice particles trailing from its wings, high fantasy digital art" -v ``` Lens example @@ -30,7 +30,7 @@ Lens and Lens Turbo require an external GPT-OSS `tokenizer.json` matching the te ### Lens Turbo ``` -.\bin\Release\sd-cli.exe --diffusion-model ..\models\diffusion_models\lens_turbo_bf16.safetensors --llm "..\models\text_encoders\gpt-oss-20b-UD-Q8_K_XL.gguf" --tokenizer ..\models\tokenizers\tokenizer_gpt_oss.json --vae ..\models\vae\flux2_ae.safetensors --cfg-scale 1.0 -p "A crystal dragon soaring through an aurora borealis sky, its entire body made of transparent faceted crystal refracting the green and purple aurora light into rainbow spectra, ice particles trailing from its wings, high fantasy digital art" --diffusion-fa -v --steps 4 +.\bin\Release\sd-cli.exe --diffusion-model ..\models\diffusion_models\lens_turbo_bf16.safetensors --llm "..\models\text_encoders\gpt-oss-20b-UD-Q8_K_XL.gguf" --tokenizer ..\models\tokenizers\tokenizer_gpt_oss.json --vae ..\models\vae\flux2_ae.safetensors --cfg-scale 1.0 -p "A crystal dragon soaring through an aurora borealis sky, its entire body made of transparent faceted crystal refracting the green and purple aurora light into rainbow spectra, ice particles trailing from its wings, high fantasy digital art" -v --steps 4 ``` Lens Turbo example diff --git a/docs/lingbot_video.md b/docs/lingbot_video.md index d1248bd5bc..b92165ab5f 100644 --- a/docs/lingbot_video.md +++ b/docs/lingbot_video.md @@ -28,5 +28,5 @@ Lingbot Video uses a Lingbot diffusion transformer, the Wan2.1 VAE, and Qwen3-VL ### LingBot-Video T2V ```sh -.\bin\Release\sd-cli.exe -M vid_gen --diffusion-model ..\models\diffusion_models\lingbot-video-dens-1.3b.safetensors --llm ..\models\text_encoders\Qwen3-VL-4B-Instruct-Q4_K_M.gguf --vae ..\models\vae\wan_2.1_vae.safetensors -p '{"caption":{"comprehensive_description":"A lovely cat sits comfortably on a soft cushion near a sunlit window, looking calm, gentle, and adorable. The cat has soft fluffy fur, bright expressive eyes, small rounded ears, delicate whiskers, and a relaxed posture. Warm daylight falls across the cat from one side, creating soft highlights on the fur and a cozy glow around the scene. The background is softly blurred, showing hints of a peaceful indoor home environment with warm tones and gentle natural light. The overall atmosphere is cute, tender, serene, and photorealistic, emphasizing the cat''s charming appearance, soft texture, and affectionate presence.","camera_info":{"color":"Warm","frame_size":"Close Up","shot_type_angle":"Eye level","lens_size":"Medium Lens","composition":"Centered balanced","lighting":"Soft light","lighting_type":"Daylight"},"world_knowledge":[],"prominent_elements":[{"name":"lovely cat","description":"A cute and gentle domestic cat with soft fluffy fur, expressive eyes, and a calm relaxed presence.","location":"center of the frame","relative_size":"large","shape_and_color":"Small animal body with rounded face, triangular ears, bright eyes, and soft fur in warm natural tones","texture":"soft, fluffy, silky","appearance_details":"The cat has clean well-groomed fur, delicate whiskers, small ears, a cute nose, and bright attentive eyes. Its expression appears calm, affectionate, and slightly curious.","relationship":"Acts as the main subject and emotional focal point of the scene.","orientation":"facing the camera","pose":"sitting comfortably with a relaxed posture","expression":"gentle, adorable, calm, slightly curious","clothing":"","gender":"","skin_tone_and_texture":""},{"name":"cat eyes","description":"Bright expressive eyes that give the cat a sweet and affectionate appearance.","location":"upper center of the cat face","relative_size":"small","shape_and_color":"Round almond-like eyes with glossy reflections","texture":"clear, glossy, reflective","appearance_details":"The eyes catch the soft daylight, creating small natural highlights that make the cat look vivid and alive.","relationship":"Enhance the emotional charm and cuteness of the cat.","orientation":"looking toward the camera","pose":"","expression":"soft and attentive","clothing":"","gender":"","skin_tone_and_texture":""},{"name":"soft cushion","description":"A comfortable cushion or blanket where the cat is resting.","location":"bottom portion of the frame","relative_size":"medium","shape_and_color":"Soft rounded fabric surface in light warm neutral tones","texture":"plush, fabric, cozy","appearance_details":"The cushion gently supports the cat and adds a comfortable home-like feeling to the scene.","relationship":"Provides a cozy resting place for the cat.","orientation":"horizontal","pose":"","expression":"","clothing":"","gender":"","skin_tone_and_texture":""},{"name":"sunlit indoor background","description":"A softly blurred indoor background with warm daylight and peaceful home atmosphere.","location":"behind the cat, filling the upper and side areas of the frame","relative_size":"large","shape_and_color":"Soft abstract shapes in warm beige, cream, and pale golden tones","texture":"soft, blurry, bokeh-like","appearance_details":"The background is intentionally out of focus, keeping attention on the cat while creating a cozy and serene mood.","relationship":"Provides a warm and gentle environment that supports the cute domestic scene.","orientation":"upright","pose":"","expression":"","clothing":"","gender":"","skin_tone_and_texture":"","is_cluster":true,"number_of_objects":"numerous"}]}}' -n '{"universal_negative":{"visual_quality":["low quality","worst quality","blurry","pixelated","jpeg artifacts","low resolution","unstable color","color flicker","underexposed","overexposed","invisible subject","subject hidden in darkness"],"artistic_style":["painting","illustration","drawing","cartoon","3d render","cgi","sketch","digital art"],"composition_and_content":["text","watermark","signature","logo","subtitles","pillarboxed","side bars","portrait image in landscape frame"],"temporal_and_motion_stability":["flickering","jittery","motion blur","temporal inconsistency","warping","morphing","incoherent motion","unnatural movement","static object with sudden jump","frame-to-frame inconsistency"],"material_and_structure":["plastic-like glass","unrealistic texture","deformed bottle","liquid freezing improperly","distorted reflections"]}}' --diffusion-fa --offload-to-cpu --cfg-scale 3 --video-frames 33 -v +.\bin\Release\sd-cli.exe -M vid_gen --diffusion-model ..\models\diffusion_models\lingbot-video-dens-1.3b.safetensors --llm ..\models\text_encoders\Qwen3-VL-4B-Instruct-Q4_K_M.gguf --vae ..\models\vae\wan_2.1_vae.safetensors -p '{"caption":{"comprehensive_description":"A lovely cat sits comfortably on a soft cushion near a sunlit window, looking calm, gentle, and adorable. The cat has soft fluffy fur, bright expressive eyes, small rounded ears, delicate whiskers, and a relaxed posture. Warm daylight falls across the cat from one side, creating soft highlights on the fur and a cozy glow around the scene. The background is softly blurred, showing hints of a peaceful indoor home environment with warm tones and gentle natural light. The overall atmosphere is cute, tender, serene, and photorealistic, emphasizing the cat''s charming appearance, soft texture, and affectionate presence.","camera_info":{"color":"Warm","frame_size":"Close Up","shot_type_angle":"Eye level","lens_size":"Medium Lens","composition":"Centered balanced","lighting":"Soft light","lighting_type":"Daylight"},"world_knowledge":[],"prominent_elements":[{"name":"lovely cat","description":"A cute and gentle domestic cat with soft fluffy fur, expressive eyes, and a calm relaxed presence.","location":"center of the frame","relative_size":"large","shape_and_color":"Small animal body with rounded face, triangular ears, bright eyes, and soft fur in warm natural tones","texture":"soft, fluffy, silky","appearance_details":"The cat has clean well-groomed fur, delicate whiskers, small ears, a cute nose, and bright attentive eyes. Its expression appears calm, affectionate, and slightly curious.","relationship":"Acts as the main subject and emotional focal point of the scene.","orientation":"facing the camera","pose":"sitting comfortably with a relaxed posture","expression":"gentle, adorable, calm, slightly curious","clothing":"","gender":"","skin_tone_and_texture":""},{"name":"cat eyes","description":"Bright expressive eyes that give the cat a sweet and affectionate appearance.","location":"upper center of the cat face","relative_size":"small","shape_and_color":"Round almond-like eyes with glossy reflections","texture":"clear, glossy, reflective","appearance_details":"The eyes catch the soft daylight, creating small natural highlights that make the cat look vivid and alive.","relationship":"Enhance the emotional charm and cuteness of the cat.","orientation":"looking toward the camera","pose":"","expression":"soft and attentive","clothing":"","gender":"","skin_tone_and_texture":""},{"name":"soft cushion","description":"A comfortable cushion or blanket where the cat is resting.","location":"bottom portion of the frame","relative_size":"medium","shape_and_color":"Soft rounded fabric surface in light warm neutral tones","texture":"plush, fabric, cozy","appearance_details":"The cushion gently supports the cat and adds a comfortable home-like feeling to the scene.","relationship":"Provides a cozy resting place for the cat.","orientation":"horizontal","pose":"","expression":"","clothing":"","gender":"","skin_tone_and_texture":""},{"name":"sunlit indoor background","description":"A softly blurred indoor background with warm daylight and peaceful home atmosphere.","location":"behind the cat, filling the upper and side areas of the frame","relative_size":"large","shape_and_color":"Soft abstract shapes in warm beige, cream, and pale golden tones","texture":"soft, blurry, bokeh-like","appearance_details":"The background is intentionally out of focus, keeping attention on the cat while creating a cozy and serene mood.","relationship":"Provides a warm and gentle environment that supports the cute domestic scene.","orientation":"upright","pose":"","expression":"","clothing":"","gender":"","skin_tone_and_texture":"","is_cluster":true,"number_of_objects":"numerous"}]}}' -n '{"universal_negative":{"visual_quality":["low quality","worst quality","blurry","pixelated","jpeg artifacts","low resolution","unstable color","color flicker","underexposed","overexposed","invisible subject","subject hidden in darkness"],"artistic_style":["painting","illustration","drawing","cartoon","3d render","cgi","sketch","digital art"],"composition_and_content":["text","watermark","signature","logo","subtitles","pillarboxed","side bars","portrait image in landscape frame"],"temporal_and_motion_stability":["flickering","jittery","motion blur","temporal inconsistency","warping","morphing","incoherent motion","unnatural movement","static object with sudden jump","frame-to-frame inconsistency"],"material_and_structure":["plastic-like glass","unrealistic texture","deformed bottle","liquid freezing improperly","distorted reflections"]}}' --offload-to-cpu --cfg-scale 3 --video-frames 33 -v ``` diff --git a/docs/llada_image.md b/docs/llada_image.md index 9b24158be9..d939e78cea 100644 --- a/docs/llada_image.md +++ b/docs/llada_image.md @@ -122,7 +122,6 @@ save_file(merged, "llada_connectors.safetensors") --height 1024 \ --steps 4 \ --cfg-scale 1.0 \ - --diffusion-fa \ --output output.png ``` @@ -145,7 +144,7 @@ only in the positive branch. Editing requires connectors that include the SigVQ unchanged instead of applying the instruction; LLaDA-Image-Turbo edits correctly at both. - Editing runs the reference and the target in one sequence, so it needs roughly twice the tokens of text to image at the same size. On 12 GB, editing at 1024x1024 needs - `--diffusion-fa`; without it the diffusion graph does not fit. + flash attention; without it the diffusion graph does not fit. - The weights total about 16 GB, but segmented execution streams them, so a much smaller budget works. At 512x512, `--max-vram 6` costs almost nothing over unconstrained execution, and `--max-vram 3` still produces byte-identical output at roughly 2.5x the time. diff --git a/docs/longcat_image.md b/docs/longcat_image.md index c628492277..ae730b4727 100644 --- a/docs/longcat_image.md +++ b/docs/longcat_image.md @@ -24,7 +24,7 @@ LongCat uses quoted text for character-level text rendering. Put target text ins ### LongCat Image ``` -.\bin\Release\sd-cli.exe --diffusion-model ..\models\diffusion_models\LongCat-Image-Q4_K_M.gguf --vae ..\models\vae\ae.sft --llm ..\models\text_encoders\Qwen2.5-VL-7B-Instruct-Q8_0.gguf -p "a lovely cat holding a sign says 'longcat.cpp'" --cfg-scale 5.0 --sampling-method euler --flow-shift 3 -v --offload-to-cpu --diffusion-fa +.\bin\Release\sd-cli.exe --diffusion-model ..\models\diffusion_models\LongCat-Image-Q4_K_M.gguf --vae ..\models\vae\ae.sft --llm ..\models\text_encoders\Qwen2.5-VL-7B-Instruct-Q8_0.gguf -p "a lovely cat holding a sign says 'longcat.cpp'" --cfg-scale 5.0 --sampling-method euler --flow-shift 3 -v --offload-to-cpu ``` longcat example diff --git a/docs/ltx2.md b/docs/ltx2.md index 9caa974113..e42698ffb3 100644 --- a/docs/ltx2.md +++ b/docs/ltx2.md @@ -55,7 +55,7 @@ To run the text encoder quantized, convert it once with sd-cli: ### LTX-2.3 dev T2V ``` -.\bin\Release\sd-cli.exe -M vid_gen --diffusion-model ..\models\diffusion_models\ltx-2.3-22b-dev-UD-Q4_K_M.gguf --vae ..\models\vae\ltx-2.3-22b-dev_video_vae.safetensors --audio-vae ..\models\vae\ltx-2.3-22b-dev_audio_vae.safetensors --llm ..\models\text_encoders\gemma-3-12b-it-qat-UD-Q4_K_XL.gguf --embeddings-connectors ..\models\text_encoders\ltx-2.3-22b-dev_embeddings_connectors.safetensors -p "a lovely cat" --cfg-scale 6.0 --sampling-method euler -v -n "worst quality, low quality, blurry, distorted, artifacts" -W 1280 -H 720 --diffusion-fa --offload-to-cpu --video-frames 33 --fps 24 -o t2v.webm +.\bin\Release\sd-cli.exe -M vid_gen --diffusion-model ..\models\diffusion_models\ltx-2.3-22b-dev-UD-Q4_K_M.gguf --vae ..\models\vae\ltx-2.3-22b-dev_video_vae.safetensors --audio-vae ..\models\vae\ltx-2.3-22b-dev_audio_vae.safetensors --llm ..\models\text_encoders\gemma-3-12b-it-qat-UD-Q4_K_XL.gguf --embeddings-connectors ..\models\text_encoders\ltx-2.3-22b-dev_embeddings_connectors.safetensors -p "a lovely cat" --cfg-scale 6.0 --sampling-method euler -v -n "worst quality, low quality, blurry, distorted, artifacts" -W 1280 -H 720 --offload-to-cpu --video-frames 33 --fps 24 -o t2v.webm ```