Skip to content

Windows CUDA x64

Windows CUDA x64 #79

# GitHub Actions Workflow: Build opencv-python with CUDA support on Windows
#
# This workflow compiles opencv-python from source with CUDA enabled on a
# GitHub-hosted Windows runner. The resulting Python wheel is then uploaded
# as a build artifact.
#
# This is a complex and long-running process. It is configured to run only
# on manual trigger (workflow_dispatch).
name: Windows CUDA x64
on:
workflow_dispatch:
inputs:
# TODO: Add cuda_version input to allow running only CUDA 12 or 13 builds for debugging
# TODO: Right now we don't correctly determine when things have changed and we require a
# rebuild, so for now we just manually trigger rebuilds between runs.
restore_build_cache:
description: "Restore build cache. Uncheck to force re-build."
required: false
type: boolean
default: true
save_build_cache:
description: "Save build cache."
required: false
type: boolean
default: true
rolling_build:
description: "Use latest commit from upstream OpenCV repo. Cache settings will be ignored."
required: false
type: boolean
default: false
jobs:
Build:
runs-on: ${{ matrix.runs-on }}
strategy:
fail-fast: false
matrix:
# Build variants control binary size vs JIT compilation tradeoff:
# - full: CUDA 12, native SASS for all GPUs (5.0-10.0), largest binary, no JIT needed
# - legacy: CUDA 11, PTX/SASS 3.5, for older GPUs (Kepler+) and systems with older drivers
build-variant: ['full', 'legacy']
python-version: ['3.13']
platform: [x64]
include:
# CUDA 12 - Full variant: All SASS targets for maximum performance
- build-variant: 'full'
runs-on: 'windows-2025'
cuda-version: '12'
cmake-toolset: 'v143'
cuda-installer: 'cuda_12.9.1_windows_network.exe'
cuda-path-version: 'v12.9'
cudnn-archive: 'cudnn-windows-x86_64-9.18.1.3_cuda12-archive.zip'
cudnn-folder: 'cudnn-windows-x86_64-9.18.1.3_cuda12-archive'
cudnn-dll-path: 'bin/x64'
video-codec-sdk-archive: 'Video_Codec_SDK_13.0.37.zip'
video-codec-sdk-folder: 'Video_Codec_SDK_13.0.37'
cuda-arch-bin: '5.0;5.2;6.0;6.1;7.0;7.5;8.0;8.6;8.9;9.0;10.0'
cuda-arch-ptx: '10.0'
cache-key: 'nvidia-deps-cuda-12.9.1-cudnn-9.18.1.3'
# CUDA 11 - Legacy variant: For older GPUs (Kepler+) and systems with older drivers
# NOTE: CUDA 11.8 requires VS2017-VS2022, so we use windows-2022 with v142 toolset
- build-variant: 'legacy'
runs-on: 'windows-2022'
cuda-version: '11'
cmake-toolset: 'v142'
cuda-installer: 'cuda_11.8.0_windows_network.exe'
cuda-path-version: 'v11.8'
cudnn-archive: 'cudnn-windows-x86_64-8.9.7.29_cuda11-archive.zip'
cudnn-folder: 'cudnn-windows-x86_64-8.9.7.29_cuda11-archive'
cudnn-dll-path: 'bin'
video-codec-sdk-archive: 'Video_Codec_SDK_13.0.37.zip'
video-codec-sdk-folder: 'Video_Codec_SDK_13.0.37'
cuda-arch-bin: '3.5'
cuda-arch-ptx: '3.5'
cache-key: 'nvidia-deps-cuda-11.8.0-cudnn-8.9.7.29'
env:
ACTIONS_ALLOW_UNSECURE_COMMANDS: true
SDIST: 0
ENABLE_HEADLESS: 0
ENABLE_CONTRIB: 1
ENABLE_ROLLING: ${{ inputs.rolling_build && 1 || 0 }}
OPENCV_TEST_DATA_PATH: ${{ github.workspace }}\opencv_extra\testdata
CUDA_ARCH_BIN: ${{ matrix.cuda-arch-bin }}
CUDA_ARCH_PTX: ${{ matrix.cuda-arch-ptx }}
steps:
- name: Cleanup
shell: bash
run: |
rm -rf ./* || true
rm -rf ./.??* || true
working-directory: ${{ github.workspace }}
- name: Checkout
uses: actions/checkout@v4
with:
submodules: false
fetch-depth: 0
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
architecture: ${{ matrix.platform }}
- name: Setup MSBuild.exe
uses: microsoft/setup-msbuild@v1.1
- name: Setup NASM
uses: ilammy/setup-nasm@v1
- name: Cache NVIDIA dependencies
id: cache-nvidia-deps
uses: actions/cache@v3
with:
path: .deps/Nvidia
key: ${{ matrix.cache-key }}
- name: Clone NVIDIA dependencies
if: steps.cache-nvidia-deps.outputs.cache-hit != 'true'
env:
SSH_PRIVATE_KEY: ${{ secrets.DEPS_REPO_SSH_KEY }}
run: |
eval "$(ssh-agent -s)"
ssh-add - <<< "${SSH_PRIVATE_KEY}"
ssh-keyscan github.com >> ~/.ssh/known_hosts 2>/dev/null
git clone git@github.com:Breakthrough/opencv-python-cuda-deps.git .deps
shell: bash
- name: 🔧 Install NVIDIA CUDA Toolkit
run: |
$installer_path = ".deps/Nvidia/${{ matrix.cuda-installer }}"
if (-not (Test-Path $installer_path)) {
throw "CUDA Toolkit installer not found at $installer_path"
}
echo "Installing CUDA ${{ matrix.cuda-version }} Toolkit silently..."
Start-Process -FilePath $installer_path -ArgumentList "-s" -Wait -NoNewWindow
echo "Adding CUDA to PATH..."
$CUDA_PATH = "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\${{ matrix.cuda-path-version }}"
echo "CUDA_PATH=$CUDA_PATH" | Out-File -FilePath $env:GITHUB_ENV -Append
Copy-Item -Path "$CUDA_PATH/bin/*" -Destination . -Include "*.dll"
shell: pwsh
- name: 🔧 Install NVIDIA CuDNN
run: |
$cudnn_path = ".deps/Nvidia/${{ matrix.cudnn-archive }}"
if (-not (Test-Path $cudnn_path)) {
throw "CuDNN archive not found at $cudnn_path"
}
echo "Installing CuDNN for CUDA ${{ matrix.cuda-version }}..."
7z x $cudnn_path
$CUDNN_PATH = "D:/a/opencv-python-cuda/opencv-python-cuda/${{ matrix.cudnn-folder }}"
echo "CUDNN_LIBRARY=$CUDNN_PATH/lib/x64/cudnn.lib" | Out-File -FilePath $env:GITHUB_ENV -Append
echo "CUDNN_INCLUDE_DIR=$CUDNN_PATH/include" | Out-File -FilePath $env:GITHUB_ENV -Append
Copy-Item -Path "$CUDNN_PATH/${{ matrix.cudnn-dll-path }}/*" -Destination . -Include "*.dll"
shell: pwsh
- name: 🔧 Install NVIDIA Video Codec SDK
run: |
$sdk_path = ".deps/Nvidia/${{ matrix.video-codec-sdk-archive }}"
if (-not (Test-Path $sdk_path)) {
throw "Video Codec SDK archive not found at $sdk_path"
}
echo "Installing Video Codec SDK..."
7z x $sdk_path
$SDK_PATH = "D:/a/opencv-python-cuda/opencv-python-cuda/${{ matrix.video-codec-sdk-folder }}"
echo "CUDA_nvcuvid_LIBRARY=$SDK_PATH/Lib/win/x64/nvcuvid.lib" | Out-File -FilePath $env:GITHUB_ENV -Append
echo "CUDA_nvencodeapi_LIBRARY=$SDK_PATH/Lib/win/x64/nvencodeapi.lib" | Out-File -FilePath $env:GITHUB_ENV -Append
echo "NVCUVID_INCLUDE_DIR=$SDK_PATH/Interface" | Out-File -FilePath $env:GITHUB_ENV -Append
shell: pwsh
- name: Restore build artifacts
uses: actions/cache/restore@v3
if: ${{ inputs.restore_build_cache && !inputs.rolling_build }}
with:
path: _skbuild
key: ${{ runner.os }}-${{ matrix.python-version }}-cuda${{ matrix.cuda-version }}-${{ matrix.build-variant }}-${{ hashFiles('**/CMakeLists.txt') }}
restore-keys: |
${{ runner.os }}-${{ matrix.python-version }}-cuda${{ matrix.cuda-version }}-${{ matrix.build-variant }}-
- name: Build a package
# CMake 3.25 regression fix. See https://stackoverflow.com/questions/74162633/problem-compiling-from-source-opencv-with-mvsc2019-in-64-bit-version
run: |
python --version
python -m pip install --upgrade pip
python -m pip install --upgrade setuptools
python -m pip install cmake==3.24.2
python -m pip install toml
python -c "import toml; c = toml.load('pyproject.toml'); print('\n'.join(c['build-system']['requires']))" > requirements.txt
python -m pip install -r requirements.txt
$CI_BUILD = 1
if (Test-Path _skbuild) {
$SKIP_CMAKE = "--skip-cmake"
}
# Set CMake generator and toolset (e.g., v142 for CUDA 11, v143 for CUDA 12)
# Note: Toolset (-T) requires Visual Studio generator, not Ninja
# Using environment variables avoids quoting issues with CMAKE_ARGS
$env:CMAKE_GENERATOR = "Visual Studio 17 2022"
$env:CMAKE_GENERATOR_PLATFORM = "x64"
$env:CMAKE_GENERATOR_TOOLSET = "${{ matrix.cmake-toolset }}"
echo "Using CMake generator: Visual Studio 17 2022, platform: x64, toolset: ${{ matrix.cmake-toolset }}"
python setup.py $SKIP_CMAKE bdist_wheel --py-limited-api=cp37 --dist-dir="$PWD\wheelhouse" -v
shell: pwsh
- name: Save build artifacts to cache
uses: actions/cache/save@v3
if: ${{ inputs.save_build_cache && !inputs.rolling_build }}
with:
path: _skbuild
key: ${{ runner.os }}-${{ matrix.python-version }}-cuda${{ matrix.cuda-version }}-${{ matrix.build-variant }}-${{ hashFiles('**/CMakeLists.txt') }}
- name: Saving all wheels
uses: actions/upload-artifact@v4
with:
name: opencv-python-cuda-${{ matrix.build-variant }}-${{ matrix.platform }}
path: wheelhouse/opencv*
Test:
needs: [Build]
runs-on: windows-2025
defaults:
run:
shell: cmd
strategy:
fail-fast: false
matrix:
python-version: ['3.12']
platform: [x64]
build-variant: ['full', 'legacy']
env:
ACTIONS_ALLOW_UNSECURE_COMMANDS: true
OPENCV_TEST_DATA_PATH: ${{ github.workspace }}\opencv_extra\testdata
steps:
- name: Cleanup
shell: bash
run: |
rm -rf ./* || true
rm -rf ./.??* || true
working-directory: ${{ github.workspace }}
- name: Checkout
uses: actions/checkout@v4
with:
submodules: true
fetch-depth: 0
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
architecture: ${{ matrix.platform }}
- name: Download a wheel accordingly to matrix
uses: actions/download-artifact@v4
with:
name: opencv-python-cuda-${{ matrix.build-variant }}-${{ matrix.platform }}
path: wheelhouse/
- name: Package installation
run: |
cd ${{ github.workspace }}/tests
&python -m pip install --user --no-warn-script-location (ls "../wheelhouse/opencv*.whl")
if ($LastExitCode -ne 0) {throw $LastExitCode}
python get_build_info.py
shell: powershell
- name: Run tests
run: |
cd ${{ github.workspace }}/tests
python test.py