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 <gitea@gerasch.dev>
This commit is contained in:
Stefan Gerasch
2026-08-07 11:26:45 +02:00
committed by GitHub
co-authored by Gary
parent 37d62e42a0
commit a8a7716b53
4 changed files with 83 additions and 19 deletions
+47 -4
View File
@@ -22,7 +22,21 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: 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: steps:
- uses: actions/checkout@v7 - uses: actions/checkout@v7
with: with:
@@ -54,12 +68,41 @@ jobs:
fi fi
echo "tags=${tags}" >> "$GITHUB_OUTPUT" 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<<BUILD_ARGS_EOF"
echo "$build_args"
echo "BUILD_ARGS_EOF"
} >> "$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<<CACHE_FROM_EOF"
echo "$cache_from"
echo "CACHE_FROM_EOF"
echo "cache_to<<CACHE_TO_EOF"
echo "$cache_to"
echo "CACHE_TO_EOF"
} >> "$GITHUB_OUTPUT"
- name: Build and push - name: Build and push
uses: docker/build-push-action@v7 uses: docker/build-push-action@v7
with: with:
context: . context: .
target: ${{ matrix.variant }} target: ${{ matrix.target }}
push: ${{ github.event_name != 'pull_request' }} push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.tags.outputs.tags }} tags: ${{ steps.tags.outputs.tags }}
cache-from: type=gha,scope=${{ matrix.variant }} build-args: ${{ steps.tags.outputs.build_args }}
cache-to: type=gha,mode=max,scope=${{ matrix.variant }} cache-from: ${{ steps.tags.outputs.cache_from }}
cache-to: ${{ steps.tags.outputs.cache_to }}
+5 -2
View File
@@ -51,14 +51,17 @@ endif()
# supported card and doesn't need to seed forward JIT compat for anything # 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 # 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 # 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. # Users can override with -DCMAKE_CUDA_ARCHITECTURES=native for local builds.
if(NOT DEFINED CMAKE_CUDA_ARCHITECTURES) if(NOT DEFINED CMAKE_CUDA_ARCHITECTURES)
find_package(CUDAToolkit QUIET) find_package(CUDAToolkit QUIET)
if(CUDAToolkit_FOUND AND CUDAToolkit_VERSION VERSION_GREATER_EQUAL "13.0") 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") 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") 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() else()
set(CMAKE_CUDA_ARCHITECTURES "61-real;75-virtual;80-virtual;86-real;89-real") set(CMAKE_CUDA_ARCHITECTURES "61-real;75-virtual;80-virtual;86-real;89-real")
endif() endif()
+8 -2
View File
@@ -15,9 +15,15 @@
# docker build --target cuda -t qwentts.cpp:cuda \ # docker build --target cuda -t qwentts.cpp:cuda \
# --build-arg CMAKE_CUDA_ARCHITECTURES=50 . # Maxwell # --build-arg CMAKE_CUDA_ARCHITECTURES=50 . # Maxwell
# See docs/DOCKER.md for details. # 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_BUILD_IMAGE=nvidia/cuda:12.9.2-devel-ubuntu22.04
ARG CUDA_RUNTIME_IMAGE=nvidia/cuda:12.4.1-runtime-ubuntu22.04 ARG CUDA_RUNTIME_IMAGE=nvidia/cuda:12.9.2-runtime-ubuntu22.04
# ---------------------------------------------------------------- CPU build # ---------------------------------------------------------------- CPU build
FROM ubuntu:22.04 AS build-cpu FROM ubuntu:22.04 AS build-cpu
+23 -11
View File
@@ -1,9 +1,16 @@
# Docker # Docker
Pre-built images: `ghcr.io/serveurpersocom/qwentts.cpp:cpu`, Pre-built images: `ghcr.io/serveurpersocom/qwentts.cpp:cpu`,
`:cuda` and `:vulkan` (also tagged per release, e.g. `:cuda-v1.2.3`). `:cuda12`, `:cuda13` and `:vulkan` (also tagged per release, e.g.
All three run `tts-server`; `qwen-tts` and `qwen-codec` are included in `:cuda12-v1.2.3`). All four run `tts-server`; `qwen-tts` and
the same image at `/app/`. `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 \ docker run --rm -p 8080:8080 \
@@ -22,9 +29,12 @@ docker run --rm --gpus all -p 8080:8080 \
-v /path/to/voices:/voices:ro \ -v /path/to/voices:/voices:ro \
-e MODEL_PATH=/models/qwen-talker-1.7b-base-Q8_0.gguf \ -e MODEL_PATH=/models/qwen-talker-1.7b-base-Q8_0.gguf \
-e CODEC_PATH=/models/qwen-tokenizer-12hz-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: 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 The `:vulkan` image bundles Mesa's Vulkan drivers (AMD/Intel). On an
NVIDIA GPU, prefer `:cuda`; running `:vulkan` there would additionally NVIDIA GPU, prefer `:cuda12` / `:cuda13`; running `:vulkan` there would
need the host's proprietary NVIDIA Vulkan ICD mounted in, which the additionally need the host's proprietary NVIDIA Vulkan ICD mounted in,
image does not provide. which the image does not provide.
## Entrypoint environment variables ## 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 detect against. This project's own `CMakeLists.txt` already handles
that by defaulting `CMAKE_CUDA_ARCHITECTURES` to a fixed Pascal-and-newer 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 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, `120a-real` with CUDA 12.8+ and Blackwell Ultra `121a-real` with CUDA
e.g. the GTX 10-series) work out of the box with no override. GPUs 12.9+) when the variable isn't set, so Pascal cards (sm_61, e.g. the
older than Pascal (Maxwell and earlier) still need the architecture GTX 10-series) work out of the box with no override -- as long as the
passed explicitly: 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 \ docker build --target cuda -t qwentts.cpp:cuda \