diff --git a/CMakeLists.txt b/CMakeLists.txt index e5d511c34c..39cbe991df 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -395,10 +395,10 @@ OCV_OPTION(WITH_OPENCL_D3D11_NV "Include NVIDIA OpenCL D3D11 support" WITH_DIREC OCV_OPTION(WITH_LIBREALSENSE "Include Intel librealsense support" OFF VISIBLE_IF NOT WITH_INTELPERC VERIFY HAVE_LIBREALSENSE) -OCV_OPTION(WITH_VA "Include VA support" OFF +OCV_OPTION(WITH_VA "Include VA support" ON VISIBLE_IF UNIX AND NOT ANDROID VERIFY HAVE_VA) -OCV_OPTION(WITH_VA_INTEL "Include Intel VA-API/OpenCL support" OFF +OCV_OPTION(WITH_VA_INTEL "Include Intel VA-API/OpenCL support" ON VISIBLE_IF UNIX AND NOT ANDROID VERIFY HAVE_VA_INTEL) OCV_OPTION(WITH_MFX "Include Intel Media SDK support" OFF diff --git a/cmake/OpenCVFindVA.cmake b/cmake/OpenCVFindVA.cmake index 9d0ceec2c5..08d034f690 100644 --- a/cmake/OpenCVFindVA.cmake +++ b/cmake/OpenCVFindVA.cmake @@ -2,21 +2,20 @@ # HAVE_VA - libva is available # HAVE_VA_INTEL - OpenCL/libva Intel interoperability extension is available -if(UNIX AND NOT ANDROID) - find_path( +find_path( VA_INCLUDE_DIR NAMES va/va.h - PATHS "/usr/include" + PATHS ${VA_ROOT_DIR} PATH_SUFFIXES include - DOC "Path to libva headers") -endif() + DOC "Path to libva headers" +) if(VA_INCLUDE_DIR) set(HAVE_VA TRUE) - if(NOT DEFINED VA_LIBRARIES) + if(NOT DEFINED VA_LIBRARIES AND NOT OPENCV_LIBVA_LINK) set(VA_LIBRARIES "va" "va-drm") endif() else() set(HAVE_VA FALSE) - message(WARNING "libva installation is not found.") + message(STATUS "libva: missing va.h header (VA_INCLUDE_DIR)") endif() diff --git a/modules/core/CMakeLists.txt b/modules/core/CMakeLists.txt index 7db716923a..470f3b953d 100644 --- a/modules/core/CMakeLists.txt +++ b/modules/core/CMakeLists.txt @@ -99,6 +99,9 @@ endif() if(HAVE_VA_INTEL_OLD_HEADER) ocv_append_source_file_compile_definitions("${CMAKE_CURRENT_LIST_DIR}/src/va_intel.cpp" "HAVE_VA_INTEL_OLD_HEADER") endif() +if(OPENCV_LIBVA_LINK) + ocv_append_source_file_compile_definitions("${CMAKE_CURRENT_LIST_DIR}/src/va_intel.cpp" "OPENCV_LIBVA_LINK=1") +endif() option(OPENCV_ENABLE_ALLOCATOR_STATS "Enable Allocator metrics" ON) diff --git a/modules/core/src/va_intel.cpp b/modules/core/src/va_intel.cpp index c640a08658..c81e6f3687 100644 --- a/modules/core/src/va_intel.cpp +++ b/modules/core/src/va_intel.cpp @@ -33,6 +33,17 @@ using namespace cv; #endif #endif +#ifdef HAVE_VA +#ifndef OPENCV_LIBVA_LINK +#include "va_wrapper.impl.hpp" +#else +namespace cv { namespace detail { +static void init_libva() { /* nothing */ } +}} // namespace +#endif +using namespace cv::detail; +#endif + namespace cv { namespace va_intel { #ifdef HAVE_VA_INTEL @@ -54,6 +65,8 @@ Context& initializeContextFromVA(VADisplay display, bool tryInterop) #if !defined(HAVE_VA) NO_VA_SUPPORT_ERROR; #else // !HAVE_VA + init_libva(); + # ifdef HAVE_VA_INTEL contextInitialized = false; if (tryInterop) @@ -507,6 +520,8 @@ void convertToVASurface(VADisplay display, InputArray src, VASurfaceID surface, #if !defined(HAVE_VA) NO_VA_SUPPORT_ERROR; #else // !HAVE_VA + init_libva(); + const int stype = CV_8UC3; int srcType = src.type(); @@ -611,6 +626,8 @@ void convertFromVASurface(VADisplay display, VASurfaceID surface, Size size, Out #if !defined(HAVE_VA) NO_VA_SUPPORT_ERROR; #else // !HAVE_VA + init_libva(); + const int dtype = CV_8UC3; // TODO Need to specify ACCESS_WRITE here somehow to prevent useless data copying! diff --git a/modules/core/src/va_wrapper.impl.hpp b/modules/core/src/va_wrapper.impl.hpp new file mode 100644 index 0000000000..260d3ba49b --- /dev/null +++ b/modules/core/src/va_wrapper.impl.hpp @@ -0,0 +1,85 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +// +// Not a standalone header, part of va_intel.cpp +// + +#include "opencv2/core/utils/plugin_loader.private.hpp" // DynamicLib + +namespace cv { namespace detail { + +typedef VAStatus (*FN_vaDeriveImage)(VADisplay dpy, VASurfaceID surface, VAImage *image); +typedef VAStatus (*FN_vaDestroyImage)(VADisplay dpy, VAImageID image); +typedef VAStatus (*FN_vaMapBuffer)(VADisplay dpy, VABufferID buf_id, void **pbuf); +typedef VAStatus (*FN_vaSyncSurface)(VADisplay dpy, VASurfaceID render_target); +typedef VAStatus (*FN_vaUnmapBuffer)(VADisplay dpy, VABufferID buf_id); + +static FN_vaDeriveImage fn_vaDeriveImage = NULL; +static FN_vaDestroyImage fn_vaDestroyImage = NULL; +static FN_vaMapBuffer fn_vaMapBuffer = NULL; +static FN_vaSyncSurface fn_vaSyncSurface = NULL; +static FN_vaUnmapBuffer fn_vaUnmapBuffer = NULL; + +#define vaDeriveImage fn_vaDeriveImage +#define vaDestroyImage fn_vaDestroyImage +#define vaMapBuffer fn_vaMapBuffer +#define vaSyncSurface fn_vaSyncSurface +#define vaUnmapBuffer fn_vaUnmapBuffer + + +static std::shared_ptr loadLibVA() +{ + std::shared_ptr lib; + const char* envPath = getenv("OPENCV_LIBVA_RUNTIME"); + if (envPath) + { + lib = std::make_shared(envPath); + return lib; + } + static const char* const candidates[] = { + "libva.so", + "libva.so.2", + "libva.so.1", + }; + for (int i = 0; i < 3; ++i) + { + lib = std::make_shared(candidates[i]); + if (lib->isLoaded()) + break; + } + return lib; +} +static void init_libva() +{ + static bool initialized = false; + static auto library = loadLibVA(); + if (!initialized) + { + if (!library || !library->isLoaded()) + { + library.reset(); + CV_Error(cv::Error::StsBadFunc, "OpenCV can't load VA library (libva)"); + } + auto& lib = *library.get(); +#define VA_LOAD_SYMBOL(name) fn_ ## name = reinterpret_cast(lib.getSymbol(#name)); \ + if (!fn_ ## name) \ + { \ + library.reset(); \ + initialized = true; \ + CV_Error_(cv::Error::StsBadFunc, ("OpenCV can't load VA library (libva), missing symbol: %s", #name)); \ + } + + VA_LOAD_SYMBOL(vaDeriveImage); + VA_LOAD_SYMBOL(vaDestroyImage); + VA_LOAD_SYMBOL(vaMapBuffer); + VA_LOAD_SYMBOL(vaSyncSurface); + VA_LOAD_SYMBOL(vaUnmapBuffer); + initialized = true; + } + if (!library) + CV_Error(cv::Error::StsBadFunc, "OpenCV can't load/initialize VA library (libva)"); +} + +}} // namespace