From a8a7716b530e49fed537c57711247c12fbbb903c Mon Sep 17 00:00:00 2001 From: Stefan Gerasch Date: Fri, 7 Aug 2026 11:26:45 +0200 Subject: [PATCH] build: split CUDA Docker images into cuda12 (12.9.x) / cuda13 (13.3.x), fix Blackwell Ultra arch gate (#23) The CMakeLists.txt >=12.8 CUDA-architecture branch claimed 121a-real (Blackwell Ultra) alongside 120a-real, but nvcc from CUDA 12.8.1 rejects compute_121 ("nvcc fatal: Unsupported gpu architecture 'compute_121'"). Confirmed against a real build: 12.8.1 compiles cleanly with 120a-real but not 121a-real; 12.9.2 compiles both. Split the >=12.8 branch into >=12.9 (full Blackwell + Ultra) and >=12.8 (Blackwell only, no Ultra). Since no single CUDA toolkit spans the full arch range -- 12.9.x is the newest 12.x that still emits Pascal (61-real) SASS, 13.x drops Pascal entirely but is otherwise more current -- the single :cuda image can no longer serve both audiences. Split it into two CI variants, :cuda12 (12.9.2, Pascal through Blackwell Ultra) and :cuda13 (13.3.1, Turing and newer). The Dockerfile's own --target cuda stage is unchanged; the CUDA_BUILD_IMAGE/CUDA_RUNTIME_IMAGE ARGs now default to 12.9.2 (was 12.4.1) and the CI matrix overrides them per variant. Both variants were build-tested against nvidia/cuda:12.8.1 and 12.9.2 locally and exercised with real end-to-end synthesis requests on an actual sm_61 card (GTX 1070 Max-Q) -- RTF ~0.4 on both, no kernel image / arch mismatch errors. Co-authored-by: Gary --- .github/workflows/docker.yml | 51 +++++++++++++++++++++++++++++++++--- CMakeLists.txt | 7 +++-- Dockerfile | 10 +++++-- docs/DOCKER.md | 34 ++++++++++++++++-------- 4 files changed, 83 insertions(+), 19 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 02dab31..e4d2cd3 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -22,7 +22,21 @@ jobs: strategy: fail-fast: false matrix: - variant: [cpu, cuda, vulkan] + include: + - variant: cpu + target: cpu + # Two CUDA variants: no single toolkit covers both Pascal and + # the newest archs (see CMakeLists.txt). + - variant: cuda12 + target: cuda + cuda_build_image: nvidia/cuda:12.9.2-devel-ubuntu22.04 + cuda_runtime_image: nvidia/cuda:12.9.2-runtime-ubuntu22.04 + - variant: cuda13 + target: cuda + cuda_build_image: nvidia/cuda:13.3.1-devel-ubuntu22.04 + cuda_runtime_image: nvidia/cuda:13.3.1-runtime-ubuntu22.04 + - variant: vulkan + target: vulkan steps: - uses: actions/checkout@v7 with: @@ -54,12 +68,41 @@ jobs: fi echo "tags=${tags}" >> "$GITHUB_OUTPUT" + # Only set these for the cuda variants, an empty value breaks cpu/vulkan. + build_args="" + if [ -n "${{ matrix.cuda_build_image }}" ]; then + build_args=$'CUDA_BUILD_IMAGE=${{ matrix.cuda_build_image }}\nCUDA_RUNTIME_IMAGE=${{ matrix.cuda_runtime_image }}' + fi + { + echo "build_args<> "$GITHUB_OUTPUT" + + # GHCR cache tag, read on every run; only pushed to when we're + # logged in (not on PR builds). + cache_ref="${image}:buildcache-${variant}" + cache_from=$'type=gha,scope='"$variant"$'\ntype=registry,ref='"$cache_ref" + cache_to="type=gha,mode=max,scope=${variant}" + if [ "${{ github.event_name }}" != "pull_request" ]; then + cache_to="${cache_to}"$'\n'"type=registry,ref=${cache_ref},mode=max" + fi + { + echo "cache_from<> "$GITHUB_OUTPUT" + - name: Build and push uses: docker/build-push-action@v7 with: context: . - target: ${{ matrix.variant }} + target: ${{ matrix.target }} push: ${{ github.event_name != 'pull_request' }} tags: ${{ steps.tags.outputs.tags }} - cache-from: type=gha,scope=${{ matrix.variant }} - cache-to: type=gha,mode=max,scope=${{ matrix.variant }} + build-args: ${{ steps.tags.outputs.build_args }} + cache-from: ${{ steps.tags.outputs.cache_from }} + cache-to: ${{ steps.tags.outputs.cache_to }} diff --git a/CMakeLists.txt b/CMakeLists.txt index 140f457..4252243 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -51,14 +51,17 @@ endif() # supported card and doesn't need to seed forward JIT compat for anything # older, unlike the 75-virtual baseline which does that for 7.5+. CUDA 13 # removed offline compilation for pre-Turing architectures, so 61-real is -# only emitted on 12.x toolkits; Blackwell (120a/121a) needs 12.8+. +# only emitted on 12.x toolkits. Blackwell (120a) needs 12.8+; Blackwell +# Ultra (121a) needs 12.9+ (nvcc 12.8 rejects compute_121). # Users can override with -DCMAKE_CUDA_ARCHITECTURES=native for local builds. if(NOT DEFINED CMAKE_CUDA_ARCHITECTURES) find_package(CUDAToolkit QUIET) if(CUDAToolkit_FOUND AND CUDAToolkit_VERSION VERSION_GREATER_EQUAL "13.0") set(CMAKE_CUDA_ARCHITECTURES "75-virtual;80-virtual;86-real;89-real;120a-real;121a-real") - elseif(CUDAToolkit_FOUND AND CUDAToolkit_VERSION VERSION_GREATER_EQUAL "12.8") + elseif(CUDAToolkit_FOUND AND CUDAToolkit_VERSION VERSION_GREATER_EQUAL "12.9") set(CMAKE_CUDA_ARCHITECTURES "61-real;75-virtual;80-virtual;86-real;89-real;120a-real;121a-real") + elseif(CUDAToolkit_FOUND AND CUDAToolkit_VERSION VERSION_GREATER_EQUAL "12.8") + set(CMAKE_CUDA_ARCHITECTURES "61-real;75-virtual;80-virtual;86-real;89-real;120a-real") else() set(CMAKE_CUDA_ARCHITECTURES "61-real;75-virtual;80-virtual;86-real;89-real") endif() diff --git a/Dockerfile b/Dockerfile index 4763a4d..7817b52 100644 --- a/Dockerfile +++ b/Dockerfile @@ -15,9 +15,15 @@ # docker build --target cuda -t qwentts.cpp:cuda \ # --build-arg CMAKE_CUDA_ARCHITECTURES=50 . # Maxwell # See docs/DOCKER.md for details. +# +# Defaults to the newest CUDA 12.x (widest arch range, see CMakeLists.txt); +# override both ARGs for CUDA 13.x instead, as the cuda13 CI variant does: +# docker build --target cuda -t qwentts.cpp:cuda13 \ +# --build-arg CUDA_BUILD_IMAGE=nvidia/cuda:13.3.1-devel-ubuntu22.04 \ +# --build-arg CUDA_RUNTIME_IMAGE=nvidia/cuda:13.3.1-runtime-ubuntu22.04 . -ARG CUDA_BUILD_IMAGE=nvidia/cuda:12.4.1-devel-ubuntu22.04 -ARG CUDA_RUNTIME_IMAGE=nvidia/cuda:12.4.1-runtime-ubuntu22.04 +ARG CUDA_BUILD_IMAGE=nvidia/cuda:12.9.2-devel-ubuntu22.04 +ARG CUDA_RUNTIME_IMAGE=nvidia/cuda:12.9.2-runtime-ubuntu22.04 # ---------------------------------------------------------------- CPU build FROM ubuntu:22.04 AS build-cpu diff --git a/docs/DOCKER.md b/docs/DOCKER.md index 5c26738..614fc4f 100644 --- a/docs/DOCKER.md +++ b/docs/DOCKER.md @@ -1,9 +1,16 @@ # Docker Pre-built images: `ghcr.io/serveurpersocom/qwentts.cpp:cpu`, -`:cuda` and `:vulkan` (also tagged per release, e.g. `:cuda-v1.2.3`). -All three run `tts-server`; `qwen-tts` and `qwen-codec` are included in -the same image at `/app/`. +`:cuda12`, `:cuda13` and `:vulkan` (also tagged per release, e.g. +`:cuda12-v1.2.3`). All four run `tts-server`; `qwen-tts` and +`qwen-codec` are included in the same image at `/app/`. + +`:cuda12` (CUDA 12.9.x) is built against the widest arch range, +Pascal (sm_61) through Blackwell Ultra (120a/121a); `:cuda13` +(CUDA 13.3.x) covers Turing and newer only -- upstream dropped +offline compilation for pre-Turing architectures in CUDA 13, so a +Pascal/Maxwell card needs `:cuda12`. See `CMakeLists.txt` for the +full per-toolkit-version arch table. ``` docker run --rm -p 8080:8080 \ @@ -22,9 +29,12 @@ docker run --rm --gpus all -p 8080:8080 \ -v /path/to/voices:/voices:ro \ -e MODEL_PATH=/models/qwen-talker-1.7b-base-Q8_0.gguf \ -e CODEC_PATH=/models/qwen-tokenizer-12hz-Q8_0.gguf \ - ghcr.io/serveurpersocom/qwentts.cpp:cuda + ghcr.io/serveurpersocom/qwentts.cpp:cuda12 ``` +Use `:cuda13` instead of `:cuda12` for a newer CUDA toolkit if your +card is Turing (sm_75) or newer -- see the note above. + Vulkan image (AMD/Intel GPUs), passing through the DRI device node: ``` @@ -36,9 +46,9 @@ docker run --rm --device /dev/dri -p 8080:8080 \ ``` The `:vulkan` image bundles Mesa's Vulkan drivers (AMD/Intel). On an -NVIDIA GPU, prefer `:cuda`; running `:vulkan` there would additionally -need the host's proprietary NVIDIA Vulkan ICD mounted in, which the -image does not provide. +NVIDIA GPU, prefer `:cuda12` / `:cuda13`; running `:vulkan` there would +additionally need the host's proprietary NVIDIA Vulkan ICD mounted in, +which the image does not provide. ## Entrypoint environment variables @@ -103,10 +113,12 @@ uses the last stage in the `Dockerfile` (`cuda`). detect against. This project's own `CMakeLists.txt` already handles that by defaulting `CMAKE_CUDA_ARCHITECTURES` to a fixed Pascal-and-newer list (`61-real;75-virtual;80-virtual;86-real;89-real`, plus Blackwell -with CUDA 12.8+) when the variable isn't set, so Pascal cards (sm_61, -e.g. the GTX 10-series) work out of the box with no override. GPUs -older than Pascal (Maxwell and earlier) still need the architecture -passed explicitly: +`120a-real` with CUDA 12.8+ and Blackwell Ultra `121a-real` with CUDA +12.9+) when the variable isn't set, so Pascal cards (sm_61, e.g. the +GTX 10-series) work out of the box with no override -- as long as the +toolkit is 12.x (CUDA 13 dropped Pascal offline compilation entirely, +see `:cuda13` above). GPUs older than Pascal (Maxwell and earlier) +still need the architecture passed explicitly: ``` docker build --target cuda -t qwentts.cpp:cuda \