Skip to content

Use OpenCV_CUDA_jll's CUDA build when it is installed - #104

Merged
ViralBShah merged 4 commits into
masterfrom
vs/cuda-backend
Nov 11, 2026
Merged

ViralBShah merged 4 commits into
masterfrom
vs/cuda-backend

Conversation

@ViralBShah

@ViralBShah ViralBShah commented Nov 9, 2026 •

Copy link
Copy Markdown
Member

Adds opt-in CUDA support: after ] add OpenCV_CUDA_jll and a restart, OpenCV loads its binaries from OpenCV_CUDA_jll (CUDA 13 + cuDNN, Linux x86_64/aarch64) instead of OpenCV_jll. This enables cv.dnn's DNN_BACKEND_CUDA. Removing OpenCV_CUDA_jll switches back to the CPU build.

Requires JuliaPackaging/Yggdrasil#15546 (OpenCV_CUDA_jll 4.14.0+1) for the CUDA path; see below.

Design

  • OpenCV_CUDA_jll is a weak dependency, not a regular one. Pkg downloads the CUDA runtime and cuDNN when OpenCV_CUDA_jll is installed, whether or not it is loaded. The artifacts are lazy, but the .pkg/select_artifacts.jl hook of CUDA-augmented JLLs selects them with include_lazy=true. In a fresh depot on a GPU machine, a hard dependency made ] add OpenCV download about 1.8 GB: CUDA_Runtime 1023 MiB, CUDNN 431 MiB, CUDA_Compiler 188 MiB, CUDA_Driver 108 MiB and OpenCV_CUDA 42 MiB. As a weak dependency, it adds nothing to the install. The [compat] entry still constrains its version when a user adds it.
  • The library is chosen in __init__. If OpenCV_CUDA_jll is in the environment and has binaries for the host, OpenCV loads it and points @wrapmodule's library callback at its libopencv_julia before @initcxx. The wrappers stay precompiled against OpenCV_jll, which works because both libraries are built from this repo's gen/. They register the same 859 bindings and export the same 25,836 symbols, and @initcxx re-resolves every function pointer by key. While output is being generated for precompilation, OpenCV always uses OpenCV_jll.
  • No package extension. An extension can't do this: @initcxx binds the library in OpenCV.__init__, and extensions load only after their parent's __init__. There is also no preference to set: installing the package is the opt-in.
  • Coexistence with OpenCV_jll. OpenCV_jll is still loaded, because it is a regular dependency. [OpenCV_CUDA] Suffix library names with _cuda JuliaPackaging/Yggdrasil#15546 renames the CUDA build's libraries (libopencv_core_cuda.so.414, …) so the two builds don't clash by soname. With the currently registered OpenCV_CUDA_jll 4.14.0+0, which lacks the renaming, OpenCV warns and stays on the CPU build.

Testing

Julia 1.13.3, 2× H100 NVL (driver 595.45, CUDA 13.2), OpenCV_jll 4.14.0+0:

  • Fresh depot, ] add OpenCV: no CUDA artifacts are downloaded (455 MB of artifacts in total, against 4.0 GB with a hard dependency), and OpenCV binds OpenCV_jll.

  • With OpenCV_CUDA_jll from Yggdrasil#15546's CI added: 313/313 tests pass, OpenCV binds OpenCV_CUDA_jll, and both builds' libraries are loaded side by side.

  • With the registered OpenCV_CUDA_jll 4.14.0+0 added: OpenCV warns, binds OpenCV_jll, and 313/313 tests pass.

  • DNN face detector (opencv_face_detector_uint8.pb, 300×300), with identical detections on all backends:

    Backend / target ms/frame
    DNN_BACKEND_OPENCV / DNN_TARGET_CPU 15.1
    DNN_BACKEND_CUDA / DNN_TARGET_CUDA 3.1
    DNN_BACKEND_CUDA / DNN_TARGET_CUDA_FP16 3.0

    Model has no generated setPreferableBackend binding, so the backend is set on a Net from readNet before wrapping it in DetectionModel.

Not covered: CI here has no GPU and does not install OpenCV_CUDA_jll, so it only exercises the CPU path. I could not test a Linux machine without an NVIDIA driver, where OpenCV_CUDA_jll should have no binaries and OpenCV should stay on the CPU build.

Bumps the version to 4.11.0, a minor release because this only adds functionality. The release also includes the unreleased OpenCV 4.14 wrappers from #103.

🤖 Generated with Claude Code

`OpenCV.set_backend!("cuda")` makes OpenCV load its binaries from
OpenCV_CUDA_jll instead of OpenCV_jll after a restart. The choice is made
at precompile time, so only one OpenCV build is ever loaded.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@codecov

codecov Bot commented Nov 9, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 37.50000% with 10 lines in your changes missing coverage. Please review.
✅ Project coverage is 89.28%. Comparing base (3263f0b) to head (1492444).

Files with missing lines Patch % Lines
src/core.jl 37.50% 10 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master     #104      +/-   ##
==========================================
- Coverage   92.79%   89.28%   -3.52%     
==========================================
  Files          11       11              
  Lines         236      252      +16     
==========================================
+ Hits          219      225       +6     
- Misses         17       27      +10     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

ViralBShah and others added 2 commits November 9, 2026 17:54
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Pkg downloads the CUDA runtime and cuDNN artifacts (about 1.8 GB) when
OpenCV_CUDA_jll is installed, even if it is never loaded: the artifact
selection hook of JLLs with CUDA platform augmentation includes lazy
artifacts. As a hard dependency, every OpenCV user on a machine with an
NVIDIA driver would pay for that.

Instead, OpenCV_CUDA_jll is a weak dependency that users opt into with
`] add OpenCV_CUDA_jll`. OpenCV's `__init__` uses it when it is installed
and has binaries for the host, binding its `libopencv_julia`, which
registers the same bindings as OpenCV_jll's, at `@initcxx`. This replaces
the backend preference.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ViralBShah ViralBShah changed the title Add a CUDA backend selected by preference Use OpenCV_CUDA_jll's CUDA build when it is installed Nov 9, 2026
OpenCV finds OpenCV_CUDA_jll anywhere on the load path, including stacked
environments such as @v1.x, where OpenCV's [compat] entry is not enforced.
Binding the wrappers to a libopencv_julia from another OpenCV release would
fail or misbehave, so fall back to OpenCV_jll with a warning when the
versions differ. Document the load-path behavior in the README.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ViralBShah

Copy link
Copy Markdown
Member Author

@yakir12 FYI.

@ViralBShah
ViralBShah merged commit 27c862a into master Nov 11, 2026
9 of 10 checks passed
@ViralBShah
ViralBShah deleted the vs/cuda-backend branch November 11, 2026 15:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant