parent
ca7f964104
commit
43b2bb2c25
27 changed files with 1025 additions and 122 deletions
@ -0,0 +1,29 @@ |
|||||||
|
if(PROJECT_NAME STREQUAL "OpenCV") |
||||||
|
set(ENABLE_PLUGINS_DEFAULT ON) |
||||||
|
if(EMSCRIPTEN OR IOS OR WINRT) |
||||||
|
set(ENABLE_PLUGINS_DEFAULT OFF) |
||||||
|
endif() |
||||||
|
set(DNN_PLUGIN_LIST "" CACHE STRING "List of DNN backends to be compiled as plugins (openvino, etc or special value 'all')") |
||||||
|
set(DNN_ENABLE_PLUGINS "${ENABLE_PLUGINS_DEFAULT}" CACHE BOOL "Allow building and using of DNN plugins") |
||||||
|
mark_as_advanced(DNN_PLUGIN_LIST DNN_ENABLE_PLUGINS) |
||||||
|
|
||||||
|
string(REPLACE "," ";" DNN_PLUGIN_LIST "${DNN_PLUGIN_LIST}") # support comma-separated list (,) too |
||||||
|
string(TOLOWER "${DNN_PLUGIN_LIST}" DNN_PLUGIN_LIST) |
||||||
|
if(NOT DNN_ENABLE_PLUGINS) |
||||||
|
if(DNN_PLUGIN_LIST) |
||||||
|
message(WARNING "DNN: plugins are disabled through DNN_ENABLE_PLUGINS, so DNN_PLUGIN_LIST='${DNN_PLUGIN_LIST}' is ignored") |
||||||
|
set(DNN_PLUGIN_LIST "") |
||||||
|
endif() |
||||||
|
else() |
||||||
|
# Make virtual plugins target |
||||||
|
if(NOT TARGET opencv_dnn_plugins) |
||||||
|
add_custom_target(opencv_dnn_plugins ALL) |
||||||
|
endif() |
||||||
|
endif() |
||||||
|
endif() |
||||||
|
|
||||||
|
# |
||||||
|
# Detect available dependencies |
||||||
|
# |
||||||
|
|
||||||
|
# OpenVINO - detected by main CMake scripts (shared with G-API) |
@ -0,0 +1,80 @@ |
|||||||
|
function(ocv_create_builtin_dnn_plugin name target) |
||||||
|
|
||||||
|
ocv_debug_message("ocv_create_builtin_dnn_plugin(${ARGV})") |
||||||
|
|
||||||
|
if(NOT TARGET ${target}) |
||||||
|
message(FATAL_ERROR "${target} does not exist!") |
||||||
|
endif() |
||||||
|
if(NOT OpenCV_SOURCE_DIR) |
||||||
|
message(FATAL_ERROR "OpenCV_SOURCE_DIR must be set to build the plugin!") |
||||||
|
endif() |
||||||
|
|
||||||
|
message(STATUS "DNN: add builtin plugin '${name}'") |
||||||
|
|
||||||
|
set(ENABLE_PRECOMPILED_HEADERS OFF) # no support for PCH in plugins, conflicts with module's source files |
||||||
|
|
||||||
|
# TODO: update CPU optimizations scripts to support plugins |
||||||
|
add_definitions(-D__OPENCV_BUILD=1) |
||||||
|
add_definitions(-DBUILD_PLUGIN=1) |
||||||
|
include_directories("${OPENCV_MODULE_opencv_dnn_BINARY_DIR}") # Cannot open include file: 'layers/layers_common.simd_declarations.hpp' |
||||||
|
|
||||||
|
foreach(src ${ARGN}) |
||||||
|
if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/src/${src}") |
||||||
|
list(APPEND sources "${CMAKE_CURRENT_LIST_DIR}/src/${src}") |
||||||
|
elseif(IS_ABSOLUTE "${src}") |
||||||
|
list(APPEND sources "${src}") |
||||||
|
else() |
||||||
|
message(FATAL_ERROR "Unknown source: ${src}") |
||||||
|
endif() |
||||||
|
endforeach() |
||||||
|
|
||||||
|
if(OPENCV_MODULE_${the_module}_SOURCES_DISPATCHED) |
||||||
|
list(APPEND sources ${OPENCV_MODULE_${the_module}_SOURCES_DISPATCHED}) |
||||||
|
endif() |
||||||
|
|
||||||
|
set(__${name}_DEPS_EXT "") |
||||||
|
ocv_compiler_optimization_process_sources(sources __${name}_DEPS_EXT ${name}) |
||||||
|
|
||||||
|
add_library(${name} MODULE ${sources}) |
||||||
|
target_include_directories(${name} PRIVATE "${CMAKE_CURRENT_BINARY_DIR}") |
||||||
|
target_link_libraries(${name} PRIVATE ${target} ${__${name}_DEPS_EXT}) |
||||||
|
target_link_libraries(${name} PRIVATE ${__plugin_libs}) |
||||||
|
|
||||||
|
foreach(mod opencv_dnn |
||||||
|
opencv_core |
||||||
|
opencv_imgproc |
||||||
|
opencv_dnn |
||||||
|
) |
||||||
|
ocv_target_link_libraries(${name} LINK_PRIVATE ${mod}) |
||||||
|
ocv_target_include_directories(${name} "${OPENCV_MODULE_${mod}_LOCATION}/include") |
||||||
|
endforeach() |
||||||
|
|
||||||
|
if(WIN32) |
||||||
|
set(OPENCV_PLUGIN_VERSION "${OPENCV_DLLVERSION}" CACHE STRING "") |
||||||
|
if(CMAKE_CXX_SIZEOF_DATA_PTR EQUAL 8) |
||||||
|
set(OPENCV_PLUGIN_ARCH "_64" CACHE STRING "") |
||||||
|
else() |
||||||
|
set(OPENCV_PLUGIN_ARCH "" CACHE STRING "") |
||||||
|
endif() |
||||||
|
else() |
||||||
|
set(OPENCV_PLUGIN_VERSION "" CACHE STRING "") |
||||||
|
set(OPENCV_PLUGIN_ARCH "" CACHE STRING "") |
||||||
|
endif() |
||||||
|
|
||||||
|
set_target_properties(${name} PROPERTIES |
||||||
|
CXX_STANDARD 11 |
||||||
|
CXX_VISIBILITY_PRESET hidden |
||||||
|
DEBUG_POSTFIX "${OPENCV_DEBUG_POSTFIX}" |
||||||
|
OUTPUT_NAME "${name}${OPENCV_PLUGIN_VERSION}${OPENCV_PLUGIN_ARCH}" |
||||||
|
) |
||||||
|
|
||||||
|
if(WIN32) |
||||||
|
set_target_properties(${name} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${EXECUTABLE_OUTPUT_PATH}) |
||||||
|
install(TARGETS ${name} OPTIONAL LIBRARY DESTINATION ${OPENCV_BIN_INSTALL_PATH} COMPONENT plugins) |
||||||
|
else() |
||||||
|
install(TARGETS ${name} OPTIONAL LIBRARY DESTINATION ${OPENCV_LIB_INSTALL_PATH} COMPONENT plugins) |
||||||
|
endif() |
||||||
|
|
||||||
|
add_dependencies(opencv_dnn_plugins ${name}) |
||||||
|
|
||||||
|
endfunction() |
@ -0,0 +1,2 @@ |
|||||||
|
#include_directories("${OPENCV_MODULE_opencv_dnn_BINARY_DIR}") # Cannot open include file: 'layers/layers_common.simd_declarations.hpp' |
||||||
|
ocv_create_builtin_dnn_plugin(opencv_dnn_openvino ocv.3rdparty.openvino ${dnn_plugin_srcs}) |
@ -0,0 +1,31 @@ |
|||||||
|
// 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 "backend.hpp" |
||||||
|
|
||||||
|
#include <opencv2/core/private.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 "factory.hpp" |
||||||
|
|
||||||
|
#include "plugin_api.hpp" |
||||||
|
#include "plugin_wrapper.impl.hpp" |
||||||
|
|
||||||
|
|
||||||
|
namespace cv { namespace dnn_backend { |
||||||
|
|
||||||
|
NetworkBackend::~NetworkBackend() |
||||||
|
{ |
||||||
|
// nothing
|
||||||
|
} |
||||||
|
|
||||||
|
}} // namespace cv::dnn_backend
|
@ -0,0 +1,43 @@ |
|||||||
|
// 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_DNN_BACKEND_HPP |
||||||
|
#define OPENCV_DNN_BACKEND_HPP |
||||||
|
|
||||||
|
#include <memory> |
||||||
|
#include <map> |
||||||
|
|
||||||
|
namespace cv { namespace dnn_backend { |
||||||
|
|
||||||
|
using namespace cv::dnn; |
||||||
|
|
||||||
|
class CV_EXPORTS NetworkBackend |
||||||
|
{ |
||||||
|
public: |
||||||
|
virtual ~NetworkBackend(); |
||||||
|
|
||||||
|
virtual void switchBackend(Net& net) = 0; |
||||||
|
|
||||||
|
/**
|
||||||
|
@param loaderID use empty "" for auto |
||||||
|
@param model see cv::dnn::readNetwork |
||||||
|
@param config see cv::dnn::readNetwork |
||||||
|
*/ |
||||||
|
virtual Net readNetwork(const std::string& loaderID, const std::string& model, const std::string& config) = 0; |
||||||
|
|
||||||
|
/** @overload */ |
||||||
|
virtual Net readNetwork( |
||||||
|
const std::string& loaderID, |
||||||
|
const uchar* bufferModelConfigPtr, size_t bufferModelConfigSize, |
||||||
|
const uchar* bufferWeightsPtr, size_t bufferWeightsSize |
||||||
|
) = 0; |
||||||
|
|
||||||
|
// TODO: target as string + configuration
|
||||||
|
virtual bool checkTarget(Target target) = 0; |
||||||
|
}; |
||||||
|
|
||||||
|
|
||||||
|
} // namespace dnn_backend
|
||||||
|
} // namespace cv
|
||||||
|
|
||||||
|
#endif // OPENCV_DNN_BACKEND_HPP
|
@ -0,0 +1,30 @@ |
|||||||
|
// 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_DNN_FACTORY_HPP |
||||||
|
#define OPENCV_DNN_FACTORY_HPP |
||||||
|
|
||||||
|
#include "backend.hpp" |
||||||
|
|
||||||
|
namespace cv { namespace dnn_backend { |
||||||
|
|
||||||
|
class IDNNBackendFactory |
||||||
|
{ |
||||||
|
public: |
||||||
|
virtual ~IDNNBackendFactory() {} |
||||||
|
virtual std::shared_ptr<cv::dnn_backend::NetworkBackend> createNetworkBackend() const = 0; |
||||||
|
}; |
||||||
|
|
||||||
|
//
|
||||||
|
// PluginDNNBackendFactory is implemented in plugin_wrapper
|
||||||
|
//
|
||||||
|
|
||||||
|
std::shared_ptr<IDNNBackendFactory> createPluginDNNBackendFactory(const std::string& baseName); |
||||||
|
|
||||||
|
/// @brief Returns createPluginDNNBackendFactory()->createNetworkBackend()
|
||||||
|
cv::dnn_backend::NetworkBackend& createPluginDNNNetworkBackend(const std::string& baseName); |
||||||
|
|
||||||
|
}} // namespace
|
||||||
|
|
||||||
|
#endif // OPENCV_DNN_FACTORY_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.
|
||||||
|
|
||||||
|
#ifndef DNN_PLUGIN_API_HPP |
||||||
|
#define DNN_PLUGIN_API_HPP |
||||||
|
|
||||||
|
#include <opencv2/core/cvdef.h> |
||||||
|
#include <opencv2/core/llapi/llapi.h> |
||||||
|
|
||||||
|
#include "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 plugin_api.hpp" |
||||||
|
#endif |
||||||
|
|
||||||
|
#endif // !defined(BUILD_PLUGIN)
|
||||||
|
|
||||||
|
typedef cv::dnn_backend::NetworkBackend* CvPluginDNNNetworkBackend; |
||||||
|
|
||||||
|
struct OpenCV_DNN_Plugin_API_v0_0_api_entries |
||||||
|
{ |
||||||
|
/** @brief Get backend API instance
|
||||||
|
|
||||||
|
@param[out] handle pointer on inference backend API handle |
||||||
|
|
||||||
|
@note API-CALL 1, API-Version == 0 |
||||||
|
*/ |
||||||
|
CvResult (CV_API_CALL *getInstance)(CV_OUT CvPluginDNNNetworkBackend* handle) CV_NOEXCEPT; |
||||||
|
}; // OpenCV_DNN_Plugin_API_v0_0_api_entries
|
||||||
|
|
||||||
|
typedef struct OpenCV_DNN_Plugin_API_v0 |
||||||
|
{ |
||||||
|
OpenCV_API_Header api_header; |
||||||
|
struct OpenCV_DNN_Plugin_API_v0_0_api_entries v0; |
||||||
|
} OpenCV_DNN_Plugin_API_v0; |
||||||
|
|
||||||
|
#if ABI_VERSION == 0 && API_VERSION == 0 |
||||||
|
typedef OpenCV_DNN_Plugin_API_v0 OpenCV_DNN_Plugin_API; |
||||||
|
#else |
||||||
|
#error "Not supported configuration: check ABI_VERSION/API_VERSION" |
||||||
|
#endif |
||||||
|
|
||||||
|
#ifdef BUILD_PLUGIN |
||||||
|
extern "C" { |
||||||
|
|
||||||
|
CV_PLUGIN_EXPORTS |
||||||
|
const OpenCV_DNN_Plugin_API* CV_API_CALL opencv_dnn_plugin_init_v0 |
||||||
|
(int requested_abi_version, int requested_api_version, void* reserved /*NULL*/) CV_NOEXCEPT; |
||||||
|
|
||||||
|
} // extern "C"
|
||||||
|
#else // BUILD_PLUGIN
|
||||||
|
typedef const OpenCV_DNN_Plugin_API* (CV_API_CALL *FN_opencv_dnn_plugin_init_t) |
||||||
|
(int requested_abi_version, int requested_api_version, void* reserved /*NULL*/); |
||||||
|
#endif // BUILD_PLUGIN
|
||||||
|
|
||||||
|
#endif // DNN_PLUGIN_API_HPP
|
@ -0,0 +1,319 @@ |
|||||||
|
// 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 backend.cpp
|
||||||
|
//
|
||||||
|
|
||||||
|
//==================================================================================================
|
||||||
|
// Dynamic backend implementation
|
||||||
|
|
||||||
|
#include "opencv2/core/utils/plugin_loader.private.hpp" |
||||||
|
|
||||||
|
namespace cv { namespace impl { |
||||||
|
|
||||||
|
using namespace cv::dnn_backend; |
||||||
|
|
||||||
|
#if OPENCV_HAVE_FILESYSTEM_SUPPORT && defined(ENABLE_PLUGINS) |
||||||
|
|
||||||
|
using namespace cv::plugin::impl; // plugin_loader.hpp
|
||||||
|
|
||||||
|
class PluginDNNBackend CV_FINAL: public std::enable_shared_from_this<PluginDNNBackend> |
||||||
|
{ |
||||||
|
protected: |
||||||
|
void initPluginAPI() |
||||||
|
{ |
||||||
|
const char* init_name = "opencv_dnn_plugin_init_v0"; |
||||||
|
FN_opencv_dnn_plugin_init_t fn_init = reinterpret_cast<FN_opencv_dnn_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, "DNN: plugin is incompatible (can't be initialized): " << lib_->getName()); |
||||||
|
return; |
||||||
|
} |
||||||
|
// NB: force strict minor version check (ABI is not preserved for now)
|
||||||
|
if (!checkCompatibility(plugin_api_->api_header, ABI_VERSION, API_VERSION, true)) |
||||||
|
{ |
||||||
|
plugin_api_ = NULL; |
||||||
|
return; |
||||||
|
} |
||||||
|
CV_LOG_INFO(NULL, "DNN: plugin is ready to use '" << plugin_api_->api_header.api_description << "'"); |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
CV_LOG_INFO(NULL, "DNN: 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, "DNN: 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, "DNN: 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, "DNN: 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, "DNN: 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, "DNN: 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, "DNN: 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_DNN_Plugin_API* plugin_api_; |
||||||
|
|
||||||
|
PluginDNNBackend(const std::shared_ptr<cv::plugin::impl::DynamicLib>& lib) |
||||||
|
: lib_(lib) |
||||||
|
, plugin_api_(NULL) |
||||||
|
{ |
||||||
|
initPluginAPI(); |
||||||
|
} |
||||||
|
|
||||||
|
std::shared_ptr<cv::dnn_backend::NetworkBackend> createNetworkBackend() const |
||||||
|
{ |
||||||
|
CV_Assert(plugin_api_); |
||||||
|
|
||||||
|
CvPluginDNNNetworkBackend 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::dnn_backend::NetworkBackend>(instancePtr, [](cv::dnn_backend::NetworkBackend*){}); // empty deleter
|
||||||
|
} |
||||||
|
} |
||||||
|
return std::shared_ptr<cv::dnn_backend::NetworkBackend>(); |
||||||
|
} |
||||||
|
|
||||||
|
}; // class PluginDNNBackend
|
||||||
|
|
||||||
|
|
||||||
|
class PluginDNNBackendFactory CV_FINAL: public IDNNBackendFactory |
||||||
|
{ |
||||||
|
public: |
||||||
|
std::string baseName_; |
||||||
|
std::shared_ptr<PluginDNNBackend> backend; |
||||||
|
bool initialized; |
||||||
|
public: |
||||||
|
PluginDNNBackendFactory(const std::string& baseName) |
||||||
|
: baseName_(baseName) |
||||||
|
, initialized(false) |
||||||
|
{ |
||||||
|
// nothing, plugins are loaded on demand
|
||||||
|
} |
||||||
|
|
||||||
|
std::shared_ptr<cv::dnn_backend::NetworkBackend> createNetworkBackend() const CV_OVERRIDE |
||||||
|
{ |
||||||
|
if (!initialized) |
||||||
|
{ |
||||||
|
const_cast<PluginDNNBackendFactory*>(this)->initBackend(); |
||||||
|
} |
||||||
|
if (backend) |
||||||
|
return backend->createNetworkBackend(); |
||||||
|
return std::shared_ptr<cv::dnn_backend::NetworkBackend>(); |
||||||
|
} |
||||||
|
|
||||||
|
protected: |
||||||
|
void initBackend() |
||||||
|
{ |
||||||
|
AutoLock lock(getInitializationMutex()); |
||||||
|
try |
||||||
|
{ |
||||||
|
if (!initialized) |
||||||
|
loadPlugin(); |
||||||
|
} |
||||||
|
catch (...) |
||||||
|
{ |
||||||
|
CV_LOG_INFO(NULL, "DNN: 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_DNN_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_DNN_PLUGIN_SUBDIRECTORY |
||||||
|
paths.push_back(binaryLocation); |
||||||
|
#else |
||||||
|
paths.push_back(binaryLocation + toFileSystemPath("/") + toFileSystemPath(CV_DNN_PLUGIN_SUBDIRECTORY_STR)); |
||||||
|
#endif |
||||||
|
} |
||||||
|
} |
||||||
|
const std::string default_expr = libraryPrefix() + "opencv_dnn_" + baseName_l + "*" + librarySuffix(); |
||||||
|
const std::string plugin_expr = getConfigurationParameterString((std::string("OPENCV_DNN_PLUGIN_") + baseName_u).c_str(), default_expr.c_str()); |
||||||
|
std::vector<FileSystemPath_t> results; |
||||||
|
#ifdef _WIN32 |
||||||
|
FileSystemPath_t moduleName = toFileSystemPath(libraryPrefix() + "opencv_dnn_" + 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, "DNN: " << 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); |
||||||
|
// Prefer candidates with higher versions
|
||||||
|
// TODO: implemented accurate versions-based comparator
|
||||||
|
std::sort(candidates.begin(), candidates.end(), std::greater<std::string>()); |
||||||
|
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 PluginDNNBackendFactory::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<PluginDNNBackend>(lib); |
||||||
|
if (!pluginBackend) |
||||||
|
{ |
||||||
|
continue; |
||||||
|
} |
||||||
|
if (pluginBackend->plugin_api_ == NULL) |
||||||
|
{ |
||||||
|
CV_LOG_ERROR(NULL, "DNN: no compatible plugin API for backend: " << baseName_ << " in " << toPrintablePath(plugin)); |
||||||
|
continue; |
||||||
|
} |
||||||
|
// NB: we are going to use backend, so prevent automatic library unloading
|
||||||
|
lib->disableAutomaticLibraryUnloading(); |
||||||
|
backend = pluginBackend; |
||||||
|
return; |
||||||
|
} |
||||||
|
catch (...) |
||||||
|
{ |
||||||
|
CV_LOG_WARNING(NULL, "DNN: exception during plugin initialization: " << toPrintablePath(plugin) << ". SKIP"); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#endif // OPENCV_HAVE_FILESYSTEM_SUPPORT && defined(ENABLE_PLUGINS)
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
namespace dnn_backend { |
||||||
|
|
||||||
|
|
||||||
|
std::shared_ptr<IDNNBackendFactory> createPluginDNNBackendFactory(const std::string& baseName) |
||||||
|
{ |
||||||
|
#if OPENCV_HAVE_FILESYSTEM_SUPPORT && defined(ENABLE_PLUGINS) |
||||||
|
const std::string baseName_u = toUpperCase(baseName); |
||||||
|
AutoLock lock(getInitializationMutex()); |
||||||
|
static std::map<std::string, std::shared_ptr<IDNNBackendFactory>> g_plugins_cache; |
||||||
|
auto it = g_plugins_cache.find(baseName_u); |
||||||
|
if (it == g_plugins_cache.end()) |
||||||
|
{ |
||||||
|
auto factory = std::make_shared<impl::PluginDNNBackendFactory>(baseName); |
||||||
|
g_plugins_cache.insert(std::pair<std::string, std::shared_ptr<IDNNBackendFactory>>(baseName_u, factory)); |
||||||
|
return factory; |
||||||
|
} |
||||||
|
return it->second; |
||||||
|
#else |
||||||
|
CV_UNUSED(baseName); |
||||||
|
return std::shared_ptr<IDNNBackendFactory>(); |
||||||
|
#endif |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
cv::dnn_backend::NetworkBackend& createPluginDNNNetworkBackend(const std::string& baseName) |
||||||
|
{ |
||||||
|
auto factory = dnn_backend::createPluginDNNBackendFactory(baseName); |
||||||
|
if (!factory) |
||||||
|
{ |
||||||
|
CV_Error(Error::StsNotImplemented, cv::format("Plugin factory is not available: '%s'", baseName.c_str())); |
||||||
|
} |
||||||
|
auto backend = factory->createNetworkBackend(); |
||||||
|
if (!backend) |
||||||
|
{ |
||||||
|
CV_Error(Error::StsNotImplemented, cv::format("Backend (plugin) is not available: '%s'", baseName.c_str())); |
||||||
|
} |
||||||
|
return *backend; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
}} // namespace
|
Loading…
Reference in new issue