diff --git a/CMakeLists.txt b/CMakeLists.txt index 72b5aa62a9..570e499f05 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -73,6 +73,10 @@ if(POLICY CMP0077) cmake_policy(SET CMP0077 NEW) # CMake 3.13+: option() honors normal variables. endif() +if(POLICY CMP0091) + cmake_policy(SET CMP0091 NEW) # CMake 3.15+: leave MSVC runtime selection out of default CMAKE__FLAGS_ flags +endif() + if(POLICY CMP0146) cmake_policy(SET CMP0146 OLD) # CMake 3.27+: use CMake FindCUDA if available. endif() @@ -549,6 +553,9 @@ OCV_OPTION(OPENCV_ENABLE_MEMALIGN "Enable posix_memalign or memalign usage" OCV_OPTION(OPENCV_DISABLE_FILESYSTEM_SUPPORT "Disable filesystem support" OFF) OCV_OPTION(OPENCV_DISABLE_THREAD_SUPPORT "Build the library without multi-threaded code." OFF) OCV_OPTION(OPENCV_SEMIHOSTING "Build the library for semihosting target (Arm). See https://developer.arm.com/documentation/100863/latest." OFF) +OCV_OPTION(ENABLE_CUDA_FIRST_CLASS_LANGUAGE "Enable CUDA as a first class language, if enabled dependant projects will need to use CMake >= 3.18" (WITH_CUDA AND NOT CMAKE_VERSION VERSION_LESS 3.18) + VISIBLE_IF (WITH_CUDA AND NOT CMAKE_VERSION VERSION_LESS 3.18) + VERIFY HAVE_CUDA) OCV_OPTION(ENABLE_PYLINT "Add target with Pylint checks" (BUILD_DOCS OR BUILD_EXAMPLES) IF (NOT CMAKE_CROSSCOMPILING AND NOT APPLE_FRAMEWORK) ) OCV_OPTION(ENABLE_FLAKE8 "Add target with Python flake8 checker" (BUILD_DOCS OR BUILD_EXAMPLES) IF (NOT CMAKE_CROSSCOMPILING AND NOT APPLE_FRAMEWORK) ) @@ -657,6 +664,51 @@ include(cmake/OpenCVCompilerOptions.cmake) ocv_cmake_hook(POST_COMPILER_OPTIONS) +# --- CUDA Support --- +if(ENABLE_CUDA_FIRST_CLASS_LANGUAGE) + if(CMAKE_VERSION VERSION_LESS 3.18) + message(WARNING "CUDA: First class language only supported for CMake versions >= 3.18, falling back to FindCUDA!") + set(ENABLE_CUDA_FIRST_CLASS_LANGUAGE OFF CACHE BOOL "Enable CUDA as a first class language, if enabled dependant projects will need to use CMake >= 3.18" FORCE) + else() + + # Check CUDA_PATH if supplied + if(UNIX AND CUDA_PATH AND NOT ENV{CUDA_PATH}) + set(ENV{CUDA_PATH} ${CUDA_PATH}) + elseif(WIN32 AND CUDA_PATH) + set(ENV{PATH} "${CUDA_PATH}\\bin\;$ENV{PATH}") + endif() + include(CheckLanguage) + check_language(CUDA) + + # Fallback to checking default locations + if(NOT CMAKE_CUDA_COMPILER) + # Checking windows default search location isn't possible because the CUDA Toolkit is installed to C:/Program Files/NVIDIA GPU Computing Toolkit/CUDA/vXX.X + if(WIN32) + if(CMAKE_GENERATOR MATCHES "Visual Studio") + message(STATUS "CUDA: Not detected, when using stand alone installations with the Visual Studio generator the path to the CUDA toolkit should be manually specified with -Tcuda=. e.g. -Tcuda=\"C:/Program Files/NVIDIA GPU Computing Toolkit/CUDA/vXX.X\"") + else() + message(STATUS "CUDA: Not detected, for stand alone installations the path to the CUDA toolkit should be manually specified with -DCUDA_PATH=. e.g. -DCUDA_PATH=\"C:/Program Files/NVIDIA GPU Computing Toolkit/CUDA/vXX.X\"") + endif() + elseif(UNIX) + message(STATUS "CUDA: Not detected, make sure you have performed the mandatory Post-installation actions described in the CUDA installation guide.\n For stand alone installations you can set the CUDA_PATH environmental or CMake variable. e.g. export CUDA_PATH=/usr/local/cuda-XX.X or -DCUDA_PATH=/usr/local/cuda-XX.X.") + message(STATUS "CUDA: Falling back to searching for the CUDA compiler in its default location (/usr/local/cuda)") + set(CUDA_PATH "/usr/local/cuda" CACHE INTERNAL "") + set(ENV{CUDA_PATH} ${CUDA_PATH}) + unset(CMAKE_CUDA_COMPILER CACHE) + unset(CMAKE_CUDA_COMPILER) + check_language(CUDA) + endif() + endif() + + cmake_policy(SET CMP0092 NEW) # CMake 3.15+: leave warning flags out of default CMAKE__FLAGS flags. + if(CMAKE_CUDA_COMPILER) + enable_language(CUDA) + elseif(UNIX) + message(WARNING "CUDA: Not detected! If you are not using the default host compiler (g++) then you need to specify both CMAKE_CUDA_HOST_COMPILER and CMAKE_CUDA_COMPILER. e.g. -DCMAKE_CUDA_HOST_COMPILER=/usr/bin/clang++ -DCMAKE_CUDA_COMPILER=/usr/local/cuda/bin/nvcc.") + endif() + endif() +endif() + # ---------------------------------------------------------------------------- # CHECK FOR SYSTEM LIBRARIES, OPTIONS, ETC.. # ---------------------------------------------------------------------------- diff --git a/cmake/OpenCVCRTLinkage.cmake b/cmake/OpenCVCRTLinkage.cmake index 0e0a54ecf9..c29daad0d1 100644 --- a/cmake/OpenCVCRTLinkage.cmake +++ b/cmake/OpenCVCRTLinkage.cmake @@ -33,34 +33,44 @@ endif() # Ignore warning: This object file does not define any previously undefined public symbols, ... set(CMAKE_STATIC_LINKER_FLAGS "${CMAKE_STATIC_LINKER_FLAGS} /IGNORE:4221") +if(POLICY CMP0091) + cmake_policy(GET CMP0091 MSVC_RUNTIME_SET_BY_ABSTRACTION) +endif() + if(NOT BUILD_SHARED_LIBS AND BUILD_WITH_STATIC_CRT) - foreach(flag_var - CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE - CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO - CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE - CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO) - if(${flag_var} MATCHES "/MD") - string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}") - endif() - if(${flag_var} MATCHES "/MDd") - string(REGEX REPLACE "/MDd" "/MTd" ${flag_var} "${${flag_var}}") - endif() - endforeach(flag_var) + if(MSVC_RUNTIME_SET_BY_ABSTRACTION STREQUAL "NEW") + set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") + else() + foreach(flag_var + CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE + CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO + CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE + CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO) + if(${flag_var} MATCHES "/MD") + string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}") + endif() + if(${flag_var} MATCHES "/MDd") + string(REGEX REPLACE "/MDd" "/MTd" ${flag_var} "${${flag_var}}") + endif() + endforeach(flag_var) + endif() set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /NODEFAULTLIB:atlthunk.lib") set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} /NODEFAULTLIB:libcmt.lib /NODEFAULTLIB:libcpmt.lib /NODEFAULTLIB:msvcrt.lib") set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /NODEFAULTLIB:libcmtd.lib /NODEFAULTLIB:libcpmtd.lib /NODEFAULTLIB:msvcrtd.lib") else() - foreach(flag_var - CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE - CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO - CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE - CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO) - if(${flag_var} MATCHES "/MT") - string(REGEX REPLACE "/MT" "/MD" ${flag_var} "${${flag_var}}") - endif() - if(${flag_var} MATCHES "/MTd") - string(REGEX REPLACE "/MTd" "/MDd" ${flag_var} "${${flag_var}}") - endif() - endforeach(flag_var) + if(NOT MSVC_RUNTIME_SET_BY_ABSTRACTION STREQUAL "NEW") + foreach(flag_var + CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE + CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO + CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE + CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO) + if(${flag_var} MATCHES "/MT") + string(REGEX REPLACE "/MT" "/MD" ${flag_var} "${${flag_var}}") + endif() + if(${flag_var} MATCHES "/MTd") + string(REGEX REPLACE "/MTd" "/MDd" ${flag_var} "${${flag_var}}") + endif() + endforeach(flag_var) + endif() endif() diff --git a/cmake/OpenCVDetectCUDA.cmake b/cmake/OpenCVDetectCUDA.cmake index 5d34a43eb2..e0c539b90a 100644 --- a/cmake/OpenCVDetectCUDA.cmake +++ b/cmake/OpenCVDetectCUDA.cmake @@ -1,10 +1,10 @@ if((WIN32 AND NOT MSVC) OR OPENCV_CMAKE_FORCE_CUDA) - message(STATUS "CUDA compilation is disabled (due to only Visual Studio compiler supported on your platform).") + message(STATUS "CUDA: Compilation is disabled (due to only Visual Studio compiler supported on your platform).") return() endif() if((NOT UNIX AND CV_CLANG) OR OPENCV_CMAKE_FORCE_CUDA) - message(STATUS "CUDA compilation is disabled (due to Clang unsupported on your platform).") + message(STATUS "CUDA: Compilation is disabled (due to Clang unsupported on your platform).") return() endif() @@ -31,444 +31,144 @@ else() list(REMOVE_AT CMAKE_MODULE_PATH 0) endif() -if(CUDA_FOUND) - unset(CUDA_nvcuvenc_LIBRARY CACHE) - set(HAVE_CUDA 1) - if(NOT CUDA_VERSION VERSION_LESS 11.0) - # CUDA 11.0 removes nppicom - ocv_list_filterout(CUDA_nppi_LIBRARY "nppicom") - ocv_list_filterout(CUDA_npp_LIBRARY "nppicom") - endif() - - if(WITH_CUFFT) - set(HAVE_CUFFT 1) - endif() - - if(WITH_CUBLAS) - set(HAVE_CUBLAS 1) - endif() - - if(WITH_CUDNN) - set(CMAKE_MODULE_PATH "${OpenCV_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH}) - find_host_package(CUDNN "${MIN_VER_CUDNN}") - list(REMOVE_AT CMAKE_MODULE_PATH 0) - - if(CUDNN_FOUND) - set(HAVE_CUDNN 1) - endif() - endif() - - if(WITH_NVCUVID OR WITH_NVCUVENC) - macro(ocv_cuda_SEARCH_NVCUVID_HEADER _filename _result) - # place header file under CUDA_TOOLKIT_TARGET_DIR or CUDA_TOOLKIT_ROOT_DIR - find_path(_header_result - ${_filename} - PATHS "${CUDA_TOOLKIT_TARGET_DIR}" "${CUDA_TOOLKIT_ROOT_DIR}" - ENV CUDA_PATH - ENV CUDA_INC_PATH - PATH_SUFFIXES include - NO_DEFAULT_PATH - ) - if("x${_header_result}" STREQUAL "x_header_result-NOTFOUND") - set(${_result} 0) - else() - set(${_result} 1) - endif() - unset(_header_result CACHE) - endmacro() - if(WITH_NVCUVID) - ocv_cuda_SEARCH_NVCUVID_HEADER("nvcuvid.h" HAVE_NVCUVID_HEADER) - ocv_cuda_SEARCH_NVCUVID_HEADER("dynlink_nvcuvid.h" HAVE_DYNLINK_NVCUVID_HEADER) - find_cuda_helper_libs(nvcuvid) - if(CUDA_nvcuvid_LIBRARY AND (${HAVE_NVCUVID_HEADER} OR ${HAVE_DYNLINK_NVCUVID_HEADER})) - # make sure to have both header and library before enabling - set(HAVE_NVCUVID 1) - endif() - endif() - if(WITH_NVCUVENC) - ocv_cuda_SEARCH_NVCUVID_HEADER("nvEncodeAPI.h" HAVE_NVCUVENC_HEADER) - if(WIN32) - find_cuda_helper_libs(nvencodeapi) - else() - find_cuda_helper_libs(nvidia-encode) - endif() - if((CUDA_nvencodeapi_LIBRARY OR CUDA_nvidia-encode_LIBRARY) AND ${HAVE_NVCUVENC_HEADER}) - set(HAVE_NVCUVENC 1) - endif() - endif() - endif() - - message(STATUS "CUDA detected: " ${CUDA_VERSION}) - - OCV_OPTION(CUDA_ENABLE_DEPRECATED_GENERATION "Enable deprecated generations in the list" OFF) - set(_generations "Maxwell" "Pascal" "Volta" "Turing" "Ampere" "Lovelace" "Hopper") - if(CUDA_ENABLE_DEPRECATED_GENERATION) - set(_generations "Fermi" "${_generations}") - set(_generations "Kepler" "${_generations}") - endif() - set(_arch_fermi "2.0") - set(_arch_kepler "3.0;3.5;3.7") - set(_arch_maxwell "5.0;5.2") - set(_arch_pascal "6.0;6.1") - set(_arch_volta "7.0") - set(_arch_turing "7.5") - set(_arch_ampere "8.0;8.6") - set(_arch_lovelace "8.9") - set(_arch_hopper "9.0") - if(NOT CMAKE_CROSSCOMPILING) - list(APPEND _generations "Auto") - endif() - set(CUDA_GENERATION "" CACHE STRING "Build CUDA device code only for specific GPU architecture. Leave empty to build for all architectures (see https://docs.opencv.org/4.x/d2/dbc/cuda_intro.html).") - if( CMAKE_VERSION VERSION_GREATER "2.8" ) - set_property( CACHE CUDA_GENERATION PROPERTY STRINGS "" ${_generations} ) - endif() - - if(CUDA_GENERATION) - if(NOT ";${_generations};" MATCHES ";${CUDA_GENERATION};") - string(REPLACE ";" ", " _generations "${_generations}") - message(FATAL_ERROR "ERROR: ${_generations} Generations are supported.") - endif() - unset(CUDA_ARCH_BIN CACHE) - unset(CUDA_ARCH_PTX CACHE) - endif() - - if(OPENCV_CUDA_DETECTION_NVCC_FLAGS MATCHES "-ccbin") - # already specified by user - elseif(CUDA_HOST_COMPILER AND EXISTS "${CUDA_HOST_COMPILER}") - get_filename_component(c_compiler_realpath "${CMAKE_C_COMPILER}" REALPATH) - # C compiler doesn't work with --run option, forcing C++ compiler instead - if(CUDA_HOST_COMPILER STREQUAL c_compiler_realpath OR CUDA_HOST_COMPILER STREQUAL CMAKE_C_COMPILER) - if(DEFINED CMAKE_CXX_COMPILER) - get_filename_component(cxx_compiler_realpath "${CMAKE_CXX_COMPILER}" REALPATH) - LIST(APPEND OPENCV_CUDA_DETECTION_NVCC_FLAGS -ccbin "${cxx_compiler_realpath}") - else() - message(STATUS "CUDA: CMAKE_CXX_COMPILER is not available. You may need to specify CUDA_HOST_COMPILER.") - endif() - else() - LIST(APPEND OPENCV_CUDA_DETECTION_NVCC_FLAGS -ccbin "${CUDA_HOST_COMPILER}") - endif() - elseif(WIN32 AND CMAKE_LINKER) # Workaround for VS cl.exe not being in the env. path - get_filename_component(host_compiler_bindir ${CMAKE_LINKER} DIRECTORY) - LIST(APPEND OPENCV_CUDA_DETECTION_NVCC_FLAGS -ccbin "${host_compiler_bindir}") - else() - if(CUDA_HOST_COMPILER) - message(STATUS "CUDA: CUDA_HOST_COMPILER='${CUDA_HOST_COMPILER}' is not valid, autodetection may not work. Specify OPENCV_CUDA_DETECTION_NVCC_FLAGS with -ccbin option for fix that") - endif() - endif() - - macro(ocv_filter_available_architecture result_list) - set(__cache_key_check "${ARGN} : ${CUDA_NVCC_EXECUTABLE} ${OPENCV_CUDA_DETECTION_NVCC_FLAGS}") - if(DEFINED OPENCV_CACHE_CUDA_SUPPORTED_CC AND OPENCV_CACHE_CUDA_SUPPORTED_CC_check STREQUAL __cache_key_check) - set(${result_list} "${OPENCV_CACHE_CUDA_SUPPORTED_CC}") - else() - set(CC_LIST ${ARGN}) - foreach(target_arch ${CC_LIST}) - string(REPLACE "." "" target_arch_short "${target_arch}") - set(NVCC_OPTION "-gencode;arch=compute_${target_arch_short},code=sm_${target_arch_short}") - set(_cmd "${CUDA_NVCC_EXECUTABLE}" ${OPENCV_CUDA_DETECTION_NVCC_FLAGS} ${NVCC_OPTION} "${OpenCV_SOURCE_DIR}/cmake/checks/OpenCVDetectCudaArch.cu" --compile) - execute_process( - COMMAND ${_cmd} - WORKING_DIRECTORY "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/" - RESULT_VARIABLE _nvcc_res - OUTPUT_VARIABLE _nvcc_out - ERROR_VARIABLE _nvcc_err - #ERROR_QUIET - OUTPUT_STRIP_TRAILING_WHITESPACE - ) - if(OPENCV_CMAKE_CUDA_DEBUG) - message(WARNING "COMMAND: ${_cmd}") - message(STATUS "Result: ${_nvcc_res}") - message(STATUS "Out: ${_nvcc_out}") - message(STATUS "Err: ${_nvcc_err}") - endif() - if(_nvcc_res EQUAL 0) - LIST(APPEND ${result_list} "${target_arch}") - endif() - endforeach() - string(STRIP "${${result_list}}" ${result_list}) - if(" ${${result_list}}" STREQUAL " ") - message(WARNING "CUDA: Autodetection arch list is empty. Please enable OPENCV_CMAKE_CUDA_DEBUG=1 and check/specify OPENCV_CUDA_DETECTION_NVCC_FLAGS variable") - endif() - - # cache detected values - set(OPENCV_CACHE_CUDA_SUPPORTED_CC ${${result_list}} CACHE INTERNAL "") - set(OPENCV_CACHE_CUDA_SUPPORTED_CC_check "${__cache_key_check}" CACHE INTERNAL "") - endif() - endmacro() - - macro(ocv_detect_native_cuda_arch status output) - set(OPENCV_CUDA_DETECT_ARCHS_COMMAND "${CUDA_NVCC_EXECUTABLE}" ${OPENCV_CUDA_DETECTION_NVCC_FLAGS} "${OpenCV_SOURCE_DIR}/cmake/checks/OpenCVDetectCudaArch.cu" "--run") - set(__cache_key_check "${OPENCV_CUDA_DETECT_ARCHS_COMMAND}") - if(DEFINED OPENCV_CACHE_CUDA_ACTIVE_CC AND OPENCV_CACHE_CUDA_ACTIVE_CC_check STREQUAL __cache_key_check) - set(${output} "${OPENCV_CACHE_CUDA_ACTIVE_CC}") - set(${status} 0) - else() - execute_process( - COMMAND ${OPENCV_CUDA_DETECT_ARCHS_COMMAND} - WORKING_DIRECTORY "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/" - RESULT_VARIABLE ${status} - OUTPUT_VARIABLE _nvcc_out - ERROR_VARIABLE _nvcc_err - ERROR_QUIET - OUTPUT_STRIP_TRAILING_WHITESPACE - ) - if(OPENCV_CMAKE_CUDA_DEBUG) - message(WARNING "COMMAND: ${OPENCV_CUDA_DETECT_ARCHS_COMMAND}") - message(STATUS "Result: ${${status}}") - message(STATUS "Out: ${_nvcc_out}") - message(STATUS "Err: ${_nvcc_err}") - endif() - string(REGEX REPLACE ".*\n" "" ${output} "${_nvcc_out}") #Strip leading warning messages, if any - - if(${status} EQUAL 0) - # cache detected values - set(OPENCV_CACHE_CUDA_ACTIVE_CC ${${output}} CACHE INTERNAL "") - set(OPENCV_CACHE_CUDA_ACTIVE_CC_check "${__cache_key_check}" CACHE INTERNAL "") - endif() - endif() - endmacro() - - set(__cuda_arch_ptx ${CUDA_ARCH_PTX}) - if(CUDA_GENERATION STREQUAL "Fermi") - set(__cuda_arch_bin ${_arch_fermi}) - elseif(CUDA_GENERATION STREQUAL "Kepler") - set(__cuda_arch_bin ${_arch_kepler}) - elseif(CUDA_GENERATION STREQUAL "Maxwell") - set(__cuda_arch_bin ${_arch_maxwell}) - elseif(CUDA_GENERATION STREQUAL "Pascal") - set(__cuda_arch_bin ${_arch_pascal}) - elseif(CUDA_GENERATION STREQUAL "Volta") - set(__cuda_arch_bin ${_arch_volta}) - elseif(CUDA_GENERATION STREQUAL "Turing") - set(__cuda_arch_bin ${_arch_turing}) - elseif(CUDA_GENERATION STREQUAL "Ampere") - set(__cuda_arch_bin ${_arch_ampere}) - elseif(CUDA_GENERATION STREQUAL "Lovelace") - set(__cuda_arch_bin ${_arch_lovelace}) - elseif(CUDA_GENERATION STREQUAL "Hopper") - set(__cuda_arch_bin ${_arch_hopper}) - elseif(CUDA_GENERATION STREQUAL "Auto") - ocv_detect_native_cuda_arch(_nvcc_res _nvcc_out) - if(NOT _nvcc_res EQUAL 0) - message(STATUS "Automatic detection of CUDA generation failed. Going to build for all known architectures.") - else() - string(REGEX MATCHALL "[0-9]+\\.[0-9]" __cuda_arch_bin "${_nvcc_out}") - endif() - elseif(CUDA_ARCH_BIN) - message(STATUS "CUDA: Using CUDA_ARCH_BIN=${CUDA_ARCH_BIN}") - set(__cuda_arch_bin ${CUDA_ARCH_BIN}) - endif() - - if(NOT DEFINED __cuda_arch_bin AND NOT DEFINED __cuda_arch_ptx) - if(ARM) - set(__cuda_arch_bin "3.2") - set(__cuda_arch_ptx "") - elseif(AARCH64) - if(NOT CMAKE_CROSSCOMPILING) - ocv_detect_native_cuda_arch(_nvcc_res _nvcc_out) - else() - set(_nvcc_res -1) # emulate error, see below - endif() - if(NOT _nvcc_res EQUAL 0) - message(STATUS "Automatic detection of CUDA generation failed. Going to build for all known architectures.") - # TX1 (5.3) TX2 (6.2) Xavier (7.2) V100 (7.0) Orin (8.7) - ocv_filter_available_architecture(__cuda_arch_bin - 5.3 - 6.2 - 7.2 - 7.0 - 8.7 - ) - else() - set(__cuda_arch_bin "${_nvcc_out}") - endif() - set(__cuda_arch_ptx "") - else() - ocv_filter_available_architecture(__cuda_arch_bin - ${_arch_fermi} - ${_arch_kepler} - ${_arch_maxwell} - ${_arch_pascal} - ${_arch_volta} - ${_arch_turing} - ${_arch_ampere} - ${_arch_lovelace} - ${_arch_hopper} - ) - list(GET __cuda_arch_bin -1 __cuda_arch_ptx) - endif() - endif() - - set(CUDA_ARCH_BIN ${__cuda_arch_bin} CACHE STRING "Specify 'real' GPU architectures to build binaries for, BIN(PTX) format is supported (see https://docs.opencv.org/4.x/d2/dbc/cuda_intro.html)") - set(CUDA_ARCH_PTX ${__cuda_arch_ptx} CACHE STRING "Specify 'virtual' PTX architectures to build PTX intermediate code for (see https://docs.opencv.org/4.x/d2/dbc/cuda_intro.html)") - - string(REGEX REPLACE "\\." "" ARCH_BIN_NO_POINTS "${CUDA_ARCH_BIN}") - string(REGEX REPLACE "\\." "" ARCH_PTX_NO_POINTS "${CUDA_ARCH_PTX}") - - # Check if user specified 1.0/2.1 compute capability: we don't support it - macro(ocv_wipeout_deprecated_cc target_cc) - if(" ${CUDA_ARCH_BIN} ${CUDA_ARCH_PTX}" MATCHES " ${target_cc}") - message(SEND_ERROR "CUDA: ${target_cc} compute capability is not supported - exclude it from ARCH/PTX list and re-run CMake") - endif() - endmacro() - ocv_wipeout_deprecated_cc("1.0") - ocv_wipeout_deprecated_cc("2.1") - - # NVCC flags to be set - set(NVCC_FLAGS_EXTRA "") - - # These vars will be passed into the templates - set(OPENCV_CUDA_ARCH_BIN "") - set(OPENCV_CUDA_ARCH_PTX "") - set(OPENCV_CUDA_ARCH_FEATURES "") - - # Tell NVCC to add binaries for the specified GPUs - string(REGEX MATCHALL "[0-9()]+" ARCH_LIST "${ARCH_BIN_NO_POINTS}") - foreach(ARCH IN LISTS ARCH_LIST) - if(ARCH MATCHES "([0-9]+)\\(([0-9]+)\\)") - # User explicitly specified PTX for the concrete BIN - set(NVCC_FLAGS_EXTRA ${NVCC_FLAGS_EXTRA} -gencode arch=compute_${CMAKE_MATCH_2},code=sm_${CMAKE_MATCH_1}) - set(OPENCV_CUDA_ARCH_BIN "${OPENCV_CUDA_ARCH_BIN} ${CMAKE_MATCH_1}") - set(OPENCV_CUDA_ARCH_FEATURES "${OPENCV_CUDA_ARCH_FEATURES} ${CMAKE_MATCH_2}") - else() - # User didn't explicitly specify PTX for the concrete BIN, we assume PTX=BIN - set(NVCC_FLAGS_EXTRA ${NVCC_FLAGS_EXTRA} -gencode arch=compute_${ARCH},code=sm_${ARCH}) - set(OPENCV_CUDA_ARCH_BIN "${OPENCV_CUDA_ARCH_BIN} ${ARCH}") - set(OPENCV_CUDA_ARCH_FEATURES "${OPENCV_CUDA_ARCH_FEATURES} ${ARCH}") - endif() - endforeach() - set(NVCC_FLAGS_EXTRA ${NVCC_FLAGS_EXTRA} -D_FORCE_INLINES) - - # Tell NVCC to add PTX intermediate code for the specified architectures - string(REGEX MATCHALL "[0-9]+" ARCH_LIST "${ARCH_PTX_NO_POINTS}") - foreach(ARCH IN LISTS ARCH_LIST) - set(NVCC_FLAGS_EXTRA ${NVCC_FLAGS_EXTRA} -gencode arch=compute_${ARCH},code=compute_${ARCH}) - set(OPENCV_CUDA_ARCH_PTX "${OPENCV_CUDA_ARCH_PTX} ${ARCH}") - set(OPENCV_CUDA_ARCH_FEATURES "${OPENCV_CUDA_ARCH_FEATURES} ${ARCH}") - endforeach() - - # These vars will be processed in other scripts - set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS} ${NVCC_FLAGS_EXTRA}) - set(OpenCV_CUDA_CC "${NVCC_FLAGS_EXTRA}") - - if(ANDROID) - set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS} "-Xptxas;-dlcm=ca") - endif() - - # Tell NVCC the maximum number of threads to be used to execute the compilation steps in parallel - # (option --threads was introduced in version 11.2) - if(NOT CUDA_VERSION VERSION_LESS "11.2") - if(CMAKE_GENERATOR MATCHES "Visual Studio" AND NOT $ENV{CMAKE_BUILD_PARALLEL_LEVEL} STREQUAL "") - set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS} "--threads=$ENV{CMAKE_BUILD_PARALLEL_LEVEL}") - endif() - endif() - - message(STATUS "CUDA NVCC target flags: ${CUDA_NVCC_FLAGS}") - - OCV_OPTION(CUDA_FAST_MATH "Enable --use_fast_math for CUDA compiler " OFF) - - if(CUDA_FAST_MATH) - set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS} --use_fast_math) - endif() - - OCV_OPTION(CUDA_ENABLE_DELAYLOAD "Enable delayed loading of CUDA DLLs" OFF VISIBLE_IF MSVC) - - mark_as_advanced(CUDA_BUILD_CUBIN CUDA_BUILD_EMULATION CUDA_VERBOSE_BUILD CUDA_SDK_ROOT_DIR) - - macro(ocv_cuda_filter_options) - foreach(var CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_RELEASE CMAKE_CXX_FLAGS_DEBUG) - set(${var}_backup_in_cuda_compile_ "${${var}}") - - if (CV_CLANG) - # we remove -Winconsistent-missing-override and -Qunused-arguments - # just in case we are compiling CUDA with gcc but OpenCV with clang - string(REPLACE "-Winconsistent-missing-override" "" ${var} "${${var}}") - string(REPLACE "-Qunused-arguments" "" ${var} "${${var}}") - endif() - - # we remove /EHa as it generates warnings under windows - string(REPLACE "/EHa" "" ${var} "${${var}}") - - # we remove -ggdb3 flag as it leads to preprocessor errors when compiling CUDA files (CUDA 4.1) - string(REPLACE "-ggdb3" "" ${var} "${${var}}") - - # we remove -Wsign-promo as it generates warnings under linux - string(REPLACE "-Wsign-promo" "" ${var} "${${var}}") - - # we remove -Wno-sign-promo as it generates warnings under linux - string(REPLACE "-Wno-sign-promo" "" ${var} "${${var}}") - - # we remove -Wno-delete-non-virtual-dtor because it's used for C++ compiler - # but NVCC uses C compiler by default - string(REPLACE "-Wno-delete-non-virtual-dtor" "" ${var} "${${var}}") - - # we remove -frtti because it's used for C++ compiler - # but NVCC uses C compiler by default - string(REPLACE "-frtti" "" ${var} "${${var}}") - - string(REPLACE "-fvisibility-inlines-hidden" "" ${var} "${${var}}") - - # cc1: warning: command line option '-Wsuggest-override' is valid for C++/ObjC++ but not for C - string(REPLACE "-Wsuggest-override" "" ${var} "${${var}}") - - # issue: #11552 (from OpenCVCompilerOptions.cmake) - string(REGEX REPLACE "-Wimplicit-fallthrough(=[0-9]+)? " "" ${var} "${${var}}") - - # removal of custom specified options - if(OPENCV_CUDA_NVCC_FILTEROUT_OPTIONS) - foreach(__flag ${OPENCV_CUDA_NVCC_FILTEROUT_OPTIONS}) - string(REPLACE "${__flag}" "" ${var} "${${var}}") - endforeach() - endif() - endforeach() - endmacro() - - macro(ocv_cuda_compile VAR) - ocv_cuda_filter_options() - - if(BUILD_SHARED_LIBS) - set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS} -Xcompiler -DCVAPI_EXPORTS) - endif() - - if(UNIX OR APPLE) - set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS} -Xcompiler -fPIC) - if(NOT " ${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_RELEASE} ${CMAKE_CXX_FLAGS_DEBUG} ${CUDA_NVCC_FLAGS}" MATCHES "-std=") - if(CUDA_VERSION VERSION_LESS "11.0") - list(APPEND CUDA_NVCC_FLAGS "--std=c++11") - else() - list(APPEND CUDA_NVCC_FLAGS "--std=c++14") - endif() - endif() - endif() - if(APPLE) - set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS} -Xcompiler -fno-finite-math-only) - endif() - - if(WIN32 AND NOT (CUDA_VERSION VERSION_LESS "11.2")) - set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS} -Xcudafe --display_error_number --diag-suppress 1394,1388) - endif() - - if(CMAKE_CROSSCOMPILING AND (ARM OR AARCH64)) - set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS} -Xlinker --unresolved-symbols=ignore-in-shared-libs) - endif() - - # disabled because of multiple warnings during building nvcc auto generated files - if(CV_GCC AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER "4.6.0") - ocv_warnings_disable(CMAKE_CXX_FLAGS -Wunused-but-set-variable) - endif() - - CUDA_COMPILE(${VAR} ${ARGN}) - - foreach(var CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_RELEASE CMAKE_CXX_FLAGS_DEBUG) - set(${var} "${${var}_backup_in_cuda_compile_}") - unset(${var}_backup_in_cuda_compile_) - endforeach() - endmacro() -else() +if(NOT CUDA_FOUND) unset(CUDA_ARCH_BIN CACHE) unset(CUDA_ARCH_PTX CACHE) + return() endif() +unset(CUDA_nvcuvenc_LIBRARY CACHE) +set(HAVE_CUDA 1) +if(NOT CUDA_VERSION VERSION_LESS 11.0) + # CUDA 11.0 removes nppicom + ocv_list_filterout(CUDA_nppi_LIBRARY "nppicom") + ocv_list_filterout(CUDA_npp_LIBRARY "nppicom") +endif() + +if(WITH_CUFFT) + set(HAVE_CUFFT 1) +endif() + +if(WITH_CUBLAS) + set(HAVE_CUBLAS 1) +endif() + +if(WITH_CUDNN) + set(CMAKE_MODULE_PATH "${OpenCV_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH}) + find_host_package(CUDNN "${MIN_VER_CUDNN}") + list(REMOVE_AT CMAKE_MODULE_PATH 0) + + if(CUDNN_FOUND) + set(HAVE_CUDNN 1) + endif() +endif() + +include(cmake/OpenCVDetectCUDAUtils.cmake) + +if(WITH_NVCUVID OR WITH_NVCUVENC) + set(cuda_toolkit_dirs "${CUDA_TOOLKIT_TARGET_DIR}" "${CUDA_TOOLKIT_ROOT_DIR}") + ocv_check_for_nvidia_video_codec_sdk("${cuda_toolkit_dirs}") +endif() + +message(STATUS "CUDA detected: " ${CUDA_VERSION}) + +ocv_set_cuda_detection_nvcc_flags(CUDA_HOST_COMPILER) +ocv_set_cuda_arch_bin_and_ptx(${CUDA_NVCC_EXECUTABLE}) + +# NVCC flags to be set +set(NVCC_FLAGS_EXTRA "") + +# These vars will be passed into the templates +set(OPENCV_CUDA_ARCH_BIN "") +set(OPENCV_CUDA_ARCH_PTX "") +set(OPENCV_CUDA_ARCH_FEATURES "") + +# Tell NVCC to add binaries for the specified GPUs +string(REGEX MATCHALL "[0-9()]+" ARCH_LIST "${ARCH_BIN_NO_POINTS}") +foreach(ARCH IN LISTS ARCH_LIST) + if(ARCH MATCHES "([0-9]+)\\(([0-9]+)\\)") + # User explicitly specified PTX for the concrete BIN + set(NVCC_FLAGS_EXTRA ${NVCC_FLAGS_EXTRA} -gencode arch=compute_${CMAKE_MATCH_2},code=sm_${CMAKE_MATCH_1}) + set(OPENCV_CUDA_ARCH_BIN "${OPENCV_CUDA_ARCH_BIN} ${CMAKE_MATCH_1}") + set(OPENCV_CUDA_ARCH_FEATURES "${OPENCV_CUDA_ARCH_FEATURES} ${CMAKE_MATCH_2}") + else() + # User didn't explicitly specify PTX for the concrete BIN, we assume PTX=BIN + set(NVCC_FLAGS_EXTRA ${NVCC_FLAGS_EXTRA} -gencode arch=compute_${ARCH},code=sm_${ARCH}) + set(OPENCV_CUDA_ARCH_BIN "${OPENCV_CUDA_ARCH_BIN} ${ARCH}") + set(OPENCV_CUDA_ARCH_FEATURES "${OPENCV_CUDA_ARCH_FEATURES} ${ARCH}") + endif() +endforeach() +set(NVCC_FLAGS_EXTRA ${NVCC_FLAGS_EXTRA} -D_FORCE_INLINES) + +# Tell NVCC to add PTX intermediate code for the specified architectures +string(REGEX MATCHALL "[0-9]+" ARCH_LIST "${ARCH_PTX_NO_POINTS}") +foreach(ARCH IN LISTS ARCH_LIST) + set(NVCC_FLAGS_EXTRA ${NVCC_FLAGS_EXTRA} -gencode arch=compute_${ARCH},code=compute_${ARCH}) + set(OPENCV_CUDA_ARCH_PTX "${OPENCV_CUDA_ARCH_PTX} ${ARCH}") + set(OPENCV_CUDA_ARCH_FEATURES "${OPENCV_CUDA_ARCH_FEATURES} ${ARCH}") +endforeach() + +# These vars will be processed in other scripts +set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS} ${NVCC_FLAGS_EXTRA}) +set(OpenCV_CUDA_CC "${NVCC_FLAGS_EXTRA}") + +if(ANDROID) + set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS} "-Xptxas;-dlcm=ca") +endif() + +ocv_set_nvcc_threads_for_vs() + +message(STATUS "CUDA: NVCC target flags ${CUDA_NVCC_FLAGS}") + +OCV_OPTION(CUDA_FAST_MATH "Enable --use_fast_math for CUDA compiler " OFF) + +if(CUDA_FAST_MATH) + set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS} --use_fast_math) +endif() + +OCV_OPTION(CUDA_ENABLE_DELAYLOAD "Enable delayed loading of CUDA DLLs" OFF VISIBLE_IF MSVC) + +mark_as_advanced(CUDA_BUILD_CUBIN CUDA_BUILD_EMULATION CUDA_VERBOSE_BUILD CUDA_SDK_ROOT_DIR) + +macro(ocv_check_windows_crt_linkage) + # The new MSVC runtime abstraction is only useable if CUDA is a first class language + if(WIN32 AND POLICY CMP0091) + cmake_policy(GET CMP0091 MSVC_RUNTIME_SET_BY_ABSTRACTION) + if(MSVC_RUNTIME_SET_BY_ABSTRACTION STREQUAL "NEW") + if(NOT BUILD_SHARED_LIBS AND BUILD_WITH_STATIC_CRT) + set(CMAKE_CXX_FLAGS_RELEASE ${CMAKE_CXX_FLAGS_RELEASE} " /MT") + set(CMAKE_CXX_FLAGS_DEBUG ${CMAKE_CXX_FLAGS_DEBUG} " /MTd") + else() + set(CMAKE_CXX_FLAGS_RELEASE ${CMAKE_CXX_FLAGS_RELEASE} " /MD") + set(CMAKE_CXX_FLAGS_DEBUG ${CMAKE_CXX_FLAGS_DEBUG} " /MDd") + endif() + endif() + endif() +endmacro() + +macro(ocv_cuda_compile VAR) + ocv_cuda_filter_options() + ocv_check_windows_crt_linkage() + ocv_nvcc_flags() + + if(UNIX OR APPLE) + if(NOT " ${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_RELEASE} ${CMAKE_CXX_FLAGS_DEBUG} ${CUDA_NVCC_FLAGS}" MATCHES "-std=") + if(CUDA_VERSION VERSION_LESS "11.0") + list(APPEND CUDA_NVCC_FLAGS "--std=c++11") + else() + list(APPEND CUDA_NVCC_FLAGS "--std=c++14") + endif() + endif() + endif() + + CUDA_COMPILE(${VAR} ${ARGN}) + + foreach(var CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_RELEASE CMAKE_CXX_FLAGS_DEBUG) + set(${var} "${${var}_backup_in_cuda_compile_}") + unset(${var}_backup_in_cuda_compile_) + endforeach() +endmacro() + if(HAVE_CUDA) set(CUDA_LIBS_PATH "") foreach(p ${CUDA_LIBRARIES} ${CUDA_npp_LIBRARY}) @@ -525,36 +225,13 @@ if(HAVE_CUDA) endif() endif() - -# ---------------------------------------------------------------------------- -# Add CUDA libraries (needed for apps/tools, samples) -# ---------------------------------------------------------------------------- if(HAVE_CUDA) - # details: https://github.com/NVIDIA/nvidia-docker/issues/775 - if(" ${CUDA_CUDA_LIBRARY}" MATCHES "/stubs/libcuda.so" AND NOT OPENCV_SKIP_CUDA_STUB_WORKAROUND) - set(CUDA_STUB_ENABLED_LINK_WORKAROUND 1) - if(EXISTS "${CUDA_CUDA_LIBRARY}" AND NOT OPENCV_SKIP_CUDA_STUB_WORKAROUND_RPATH_LINK) - set(CUDA_STUB_TARGET_PATH "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/") - execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink "${CUDA_CUDA_LIBRARY}" "${CUDA_STUB_TARGET_PATH}/libcuda.so.1" - RESULT_VARIABLE CUDA_STUB_SYMLINK_RESULT) - if(NOT CUDA_STUB_SYMLINK_RESULT EQUAL 0) - execute_process(COMMAND ${CMAKE_COMMAND} -E copy_if_different "${CUDA_CUDA_LIBRARY}" "${CUDA_STUB_TARGET_PATH}/libcuda.so.1" - RESULT_VARIABLE CUDA_STUB_COPY_RESULT) - if(NOT CUDA_STUB_COPY_RESULT EQUAL 0) - set(CUDA_STUB_ENABLED_LINK_WORKAROUND 0) - endif() - endif() - if(CUDA_STUB_ENABLED_LINK_WORKAROUND) - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-rpath-link,\"${CUDA_STUB_TARGET_PATH}\"") - endif() - else() - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--allow-shlib-undefined") - endif() - if(NOT CUDA_STUB_ENABLED_LINK_WORKAROUND) - message(WARNING "CUDA: workaround for stubs/libcuda.so.1 is not applied") - endif() - endif() + ocv_apply_cuda_stub_workaround("${CUDA_CUDA_LIBRARY}") + ocv_check_cuda_delayed_load("${CUDA_TOOLKIT_ROOT_DIR}") + # ---------------------------------------------------------------------------- + # Add CUDA libraries (needed for apps/tools, samples) + # ---------------------------------------------------------------------------- set(OPENCV_LINKER_LIBS ${OPENCV_LINKER_LIBS} ${CUDA_LIBRARIES} ${CUDA_npp_LIBRARY}) if(HAVE_CUBLAS) set(OPENCV_LINKER_LIBS ${OPENCV_LINKER_LIBS} ${CUDA_cublas_LIBRARY}) @@ -572,19 +249,4 @@ if(HAVE_CUDA) set(OPENCV_LINKER_LIBS ${OPENCV_LINKER_LIBS} ${CMAKE_LIBRARY_PATH_FLAG}${p}) endif() endforeach() - - if(MSVC AND CUDA_ENABLE_DELAYLOAD) - set(DELAYFLAGS "delayimp.lib") - file(GLOB CUDA_DLLS "${CUDA_TOOLKIT_ROOT_DIR}/bin/*.dll") - foreach(d ${CUDA_DLLS}) - cmake_path(GET "d" FILENAME DLL_NAME) - if(NOT ${DLL_NAME} MATCHES "cudart") - set(DELAYFLAGS "${DELAYFLAGS} /DELAYLOAD:${DLL_NAME}") - endif() - endforeach() - set(DELAYFLAGS "${DELAYFLAGS} /DELAYLOAD:nvcuda.dll /DELAYLOAD:nvml.dll /IGNORE:4199") - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${DELAYFLAGS}") - set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${DELAYFLAGS}") - set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${DELAYFLAGS}") - endif() endif() diff --git a/cmake/OpenCVDetectCUDALanguage.cmake b/cmake/OpenCVDetectCUDALanguage.cmake new file mode 100644 index 0000000000..0eeea77f2c --- /dev/null +++ b/cmake/OpenCVDetectCUDALanguage.cmake @@ -0,0 +1,154 @@ +####################### +# Previously in FindCUDA and still required for FindCUDNN +macro(FIND_CUDA_HELPER_LIBS _name) + if(CMAKE_CROSSCOMPILING AND (ARM OR AARCH64)) + set(_cuda_cross_arm_lib_dir "lib/stubs") + endif() + find_library(CUDA_${_name}_LIBRARY ${_name} + NAMES ${_name} + PATHS "${CUDAToolkit_LIBRARY_ROOT}" + PATH_SUFFIXES "lib/x64" "lib64" ${_cuda_cross_arm_lib_dir} "lib/Win32" "lib" + DOC "\"${_name}\" library" + ) + mark_as_advanced(CUDA_${_name}_LIBRARY) +endmacro() +####################### +include(cmake/OpenCVDetectCUDAUtils.cmake) + +if((WIN32 AND NOT MSVC) OR OPENCV_CMAKE_FORCE_CUDA) + message(STATUS "CUDA: Compilation is disabled (due to only Visual Studio compiler supported on your platform).") + return() +endif() + +if((NOT UNIX AND CV_CLANG) OR OPENCV_CMAKE_FORCE_CUDA) + message(STATUS "CUDA: Compilation is disabled (due to Clang unsupported on your platform).") + return() +endif() + +#set(OPENCV_CMAKE_CUDA_DEBUG 1) + +find_package(CUDAToolkit) +if(CMAKE_CUDA_COMPILER AND CUDAToolkit_FOUND) + set(CUDA_FOUND TRUE) + set(CUDA_TOOLKIT_INCLUDE ${CUDAToolkit_INCLUDE_DIRS}) + set(CUDA_VERSION_STRING ${CUDAToolkit_VERSION}) + set(CUDA_VERSION ${CUDAToolkit_VERSION}) + if(NOT CUDA_VERSION VERSION_LESS 11.0) + set(CMAKE_CUDA_STANDARD 14) + else() + set(CMAKE_CUDA_STANDARD 11) + endif() + if(UNIX AND NOT BUILD_SHARED_LIBS) + set(CUDA_LIB_EXT "_static") + endif() +endif() + +if(NOT CUDA_FOUND) + unset(CUDA_ARCH_BIN CACHE) + unset(CUDA_ARCH_PTX CACHE) + return() +endif() + +set(HAVE_CUDA 1) + +if(WITH_CUFFT) + set(HAVE_CUFFT 1) +endif() + +if(WITH_CUBLAS) + set(HAVE_CUBLAS 1) +endif() + +if(WITH_CUDNN) + set(CMAKE_MODULE_PATH "${OpenCV_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH}) + find_host_package(CUDNN "${MIN_VER_CUDNN}") + list(REMOVE_AT CMAKE_MODULE_PATH 0) + + if(CUDNN_FOUND) + set(HAVE_CUDNN 1) + endif() +endif() + +if(WITH_NVCUVID OR WITH_NVCUVENC) + ocv_check_for_nvidia_video_codec_sdk("${CUDAToolkit_LIBRARY_ROOT}") +endif() + +ocv_check_for_cmake_cuda_architectures() +ocv_set_cuda_detection_nvcc_flags(CMAKE_CUDA_HOST_COMPILER) +ocv_set_cuda_arch_bin_and_ptx(${CUDAToolkit_NVCC_EXECUTABLE}) + +# NVCC flags to be set +set(NVCC_FLAGS_EXTRA "") + +# These vars will be passed into the templates +set(OPENCV_CUDA_ARCH_BIN "") +set(OPENCV_CUDA_ARCH_PTX "") +set(OPENCV_CUDA_ARCH_FEATURES "") + +# Tell NVCC to add binaries for the specified GPUs +string(REGEX MATCHALL "[0-9()]+" ARCH_LIST "${ARCH_BIN_NO_POINTS}") +foreach(ARCH IN LISTS ARCH_LIST) + if(ARCH MATCHES "([0-9]+)\\(([0-9]+)\\)") + # User explicitly specified PTX for the concrete BIN + set(CMAKE_CUDA_ARCHITECTURES ${CMAKE_CUDA_ARCHITECTURES} ${CMAKE_MATCH_2}-virtual;${CMAKE_MATCH_1}-real;) + set(OPENCV_CUDA_ARCH_BIN "${OPENCV_CUDA_ARCH_BIN} ${CMAKE_MATCH_1}") + set(OPENCV_CUDA_ARCH_FEATURES "${OPENCV_CUDA_ARCH_FEATURES} ${CMAKE_MATCH_2}") + else() + # User didn't explicitly specify PTX for the concrete BIN, we assume PTX=BIN + set(CMAKE_CUDA_ARCHITECTURES ${CMAKE_CUDA_ARCHITECTURES} ${ARCH}-real;) + set(OPENCV_CUDA_ARCH_BIN "${OPENCV_CUDA_ARCH_BIN} ${ARCH}") + set(OPENCV_CUDA_ARCH_FEATURES "${OPENCV_CUDA_ARCH_FEATURES} ${ARCH}") + endif() +endforeach() +set(NVCC_FLAGS_EXTRA ${NVCC_FLAGS_EXTRA} -D_FORCE_INLINES) + +# Tell NVCC to add PTX intermediate code for the specified architectures +string(REGEX MATCHALL "[0-9]+" ARCH_LIST "${ARCH_PTX_NO_POINTS}") +foreach(ARCH IN LISTS ARCH_LIST) + set(CMAKE_CUDA_ARCHITECTURES ${CMAKE_CUDA_ARCHITECTURES} ${ARCH}-virtual;) + set(OPENCV_CUDA_ARCH_PTX "${OPENCV_CUDA_ARCH_PTX} ${ARCH}") + set(OPENCV_CUDA_ARCH_FEATURES "${OPENCV_CUDA_ARCH_FEATURES} ${ARCH}") +endforeach() + +ocv_set_nvcc_threads_for_vs() + +# These vars will be processed in other scripts +set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS} ${NVCC_FLAGS_EXTRA}) +set(OpenCV_CUDA_CC "${CMAKE_CUDA_ARCHITECTURES}") + +if(ANDROID) + set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS} "-Xptxas;-dlcm=ca") +endif() + +message(STATUS "CUDA: NVCC target flags ${CUDA_NVCC_FLAGS}") + +OCV_OPTION(CUDA_FAST_MATH "Enable --use_fast_math for CUDA compiler " OFF) + +if(CUDA_FAST_MATH) + set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS} --use_fast_math) +endif() + +OCV_OPTION(CUDA_ENABLE_DELAYLOAD "Enable delayed loading of CUDA DLLs" OFF VISIBLE_IF MSVC) + +mark_as_advanced(CUDA_BUILD_CUBIN CUDA_BUILD_EMULATION CUDA_VERBOSE_BUILD CUDA_SDK_ROOT_DIR) + +macro(ocv_cuda_unfilter_options) + foreach(var CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_RELEASE CMAKE_CXX_FLAGS_DEBUG) + set(${var} "${${var}_backup_in_cuda_compile_}") + unset(${var}_backup_in_cuda_compile_) + endforeach() +endmacro() + +macro(ocv_cuda_compile_flags) + ocv_cuda_filter_options() + ocv_nvcc_flags() + set(CMAKE_CXX_FLAGS_CUDA ${CMAKE_CXX_FLAGS}) + set(CMAKE_CXX_FLAGS_RELEASE_CUDA ${CMAKE_CXX_FLAGS_RELEASE}) + set(CMAKE_CXX_FLAGS_DEBUG_CUDA ${CMAKE_CXX_FLAGS_DEBUG}) + ocv_cuda_unfilter_options() +endmacro() + +if(HAVE_CUDA) + ocv_apply_cuda_stub_workaround("${CUDA_cuda_driver_LIBRARY}") + ocv_check_cuda_delayed_load("${cuda_toolkit_root_dir}") +endif() \ No newline at end of file diff --git a/cmake/OpenCVDetectCUDAUtils.cmake b/cmake/OpenCVDetectCUDAUtils.cmake new file mode 100644 index 0000000000..97676628ab --- /dev/null +++ b/cmake/OpenCVDetectCUDAUtils.cmake @@ -0,0 +1,442 @@ +macro(ocv_check_for_nvidia_video_codec_sdk cuda_toolkit_dirs) + macro(ocv_cuda_SEARCH_NVCUVID_HEADER _filename _result) + # place header file under CUDAToolkit_LIBRARY_ROOT + find_path(_header_result + ${_filename} + PATHS ${cuda_toolkit_dirs} + PATH_SUFFIXES include + NO_DEFAULT_PATH + ) + if("x${_header_result}" STREQUAL "x_header_result-NOTFOUND") + set(${_result} 0) + else() + set(${_result} 1) + endif() + unset(_header_result CACHE) + endmacro() + if(WITH_NVCUVID) + ocv_cuda_SEARCH_NVCUVID_HEADER("nvcuvid.h" HAVE_NVCUVID_HEADER) + # make sure to have both header and library before enabling + if(${HAVE_NVCUVID_HEADER}) + find_cuda_helper_libs(nvcuvid) + if(CUDA_nvcuvid_LIBRARY) + set(HAVE_NVCUVID 1) + message(STATUS "Found NVCUVID: ${CUDA_nvcuvid_LIBRARY}") + else() + if(WIN32) + message(STATUS "NVCUVID: Library not found, WITH_NVCUVID requires Nvidia decoding library nvcuvid.lib to either be inside ${cuda_toolkit_dirs}/lib or its location manually set with CUDA_nvcuvid_LIBRARY, i.e. CUDA_nvcuvid_LIBRARY=${cuda_toolkit_dirs}/lib/nvcuvid.lib") + else() + message(STATUS "NVCUVID: Library not found, WITH_NVCUVID requires the Nvidia decoding shared library nvcuvid.so from the driver installation or the location of the stub library to be manually set with CUDA_nvcuvid_LIBRARY i.e. CUDA_nvcuvid_LIBRARY=/home/user/Video_Codec_SDK_X.X.X/Lib/linux/stubs/x86_64/nvcuvid.so") + endif() + endif() + else() + message(STATUS "NVCUVID: Header not found, WITH_NVCUVID requires Nvidia decoding library header ${cuda_toolkit_dirs}/include/nvcuvid.h") + endif() + endif() + + if(WITH_NVCUVENC) + ocv_cuda_SEARCH_NVCUVID_HEADER("nvEncodeAPI.h" HAVE_NVCUVENC_HEADER) + if(${HAVE_NVCUVENC_HEADER}) + if(WIN32) + find_cuda_helper_libs(nvencodeapi) + else() + find_cuda_helper_libs(nvidia-encode) + endif() + if(CUDA_nvencodeapi_LIBRARY OR CUDA_nvidia-encode_LIBRARY) + set(HAVE_NVCUVENC 1) + message(STATUS "Found NVCUVENC: ${CUDA_nvencodeapi_LIBRARY} ${CUDA_nvidia-encode_LIBRARY}") + else() + if(WIN32) + message(STATUS "NVCUVENC: Library not found, WITH_NVCUVENC requires Nvidia encoding library nvencodeapi.lib to either be inside ${cuda_toolkit_dirs}/lib or its location manually set with CUDA_nvencodeapi_LIBRARY, i.e. CUDA_nvencodeapi_LIBRARY=${cuda_toolkit_dirs}/lib/nvencodeapi.lib") + else() + message(STATUS "NVCUVENC: Library not found, WITH_NVCUVENC requires the Nvidia encoding shared library libnvidia-encode.so from the driver installation or the location of the stub library to be manually set with CUDA_nvidia-encode_LIBRARY i.e. CUDA_nvidia-encode_LIBRARY=/home/user/Video_Codec_SDK_X.X.X/Lib/linux/stubs/x86_64/libnvidia-encode.so") + endif() + endif() + else() + message(STATUS "NVCUVENC: Header not found, WITH_NVCUVENC requires Nvidia encoding library header ${cuda_toolkit_dirs}/include/nvEncodeAPI.h") + endif() + endif() +endmacro() + +# Use CMAKE_CUDA_ARCHITECTURES if provided: order of preference CMAKE_CUDA_ARCHITECTURES > CUDA_GENERATION > CUDA_ARCH_BIN and/or CUDA_ARCH_PTX +function(ocv_check_for_cmake_cuda_architectures) + if(NOT CMAKE_CUDA_ARCHITECTURES) + return() + endif() + if(CMAKE_CUDA_ARCHITECTURES STREQUAL "all" OR CMAKE_CUDA_ARCHITECTURES STREQUAL "all-major" OR CMAKE_CUDA_ARCHITECTURES STREQUAL "native") + message(WARNING "CUDA: CMAKE_CUDA_ARCHITECTURES=${CMAKE_CUDA_ARCHITECTURES}, special values all, all-major and native are not supported by OpenCV, specify only CUDA real and/or virtual architectures or use combinations of CUDA_ARCH_BIN and CUDA_ARCH_PTX or specify the CUDA_GENERATION where -DCUDA_GENERATION=Auto is equivalent to native!") + return() + endif() + set(internal_ptx "") + set(internal_bin "") + foreach(ARCH IN LISTS CMAKE_CUDA_ARCHITECTURES) + if(ARCH MATCHES "([0-9]+)\-real") + set(internal_bin ${internal_bin} ${CMAKE_MATCH_1};) + elseif(ARCH MATCHES "([0-9]+)\-virtual") + set(internal_ptx ${internal_ptx} ${CMAKE_MATCH_1};) + elseif(ARCH MATCHES "([0-9]+)") + set(internal_bin ${internal_bin} ${CMAKE_MATCH_1};) + set(internal_ptx ${internal_ptx} ${CMAKE_MATCH_1};) + endif() + endforeach() + if(internal_bin OR internal_ptx) + unset(CUDA_ARCH_BIN CACHE) + unset(CUDA_ARCH_PTX CACHE) + endif() + if(internal_ptx) + set(CUDA_ARCH_PTX ${internal_ptx} CACHE STRING "Specify 'virtual' PTX architectures to build PTX intermediate code for (see https://docs.opencv.org/4.x/d2/dbc/cuda_intro.html)") + endif() + if(internal_bin) + set(CUDA_ARCH_BIN ${internal_bin} CACHE STRING "Specify 'real' GPU architectures to build binaries for, BIN(PTX) format is supported (see https://docs.opencv.org/4.x/d2/dbc/cuda_intro.html)") + endif() + set(CMAKE_CUDA_ARCHITECTURES "" PARENT) + unset(CUDA_GENERATION CACHE) +endfunction() + +macro(ocv_initialize_nvidia_device_generations) + OCV_OPTION(CUDA_ENABLE_DEPRECATED_GENERATION "Enable deprecated generations in the list" OFF) + set(_generations "Maxwell" "Pascal" "Volta" "Turing" "Ampere" "Lovelace" "Hopper") + if(CUDA_ENABLE_DEPRECATED_GENERATION) + set(_generations "Fermi" "${_generations}") + set(_generations "Kepler" "${_generations}") + endif() + set(_arch_fermi "2.0") + set(_arch_kepler "3.0;3.5;3.7") + set(_arch_maxwell "5.0;5.2") + set(_arch_pascal "6.0;6.1") + set(_arch_volta "7.0") + set(_arch_turing "7.5") + set(_arch_ampere "8.0;8.6") + set(_arch_lovelace "8.9") + set(_arch_hopper "9.0") + if(NOT CMAKE_CROSSCOMPILING) + list(APPEND _generations "Auto") + endif() + set(CUDA_GENERATION "" CACHE STRING "Build CUDA device code only for specific GPU architecture. Leave empty to build for all architectures (see https://docs.opencv.org/4.x/d2/dbc/cuda_intro.html).") + if( CMAKE_VERSION VERSION_GREATER "2.8" ) + set_property( CACHE CUDA_GENERATION PROPERTY STRINGS "" ${_generations} ) + endif() + + if(CUDA_GENERATION) + if(NOT ";${_generations};" MATCHES ";${CUDA_GENERATION};") + string(REPLACE ";" ", " _generations "${_generations}") + message(FATAL_ERROR "ERROR: ${_generations} Generations are supported.") + endif() + unset(CUDA_ARCH_BIN CACHE) + unset(CUDA_ARCH_PTX CACHE) + endif() +endmacro() + +macro(ocv_set_cuda_detection_nvcc_flags cuda_host_compiler_var) + if(OPENCV_CUDA_DETECTION_NVCC_FLAGS MATCHES "-ccbin") + # already specified by user + elseif(${cuda_host_compiler_var} AND EXISTS "${${cuda_host_compiler_var}}") + get_filename_component(c_compiler_realpath "${CMAKE_C_COMPILER}" REALPATH) + # C compiler doesn't work with --run option, forcing C++ compiler instead + if(${cuda_host_compiler_var} STREQUAL c_compiler_realpath OR ${cuda_host_compiler_var} STREQUAL CMAKE_C_COMPILER) + if(DEFINED CMAKE_CXX_COMPILER) + get_filename_component(cxx_compiler_realpath "${CMAKE_CXX_COMPILER}" REALPATH) + LIST(APPEND OPENCV_CUDA_DETECTION_NVCC_FLAGS -ccbin "${cxx_compiler_realpath}") + else() + message(STATUS "CUDA: CMAKE_CXX_COMPILER is not available. You may need to specify ${cuda_host_compiler_var}.") + endif() + else() + LIST(APPEND OPENCV_CUDA_DETECTION_NVCC_FLAGS -ccbin "${${cuda_host_compiler_var}}") + endif() + elseif(WIN32 AND CMAKE_LINKER) # Workaround for VS cl.exe not being in the env. path + get_filename_component(host_compiler_bindir ${CMAKE_LINKER} DIRECTORY) + LIST(APPEND OPENCV_CUDA_DETECTION_NVCC_FLAGS -ccbin "${host_compiler_bindir}") + else() + if(${cuda_host_compiler_var}) + message(STATUS "CUDA: ${cuda_host_compiler_var}='${cuda_host_compiler}' is not valid, autodetection may not work. Specify OPENCV_CUDA_DETECTION_NVCC_FLAGS with -ccbin option for fix that") + endif() + endif() +endmacro() + +macro(ocv_filter_available_architecture nvcc_executable result_list) + set(__cache_key_check "${ARGN} : ${nvcc_executable} ${OPENCV_CUDA_DETECTION_NVCC_FLAGS}") + if(DEFINED OPENCV_CACHE_CUDA_SUPPORTED_CC AND OPENCV_CACHE_CUDA_SUPPORTED_CC_check STREQUAL __cache_key_check) + set(${result_list} "${OPENCV_CACHE_CUDA_SUPPORTED_CC}") + else() + set(CC_LIST ${ARGN}) + foreach(target_arch ${CC_LIST}) + string(REPLACE "." "" target_arch_short "${target_arch}") + set(NVCC_OPTION "-gencode;arch=compute_${target_arch_short},code=sm_${target_arch_short}") + set(_cmd "${nvcc_executable}" ${OPENCV_CUDA_DETECTION_NVCC_FLAGS} ${NVCC_OPTION} "${OpenCV_SOURCE_DIR}/cmake/checks/OpenCVDetectCudaArch.cu" --compile) + execute_process( + COMMAND ${_cmd} + WORKING_DIRECTORY "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/" + RESULT_VARIABLE _nvcc_res + OUTPUT_VARIABLE _nvcc_out + ERROR_VARIABLE _nvcc_err + #ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + if(OPENCV_CMAKE_CUDA_DEBUG) + message(WARNING "COMMAND: ${_cmd}") + message(STATUS "Result: ${_nvcc_res}") + message(STATUS "Out: ${_nvcc_out}") + message(STATUS "Err: ${_nvcc_err}") + endif() + if(_nvcc_res EQUAL 0) + LIST(APPEND ${result_list} "${target_arch}") + endif() + endforeach() + string(STRIP "${${result_list}}" ${result_list}) + if(" ${${result_list}}" STREQUAL " ") + message(WARNING "CUDA: Autodetection arch list is empty. Please enable OPENCV_CMAKE_CUDA_DEBUG=1 and check/specify OPENCV_CUDA_DETECTION_NVCC_FLAGS variable") + endif() + + # cache detected values + set(OPENCV_CACHE_CUDA_SUPPORTED_CC ${${result_list}} CACHE INTERNAL "") + set(OPENCV_CACHE_CUDA_SUPPORTED_CC_check "${__cache_key_check}" CACHE INTERNAL "") + endif() +endmacro() + +macro(ocv_detect_native_cuda_arch nvcc_executable status output) + set(OPENCV_CUDA_DETECT_ARCHS_COMMAND "${nvcc_executable}" ${OPENCV_CUDA_DETECTION_NVCC_FLAGS} "${OpenCV_SOURCE_DIR}/cmake/checks/OpenCVDetectCudaArch.cu" "--run") + set(__cache_key_check "${OPENCV_CUDA_DETECT_ARCHS_COMMAND}") + if(DEFINED OPENCV_CACHE_CUDA_ACTIVE_CC AND OPENCV_CACHE_CUDA_ACTIVE_CC_check STREQUAL __cache_key_check) + set(${output} "${OPENCV_CACHE_CUDA_ACTIVE_CC}") + set(${status} 0) + else() + execute_process( + COMMAND ${OPENCV_CUDA_DETECT_ARCHS_COMMAND} + WORKING_DIRECTORY "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/" + RESULT_VARIABLE ${status} + OUTPUT_VARIABLE _nvcc_out + ERROR_VARIABLE _nvcc_err + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + if(OPENCV_CMAKE_CUDA_DEBUG) + message(WARNING "COMMAND: ${OPENCV_CUDA_DETECT_ARCHS_COMMAND}") + message(STATUS "Result: ${${status}}") + message(STATUS "Out: ${_nvcc_out}") + message(STATUS "Err: ${_nvcc_err}") + endif() + string(REGEX REPLACE ".*\n" "" ${output} "${_nvcc_out}") #Strip leading warning messages, if any + + if(${status} EQUAL 0) + # cache detected values + set(OPENCV_CACHE_CUDA_ACTIVE_CC ${${output}} CACHE INTERNAL "") + set(OPENCV_CACHE_CUDA_ACTIVE_CC_check "${__cache_key_check}" CACHE INTERNAL "") + endif() + endif() +endmacro() + +macro(ocv_set_cuda_arch_bin_and_ptx nvcc_executable) + ocv_initialize_nvidia_device_generations() + set(__cuda_arch_ptx ${CUDA_ARCH_PTX}) + if(CUDA_GENERATION STREQUAL "Fermi") + set(__cuda_arch_bin ${_arch_fermi}) + elseif(CUDA_GENERATION STREQUAL "Kepler") + set(__cuda_arch_bin ${_arch_kepler}) + elseif(CUDA_GENERATION STREQUAL "Maxwell") + set(__cuda_arch_bin ${_arch_maxwell}) + elseif(CUDA_GENERATION STREQUAL "Pascal") + set(__cuda_arch_bin ${_arch_pascal}) + elseif(CUDA_GENERATION STREQUAL "Volta") + set(__cuda_arch_bin ${_arch_volta}) + elseif(CUDA_GENERATION STREQUAL "Turing") + set(__cuda_arch_bin ${_arch_turing}) + elseif(CUDA_GENERATION STREQUAL "Ampere") + set(__cuda_arch_bin ${_arch_ampere}) + elseif(CUDA_GENERATION STREQUAL "Lovelace") + set(__cuda_arch_bin ${_arch_lovelace}) + elseif(CUDA_GENERATION STREQUAL "Hopper") + set(__cuda_arch_bin ${_arch_hopper}) + elseif(CUDA_GENERATION STREQUAL "Auto") + ocv_detect_native_cuda_arch(${nvcc_executable} _nvcc_res _nvcc_out) + if(NOT _nvcc_res EQUAL 0) + message(STATUS "CUDA: Automatic detection of CUDA generation failed. Going to build for all known architectures") + else() + string(REGEX MATCHALL "[0-9]+\\.[0-9]" __cuda_arch_bin "${_nvcc_out}") + endif() + elseif(CUDA_ARCH_BIN) + message(STATUS "CUDA: Using CUDA_ARCH_BIN=${CUDA_ARCH_BIN}") + set(__cuda_arch_bin ${CUDA_ARCH_BIN}) + endif() + + if(NOT DEFINED __cuda_arch_bin AND NOT DEFINED __cuda_arch_ptx) + if(ARM) + set(__cuda_arch_bin "3.2") + set(__cuda_arch_ptx "") + elseif(AARCH64) + if(NOT CMAKE_CROSSCOMPILING) + ocv_detect_native_cuda_arch(${nvcc_executable} _nvcc_res _nvcc_out) + else() + set(_nvcc_res -1) # emulate error, see below + endif() + if(NOT _nvcc_res EQUAL 0) + message(STATUS "CUDA: Automatic detection of CUDA generation failed. Going to build for all known architectures") + # TX1 (5.3) TX2 (6.2) Xavier (7.2) V100 (7.0) Orin (8.7) + ocv_filter_available_architecture(${nvcc_executable} __cuda_arch_bin + 5.3 + 6.2 + 7.2 + 7.0 + 8.7 + ) + else() + set(__cuda_arch_bin "${_nvcc_out}") + endif() + set(__cuda_arch_ptx "") + else() + ocv_filter_available_architecture(${nvcc_executable} __cuda_arch_bin + ${_arch_fermi} + ${_arch_kepler} + ${_arch_maxwell} + ${_arch_pascal} + ${_arch_volta} + ${_arch_turing} + ${_arch_ampere} + ${_arch_lovelace} + ${_arch_hopper} + ) + list(GET __cuda_arch_bin -1 __cuda_arch_ptx) + endif() + endif() + + set(CUDA_ARCH_BIN ${__cuda_arch_bin} CACHE STRING "Specify 'real' GPU architectures to build binaries for, BIN(PTX) format is supported (see https://docs.opencv.org/4.x/d2/dbc/cuda_intro.html)") + set(CUDA_ARCH_PTX ${__cuda_arch_ptx} CACHE STRING "Specify 'virtual' PTX architectures to build PTX intermediate code for (see https://docs.opencv.org/4.x/d2/dbc/cuda_intro.html)") + string(REGEX REPLACE "\\." "" ARCH_BIN_NO_POINTS "${CUDA_ARCH_BIN}") + string(REGEX REPLACE "\\." "" ARCH_PTX_NO_POINTS "${CUDA_ARCH_PTX}") + + # Check if user specified 1.0/2.1 compute capability: we don't support it + macro(ocv_wipeout_deprecated_cc target_cc) + if(" ${CUDA_ARCH_BIN} ${CUDA_ARCH_PTX}" MATCHES " ${target_cc}") + message(SEND_ERROR "CUDA: ${target_cc} compute capability is not supported - exclude it from ARCH/PTX list and re-run CMake") + endif() + endmacro() + ocv_wipeout_deprecated_cc("1.0") + ocv_wipeout_deprecated_cc("2.1") +endmacro() + +macro(ocv_set_nvcc_threads_for_vs) + # Tell NVCC the maximum number of threads to be used to execute the compilation steps in parallel + # (option --threads was introduced in version 11.2) + if(NOT CUDA_VERSION VERSION_LESS "11.2") + if(CMAKE_GENERATOR MATCHES "Visual Studio" AND NOT $ENV{CMAKE_BUILD_PARALLEL_LEVEL} STREQUAL "") + set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS} "--threads=$ENV{CMAKE_BUILD_PARALLEL_LEVEL}") + endif() + endif() +endmacro() + +macro(ocv_cuda_filter_options) + foreach(var CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_RELEASE CMAKE_CXX_FLAGS_DEBUG) + set(${var}_backup_in_cuda_compile_ "${${var}}") + + if (CV_CLANG) + # we remove -Winconsistent-missing-override and -Qunused-arguments + # just in case we are compiling CUDA with gcc but OpenCV with clang + string(REPLACE "-Winconsistent-missing-override" "" ${var} "${${var}}") + string(REPLACE "-Qunused-arguments" "" ${var} "${${var}}") + endif() + + # we remove /EHa as it generates warnings under windows + string(REPLACE "/EHa" "" ${var} "${${var}}") + + # we remove -ggdb3 flag as it leads to preprocessor errors when compiling CUDA files (CUDA 4.1) + string(REPLACE "-ggdb3" "" ${var} "${${var}}") + + # we remove -Wsign-promo as it generates warnings under linux + string(REPLACE "-Wsign-promo" "" ${var} "${${var}}") + + # we remove -Wno-sign-promo as it generates warnings under linux + string(REPLACE "-Wno-sign-promo" "" ${var} "${${var}}") + + # we remove -Wno-delete-non-virtual-dtor because it's used for C++ compiler + # but NVCC uses C compiler by default + string(REPLACE "-Wno-delete-non-virtual-dtor" "" ${var} "${${var}}") + + # we remove -frtti because it's used for C++ compiler + # but NVCC uses C compiler by default + string(REPLACE "-frtti" "" ${var} "${${var}}") + + string(REPLACE "-fvisibility-inlines-hidden" "" ${var} "${${var}}") + + # cc1: warning: command line option '-Wsuggest-override' is valid for C++/ObjC++ but not for C + string(REPLACE "-Wsuggest-override" "" ${var} "${${var}}") + + # issue: #11552 (from OpenCVCompilerOptions.cmake) + string(REGEX REPLACE "-Wimplicit-fallthrough(=[0-9]+)? " "" ${var} "${${var}}") + + # removal of custom specified options + if(OPENCV_CUDA_NVCC_FILTEROUT_OPTIONS) + foreach(__flag ${OPENCV_CUDA_NVCC_FILTEROUT_OPTIONS}) + string(REPLACE "${__flag}" "" ${var} "${${var}}") + endforeach() + endif() + endforeach() +endmacro() + +macro(ocv_nvcc_flags) + if(BUILD_SHARED_LIBS) + set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS} -Xcompiler=-DCVAPI_EXPORTS) + endif() + + if(UNIX OR APPLE) + set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS} -Xcompiler=-fPIC) + endif() + if(APPLE) + set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS} -Xcompiler=-fno-finite-math-only) + endif() + + if(WIN32 AND NOT (CUDA_VERSION VERSION_LESS "11.2")) + set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS} -Xcudafe --display_error_number --diag-suppress 1394,1388) + endif() + + if(CMAKE_CROSSCOMPILING AND (ARM OR AARCH64)) + set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS} -Xlinker --unresolved-symbols=ignore-in-shared-libs) + endif() + + # disabled because of multiple warnings during building nvcc auto generated files + if(CV_GCC AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER "4.6.0") + ocv_warnings_disable(CMAKE_CXX_FLAGS -Wunused-but-set-variable) + endif() +endmacro() + +macro(ocv_apply_cuda_stub_workaround cuda_driver_library_path) + # details: https://github.com/NVIDIA/nvidia-docker/issues/775 + if(" ${cuda_driver_library_path}" MATCHES "/stubs/libcuda.so" AND NOT OPENCV_SKIP_CUDA_STUB_WORKAROUND) + set(CUDA_STUB_ENABLED_LINK_WORKAROUND 1) + if(EXISTS "${cuda_driver_library_path}" AND NOT OPENCV_SKIP_CUDA_STUB_WORKAROUND_RPATH_LINK) + set(CUDA_STUB_TARGET_PATH "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/") + execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink "${cuda_driver_library_path}" "${CUDA_STUB_TARGET_PATH}/libcuda.so.1" + RESULT_VARIABLE CUDA_STUB_SYMLINK_RESULT) + if(NOT CUDA_STUB_SYMLINK_RESULT EQUAL 0) + execute_process(COMMAND ${CMAKE_COMMAND} -E copy_if_different "${cuda_driver_library_path}" "${CUDA_STUB_TARGET_PATH}/libcuda.so.1" + RESULT_VARIABLE CUDA_STUB_COPY_RESULT) + if(NOT CUDA_STUB_COPY_RESULT EQUAL 0) + set(CUDA_STUB_ENABLED_LINK_WORKAROUND 0) + endif() + endif() + if(CUDA_STUB_ENABLED_LINK_WORKAROUND) + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-rpath-link,\"${CUDA_STUB_TARGET_PATH}\"") + endif() + else() + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--allow-shlib-undefined") + endif() + if(NOT CUDA_STUB_ENABLED_LINK_WORKAROUND) + message(WARNING "CUDA: Workaround for stubs/libcuda.so.1 is not applied") + endif() + endif() +endmacro() + +macro(ocv_check_cuda_delayed_load cuda_toolkit_root_dir) + if(MSVC AND CUDA_ENABLE_DELAYLOAD) + set(DELAYFLAGS "delayimp.lib") + file(GLOB CUDA_DLLS "${cuda_toolkit_root_dir}/bin/*.dll") + foreach(d ${CUDA_DLLS}) + cmake_path(GET "d" FILENAME DLL_NAME) + if(NOT ${DLL_NAME} MATCHES "cudart") + set(DELAYFLAGS "${DELAYFLAGS} /DELAYLOAD:${DLL_NAME}") + endif() + endforeach() + set(DELAYFLAGS "${DELAYFLAGS} /DELAYLOAD:nvcuda.dll /DELAYLOAD:nvml.dll /IGNORE:4199") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${DELAYFLAGS}") + set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${DELAYFLAGS}") + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${DELAYFLAGS}") + endif() +endmacro() diff --git a/cmake/OpenCVFindLibsPerf.cmake b/cmake/OpenCVFindLibsPerf.cmake index a191afde58..5f72a67d89 100644 --- a/cmake/OpenCVFindLibsPerf.cmake +++ b/cmake/OpenCVFindLibsPerf.cmake @@ -40,7 +40,11 @@ endif() # --- CUDA --- if(WITH_CUDA) - include("${OpenCV_SOURCE_DIR}/cmake/OpenCVDetectCUDA.cmake") + if(ENABLE_CUDA_FIRST_CLASS_LANGUAGE) + include("${OpenCV_SOURCE_DIR}/cmake/OpenCVDetectCUDALanguage.cmake") + else() + include("${OpenCV_SOURCE_DIR}/cmake/OpenCVDetectCUDA.cmake") + endif() if(NOT HAVE_CUDA) message(WARNING "OpenCV is not able to find/configure CUDA SDK (required by WITH_CUDA). CUDA support will be disabled in OpenCV build. diff --git a/cmake/OpenCVGenConfig.cmake b/cmake/OpenCVGenConfig.cmake index 44297b813f..df48ae0848 100644 --- a/cmake/OpenCVGenConfig.cmake +++ b/cmake/OpenCVGenConfig.cmake @@ -12,7 +12,11 @@ else() endif() if(HAVE_CUDA) - ocv_cmake_configure("${CMAKE_CURRENT_LIST_DIR}/templates/OpenCVConfig-CUDA.cmake.in" CUDA_CONFIGCMAKE @ONLY) + if(ENABLE_CUDA_FIRST_CLASS_LANGUAGE) + ocv_cmake_configure("${CMAKE_CURRENT_LIST_DIR}/templates/OpenCVConfig-CUDALanguage.cmake.in" CUDA_CONFIGCMAKE @ONLY) + else() + ocv_cmake_configure("${CMAKE_CURRENT_LIST_DIR}/templates/OpenCVConfig-CUDA.cmake.in" CUDA_CONFIGCMAKE @ONLY) + endif() endif() if(ANDROID) diff --git a/cmake/OpenCVModule.cmake b/cmake/OpenCVModule.cmake index b6cee904a9..5411a28c61 100644 --- a/cmake/OpenCVModule.cmake +++ b/cmake/OpenCVModule.cmake @@ -1003,7 +1003,7 @@ macro(_ocv_create_module) INTERFACE ${OPENCV_MODULE_${the_module}_DEPS_EXT} ) ocv_target_link_libraries(${the_module} PRIVATE ${OPENCV_LINKER_LIBS} ${OPENCV_HAL_LINKER_LIBS} ${IPP_LIBS} ${ARGN}) - if (HAVE_CUDA) + if (NOT ENABLE_CUDA_FIRST_CLASS_LANGUAGE AND HAVE_CUDA) ocv_target_link_libraries(${the_module} PRIVATE ${CUDA_LIBRARIES} ${CUDA_npp_LIBRARY}) endif() diff --git a/cmake/OpenCVUtils.cmake b/cmake/OpenCVUtils.cmake index 108c37907d..444aa7cedd 100644 --- a/cmake/OpenCVUtils.cmake +++ b/cmake/OpenCVUtils.cmake @@ -1557,13 +1557,23 @@ function(_ocv_append_target_includes target) endif() endfunction() +macro(ocv_add_cuda_compile_flags) + ocv_cuda_compile_flags() + target_compile_options(${target} PRIVATE $<$: ${CUDA_NVCC_FLAGS} + "-Xcompiler=${CMAKE_CXX_FLAGS_CUDA} $<$:${CMAKE_CXX_FLAGS_DEBUG_CUDA}> \ + $<$:${CMAKE_CXX_FLAGS_RELEASE_CUDA}>" >) +endmacro() + function(ocv_add_executable target) add_executable(${target} ${ARGN}) + if(ENABLE_CUDA_FIRST_CLASS_LANGUAGE AND HAVE_CUDA) + ocv_add_cuda_compile_flags() + endif() _ocv_append_target_includes(${target}) endfunction() function(ocv_add_library target) - if(HAVE_CUDA AND ARGN MATCHES "\\.cu") + if(NOT ENABLE_CUDA_FIRST_CLASS_LANGUAGE AND HAVE_CUDA AND ARGN MATCHES "\\.cu") ocv_include_directories(${CUDA_INCLUDE_DIRS}) ocv_cuda_compile(cuda_objs ${ARGN}) set(OPENCV_MODULE_${target}_CUDA_OBJECTS ${cuda_objs} CACHE INTERNAL "Compiled CUDA object files") @@ -1571,6 +1581,10 @@ function(ocv_add_library target) add_library(${target} ${ARGN} ${cuda_objs}) + if(ENABLE_CUDA_FIRST_CLASS_LANGUAGE AND HAVE_CUDA) + ocv_add_cuda_compile_flags() + endif() + if(APPLE_FRAMEWORK AND BUILD_SHARED_LIBS) message(STATUS "Setting Apple target properties for ${target}") diff --git a/cmake/templates/OpenCVConfig-CUDALanguage.cmake.in b/cmake/templates/OpenCVConfig-CUDALanguage.cmake.in new file mode 100644 index 0000000000..259141006a --- /dev/null +++ b/cmake/templates/OpenCVConfig-CUDALanguage.cmake.in @@ -0,0 +1,31 @@ +# Version Compute Capability from which OpenCV has been compiled is remembered +set(OpenCV_COMPUTE_CAPABILITIES "@OpenCV_CUDA_CC@") + +set(OpenCV_CUDA_VERSION "@CUDA_VERSION_STRING@") +set(OpenCV_USE_CUBLAS "@HAVE_CUBLAS@") +set(OpenCV_USE_CUFFT "@HAVE_CUFFT@") +set(OpenCV_USE_NVCUVID "@HAVE_NVCUVID@") +set(OpenCV_USE_NVCUVENC "@HAVE_NVCUVENC@") +set(OpenCV_CUDNN_VERSION "@CUDNN_VERSION@") +set(OpenCV_USE_CUDNN "@HAVE_CUDNN@") +set(ENABLE_CUDA_FIRST_CLASS_LANGUAGE ON) + +if(NOT CUDAToolkit_FOUND) + if(NOT CMAKE_VERSION VERSION_LESS 3.18) + if(UNIX AND NOT CMAKE_CUDA_COMPILER AND NOT CUDAToolkit_ROOT) + message(STATUS "Checking for CUDAToolkit in default location (/usr/local/cuda)") + set(CUDA_PATH "/usr/local/cuda" CACHE INTERNAL "") + set(ENV{CUDA_PATH} ${CUDA_PATH}) + endif() + find_package(CUDAToolkit ${OpenCV_CUDA_VERSION} EXACT REQUIRED) + else() + message(FATAL_ERROR "Using OpenCV compiled with CUDA as first class language requires CMake \>= 3.18.") + endif() +else() + if(CUDAToolkit_FOUND) + set(CUDA_VERSION_STRING ${CUDAToolkit_VERSION}) + endif() + if(NOT CUDA_VERSION_STRING VERSION_EQUAL OpenCV_CUDA_VERSION) + message(FATAL_ERROR "OpenCV library was compiled with CUDA ${OpenCV_CUDA_VERSION} support. Please, use the same version or rebuild OpenCV with CUDA ${CUDA_VERSION_STRING}") + endif() +endif() diff --git a/modules/core/CMakeLists.txt b/modules/core/CMakeLists.txt index bf3a65c7c3..16f32c994a 100644 --- a/modules/core/CMakeLists.txt +++ b/modules/core/CMakeLists.txt @@ -49,13 +49,6 @@ if(DEFINED WINRT AND NOT DEFINED ENABLE_WINRT_MODE_NATIVE) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /ZW") endif() -if(HAVE_CUDA) - if(NOT HAVE_opencv_cudev) - message(FATAL_ERROR "CUDA: OpenCV requires enabled 'cudev' module from 'opencv_contrib' repository: https://github.com/opencv/opencv_contrib") - endif() - ocv_warnings_disable(CMAKE_CXX_FLAGS -Wundef -Wenum-compare -Wunused-function -Wshadow) -endif() - if(CV_TRACE AND HAVE_ITT) add_definitions(-DOPENCV_WITH_ITT=1) endif() @@ -153,7 +146,6 @@ elseif(HAVE_CXX11 OR DEFINED OPENCV_ALLOCATOR_STATS_COUNTER_TYPE) endif() endif() - if(PARALLEL_ENABLE_PLUGINS) ocv_append_source_file_compile_definitions(${CMAKE_CURRENT_SOURCE_DIR}/src/parallel/parallel.cpp "PARALLEL_ENABLE_PLUGINS=1") if(OPENCV_DEBUG_POSTFIX) @@ -161,6 +153,15 @@ if(PARALLEL_ENABLE_PLUGINS) endif() endif() +if(HAVE_CUDA) + if(NOT HAVE_opencv_cudev) + message(FATAL_ERROR "CUDA: OpenCV requires enabled 'cudev' module from 'opencv_contrib' repository: https://github.com/opencv/opencv_contrib") + endif() + if(ENABLE_CUDA_FIRST_CLASS_LANGUAGE) + ocv_module_include_directories(${CUDAToolkit_INCLUDE_DIRS}) + endif() + ocv_warnings_disable(CMAKE_CXX_FLAGS -Wundef -Wenum-compare -Wunused-function -Wshadow) +endif() ocv_create_module(${extra_libs}) diff --git a/modules/dnn/CMakeLists.txt b/modules/dnn/CMakeLists.txt index d6fd52f9ab..562b14483c 100644 --- a/modules/dnn/CMakeLists.txt +++ b/modules/dnn/CMakeLists.txt @@ -164,6 +164,12 @@ if(OPENCV_DNN_CUDA AND HAVE_CUDA AND HAVE_CUBLAS AND HAVE_CUDNN) endif() endforeach() unset(CC_LIST) + if(ENABLE_CUDA_FIRST_CLASS_LANGUAGE) + list(APPEND libs ${CUDNN_LIBRARIES} CUDA::cublas${CUDA_LIB_EXT}) + if(NOT CUDA_VERSION VERSION_LESS 10.1) + list(APPEND libs CUDA::cublasLt${CUDA_LIB_EXT}) + endif() + endif() else() set(sources_options ${sources_options} EXCLUDE_CUDA) endif()