Skip to content

Windows CUDA x64

Windows CUDA x64 #84

# 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:
python-version: ['3.13']
platform: [x64]
cuda-version: ['12']
include:
# CUDA 12: Supports Maxwell (5.0) through Blackwell (10.0)
- cuda-version: '12'
runs-on: 'windows-2025'
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'
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'
# TODO: Re-enable CUDA 13 after updating to OpenCV 4.13+
# CUDA 13: Supports Turing (7.5) through Blackwell (12.0)
# - cuda-version: '13'
# runs-on: 'windows-2025'
# cuda-installer: 'cuda_13.1.1_windows_network.exe'
# cuda-path-version: 'v13.1'
# cudnn-archive: 'cudnn-windows-x86_64-9.18.1.3_cuda13-archive.zip'
# cudnn-folder: 'cudnn-windows-x86_64-9.18.1.3_cuda13-archive'
# video-codec-sdk-archive: 'Video_Codec_SDK_13.0.37.zip'
# video-codec-sdk-folder: 'Video_Codec_SDK_13.0.37'
# cuda-arch-bin: '7.5;8.0;8.6;8.9;9.0;10.0;12.0'
# cuda-arch-ptx: '12.0'
# cache-key: 'nvidia-deps-cuda-13.1.1-cudnn-9.18.1.3'
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/[email protected]
- 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 [email protected]: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/bin/x64/*" -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 }}-${{ hashFiles('**/CMakeLists.txt') }}
restore-keys: |
${{ runner.os }}-${{ matrix.python-version }}-cuda${{ matrix.cuda-version }}-
- 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"
}
python setup.py $SKIP_CMAKE bdist_wheel --py-limited-api=cp37 --dist-dir="$PWD\wheelhouse" -v
shell: pwsh
- name: Repack wheel with maximum compression
run: |
python -c "
import zipfile, os
whl_dir = 'wheelhouse'
for name in os.listdir(whl_dir):
if not name.endswith('.whl'):
continue
src = os.path.join(whl_dir, name)
dst = src + '.tmp'
src_size = os.path.getsize(src)
print(f'Repacking {name} ({src_size / 1e9:.2f} GB)...')
with zipfile.ZipFile(src, 'r') as zin, zipfile.ZipFile(dst, 'w', zipfile.ZIP_DEFLATED, compresslevel=9) as zout:
for item in zin.infolist():
zout.writestr(item, zin.read(item.name))
dst_size = os.path.getsize(dst)
saved = src_size - dst_size
print(f'Done: {dst_size / 1e9:.2f} GB (saved {saved / 1e6:.1f} MB, {100*saved/src_size:.1f}%)')
os.replace(dst, src)
"
shell: bash
- 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 }}-${{ hashFiles('**/CMakeLists.txt') }}
- name: Saving all wheels
uses: actions/upload-artifact@v4
with:
name: wheel-cuda${{ matrix.cuda-version }}-${{ 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]
cuda-version: ['12'] # TODO: Re-enable '13' after updating to OpenCV 4.13+
env:
ACTIONS_ALLOW_UNSECURE_COMMANDS: true
OPENCV_TEST_DATA_PATH: ${{ github.workspace }}\opencv_extra\testdata
PlatformToolset: v143
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: wheel-cuda${{ matrix.cuda-version }}-${{ 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