mirror of https://github.com/opencv/opencv.git
parent
e5d78960c6
commit
cc73c36e32
35 changed files with 1509 additions and 354 deletions
@ -0,0 +1,127 @@ |
||||
# Standalone OpenCV plugins build scripts |
||||
# |
||||
# Useful OpenCV common build variables: |
||||
# - CMAKE_BUILD_TYPE=Release/Debug |
||||
# - BUILD_WITH_DEBUG_INFO=ON |
||||
# - ENABLE_BUILD_HARDENING=ON |
||||
# |
||||
# Plugin configuration variables: |
||||
# - OPENCV_PLUGIN_DEPS - set of extra dependencies (modules), used for include dirs, target_link_libraries |
||||
# - OPENCV_PLUGIN_SUFFIX |
||||
# - OPENCV_PLUGIN_NAME |
||||
# - OPENCV_PLUGIN_OUTPUT_NAME_FULL (overrides both OPENCV_PLUGIN_NAME / OPENCV_PLUGIN_SUFFIX) |
||||
# |
||||
#============================================= |
||||
|
||||
if(NOT OpenCV_SOURCE_DIR) |
||||
message(FATAL_ERROR "OpenCV_SOURCE_DIR must be set to build the plugin!") |
||||
endif() |
||||
|
||||
if(NOT DEFINED CMAKE_BUILD_TYPE) |
||||
set(CMAKE_BUILD_TYPE "Release") |
||||
endif() |
||||
message(STATUS "CMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}") |
||||
|
||||
set(BUILD_SHARED_LIBS ON CACHE BOOL "") |
||||
if(NOT BUILD_SHARED_LIBS) |
||||
message(FATAL_ERROR "Static plugin build does not make sense") |
||||
endif() |
||||
|
||||
# re-use OpenCV build scripts |
||||
include("${OpenCV_SOURCE_DIR}/cmake/OpenCVUtils.cmake") |
||||
include("${OpenCV_SOURCE_DIR}/cmake/OpenCVDetectCXXCompiler.cmake") |
||||
include("${OpenCV_SOURCE_DIR}/cmake/OpenCVCompilerOptions.cmake") |
||||
|
||||
function(ocv_create_plugin module default_name dependency_target dependency_target_desc) |
||||
|
||||
set(OPENCV_PLUGIN_NAME ${default_name} CACHE STRING "") |
||||
set(OPENCV_PLUGIN_DESTINATION "" CACHE PATH "") |
||||
project(${OPENCV_PLUGIN_NAME} LANGUAGES CXX) |
||||
|
||||
if(NOT TARGET ${dependency_target}) |
||||
message(FATAL_ERROR "${dependency_target_desc} was not found! (missing target ${dependency_target})") |
||||
endif() |
||||
|
||||
set(modules_ROOT "${OpenCV_SOURCE_DIR}/modules") |
||||
set(module_ROOT "${modules_ROOT}/${module}") |
||||
|
||||
foreach(src ${ARGN}) |
||||
list(APPEND sources "${module_ROOT}/${src}") |
||||
endforeach() |
||||
|
||||
add_library(${OPENCV_PLUGIN_NAME} MODULE |
||||
"${sources}" |
||||
${OPENCV_PLUGIN_EXTRA_SRC_FILES} |
||||
) |
||||
|
||||
if(OPENCV_PLUGIN_DEPS) |
||||
foreach(d ${OPENCV_PLUGIN_DEPS}) |
||||
list(APPEND OPENCV_PLUGIN_EXTRA_INCLUDES "${modules_ROOT}/${d}/include") |
||||
endforeach() |
||||
endif() |
||||
|
||||
target_include_directories(${OPENCV_PLUGIN_NAME} PRIVATE |
||||
"${CMAKE_CURRENT_BINARY_DIR}" |
||||
"${module_ROOT}/src" |
||||
"${module_ROOT}/include" |
||||
${OPENCV_PLUGIN_EXTRA_INCLUDES} |
||||
) |
||||
target_compile_definitions(${OPENCV_PLUGIN_NAME} PRIVATE "BUILD_PLUGIN=1") |
||||
|
||||
target_link_libraries(${OPENCV_PLUGIN_NAME} PRIVATE ${dependency_target}) |
||||
set_target_properties(${OPENCV_PLUGIN_NAME} PROPERTIES |
||||
CXX_STANDARD 11 |
||||
CXX_VISIBILITY_PRESET hidden |
||||
) |
||||
|
||||
if(DEFINED OPENCV_PLUGIN_MODULE_PREFIX) |
||||
set_target_properties(${OPENCV_PLUGIN_NAME} PROPERTIES PREFIX "${OPENCV_PLUGIN_MODULE_PREFIX}") |
||||
endif() |
||||
|
||||
# Hack for Windows only, Linux/MacOS uses global symbol table (without exact .so binding) |
||||
if(WIN32) |
||||
find_package(OpenCV REQUIRED ${module} ${OPENCV_PLUGIN_DEPS}) |
||||
target_link_libraries(${OPENCV_PLUGIN_NAME} PRIVATE ${OpenCV_LIBRARIES}) |
||||
endif() |
||||
|
||||
if(NOT OpenCV_FOUND) # build against sources (Linux) |
||||
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/opencv2/opencv_modules.hpp" "#pragma once") |
||||
endif() |
||||
|
||||
if(WIN32) |
||||
ocv_update(OPENCV_DEBUG_POSTFIX d) |
||||
endif() |
||||
set_target_properties(${OPENCV_PLUGIN_NAME} PROPERTIES DEBUG_POSTFIX "${OPENCV_DEBUG_POSTFIX}") |
||||
|
||||
if(DEFINED OPENCV_PLUGIN_SUFFIX) |
||||
# custom value |
||||
else() |
||||
if(WIN32) |
||||
ocv_update(OPENCV_PLUGIN_VERSION "${OpenCV_VERSION_MAJOR}${OpenCV_VERSION_MINOR}${OpenCV_VERSION_PATCH}") |
||||
if(CMAKE_CXX_SIZEOF_DATA_PTR EQUAL 8) |
||||
ocv_update(OPENCV_PLUGIN_ARCH "_64") |
||||
else() |
||||
ocv_update(OPENCV_PLUGIN_ARCH "") |
||||
endif() |
||||
else() |
||||
# empty |
||||
endif() |
||||
ocv_update(OPENCV_PLUGIN_SUFFIX "${OPENCV_PLUGIN_VERSION}${OPENCV_PLUGIN_ARCH}") |
||||
endif() |
||||
|
||||
if(OPENCV_PLUGIN_DESTINATION) |
||||
set_target_properties(${OPENCV_PLUGIN_NAME} PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${OPENCV_PLUGIN_DESTINATION}") |
||||
message(STATUS "Output destination: ${OPENCV_PLUGIN_DESTINATION}") |
||||
endif() |
||||
|
||||
if(OPENCV_PLUGIN_OUTPUT_NAME_FULL) |
||||
set_target_properties(${OPENCV_PLUGIN_NAME} PROPERTIES OUTPUT_NAME "${OPENCV_PLUGIN_OUTPUT_NAME_FULL}") |
||||
elseif(OPENCV_PLUGIN_OUTPUT_NAME) |
||||
set_target_properties(${OPENCV_PLUGIN_NAME} PROPERTIES OUTPUT_NAME "${OPENCV_PLUGIN_OUTPUT_NAME}${OPENCV_PLUGIN_SUFFIX}") |
||||
endif() |
||||
|
||||
install(TARGETS ${OPENCV_PLUGIN_NAME} LIBRARY DESTINATION . COMPONENT plugins) |
||||
|
||||
message(STATUS "Library name: ${OPENCV_PLUGIN_NAME}") |
||||
|
||||
endfunction() |
@ -0,0 +1,13 @@ |
||||
if(CMAKE_VERSION VERSION_LESS "3.9") |
||||
message(STATUS "OpenMP detection requires CMake 3.9+") # OpenMP::OpenMP_CXX target |
||||
endif() |
||||
|
||||
find_package(OpenMP) |
||||
if(OpenMP_FOUND) |
||||
if(TARGET OpenMP::OpenMP_CXX) |
||||
set(HAVE_OPENMP 1) |
||||
ocv_add_external_target(openmp "" "OpenMP::OpenMP_CXX" "HAVE_OPENMP=1") |
||||
else() |
||||
message(WARNING "OpenMP: missing OpenMP::OpenMP_CXX target") |
||||
endif() |
||||
endif() |
@ -0,0 +1,5 @@ |
||||
include("${OpenCV_SOURCE_DIR}/cmake/OpenCVDetectTBB.cmake") |
||||
|
||||
if(HAVE_TBB) |
||||
ocv_add_external_target(tbb "" "tbb" "HAVE_TBB=1") |
||||
endif() |
@ -0,0 +1,8 @@ |
||||
macro(ocv_add_core_parallel_backend backend_id cond_var) |
||||
if(${cond_var}) |
||||
include("${CMAKE_CURRENT_LIST_DIR}/detect_${backend_id}.cmake") |
||||
endif() |
||||
endmacro() |
||||
|
||||
ocv_add_core_parallel_backend("tbb" WITH_TBB) |
||||
ocv_add_core_parallel_backend("openmp" WITH_OPENMP) |
@ -0,0 +1,163 @@ |
||||
// 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.
|
||||
|
||||
#ifndef OPENCV_UTILS_PLUGIN_LOADER_HPP |
||||
#define OPENCV_UTILS_PLUGIN_LOADER_HPP |
||||
|
||||
#include "opencv2/core/utils/filesystem.hpp" |
||||
#include "opencv2/core/utils/filesystem.private.hpp" |
||||
|
||||
#if OPENCV_HAVE_FILESYSTEM_SUPPORT |
||||
|
||||
#if defined(_WIN32) |
||||
#include <windows.h> |
||||
#elif defined(__linux__) || defined(__APPLE__) || defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__HAIKU__) || defined(__GLIBC__) |
||||
#include <dlfcn.h> |
||||
#endif |
||||
|
||||
namespace cv { namespace plugin { namespace impl { |
||||
|
||||
#if defined(_WIN32) |
||||
typedef HMODULE LibHandle_t; |
||||
typedef wchar_t FileSystemChar_t; |
||||
typedef std::wstring FileSystemPath_t; |
||||
|
||||
// TODO wchar_t <=> UTF-8
|
||||
static inline |
||||
FileSystemPath_t toFileSystemPath(const std::string& p) |
||||
{ |
||||
FileSystemPath_t result; |
||||
result.resize(p.size()); |
||||
for (size_t i = 0; i < p.size(); i++) |
||||
result[i] = (wchar_t)p[i]; |
||||
return result; |
||||
} |
||||
|
||||
// TODO wchar_t <=> UTF-8
|
||||
static inline |
||||
std::string toPrintablePath(const FileSystemPath_t& p) |
||||
{ |
||||
std::string result; |
||||
result.resize(p.size()); |
||||
for (size_t i = 0; i < p.size(); i++) |
||||
{ |
||||
wchar_t ch = p[i]; |
||||
if ((int)ch >= ' ' && (int)ch < 128) |
||||
result[i] = (char)ch; |
||||
else |
||||
result[i] = '?'; |
||||
} |
||||
return result; |
||||
} |
||||
#else // !_WIN32
|
||||
typedef void* LibHandle_t; |
||||
typedef char FileSystemChar_t; |
||||
typedef std::string FileSystemPath_t; |
||||
|
||||
static inline FileSystemPath_t toFileSystemPath(const std::string& p) { return p; } |
||||
static inline std::string toPrintablePath(const FileSystemPath_t& p) { return p; } |
||||
#endif |
||||
|
||||
|
||||
static inline |
||||
void* getSymbol_(LibHandle_t h, const char* symbolName) |
||||
{ |
||||
#if defined(_WIN32) |
||||
return (void*)GetProcAddress(h, symbolName); |
||||
#elif defined(__linux__) || defined(__APPLE__) || defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__HAIKU__) || defined(__GLIBC__) |
||||
return dlsym(h, symbolName); |
||||
#endif |
||||
} |
||||
|
||||
static inline |
||||
LibHandle_t libraryLoad_(const FileSystemPath_t& filename) |
||||
{ |
||||
#if defined(_WIN32) |
||||
# ifdef WINRT |
||||
return LoadPackagedLibrary(filename.c_str(), 0); |
||||
# else |
||||
return LoadLibraryW(filename.c_str()); |
||||
#endif |
||||
#elif defined(__linux__) || defined(__APPLE__) || defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__HAIKU__) || defined(__GLIBC__) |
||||
return dlopen(filename.c_str(), RTLD_LAZY); |
||||
#endif |
||||
} |
||||
|
||||
static inline |
||||
void libraryRelease_(LibHandle_t h) |
||||
{ |
||||
#if defined(_WIN32) |
||||
FreeLibrary(h); |
||||
#elif defined(__linux__) || defined(__APPLE__) || defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__HAIKU__) || defined(__GLIBC__) |
||||
dlclose(h); |
||||
#endif |
||||
} |
||||
|
||||
static inline |
||||
std::string libraryPrefix() |
||||
{ |
||||
#if defined(_WIN32) |
||||
return ""; |
||||
#else |
||||
return "lib"; |
||||
#endif |
||||
} |
||||
static inline |
||||
std::string librarySuffix() |
||||
{ |
||||
#if defined(_WIN32) |
||||
const char* suffix = "" |
||||
CVAUX_STR(CV_MAJOR_VERSION) CVAUX_STR(CV_MINOR_VERSION) CVAUX_STR(CV_SUBMINOR_VERSION) |
||||
#if (defined _MSC_VER && defined _M_X64) || (defined __GNUC__ && defined __x86_64__) |
||||
"_64" |
||||
#endif |
||||
#if defined(_DEBUG) && defined(DEBUG_POSTFIX) |
||||
CVAUX_STR(DEBUG_POSTFIX) |
||||
#endif |
||||
".dll"; |
||||
return suffix; |
||||
#else |
||||
return ".so"; |
||||
#endif |
||||
} |
||||
|
||||
|
||||
//============================
|
||||
|
||||
class CV_EXPORTS DynamicLib |
||||
{ |
||||
private: |
||||
LibHandle_t handle; |
||||
const FileSystemPath_t fname; |
||||
bool disableAutoUnloading_; |
||||
|
||||
public: |
||||
DynamicLib(const FileSystemPath_t& filename); |
||||
~DynamicLib(); |
||||
/** Do not automatically unload library in destructor */ |
||||
inline void disableAutomaticLibraryUnloading() |
||||
{ |
||||
disableAutoUnloading_ = true; |
||||
} |
||||
inline bool isLoaded() const |
||||
{ |
||||
return handle != NULL; |
||||
} |
||||
void* getSymbol(const char* symbolName) const; |
||||
const std::string getName() const; |
||||
private: |
||||
void libraryLoad(const FileSystemPath_t& filename); |
||||
void libraryRelease(); |
||||
|
||||
private: |
||||
DynamicLib(const DynamicLib &) = delete; |
||||
DynamicLib &operator=(const DynamicLib &) = delete; |
||||
}; |
||||
|
||||
|
||||
}}} // namespace
|
||||
|
||||
#endif // OPENCV_HAVE_FILESYSTEM_SUPPORT
|
||||
|
||||
#endif // OPENCV_UTILS_PLUGIN_LOADER_HPP
|
@ -0,0 +1,12 @@ |
||||
cmake_minimum_required(VERSION 3.5) |
||||
project(opencv_core_parallel_openmp CXX) |
||||
|
||||
get_filename_component(OpenCV_SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}/../../../../.." ABSOLUTE) |
||||
include("${OpenCV_SOURCE_DIR}/cmake/OpenCVPluginStandalone.cmake") |
||||
|
||||
# scan dependencies |
||||
set(WITH_OPENMP ON) |
||||
include("${OpenCV_SOURCE_DIR}/modules/core/cmake/parallel/init.cmake") |
||||
|
||||
message(STATUS "OpenMP: ${OPENMP_VERSION}") |
||||
ocv_create_plugin(core "opencv_core_parallel_openmp" "ocv.3rdparty.openmp" "OPENMP" "src/parallel/parallel_openmp.cpp") |
@ -0,0 +1,12 @@ |
||||
cmake_minimum_required(VERSION 3.5) |
||||
project(opencv_core_parallel_tbb CXX) |
||||
|
||||
get_filename_component(OpenCV_SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}/../../../../.." ABSOLUTE) |
||||
include("${OpenCV_SOURCE_DIR}/cmake/OpenCVPluginStandalone.cmake") |
||||
|
||||
# scan dependencies |
||||
set(WITH_TBB ON) |
||||
include("${OpenCV_SOURCE_DIR}/modules/core/cmake/parallel/init.cmake") |
||||
|
||||
message(STATUS "TBB: ver ${TBB_VERSION_MAJOR}.${TBB_VERSION_MINOR} interface ${TBB_INTERFACE_VERSION}") |
||||
ocv_create_plugin(core "opencv_core_parallel_tbb" "ocv.3rdparty.tbb" "TBB" "src/parallel/parallel_tbb.cpp") |
@ -0,0 +1,48 @@ |
||||
// 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.
|
||||
|
||||
#ifndef OPENCV_CORE_PARALLEL_FACTORY_HPP |
||||
#define OPENCV_CORE_PARALLEL_FACTORY_HPP |
||||
|
||||
#include "opencv2/core/parallel/parallel_backend.hpp" |
||||
|
||||
namespace cv { namespace parallel { |
||||
|
||||
class IParallelBackendFactory |
||||
{ |
||||
public: |
||||
virtual ~IParallelBackendFactory() {} |
||||
virtual std::shared_ptr<cv::parallel::ParallelForAPI> create() const = 0; |
||||
}; |
||||
|
||||
|
||||
class StaticBackendFactory CV_FINAL: public IParallelBackendFactory |
||||
{ |
||||
protected: |
||||
std::function<std::shared_ptr<cv::parallel::ParallelForAPI>(void)> create_fn_; |
||||
|
||||
public: |
||||
StaticBackendFactory(std::function<std::shared_ptr<cv::parallel::ParallelForAPI>(void)>&& create_fn) |
||||
: create_fn_(create_fn) |
||||
{ |
||||
// nothing
|
||||
} |
||||
|
||||
~StaticBackendFactory() CV_OVERRIDE {} |
||||
|
||||
std::shared_ptr<cv::parallel::ParallelForAPI> create() const CV_OVERRIDE |
||||
{ |
||||
return create_fn_(); |
||||
} |
||||
}; |
||||
|
||||
//
|
||||
// PluginBackendFactory is implemented in plugin_wrapper.cpp
|
||||
//
|
||||
|
||||
std::shared_ptr<IParallelBackendFactory> createPluginParallelBackendFactory(const std::string& baseName); |
||||
|
||||
}} // namespace
|
||||
|
||||
#endif // OPENCV_CORE_PARALLEL_FACTORY_HPP
|
@ -0,0 +1,173 @@ |
||||
// 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.
|
||||
#include "../precomp.hpp" |
||||
#include "parallel.hpp" |
||||
|
||||
#include <opencv2/core/utils/configuration.private.hpp> |
||||
#include <opencv2/core/utils/logger.defines.hpp> |
||||
#ifdef NDEBUG |
||||
#define CV_LOG_STRIP_LEVEL CV_LOG_LEVEL_DEBUG + 1 |
||||
#else |
||||
#define CV_LOG_STRIP_LEVEL CV_LOG_LEVEL_VERBOSE + 1 |
||||
#endif |
||||
#include <opencv2/core/utils/logger.hpp> |
||||
|
||||
|
||||
#include "registry_parallel.hpp" |
||||
#include "registry_parallel.impl.hpp" |
||||
|
||||
#include "plugin_parallel_api.hpp" |
||||
#include "plugin_parallel_wrapper.impl.hpp" |
||||
|
||||
|
||||
namespace cv { namespace parallel { |
||||
|
||||
int numThreads = -1; |
||||
|
||||
ParallelForAPI::~ParallelForAPI() |
||||
{ |
||||
// nothing
|
||||
} |
||||
|
||||
static |
||||
std::string& getParallelBackendName() |
||||
{ |
||||
static std::string g_backendName = toUpperCase(cv::utils::getConfigurationParameterString("OPENCV_PARALLEL_BACKEND", "")); |
||||
return g_backendName; |
||||
} |
||||
|
||||
static bool g_initializedParallelForAPI = false; |
||||
|
||||
static |
||||
std::shared_ptr<ParallelForAPI> createParallelForAPI() |
||||
{ |
||||
const std::string& name = getParallelBackendName(); |
||||
bool isKnown = false; |
||||
const auto& backends = getParallelBackendsInfo(); |
||||
if (!name.empty()) |
||||
{ |
||||
CV_LOG_INFO(NULL, "core(parallel): requested backend name: " << name); |
||||
} |
||||
for (size_t i = 0; i < backends.size(); i++) |
||||
{ |
||||
const auto& info = backends[i]; |
||||
if (!name.empty()) |
||||
{ |
||||
if (name != info.name) |
||||
{ |
||||
continue; |
||||
} |
||||
isKnown = true; |
||||
} |
||||
try |
||||
{ |
||||
CV_LOG_DEBUG(NULL, "core(parallel): trying backend: " << info.name << " (priority=" << info.priority << ")"); |
||||
CV_Assert(info.backendFactory); |
||||
std::shared_ptr<ParallelForAPI> backend = info.backendFactory->create(); |
||||
if (!backend) |
||||
{ |
||||
CV_LOG_VERBOSE(NULL, 0, "core(parallel): not available: " << info.name); |
||||
continue; |
||||
} |
||||
CV_LOG_INFO(NULL, "core(parallel): using backend: " << info.name << " (priority=" << info.priority << ")"); |
||||
g_initializedParallelForAPI = true; |
||||
getParallelBackendName() = info.name; |
||||
return backend; |
||||
} |
||||
catch (const std::exception& e) |
||||
{ |
||||
CV_LOG_WARNING(NULL, "core(parallel): can't initialize " << info.name << " backend: " << e.what()); |
||||
} |
||||
catch (...) |
||||
{ |
||||
CV_LOG_WARNING(NULL, "core(parallel): can't initialize " << info.name << " backend: Unknown C++ exception"); |
||||
} |
||||
} |
||||
if (name.empty()) |
||||
{ |
||||
CV_LOG_DEBUG(NULL, "core(parallel): fallback on builtin code"); |
||||
} |
||||
else |
||||
{ |
||||
if (!isKnown) |
||||
CV_LOG_INFO(NULL, "core(parallel): unknown backend: " << name); |
||||
} |
||||
g_initializedParallelForAPI = true; |
||||
return std::shared_ptr<ParallelForAPI>(); |
||||
} |
||||
|
||||
static inline |
||||
std::shared_ptr<ParallelForAPI> createDefaultParallelForAPI() |
||||
{ |
||||
CV_LOG_DEBUG(NULL, "core(parallel): Initializing parallel backend..."); |
||||
return createParallelForAPI(); |
||||
} |
||||
|
||||
std::shared_ptr<ParallelForAPI>& getCurrentParallelForAPI() |
||||
{ |
||||
static std::shared_ptr<ParallelForAPI> g_currentParallelForAPI = createDefaultParallelForAPI(); |
||||
return g_currentParallelForAPI; |
||||
} |
||||
|
||||
void setParallelForBackend(const std::shared_ptr<ParallelForAPI>& api, bool propagateNumThreads) |
||||
{ |
||||
getCurrentParallelForAPI() = api; |
||||
if (propagateNumThreads && api) |
||||
{ |
||||
setNumThreads(numThreads); |
||||
} |
||||
} |
||||
|
||||
bool setParallelForBackend(const std::string& backendName, bool propagateNumThreads) |
||||
{ |
||||
CV_TRACE_FUNCTION(); |
||||
|
||||
std::string backendName_u = toUpperCase(backendName); |
||||
if (g_initializedParallelForAPI) |
||||
{ |
||||
// ... already initialized
|
||||
if (getParallelBackendName() == backendName_u) |
||||
{ |
||||
CV_LOG_INFO(NULL, "core(parallel): backend is already activated: " << (backendName.empty() ? "builtin(legacy)" : backendName)); |
||||
return true; |
||||
} |
||||
else |
||||
{ |
||||
// ... re-create new
|
||||
CV_LOG_DEBUG(NULL, "core(parallel): replacing parallel backend..."); |
||||
getParallelBackendName() = backendName_u; |
||||
getCurrentParallelForAPI() = createParallelForAPI(); |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
// ... no backend exists, just specify the name (initialization is triggered by getCurrentParallelForAPI() call)
|
||||
getParallelBackendName() = backendName_u; |
||||
} |
||||
std::shared_ptr<ParallelForAPI> api = getCurrentParallelForAPI(); |
||||
if (!api) |
||||
{ |
||||
if (!backendName.empty()) |
||||
{ |
||||
CV_LOG_WARNING(NULL, "core(parallel): backend is not available: " << backendName << " (using builtin legacy code)"); |
||||
return false; |
||||
} |
||||
else |
||||
{ |
||||
CV_LOG_WARNING(NULL, "core(parallel): switched to builtin code (legacy)"); |
||||
} |
||||
} |
||||
if (!backendName_u.empty()) |
||||
{ |
||||
CV_Assert(backendName_u == getParallelBackendName()); // data race?
|
||||
} |
||||
|
||||
if (propagateNumThreads) |
||||
{ |
||||
setNumThreads(numThreads); |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
}} // namespace
|
@ -0,0 +1,29 @@ |
||||
// 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.
|
||||
#ifndef OPENCV_CORE_SRC_PARALLEL_PARALLEL_HPP |
||||
#define OPENCV_CORE_SRC_PARALLEL_PARALLEL_HPP |
||||
|
||||
#include "opencv2/core/parallel/parallel_backend.hpp" |
||||
|
||||
namespace cv { namespace parallel { |
||||
|
||||
extern int numThreads; |
||||
|
||||
std::shared_ptr<ParallelForAPI>& getCurrentParallelForAPI(); |
||||
|
||||
#ifndef BUILD_PLUGIN |
||||
|
||||
#ifdef HAVE_TBB |
||||
std::shared_ptr<cv::parallel::ParallelForAPI> createParallelBackendTBB(); |
||||
#endif |
||||
|
||||
#ifdef HAVE_OPENMP |
||||
std::shared_ptr<cv::parallel::ParallelForAPI> createParallelBackendOpenMP(); |
||||
#endif |
||||
|
||||
#endif // BUILD_PLUGIN
|
||||
|
||||
}} // namespace
|
||||
|
||||
#endif // OPENCV_CORE_SRC_PARALLEL_PARALLEL_HPP
|
@ -0,0 +1,72 @@ |
||||
// 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.
|
||||
#include "../precomp.hpp" |
||||
|
||||
#ifdef HAVE_OPENMP |
||||
|
||||
#include "parallel.hpp" |
||||
#include "opencv2/core/parallel/backend/parallel_for.openmp.hpp" |
||||
|
||||
namespace cv { namespace parallel { |
||||
|
||||
static |
||||
std::shared_ptr<cv::parallel::openmp::ParallelForBackend>& getInstance() |
||||
{ |
||||
static std::shared_ptr<cv::parallel::openmp::ParallelForBackend> g_instance = std::make_shared<cv::parallel::openmp::ParallelForBackend>(); |
||||
return g_instance; |
||||
} |
||||
|
||||
#ifndef BUILD_PLUGIN |
||||
std::shared_ptr<cv::parallel::ParallelForAPI> createParallelBackendOpenMP() |
||||
{ |
||||
return getInstance(); |
||||
} |
||||
#endif |
||||
|
||||
}} // namespace
|
||||
|
||||
#ifdef BUILD_PLUGIN |
||||
|
||||
#define ABI_VERSION 0 |
||||
#define API_VERSION 0 |
||||
#include "plugin_parallel_api.hpp" |
||||
|
||||
static |
||||
CvResult cv_getInstance(CV_OUT CvPluginParallelBackendAPI* handle) CV_NOEXCEPT |
||||
{ |
||||
try |
||||
{ |
||||
if (!handle) |
||||
return CV_ERROR_FAIL; |
||||
*handle = cv::parallel::getInstance().get(); |
||||
return CV_ERROR_OK; |
||||
} |
||||
catch (...) |
||||
{ |
||||
return CV_ERROR_FAIL; |
||||
} |
||||
} |
||||
|
||||
static const OpenCV_Core_Parallel_Plugin_API plugin_api = |
||||
{ |
||||
{ |
||||
sizeof(OpenCV_Core_Parallel_Plugin_API), ABI_VERSION, API_VERSION, |
||||
CV_VERSION_MAJOR, CV_VERSION_MINOR, CV_VERSION_REVISION, CV_VERSION_STATUS, |
||||
"OpenMP (" CVAUX_STR(_OPENMP) ") OpenCV parallel plugin" |
||||
}, |
||||
{ |
||||
/* 1*/cv_getInstance |
||||
} |
||||
}; |
||||
|
||||
const OpenCV_Core_Parallel_Plugin_API* CV_API_CALL opencv_core_parallel_plugin_init_v0(int requested_abi_version, int requested_api_version, void* /*reserved=NULL*/) CV_NOEXCEPT |
||||
{ |
||||
if (requested_abi_version == ABI_VERSION && requested_api_version <= API_VERSION) |
||||
return &plugin_api; |
||||
return NULL; |
||||
} |
||||
|
||||
#endif // BUILD_PLUGIN
|
||||
|
||||
#endif // HAVE_TBB
|
@ -0,0 +1,74 @@ |
||||
// 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.
|
||||
#include "../precomp.hpp" |
||||
|
||||
#include "factory_parallel.hpp" |
||||
|
||||
#ifdef HAVE_TBB |
||||
|
||||
#include "parallel.hpp" |
||||
#include "opencv2/core/parallel/backend/parallel_for.tbb.hpp" |
||||
|
||||
namespace cv { namespace parallel { |
||||
|
||||
static |
||||
std::shared_ptr<cv::parallel::tbb::ParallelForBackend>& getInstance() |
||||
{ |
||||
static std::shared_ptr<cv::parallel::tbb::ParallelForBackend> g_instance = std::make_shared<cv::parallel::tbb::ParallelForBackend>(); |
||||
return g_instance; |
||||
} |
||||
|
||||
#ifndef BUILD_PLUGIN |
||||
std::shared_ptr<cv::parallel::ParallelForAPI> createParallelBackendTBB() |
||||
{ |
||||
return getInstance(); |
||||
} |
||||
#endif |
||||
|
||||
}} // namespace
|
||||
|
||||
#ifdef BUILD_PLUGIN |
||||
|
||||
#define ABI_VERSION 0 |
||||
#define API_VERSION 0 |
||||
#include "plugin_parallel_api.hpp" |
||||
|
||||
static |
||||
CvResult cv_getInstance(CV_OUT CvPluginParallelBackendAPI* handle) CV_NOEXCEPT |
||||
{ |
||||
try |
||||
{ |
||||
if (!handle) |
||||
return CV_ERROR_FAIL; |
||||
*handle = cv::parallel::getInstance().get(); |
||||
return CV_ERROR_OK; |
||||
} |
||||
catch (...) |
||||
{ |
||||
return CV_ERROR_FAIL; |
||||
} |
||||
} |
||||
|
||||
static const OpenCV_Core_Parallel_Plugin_API plugin_api = |
||||
{ |
||||
{ |
||||
sizeof(OpenCV_Core_Parallel_Plugin_API), ABI_VERSION, API_VERSION, |
||||
CV_VERSION_MAJOR, CV_VERSION_MINOR, CV_VERSION_REVISION, CV_VERSION_STATUS, |
||||
"TBB (interface " CVAUX_STR(TBB_INTERFACE_VERSION) ") OpenCV parallel plugin" |
||||
}, |
||||
{ |
||||
/* 1*/cv_getInstance |
||||
} |
||||
}; |
||||
|
||||
const OpenCV_Core_Parallel_Plugin_API* CV_API_CALL opencv_core_parallel_plugin_init_v0(int requested_abi_version, int requested_api_version, void* /*reserved=NULL*/) CV_NOEXCEPT |
||||
{ |
||||
if (requested_abi_version == ABI_VERSION && requested_api_version <= API_VERSION) |
||||
return &plugin_api; |
||||
return NULL; |
||||
} |
||||
|
||||
#endif // BUILD_PLUGIN
|
||||
|
||||
#endif // HAVE_TBB
|
@ -0,0 +1,72 @@ |
||||
// 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.
|
||||
|
||||
#ifndef PARALLEL_PLUGIN_API_HPP |
||||
#define PARALLEL_PLUGIN_API_HPP |
||||
|
||||
#include <opencv2/core/cvdef.h> |
||||
#include <opencv2/core/llapi/llapi.h> |
||||
|
||||
#include "opencv2/core/parallel/parallel_backend.hpp" |
||||
|
||||
#if !defined(BUILD_PLUGIN) |
||||
|
||||
/// increased for backward-compatible changes, e.g. add new function
|
||||
/// Caller API <= Plugin API -> plugin is fully compatible
|
||||
/// Caller API > Plugin API -> plugin is not fully compatible, caller should use extra checks to use plugins with older API
|
||||
#define API_VERSION 0 // preview
|
||||
|
||||
/// increased for incompatible changes, e.g. remove function argument
|
||||
/// Caller ABI == Plugin ABI -> plugin is compatible
|
||||
/// Caller ABI > Plugin ABI -> plugin is not compatible, caller should use shim code to use old ABI plugins (caller may know how lower ABI works, so it is possible)
|
||||
/// Caller ABI < Plugin ABI -> plugin can't be used (plugin should provide interface with lower ABI to handle that)
|
||||
#define ABI_VERSION 0 // preview
|
||||
|
||||
#else // !defined(BUILD_PLUGIN)
|
||||
|
||||
#if !defined(ABI_VERSION) || !defined(API_VERSION) |
||||
#error "Plugin must define ABI_VERSION and API_VERSION before including parallel_plugin_api.hpp" |
||||
#endif |
||||
|
||||
#endif // !defined(BUILD_PLUGIN)
|
||||
|
||||
typedef cv::parallel::ParallelForAPI* CvPluginParallelBackendAPI; |
||||
|
||||
struct OpenCV_Core_Parallel_Plugin_API_v0_0_api_entries |
||||
{ |
||||
/** @brief Get parallel backend API instance
|
||||
|
||||
@param[out] handle pointer on backend API handle |
||||
|
||||
@note API-CALL 1, API-Version == 0 |
||||
*/ |
||||
CvResult (CV_API_CALL *getInstance)(CV_OUT CvPluginParallelBackendAPI* handle) CV_NOEXCEPT; |
||||
}; // OpenCV_Core_Parallel_Plugin_API_v0_0_api_entries
|
||||
|
||||
typedef struct OpenCV_Core_Parallel_Plugin_API_v0 |
||||
{ |
||||
OpenCV_API_Header api_header; |
||||
struct OpenCV_Core_Parallel_Plugin_API_v0_0_api_entries v0; |
||||
} OpenCV_Core_Parallel_Plugin_API_v0; |
||||
|
||||
#if ABI_VERSION == 0 && API_VERSION == 0 |
||||
typedef OpenCV_Core_Parallel_Plugin_API_v0 OpenCV_Core_Parallel_Plugin_API; |
||||
#else |
||||
#error "Not supported configuration: check ABI_VERSION/API_VERSION" |
||||
#endif |
||||
|
||||
#ifdef BUILD_PLUGIN |
||||
extern "C" { |
||||
|
||||
CV_PLUGIN_EXPORTS |
||||
const OpenCV_Core_Parallel_Plugin_API* CV_API_CALL opencv_core_parallel_plugin_init_v0 |
||||
(int requested_abi_version, int requested_api_version, void* reserved /*NULL*/) CV_NOEXCEPT; |
||||
|
||||
} // extern "C"
|
||||
#else // BUILD_PLUGIN
|
||||
typedef const OpenCV_Core_Parallel_Plugin_API* (CV_API_CALL *FN_opencv_core_parallel_plugin_init_t) |
||||
(int requested_abi_version, int requested_api_version, void* reserved /*NULL*/); |
||||
#endif // BUILD_PLUGIN
|
||||
|
||||
#endif // PARALLEL_PLUGIN_API_HPP
|
@ -0,0 +1,286 @@ |
||||
// 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 parallel.cpp
|
||||
//
|
||||
|
||||
//==================================================================================================
|
||||
// Dynamic backend implementation
|
||||
|
||||
#include "opencv2/core/utils/plugin_loader.private.hpp" |
||||
|
||||
namespace cv { namespace impl { |
||||
|
||||
using namespace cv::parallel; |
||||
|
||||
#if OPENCV_HAVE_FILESYSTEM_SUPPORT && defined(PARALLEL_ENABLE_PLUGINS) |
||||
|
||||
using namespace cv::plugin::impl; // plugin_loader.hpp
|
||||
|
||||
class PluginParallelBackend CV_FINAL: public std::enable_shared_from_this<PluginParallelBackend> |
||||
{ |
||||
protected: |
||||
void initPluginAPI() |
||||
{ |
||||
const char* init_name = "opencv_core_parallel_plugin_init_v0"; |
||||
FN_opencv_core_parallel_plugin_init_t fn_init = reinterpret_cast<FN_opencv_core_parallel_plugin_init_t>(lib_->getSymbol(init_name)); |
||||
if (fn_init) |
||||
{ |
||||
CV_LOG_DEBUG(NULL, "Found entry: '" << init_name << "'"); |
||||
for (int supported_api_version = API_VERSION; supported_api_version >= 0; supported_api_version--) |
||||
{ |
||||
plugin_api_ = fn_init(ABI_VERSION, supported_api_version, NULL); |
||||
if (plugin_api_) |
||||
break; |
||||
} |
||||
if (!plugin_api_) |
||||
{ |
||||
CV_LOG_INFO(NULL, "core(parallel): plugin is incompatible (can't be initialized): " << lib_->getName()); |
||||
return; |
||||
} |
||||
if (!checkCompatibility(plugin_api_->api_header, ABI_VERSION, API_VERSION, false)) |
||||
{ |
||||
plugin_api_ = NULL; |
||||
return; |
||||
} |
||||
CV_LOG_INFO(NULL, "core(parallel): plugin is ready to use '" << plugin_api_->api_header.api_description << "'"); |
||||
} |
||||
else |
||||
{ |
||||
CV_LOG_INFO(NULL, "core(parallel): plugin is incompatible, missing init function: '" << init_name << "', file: " << lib_->getName()); |
||||
} |
||||
} |
||||
|
||||
|
||||
bool checkCompatibility(const OpenCV_API_Header& api_header, unsigned int abi_version, unsigned int api_version, bool checkMinorOpenCVVersion) |
||||
{ |
||||
if (api_header.opencv_version_major != CV_VERSION_MAJOR) |
||||
{ |
||||
CV_LOG_ERROR(NULL, "core(parallel): wrong OpenCV major version used by plugin '" << api_header.api_description << "': " << |
||||
cv::format("%d.%d, OpenCV version is '" CV_VERSION "'", api_header.opencv_version_major, api_header.opencv_version_minor)) |
||||
return false; |
||||
} |
||||
if (!checkMinorOpenCVVersion) |
||||
{ |
||||
// no checks for OpenCV minor version
|
||||
} |
||||
else if (api_header.opencv_version_minor != CV_VERSION_MINOR) |
||||
{ |
||||
CV_LOG_ERROR(NULL, "core(parallel): wrong OpenCV minor version used by plugin '" << api_header.api_description << "': " << |
||||
cv::format("%d.%d, OpenCV version is '" CV_VERSION "'", api_header.opencv_version_major, api_header.opencv_version_minor)) |
||||
return false; |
||||
} |
||||
CV_LOG_DEBUG(NULL, "core(parallel): initialized '" << api_header.api_description << "': built with " |
||||
<< cv::format("OpenCV %d.%d (ABI/API = %d/%d)", |
||||
api_header.opencv_version_major, api_header.opencv_version_minor, |
||||
api_header.min_api_version, api_header.api_version) |
||||
<< ", current OpenCV version is '" CV_VERSION "' (ABI/API = " << abi_version << "/" << api_version << ")" |
||||
); |
||||
if (api_header.min_api_version != abi_version) // future: range can be here
|
||||
{ |
||||
// actually this should never happen due to checks in plugin's init() function
|
||||
CV_LOG_ERROR(NULL, "core(parallel): plugin is not supported due to incompatible ABI = " << api_header.min_api_version); |
||||
return false; |
||||
} |
||||
if (api_header.api_version != api_version) |
||||
{ |
||||
CV_LOG_INFO(NULL, "core(parallel): NOTE: plugin is supported, but there is API version mismath: " |
||||
<< cv::format("plugin API level (%d) != OpenCV API level (%d)", api_header.api_version, api_version)); |
||||
if (api_header.api_version < api_version) |
||||
{ |
||||
CV_LOG_INFO(NULL, "core(parallel): NOTE: some functionality may be unavailable due to lack of support by plugin implementation"); |
||||
} |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
public: |
||||
std::shared_ptr<cv::plugin::impl::DynamicLib> lib_; |
||||
const OpenCV_Core_Parallel_Plugin_API* plugin_api_; |
||||
|
||||
PluginParallelBackend(const std::shared_ptr<cv::plugin::impl::DynamicLib>& lib) |
||||
: lib_(lib) |
||||
, plugin_api_(NULL) |
||||
{ |
||||
initPluginAPI(); |
||||
} |
||||
|
||||
std::shared_ptr<cv::parallel::ParallelForAPI> create() const |
||||
{ |
||||
CV_Assert(plugin_api_); |
||||
|
||||
CvPluginParallelBackendAPI instancePtr = NULL; |
||||
|
||||
if (plugin_api_->v0.getInstance) |
||||
{ |
||||
if (CV_ERROR_OK == plugin_api_->v0.getInstance(&instancePtr)) |
||||
{ |
||||
CV_Assert(instancePtr); |
||||
// TODO C++20 "aliasing constructor"
|
||||
return std::shared_ptr<cv::parallel::ParallelForAPI>(instancePtr, [](cv::parallel::ParallelForAPI*){}); // empty deleter
|
||||
} |
||||
} |
||||
return std::shared_ptr<cv::parallel::ParallelForAPI>(); |
||||
} |
||||
}; |
||||
|
||||
|
||||
class PluginParallelBackendFactory CV_FINAL: public IParallelBackendFactory |
||||
{ |
||||
public: |
||||
std::string baseName_; |
||||
std::shared_ptr<PluginParallelBackend> backend; |
||||
bool initialized; |
||||
public: |
||||
PluginParallelBackendFactory(const std::string& baseName) |
||||
: baseName_(baseName) |
||||
, initialized(false) |
||||
{ |
||||
// nothing, plugins are loaded on demand
|
||||
} |
||||
|
||||
std::shared_ptr<cv::parallel::ParallelForAPI> create() const CV_OVERRIDE |
||||
{ |
||||
if (!initialized) |
||||
{ |
||||
const_cast<PluginParallelBackendFactory*>(this)->initBackend(); |
||||
} |
||||
if (backend) |
||||
return backend->create(); |
||||
return std::shared_ptr<cv::parallel::ParallelForAPI>(); |
||||
} |
||||
protected: |
||||
void initBackend() |
||||
{ |
||||
AutoLock lock(getInitializationMutex()); |
||||
try |
||||
{ |
||||
if (!initialized) |
||||
loadPlugin(); |
||||
} |
||||
catch (...) |
||||
{ |
||||
CV_LOG_INFO(NULL, "core(parallel): exception during plugin loading: " << baseName_ << ". SKIP"); |
||||
} |
||||
initialized = true; |
||||
} |
||||
void loadPlugin(); |
||||
}; |
||||
|
||||
static |
||||
std::vector<FileSystemPath_t> getPluginCandidates(const std::string& baseName) |
||||
{ |
||||
using namespace cv::utils; |
||||
using namespace cv::utils::fs; |
||||
const std::string baseName_l = toLowerCase(baseName); |
||||
const std::string baseName_u = toUpperCase(baseName); |
||||
const FileSystemPath_t baseName_l_fs = toFileSystemPath(baseName_l); |
||||
std::vector<FileSystemPath_t> paths; |
||||
// TODO OPENCV_PLUGIN_PATH
|
||||
const std::vector<std::string> paths_ = getConfigurationParameterPaths("OPENCV_CORE_PLUGIN_PATH", std::vector<std::string>()); |
||||
if (paths_.size() != 0) |
||||
{ |
||||
for (size_t i = 0; i < paths_.size(); i++) |
||||
{ |
||||
paths.push_back(toFileSystemPath(paths_[i])); |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
FileSystemPath_t binaryLocation; |
||||
if (getBinLocation(binaryLocation)) |
||||
{ |
||||
binaryLocation = getParent(binaryLocation); |
||||
#ifndef CV_CORE_PARALLEL_PLUGIN_SUBDIRECTORY |
||||
paths.push_back(binaryLocation); |
||||
#else |
||||
paths.push_back(binaryLocation + toFileSystemPath("/") + toFileSystemPath(CV_CORE_PARALLEL_PLUGIN_SUBDIRECTORY_STR)); |
||||
#endif |
||||
} |
||||
} |
||||
const std::string default_expr = libraryPrefix() + "opencv_core_parallel_" + baseName_l + "*" + librarySuffix(); |
||||
const std::string plugin_expr = getConfigurationParameterString((std::string("OPENCV_CORE_PARALLEL_PLUGIN_") + baseName_u).c_str(), default_expr.c_str()); |
||||
std::vector<FileSystemPath_t> results; |
||||
#ifdef _WIN32 |
||||
FileSystemPath_t moduleName = toFileSystemPath(libraryPrefix() + "opencv_core_parallel_" + baseName_l + librarySuffix()); |
||||
if (plugin_expr != default_expr) |
||||
{ |
||||
moduleName = toFileSystemPath(plugin_expr); |
||||
results.push_back(moduleName); |
||||
} |
||||
for (const FileSystemPath_t& path : paths) |
||||
{ |
||||
results.push_back(path + L"\\" + moduleName); |
||||
} |
||||
results.push_back(moduleName); |
||||
#else |
||||
CV_LOG_DEBUG(NULL, "core(parallel): " << baseName << " plugin's glob is '" << plugin_expr << "', " << paths.size() << " location(s)"); |
||||
for (const std::string& path : paths) |
||||
{ |
||||
if (path.empty()) |
||||
continue; |
||||
std::vector<std::string> candidates; |
||||
cv::glob(utils::fs::join(path, plugin_expr), candidates); |
||||
CV_LOG_DEBUG(NULL, " - " << path << ": " << candidates.size()); |
||||
copy(candidates.begin(), candidates.end(), back_inserter(results)); |
||||
} |
||||
#endif |
||||
CV_LOG_DEBUG(NULL, "Found " << results.size() << " plugin(s) for " << baseName); |
||||
return results; |
||||
} |
||||
|
||||
void PluginParallelBackendFactory::loadPlugin() |
||||
{ |
||||
for (const FileSystemPath_t& plugin : getPluginCandidates(baseName_)) |
||||
{ |
||||
auto lib = std::make_shared<cv::plugin::impl::DynamicLib>(plugin); |
||||
if (!lib->isLoaded()) |
||||
{ |
||||
continue; |
||||
} |
||||
try |
||||
{ |
||||
auto pluginBackend = std::make_shared<PluginParallelBackend>(lib); |
||||
if (!pluginBackend) |
||||
{ |
||||
continue; |
||||
} |
||||
if (pluginBackend->plugin_api_ == NULL) |
||||
{ |
||||
CV_LOG_ERROR(NULL, "core(parallel): no compatible plugin API for backend: " << baseName_ << " in " << toPrintablePath(plugin)); |
||||
continue; |
||||
} |
||||
#if !defined(_WIN32) |
||||
// NB: we are going to use parallel backend, so prevent automatic library unloading
|
||||
// (avoid uncontrolled crashes in worker threads of underlying libraries: libgomp, libtbb)
|
||||
// details: https://github.com/opencv/opencv/pull/19470#pullrequestreview-589834777
|
||||
lib->disableAutomaticLibraryUnloading(); |
||||
#endif |
||||
backend = pluginBackend; |
||||
return; |
||||
} |
||||
catch (...) |
||||
{ |
||||
CV_LOG_WARNING(NULL, "core(parallel): exception during plugin initialization: " << toPrintablePath(plugin) << ". SKIP"); |
||||
} |
||||
} |
||||
} |
||||
|
||||
#endif // OPENCV_HAVE_FILESYSTEM_SUPPORT && defined(PARALLEL_ENABLE_PLUGINS)
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace parallel { |
||||
|
||||
std::shared_ptr<IParallelBackendFactory> createPluginParallelBackendFactory(const std::string& baseName) |
||||
{ |
||||
#if OPENCV_HAVE_FILESYSTEM_SUPPORT && defined(PARALLEL_ENABLE_PLUGINS) |
||||
return std::make_shared<impl::PluginParallelBackendFactory>(baseName); |
||||
#else |
||||
return std::shared_ptr<IParallelBackendFactory>(); |
||||
#endif |
||||
} |
||||
|
||||
}} // namespace
|
@ -0,0 +1,25 @@ |
||||
// 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.
|
||||
|
||||
#ifndef OPENCV_CORE_PARALLEL_REGISTRY_HPP |
||||
#define OPENCV_CORE_PARALLEL_REGISTRY_HPP |
||||
|
||||
#include "factory_parallel.hpp" |
||||
|
||||
namespace cv { namespace parallel { |
||||
|
||||
struct ParallelBackendInfo |
||||
{ |
||||
int priority; // 1000-<index*10> - default builtin priority
|
||||
// 0 - disabled (OPENCV_PARALLEL_PRIORITY_<name> = 0)
|
||||
// >10000 - prioritized list (OPENCV_PARALLEL_PRIORITY_LIST)
|
||||
std::string name; |
||||
std::shared_ptr<IParallelBackendFactory> backendFactory; |
||||
}; |
||||
|
||||
const std::vector<ParallelBackendInfo>& getParallelBackendsInfo(); |
||||
|
||||
}} // namespace
|
||||
|
||||
#endif // OPENCV_CORE_PARALLEL_REGISTRY_HPP
|
@ -0,0 +1,167 @@ |
||||
// 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 parallel.cpp
|
||||
//
|
||||
|
||||
namespace cv { namespace parallel { |
||||
|
||||
#define DECLARE_DYNAMIC_BACKEND(name) \ |
||||
ParallelBackendInfo { \
|
||||
1000, name, createPluginParallelBackendFactory(name) \
|
||||
} |
||||
|
||||
#define DECLARE_STATIC_BACKEND(name, createBackendAPI) \ |
||||
ParallelBackendInfo { \
|
||||
1000, name, std::make_shared<cv::parallel::StaticBackendFactory>([=] () -> std::shared_ptr<cv::parallel::ParallelForAPI> { return createBackendAPI(); }) \
|
||||
} |
||||
|
||||
static |
||||
std::vector<ParallelBackendInfo>& getBuiltinParallelBackendsInfo() |
||||
{ |
||||
static std::vector<ParallelBackendInfo> g_backends |
||||
{ |
||||
#ifdef HAVE_TBB |
||||
DECLARE_STATIC_BACKEND("TBB", createParallelBackendTBB), |
||||
#elif defined(PARALLEL_ENABLE_PLUGINS) |
||||
DECLARE_DYNAMIC_BACKEND("ONETBB"), // dedicated oneTBB plugin (interface >= 12000, binary incompatibe with TBB 2017-2020)
|
||||
DECLARE_DYNAMIC_BACKEND("TBB"), // generic TBB plugins
|
||||
#endif |
||||
|
||||
#ifdef HAVE_OPENMP |
||||
DECLARE_STATIC_BACKEND("OPENMP", createParallelBackendOpenMP), |
||||
#elif defined(PARALLEL_ENABLE_PLUGINS) |
||||
DECLARE_DYNAMIC_BACKEND("OPENMP") // TODO Intel OpenMP?
|
||||
#endif |
||||
}; |
||||
return g_backends; |
||||
}; |
||||
|
||||
static |
||||
bool sortByPriority(const ParallelBackendInfo &lhs, const ParallelBackendInfo &rhs) |
||||
{ |
||||
return lhs.priority > rhs.priority; |
||||
} |
||||
|
||||
/** @brief Manages list of enabled backends
|
||||
*/ |
||||
class ParallelBackendRegistry |
||||
{ |
||||
protected: |
||||
std::vector<ParallelBackendInfo> enabledBackends; |
||||
ParallelBackendRegistry() |
||||
{ |
||||
enabledBackends = getBuiltinParallelBackendsInfo(); |
||||
int N = (int)enabledBackends.size(); |
||||
for (int i = 0; i < N; i++) |
||||
{ |
||||
ParallelBackendInfo& info = enabledBackends[i]; |
||||
info.priority = 1000 - i * 10; |
||||
} |
||||
CV_LOG_DEBUG(NULL, "core(parallel): Builtin backends(" << N << "): " << dumpBackends()); |
||||
if (readPrioritySettings()) |
||||
{ |
||||
CV_LOG_INFO(NULL, "core(parallel): Updated backends priorities: " << dumpBackends()); |
||||
N = (int)enabledBackends.size(); |
||||
} |
||||
int enabled = 0; |
||||
for (int i = 0; i < N; i++) |
||||
{ |
||||
ParallelBackendInfo& info = enabledBackends[enabled]; |
||||
if (enabled != i) |
||||
info = enabledBackends[i]; |
||||
size_t param_priority = utils::getConfigurationParameterSizeT(cv::format("OPENCV_PARALLEL_PRIORITY_%s", info.name.c_str()).c_str(), (size_t)info.priority); |
||||
CV_Assert(param_priority == (size_t)(int)param_priority); // overflow check
|
||||
if (param_priority > 0) |
||||
{ |
||||
info.priority = (int)param_priority; |
||||
enabled++; |
||||
} |
||||
else |
||||
{ |
||||
CV_LOG_INFO(NULL, "core(parallel): Disable backend: " << info.name); |
||||
} |
||||
} |
||||
enabledBackends.resize(enabled); |
||||
CV_LOG_DEBUG(NULL, "core(parallel): Available backends(" << enabled << "): " << dumpBackends()); |
||||
std::sort(enabledBackends.begin(), enabledBackends.end(), sortByPriority); |
||||
CV_LOG_INFO(NULL, "core(parallel): Enabled backends(" << enabled << ", sorted by priority): " << (enabledBackends.empty() ? std::string("N/A") : dumpBackends())); |
||||
} |
||||
|
||||
static std::vector<std::string> tokenize_string(const std::string& input, char token) |
||||
{ |
||||
std::vector<std::string> result; |
||||
std::string::size_type prev_pos = 0, pos = 0; |
||||
while((pos = input.find(token, pos)) != std::string::npos) |
||||
{ |
||||
result.push_back(input.substr(prev_pos, pos-prev_pos)); |
||||
prev_pos = ++pos; |
||||
} |
||||
result.push_back(input.substr(prev_pos)); |
||||
return result; |
||||
} |
||||
bool readPrioritySettings() |
||||
{ |
||||
bool hasChanges = false; |
||||
cv::String prioritized_backends = utils::getConfigurationParameterString("OPENCV_PARALLEL_PRIORITY_LIST", NULL); |
||||
if (prioritized_backends.empty()) |
||||
return hasChanges; |
||||
CV_LOG_INFO(NULL, "core(parallel): Configured priority list (OPENCV_PARALLEL_PRIORITY_LIST): " << prioritized_backends); |
||||
const std::vector<std::string> names = tokenize_string(prioritized_backends, ','); |
||||
for (size_t i = 0; i < names.size(); i++) |
||||
{ |
||||
const std::string& name = names[i]; |
||||
int priority = (int)(100000 + (names.size() - i) * 1000); |
||||
bool found = false; |
||||
for (size_t k = 0; k < enabledBackends.size(); k++) |
||||
{ |
||||
ParallelBackendInfo& info = enabledBackends[k]; |
||||
if (name == info.name) |
||||
{ |
||||
info.priority = priority; |
||||
CV_LOG_DEBUG(NULL, "core(parallel): New backend priority: '" << name << "' => " << info.priority); |
||||
found = true; |
||||
hasChanges = true; |
||||
break; |
||||
} |
||||
} |
||||
if (!found) |
||||
{ |
||||
CV_LOG_INFO(NULL, "core(parallel): Adding parallel backend (plugin): '" << name << "'"); |
||||
enabledBackends.push_back(ParallelBackendInfo{priority, name, createPluginParallelBackendFactory(name)}); |
||||
hasChanges = true; |
||||
} |
||||
} |
||||
return hasChanges; |
||||
} |
||||
public: |
||||
std::string dumpBackends() const |
||||
{ |
||||
std::ostringstream os; |
||||
for (size_t i = 0; i < enabledBackends.size(); i++) |
||||
{ |
||||
if (i > 0) os << "; "; |
||||
const ParallelBackendInfo& info = enabledBackends[i]; |
||||
os << info.name << '(' << info.priority << ')'; |
||||
} |
||||
return os.str(); |
||||
} |
||||
|
||||
static ParallelBackendRegistry& getInstance() |
||||
{ |
||||
static ParallelBackendRegistry g_instance; |
||||
return g_instance; |
||||
} |
||||
|
||||
inline const std::vector<ParallelBackendInfo>& getEnabledBackends() const { return enabledBackends; } |
||||
}; |
||||
|
||||
|
||||
const std::vector<ParallelBackendInfo>& getParallelBackendsInfo() |
||||
{ |
||||
return cv::parallel::ParallelBackendRegistry::getInstance().getEnabledBackends(); |
||||
} |
||||
|
||||
}} // namespace
|
@ -0,0 +1,80 @@ |
||||
// 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 filesystem.cpp
|
||||
//
|
||||
|
||||
#include "opencv2/core/utils/plugin_loader.private.hpp" |
||||
|
||||
#if !OPENCV_HAVE_FILESYSTEM_SUPPORT |
||||
#error "Invalid build configuration" |
||||
#endif |
||||
|
||||
#if 0 // TODO
|
||||
#ifdef NDEBUG |
||||
#define CV_LOG_STRIP_LEVEL CV_LOG_LEVEL_DEBUG + 1 |
||||
#else |
||||
#define CV_LOG_STRIP_LEVEL CV_LOG_LEVEL_VERBOSE + 1 |
||||
#endif |
||||
#include <opencv2/core/utils/logger.hpp> |
||||
#endif |
||||
|
||||
namespace cv { namespace plugin { namespace impl { |
||||
|
||||
DynamicLib::DynamicLib(const FileSystemPath_t& filename) |
||||
: handle(0), fname(filename), disableAutoUnloading_(false) |
||||
{ |
||||
libraryLoad(filename); |
||||
} |
||||
|
||||
DynamicLib::~DynamicLib() |
||||
{ |
||||
if (!disableAutoUnloading_) |
||||
{ |
||||
libraryRelease(); |
||||
} |
||||
else if (handle) |
||||
{ |
||||
CV_LOG_INFO(NULL, "skip auto unloading (disabled): " << toPrintablePath(fname)); |
||||
handle = 0; |
||||
} |
||||
} |
||||
|
||||
void* DynamicLib::getSymbol(const char* symbolName) const |
||||
{ |
||||
if (!handle) |
||||
{ |
||||
return 0; |
||||
} |
||||
void* res = getSymbol_(handle, symbolName); |
||||
if (!res) |
||||
{ |
||||
CV_LOG_DEBUG(NULL, "No symbol '" << symbolName << "' in " << toPrintablePath(fname)); |
||||
} |
||||
return res; |
||||
} |
||||
|
||||
const std::string DynamicLib::getName() const |
||||
{ |
||||
return toPrintablePath(fname); |
||||
} |
||||
|
||||
void DynamicLib::libraryLoad(const FileSystemPath_t& filename) |
||||
{ |
||||
handle = libraryLoad_(filename); |
||||
CV_LOG_INFO(NULL, "load " << toPrintablePath(filename) << " => " << (handle ? "OK" : "FAILED")); |
||||
} |
||||
|
||||
void DynamicLib::libraryRelease() |
||||
{ |
||||
if (handle) |
||||
{ |
||||
CV_LOG_INFO(NULL, "unload "<< toPrintablePath(fname)); |
||||
libraryRelease_(handle); |
||||
handle = 0; |
||||
} |
||||
} |
||||
|
||||
}}} // namespace
|
@ -1,80 +0,0 @@ |
||||
#============================================= |
||||
# standalone build |
||||
|
||||
include(FindPkgConfig) |
||||
|
||||
#============================================= |
||||
# build with OpenCV |
||||
include("${OpenCV_SOURCE_DIR}/cmake/OpenCVUtils.cmake") |
||||
|
||||
function(ocv_create_videoio_plugin default_name target target_desc videoio_src_file) |
||||
|
||||
set(OPENCV_PLUGIN_NAME ${default_name} CACHE STRING "") |
||||
set(OPENCV_PLUGIN_DESTINATION "" CACHE PATH "") |
||||
project(${OPENCV_PLUGIN_NAME} LANGUAGES CXX) |
||||
|
||||
set(BUILD_SHARED_LIBS ON CACHE BOOL "") |
||||
if(NOT BUILD_SHARED_LIBS) |
||||
message(FATAL_ERROR "Static plugin build does not make sense") |
||||
endif() |
||||
|
||||
if(NOT OpenCV_SOURCE_DIR) |
||||
message(FATAL_ERROR "OpenCV_SOURCE_DIR must be set to build the plugin!") |
||||
endif() |
||||
|
||||
include("${OpenCV_SOURCE_DIR}/modules/videoio/cmake/init.cmake") |
||||
|
||||
if(NOT TARGET ${target}) |
||||
message(FATAL_ERROR "${target_desc} was not found!") |
||||
endif() |
||||
|
||||
get_filename_component(modules_ROOT "${CMAKE_CURRENT_LIST_DIR}/../../.." ABSOLUTE) |
||||
set(videoio_ROOT "${modules_ROOT}/videoio") |
||||
set(core_ROOT "${modules_ROOT}/core") |
||||
set(imgproc_ROOT "${modules_ROOT}/imgproc") |
||||
set(imgcodecs_ROOT "${modules_ROOT}/imgcodecs") |
||||
|
||||
add_library(${OPENCV_PLUGIN_NAME} MODULE |
||||
"${videoio_ROOT}/src/${videoio_src_file}" |
||||
${OPENCV_PLUGIN_EXTRA_SRC_FILES} |
||||
) |
||||
target_include_directories(${OPENCV_PLUGIN_NAME} PRIVATE |
||||
"${CMAKE_CURRENT_BINARY_DIR}" |
||||
"${videoio_ROOT}/src" |
||||
"${videoio_ROOT}/include" |
||||
"${core_ROOT}/include" |
||||
"${imgproc_ROOT}/include" |
||||
"${imgcodecs_ROOT}/include" |
||||
) |
||||
target_compile_definitions(${OPENCV_PLUGIN_NAME} PRIVATE BUILD_PLUGIN) |
||||
|
||||
target_link_libraries(${OPENCV_PLUGIN_NAME} PRIVATE ${target}) |
||||
set_target_properties(${OPENCV_PLUGIN_NAME} PROPERTIES |
||||
CXX_STANDARD 11 |
||||
CXX_VISIBILITY_PRESET hidden |
||||
) |
||||
|
||||
if(DEFINED OPENCV_PLUGIN_MODULE_PREFIX) |
||||
set_target_properties(${OPENCV_PLUGIN_NAME} PROPERTIES PREFIX "${OPENCV_PLUGIN_MODULE_PREFIX}") |
||||
endif() |
||||
|
||||
# Hack for Windows |
||||
if(WIN32) |
||||
find_package(OpenCV REQUIRED core imgproc videoio) |
||||
target_link_libraries(${OPENCV_PLUGIN_NAME} PRIVATE ${OpenCV_LIBS}) |
||||
endif() |
||||
|
||||
if(NOT OpenCV_FOUND) # build against sources (Linux) |
||||
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/opencv2/opencv_modules.hpp" "#pragma once") |
||||
endif() |
||||
|
||||
if(OPENCV_PLUGIN_DESTINATION) |
||||
set_target_properties(${OPENCV_PLUGIN_NAME} PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${OPENCV_PLUGIN_DESTINATION}") |
||||
message(STATUS "Output destination: ${OPENCV_PLUGIN_DESTINATION}") |
||||
endif() |
||||
|
||||
install(TARGETS ${OPENCV_PLUGIN_NAME} LIBRARY DESTINATION . COMPONENT plugins) |
||||
|
||||
message(STATUS "Library name: ${OPENCV_PLUGIN_NAME}") |
||||
|
||||
endfunction() |
@ -1,8 +1,13 @@ |
||||
cmake_minimum_required(VERSION 3.5) |
||||
|
||||
set(OpenCV_SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}/../../../..") |
||||
get_filename_component(OpenCV_SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}/../../../.." ABSOLUTE) |
||||
include("${OpenCV_SOURCE_DIR}/cmake/OpenCVPluginStandalone.cmake") |
||||
|
||||
# scan dependencies |
||||
set(WITH_GSTREAMER ON) |
||||
include("${OpenCV_SOURCE_DIR}/modules/videoio/cmake/plugin_standalone.cmake") |
||||
ocv_create_videoio_plugin("opencv_videoio_gstreamer" "ocv.3rdparty.gstreamer" "GStreamer" "cap_gstreamer.cpp") |
||||
include("${OpenCV_SOURCE_DIR}/modules/videoio/cmake/init.cmake") |
||||
|
||||
set(OPENCV_PLUGIN_DEPS core imgproc imgcodecs) |
||||
ocv_create_plugin(videoio "opencv_videoio_gstreamer" "ocv.3rdparty.gstreamer" "GStreamer" "src/cap_gstreamer.cpp") |
||||
|
||||
message(STATUS "Using GStreamer: ${GSTREAMER_VERSION}") |
||||
|
Loading…
Reference in new issue