mirror of
https://github.com/opencv/opencv.git
synced 2026-07-29 23:33:05 +04:00
Merge pull request #21688 from sivanov-work:vpp_ie_integration
G-API: VPP preprocessing GIEBackend integration * Add ROI in VPP prepro * Apply comments * Integration to IE * Removed extra invocations * Fix no-vpl compilation * Fix compilations * Apply comments * Use thin wrapper for device & ctx * Implement Device/Context constructor functions * Apply samples comment * Fix compilation * Fix compilation * Fix build * Separate Device&Context from selector, apply other comments * Fix typo * Intercept OV exception with pretty print out
This commit is contained in:
@@ -64,6 +64,9 @@ template<typename T> using QueueClass = cv::gapi::own::concurrent_bounded_queue<
|
||||
|
||||
#include "utils/itt.hpp"
|
||||
|
||||
#include "streaming/onevpl/engine/preproc_engine_interface.hpp"
|
||||
#include "streaming/onevpl/engine/preproc/preproc_dispatcher.hpp"
|
||||
|
||||
namespace IE = InferenceEngine;
|
||||
|
||||
namespace {
|
||||
@@ -261,12 +264,36 @@ struct IEUnit {
|
||||
|
||||
InferenceEngine::RemoteContext::Ptr rctx = nullptr;
|
||||
|
||||
std::shared_ptr<cv::gapi::wip::IPreprocEngine> preproc_engine_impl;
|
||||
|
||||
// FIXME: Unlike loadNetwork case, importNetwork requires that preprocessing
|
||||
// should be passed as ExecutableNetwork::SetBlob method, so need to collect
|
||||
// and store this information at the graph compilation stage (outMeta) and use in runtime.
|
||||
using PreProcMap = std::unordered_map<std::string, IE::PreProcessInfo>;
|
||||
PreProcMap preproc_map;
|
||||
|
||||
// NEW FIXME: Need to aggregate getInputInfo & GetInputInfo from network
|
||||
// into generic wrapper and invoke it at once in single place instead of
|
||||
// analyzing ParamDesc::Kind::Load/Import every time when we need to get access
|
||||
// for network info.
|
||||
// In term of introducing custom VPP/VPL preprocessing functionality
|
||||
// It was decided to use GFrameDesc as such aggregated network info with limitation
|
||||
// that VPP/VPL produces cv::MediaFrame only. But it should be not considered as
|
||||
// final solution
|
||||
class InputFramesDesc {
|
||||
using input_name_type = std::string;
|
||||
using description_type = cv::GFrameDesc;
|
||||
std::map<input_name_type, description_type> map;
|
||||
public:
|
||||
static bool is_applicable(const cv::GMetaArg &mm);
|
||||
const description_type &get_param(const input_name_type &input) const;
|
||||
|
||||
void set_param(const input_name_type &input,
|
||||
const IE::TensorDesc& desc);
|
||||
};
|
||||
|
||||
InputFramesDesc net_input_params;
|
||||
|
||||
explicit IEUnit(const cv::gapi::ie::detail::ParamDesc &pp)
|
||||
: params(pp) {
|
||||
InferenceEngine::ParamMap* ctx_params =
|
||||
@@ -336,6 +363,17 @@ struct IEUnit {
|
||||
} else {
|
||||
cv::util::throw_error(std::logic_error("Unsupported ParamDesc::Kind"));
|
||||
}
|
||||
|
||||
using namespace cv::gapi::wip::onevpl;
|
||||
if (params.vpl_preproc_device.has_value() && params.vpl_preproc_ctx.has_value()) {
|
||||
using namespace cv::gapi::wip;
|
||||
GAPI_LOG_INFO(nullptr, "VPP preproc creation requested");
|
||||
preproc_engine_impl =
|
||||
IPreprocEngine::create_preproc_engine<onevpl::VPPPreprocDispatcher>(
|
||||
params.vpl_preproc_device.value(),
|
||||
params.vpl_preproc_ctx.value());
|
||||
GAPI_LOG_INFO(nullptr, "VPP preproc created successfuly");
|
||||
}
|
||||
}
|
||||
|
||||
// This method is [supposed to be] called at Island compilation stage
|
||||
@@ -354,6 +392,39 @@ struct IEUnit {
|
||||
}
|
||||
};
|
||||
|
||||
bool IEUnit::InputFramesDesc::is_applicable(const cv::GMetaArg &mm) {
|
||||
return cv::util::holds_alternative<cv::GFrameDesc>(mm);
|
||||
}
|
||||
|
||||
const IEUnit::InputFramesDesc::description_type &
|
||||
IEUnit::InputFramesDesc::get_param(const input_name_type &input) const {
|
||||
auto it = map.find(input);
|
||||
GAPI_Assert(it != map.end() && "No appropriate input is found in InputFramesDesc");
|
||||
return it->second;
|
||||
}
|
||||
|
||||
void IEUnit::InputFramesDesc::set_param(const input_name_type &input,
|
||||
const IE::TensorDesc& desc) {
|
||||
description_type ret;
|
||||
ret.fmt = cv::MediaFormat::NV12;
|
||||
const InferenceEngine::SizeVector& inDims = desc.getDims();
|
||||
auto layout = desc.getLayout();
|
||||
GAPI_LOG_DEBUG(nullptr, "network input: " << input <<
|
||||
", tensor dims: " << inDims[0] << ", " << inDims[1] <<
|
||||
", " << inDims[2] << ", " << inDims[3]);
|
||||
if (layout != InferenceEngine::NHWC && layout != InferenceEngine::NCHW) {
|
||||
GAPI_LOG_WARNING(nullptr, "Unsupported layout for VPP preproc: " << layout <<
|
||||
", input name: " << input);
|
||||
GAPI_Assert(false && "Unsupported layout for VPP preproc");
|
||||
}
|
||||
GAPI_Assert(inDims.size() == 4u);
|
||||
ret.size.width = static_cast<int>(inDims[3]);
|
||||
ret.size.height = static_cast<int>(inDims[2]);
|
||||
|
||||
auto res = map.emplace(input, ret);
|
||||
GAPI_Assert(res.second && "Duplicated input info in InputFramesDesc are not allowable");
|
||||
}
|
||||
|
||||
class IECallContext
|
||||
{
|
||||
public:
|
||||
@@ -396,6 +467,9 @@ public:
|
||||
// To store exception appeared in callback.
|
||||
std::exception_ptr eptr;
|
||||
|
||||
using req_key_t = void*;
|
||||
cv::MediaFrame* prepareKeepAliveFrameSlot(req_key_t key);
|
||||
size_t releaseKeepAliveFrame(req_key_t key);
|
||||
private:
|
||||
cv::detail::VectorRef& outVecRef(std::size_t idx);
|
||||
|
||||
@@ -417,6 +491,10 @@ private:
|
||||
// Input parameters passed to an inference operation.
|
||||
cv::GArgs m_args;
|
||||
cv::GShapes m_in_shapes;
|
||||
|
||||
// keep alive preprocessed frames
|
||||
std::mutex keep_alive_frames_mutex;
|
||||
std::unordered_map<req_key_t, cv::MediaFrame> keep_alive_pp_frames;
|
||||
};
|
||||
|
||||
IECallContext::IECallContext(const IEUnit & unit,
|
||||
@@ -516,6 +594,35 @@ cv::GArg IECallContext::packArg(const cv::GArg &arg) {
|
||||
}
|
||||
}
|
||||
|
||||
cv::MediaFrame* IECallContext::prepareKeepAliveFrameSlot(req_key_t key) {
|
||||
std::lock_guard<std::mutex> lock(keep_alive_frames_mutex);
|
||||
return &keep_alive_pp_frames[key];
|
||||
}
|
||||
|
||||
size_t IECallContext::releaseKeepAliveFrame(req_key_t key) {
|
||||
size_t elapsed_count = 0;
|
||||
void *prev_slot = nullptr;
|
||||
// NB: release MediaFrame previously captured by prepareKeepAliveFrameSlot
|
||||
// We must capture it to keep a reference counter on inner media adapter
|
||||
// to ensure that frame resource would be locked until inference done.
|
||||
// Otherwise decoder could seized this frame resource as free/unlocked resource
|
||||
// from resource pool
|
||||
// Current function just take a unique frame `key` and overwrite stored
|
||||
// actual frame by empty frame
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(keep_alive_frames_mutex);
|
||||
auto ka_frame_it = keep_alive_pp_frames.find(key);
|
||||
if (ka_frame_it != keep_alive_pp_frames.end()) {
|
||||
prev_slot = &ka_frame_it->second;
|
||||
ka_frame_it->second = cv::MediaFrame();
|
||||
}
|
||||
elapsed_count = keep_alive_pp_frames.size();
|
||||
}
|
||||
GAPI_LOG_DEBUG(nullptr, "Release keep alive frame, slot: " << prev_slot <<
|
||||
", reserved frames count: " << elapsed_count);
|
||||
return elapsed_count;
|
||||
}
|
||||
|
||||
struct IECallable {
|
||||
static const char *name() { return "IERequestCallable"; }
|
||||
using Run = std::function<void(std::shared_ptr<IECallContext>, cv::gimpl::ie::RequestPool&)>;
|
||||
@@ -552,11 +659,65 @@ using GConstGIEModel = ade::ConstTypedGraph
|
||||
, IECallable
|
||||
>;
|
||||
|
||||
inline IE::Blob::Ptr extractRemoteBlob(IECallContext& ctx, std::size_t i) {
|
||||
cv::MediaFrame preprocess_frame_impl(cv::MediaFrame &&in_frame, const std::string &layer_name,
|
||||
IECallContext& ctx,
|
||||
const cv::util::optional<cv::Rect> &opt_roi,
|
||||
cv::MediaFrame* out_keep_alive_frame,
|
||||
bool* out_is_preprocessed) {
|
||||
cv::util::optional<cv::gapi::wip::pp_params> param =
|
||||
ctx.uu.preproc_engine_impl->is_applicable(in_frame);
|
||||
if (param.has_value()) {
|
||||
GAPI_LOG_DEBUG(nullptr, "VPP preprocessing for decoded remote frame will be used");
|
||||
cv::GFrameDesc expected_net_input_descr =
|
||||
ctx.uu.net_input_params.get_param(layer_name);
|
||||
|
||||
// TODO: Find a better place to configure media format for GPU
|
||||
// adjust color conversion to NV12 according to OV GPU limitation
|
||||
if(ctx.uu.params.device_id.find("GPU") != std::string::npos &&
|
||||
ctx.uu.rctx) {
|
||||
auto it = ctx.uu.params.config.find(std::string("GPU_NV12_TWO_INPUTS"));
|
||||
if (it != ctx.uu.params.config.end()) {
|
||||
if (it->second == "YES") {
|
||||
GAPI_LOG_DEBUG(nullptr, "Adjust preprocessing GPU media format to NV12");
|
||||
expected_net_input_descr.fmt = cv::MediaFormat::NV12;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cv::gapi::wip::pp_session pp_sess =
|
||||
ctx.uu.preproc_engine_impl->initialize_preproc(param.value(),
|
||||
expected_net_input_descr);
|
||||
|
||||
in_frame = ctx.uu.preproc_engine_impl->run_sync(pp_sess, in_frame, opt_roi);
|
||||
|
||||
if (out_keep_alive_frame != nullptr) {
|
||||
GAPI_LOG_DEBUG(nullptr, "remember preprocessed remote frame to keep it busy from reuse, slot: " <<
|
||||
out_keep_alive_frame);
|
||||
*out_keep_alive_frame = in_frame;
|
||||
}
|
||||
if (out_is_preprocessed) {
|
||||
*out_is_preprocessed = true;
|
||||
}
|
||||
} // otherwise it is not suitable frame, then check on other preproc backend or rely on IE plugin
|
||||
return std::move(in_frame);
|
||||
}
|
||||
|
||||
inline IE::Blob::Ptr extractRemoteBlob(IECallContext& ctx, std::size_t i,
|
||||
const std::string &layer_name,
|
||||
const cv::util::optional<cv::Rect> &opt_roi,
|
||||
cv::MediaFrame* out_keep_alive_frame,
|
||||
bool* out_is_preprocessed) {
|
||||
GAPI_Assert(ctx.inShape(i) == cv::GShape::GFRAME &&
|
||||
"Remote blob is supported for MediaFrame only");
|
||||
cv::MediaFrame frame = ctx.inFrame(i);
|
||||
if (ctx.uu.preproc_engine_impl) {
|
||||
GAPI_LOG_DEBUG(nullptr, "Try to use preprocessing for decoded remote frame in remote ctx");
|
||||
frame = preprocess_frame_impl(std::move(frame), layer_name, ctx, opt_roi,
|
||||
out_keep_alive_frame, out_is_preprocessed);
|
||||
}
|
||||
|
||||
cv::util::any any_blob_params = ctx.inFrame(i).blobParams();
|
||||
// Request params for result frame whatever it got preprocessed or not
|
||||
cv::util::any any_blob_params = frame.blobParams();
|
||||
|
||||
using ParamType = std::pair<InferenceEngine::TensorDesc, InferenceEngine::ParamMap>;
|
||||
using NV12ParamType = std::pair<ParamType, ParamType>;
|
||||
@@ -582,14 +743,24 @@ inline IE::Blob::Ptr extractRemoteBlob(IECallContext& ctx, std::size_t i) {
|
||||
|
||||
inline IE::Blob::Ptr extractBlob(IECallContext& ctx,
|
||||
std::size_t i,
|
||||
cv::gapi::ie::TraitAs hint) {
|
||||
cv::gapi::ie::TraitAs hint,
|
||||
const std::string& layer_name,
|
||||
const cv::util::optional<cv::Rect> &opt_roi,
|
||||
cv::MediaFrame* out_keep_alive_frame = nullptr,
|
||||
bool* out_is_preprocessed = nullptr) {
|
||||
if (ctx.uu.rctx != nullptr) {
|
||||
return extractRemoteBlob(ctx, i);
|
||||
return extractRemoteBlob(ctx, i, layer_name, opt_roi,
|
||||
out_keep_alive_frame, out_is_preprocessed);
|
||||
}
|
||||
|
||||
switch (ctx.inShape(i)) {
|
||||
case cv::GShape::GFRAME: {
|
||||
const auto& frame = ctx.inFrame(i);
|
||||
auto frame = ctx.inFrame(i);
|
||||
if (ctx.uu.preproc_engine_impl) {
|
||||
GAPI_LOG_DEBUG(nullptr, "Try to use preprocessing for decoded frame in local ctx");
|
||||
frame = preprocess_frame_impl(std::move(frame), layer_name, ctx, opt_roi,
|
||||
out_keep_alive_frame, out_is_preprocessed);
|
||||
}
|
||||
ctx.views.emplace_back(new cv::MediaFrame::View(frame.access(cv::MediaFrame::Access::R)));
|
||||
return wrapIE(*(ctx.views.back()), frame.desc());
|
||||
}
|
||||
@@ -626,10 +797,20 @@ static void setROIBlob(InferenceEngine::InferRequest& req,
|
||||
const IECallContext& ctx) {
|
||||
if (ctx.uu.params.device_id.find("GPU") != std::string::npos &&
|
||||
ctx.uu.rctx) {
|
||||
GAPI_LOG_WARNING(nullptr, "ROI blob creation for device_id: " <<
|
||||
ctx.uu.params.device_id << ", layer: " << layer_name <<
|
||||
"is not supported yet");
|
||||
GAPI_Assert(false && "Unsupported ROI blob creation for GPU remote context");
|
||||
try {
|
||||
// NB: make_shared_blob() cannot work with GPU NV12 & ROI at the moment.
|
||||
// OpenVINO produces exception with unsupported status.
|
||||
// To do not encounter with silent crash situation we should catch OV exception
|
||||
// and suggest to avoid this problem by using inner preprocessing feature.
|
||||
// VPP/VPL proprocessing are supported at the moment
|
||||
setBlob(req, layer_name, IE::make_shared_blob(blob, toIE(roi)), ctx);
|
||||
} catch (const std::exception &ex) {
|
||||
GAPI_LOG_WARNING(nullptr, "cannot set ROI blob for layer: " << layer_name <<
|
||||
", reason:\n" << ex.what() <<
|
||||
"\nTry using self GAPI preprocessing feature: "
|
||||
" Check method `cfgPreprocessingParams` in `cv::gapi::ie::Params`");
|
||||
throw;
|
||||
}
|
||||
} else {
|
||||
setBlob(req, layer_name, IE::make_shared_blob(blob, toIE(roi)), ctx);
|
||||
}
|
||||
@@ -975,6 +1156,8 @@ static void PostOutputs(InferenceEngine::InferRequest &request,
|
||||
ctx->out.meta(output, ctx->input(0).meta);
|
||||
ctx->out.post(std::move(output), ctx->eptr);
|
||||
}
|
||||
|
||||
ctx->releaseKeepAliveFrame(&request);
|
||||
}
|
||||
|
||||
class PostOutputsList {
|
||||
@@ -1088,6 +1271,12 @@ struct Infer: public cv::detail::KernelTag {
|
||||
if (isApplicableForResize(ii->getTensorDesc())) {
|
||||
ii->getPreProcess().setResizeAlgorithm(IE::RESIZE_BILINEAR);
|
||||
}
|
||||
|
||||
// NB: configure input param for further preproc
|
||||
if (uu.net_input_params.is_applicable(mm)) {
|
||||
const_cast<IEUnit::InputFramesDesc &>(uu.net_input_params)
|
||||
.set_param(input_name, ii->getTensorDesc());
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: This isn't the best place to call reshape function.
|
||||
@@ -1107,6 +1296,12 @@ struct Infer: public cv::detail::KernelTag {
|
||||
auto ii = inputs.at(input_name);
|
||||
const auto & mm = std::get<1>(it);
|
||||
non_const_prepm->emplace(input_name, configurePreProcInfo(ii, mm));
|
||||
|
||||
// NB: configure input param for further preproc
|
||||
if (uu.net_input_params.is_applicable(mm)) {
|
||||
const_cast<IEUnit::InputFramesDesc &>(uu.net_input_params)
|
||||
.set_param(input_name, ii->getTensorDesc());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1145,7 +1340,9 @@ struct Infer: public cv::detail::KernelTag {
|
||||
(layout == IE::Layout::NCHW || layout == IE::Layout::NHWC)
|
||||
? cv::gapi::ie::TraitAs::IMAGE : cv::gapi::ie::TraitAs::TENSOR;
|
||||
|
||||
IE::Blob::Ptr this_blob = extractBlob(*ctx, i, hint);
|
||||
IE::Blob::Ptr this_blob = extractBlob(*ctx, i, hint,
|
||||
layer_name,
|
||||
cv::util::optional<cv::Rect>{});
|
||||
setBlob(req, layer_name, this_blob, *ctx);
|
||||
}
|
||||
// FIXME: Should it be done by kernel ?
|
||||
@@ -1200,6 +1397,12 @@ struct InferROI: public cv::detail::KernelTag {
|
||||
if (!input_reshape_table.empty()) {
|
||||
const_cast<IE::CNNNetwork *>(&uu.net)->reshape(input_reshape_table);
|
||||
}
|
||||
|
||||
// NB: configure input param for further preproc
|
||||
if (uu.net_input_params.is_applicable(mm)) {
|
||||
const_cast<IEUnit::InputFramesDesc &>(uu.net_input_params)
|
||||
.set_param(input_name, ii->getTensorDesc());
|
||||
}
|
||||
} else {
|
||||
GAPI_Assert(uu.params.kind == cv::gapi::ie::detail::ParamDesc::Kind::Import);
|
||||
auto inputs = uu.this_network.GetInputsInfo();
|
||||
@@ -1207,6 +1410,12 @@ struct InferROI: public cv::detail::KernelTag {
|
||||
auto* non_const_prepm = const_cast<IEUnit::PreProcMap*>(&uu.preproc_map);
|
||||
auto ii = inputs.at(input_name);
|
||||
non_const_prepm->emplace(input_name, configurePreProcInfo(ii, mm));
|
||||
|
||||
// NB: configure intput param for further preproc
|
||||
if (uu.net_input_params.is_applicable(mm)) {
|
||||
const_cast<IEUnit::InputFramesDesc &>(uu.net_input_params)
|
||||
.set_param(input_name, ii->getTensorDesc());
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: It would be nice here to have an exact number of network's
|
||||
@@ -1236,13 +1445,26 @@ struct InferROI: public cv::detail::KernelTag {
|
||||
GAPI_Assert(ctx->uu.params.num_in == 1);
|
||||
auto&& this_roi = ctx->inArg<cv::detail::OpaqueRef>(0).rref<cv::Rect>();
|
||||
|
||||
// reserve unique slot for keep alive preprocessed frame
|
||||
cv::MediaFrame* slot_ptr = ctx->prepareKeepAliveFrameSlot(&req);
|
||||
|
||||
// NB: This blob will be used to make roi from its, so
|
||||
// it should be treated as image
|
||||
bool preprocessed = false;
|
||||
IE::Blob::Ptr this_blob =
|
||||
extractBlob(*ctx, 1, cv::gapi::ie::TraitAs::IMAGE);
|
||||
setROIBlob(req,
|
||||
extractBlob(*ctx, 1, cv::gapi::ie::TraitAs::IMAGE,
|
||||
*(ctx->uu.params.input_names.begin()),
|
||||
cv::util::make_optional(this_roi),
|
||||
slot_ptr, &preprocessed);
|
||||
if (!preprocessed) {
|
||||
setROIBlob(req,
|
||||
*(ctx->uu.params.input_names.begin()),
|
||||
this_blob, this_roi, *ctx);
|
||||
} else {
|
||||
setBlob(req,
|
||||
*(ctx->uu.params.input_names.begin()),
|
||||
this_blob, *ctx);
|
||||
}
|
||||
// FIXME: Should it be done by kernel ?
|
||||
// What about to do that in RequestPool ?
|
||||
req.StartAsync();
|
||||
@@ -1336,7 +1558,9 @@ struct InferList: public cv::detail::KernelTag {
|
||||
|
||||
// NB: This blob will be used to make roi from its, so
|
||||
// it should be treated as image
|
||||
IE::Blob::Ptr this_blob = extractBlob(*ctx, 1, cv::gapi::ie::TraitAs::IMAGE);
|
||||
IE::Blob::Ptr this_blob = extractBlob(*ctx, 1, cv::gapi::ie::TraitAs::IMAGE,
|
||||
ctx->uu.params.input_names[0u],
|
||||
cv::util::optional<cv::Rect>{});
|
||||
|
||||
std::vector<std::vector<int>> cached_dims(ctx->uu.params.num_out);
|
||||
for (auto i : ade::util::iota(ctx->uu.params.num_out)) {
|
||||
@@ -1483,7 +1707,9 @@ struct InferList2: public cv::detail::KernelTag {
|
||||
&& "This operation must have at least two arguments");
|
||||
// NB: This blob will be used to make roi from its, so
|
||||
// it should be treated as image
|
||||
IE::Blob::Ptr blob_0 = extractBlob(*ctx, 0, cv::gapi::ie::TraitAs::IMAGE);
|
||||
IE::Blob::Ptr blob_0 = extractBlob(*ctx, 0, cv::gapi::ie::TraitAs::IMAGE,
|
||||
ctx->uu.params.input_names[0u],
|
||||
cv::util::optional<cv::Rect>{});
|
||||
const auto list_size = ctx->inArg<cv::detail::VectorRef>(1u).size();
|
||||
if (list_size == 0u) {
|
||||
for (auto i : ade::util::iota(ctx->uu.params.num_out)) {
|
||||
|
||||
@@ -38,6 +38,20 @@ namespace gapi {
|
||||
namespace wip {
|
||||
namespace onevpl {
|
||||
|
||||
std::vector<CfgParam> insertCfgparam(std::vector<CfgParam> &¶m_array, AccelType type) {
|
||||
switch (type) {
|
||||
case AccelType::HOST:
|
||||
break;
|
||||
case AccelType::DX11:
|
||||
param_array.push_back(CfgParam::create_acceleration_mode(MFX_ACCEL_MODE_VIA_D3D11));
|
||||
break;
|
||||
default:
|
||||
GAPI_DbgAssert(false && "Unexpected AccelType");
|
||||
break;
|
||||
}
|
||||
return std::move(param_array);
|
||||
}
|
||||
|
||||
CfgParamDeviceSelector::CfgParamDeviceSelector(const CfgParams& cfg_params) :
|
||||
suggested_device(IDeviceSelector::create<Device>(nullptr, "CPU", AccelType::HOST)),
|
||||
suggested_context(IDeviceSelector::create<Context>(nullptr, AccelType::HOST)) {
|
||||
@@ -231,6 +245,52 @@ CfgParamDeviceSelector::CfgParamDeviceSelector(Device::Ptr device_ptr,
|
||||
}
|
||||
}
|
||||
|
||||
CfgParamDeviceSelector::CfgParamDeviceSelector(const Device &device,
|
||||
const Context &ctx,
|
||||
CfgParams) :
|
||||
suggested_device(device),
|
||||
suggested_context(ctx) {
|
||||
|
||||
switch(device.get_type()) {
|
||||
case AccelType::DX11: {
|
||||
#ifdef HAVE_DIRECTX
|
||||
#ifdef HAVE_D3D11
|
||||
ID3D11Device* dx_device_ptr =
|
||||
reinterpret_cast<ID3D11Device*>(suggested_device.get_ptr());
|
||||
dx_device_ptr->AddRef();
|
||||
|
||||
ID3D11DeviceContext* dx_ctx_ptr =
|
||||
reinterpret_cast<ID3D11DeviceContext*>(suggested_context.get_ptr());
|
||||
|
||||
// oneVPL recommendation
|
||||
{
|
||||
ID3D11Multithread *pD11Multithread = nullptr;
|
||||
dx_ctx_ptr->QueryInterface(IID_PPV_ARGS(&pD11Multithread));
|
||||
pD11Multithread->SetMultithreadProtected(true);
|
||||
pD11Multithread->Release();
|
||||
}
|
||||
|
||||
dx_ctx_ptr->AddRef();
|
||||
break;
|
||||
#else
|
||||
GAPI_LOG_WARNING(nullptr, "Unavailable \"" << CfgParam::acceleration_mode_name() <<
|
||||
": MFX_ACCEL_MODE_VIA_D3D11\""
|
||||
"was chosen for current project configuration");
|
||||
throw std::logic_error(std::string("Unsupported \"") +
|
||||
CfgParam::acceleration_mode_name() + ": MFX_ACCEL_MODE_VIA_D3D11\"");
|
||||
#endif // HAVE_DIRECTX
|
||||
#endif // HAVE_D3D11
|
||||
}
|
||||
case AccelType::HOST:
|
||||
break;
|
||||
default:
|
||||
throw std::logic_error(std::string("Unsupported \"") + CfgParam::acceleration_mode_name() +
|
||||
"\" requested: " +
|
||||
to_cstring(device.get_type()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
CfgParamDeviceSelector::~CfgParamDeviceSelector() {
|
||||
GAPI_LOG_INFO(nullptr, "release context: " << suggested_context.get_ptr());
|
||||
AccelType ctype = suggested_context.get_type();
|
||||
|
||||
@@ -7,14 +7,14 @@
|
||||
#ifndef GAPI_STREAMING_ONEVPL_CFG_PARAM_DEVICE_SELECTOR_HPP
|
||||
#define GAPI_STREAMING_ONEVPL_CFG_PARAM_DEVICE_SELECTOR_HPP
|
||||
|
||||
#ifdef HAVE_ONEVPL
|
||||
|
||||
#include <opencv2/gapi/streaming/onevpl/device_selector_interface.hpp>
|
||||
#include <opencv2/gapi/streaming/onevpl/cfg_params.hpp>
|
||||
#include <opencv2/gapi/streaming/onevpl/source.hpp>
|
||||
|
||||
#include "opencv2/gapi/own/exports.hpp" // GAPI_EXPORTS
|
||||
|
||||
#ifdef HAVE_ONEVPL
|
||||
|
||||
namespace cv {
|
||||
namespace gapi {
|
||||
namespace wip {
|
||||
@@ -26,6 +26,9 @@ struct GAPI_EXPORTS CfgParamDeviceSelector final: public IDeviceSelector {
|
||||
const std::string& device_id,
|
||||
Context::Ptr ctx_ptr,
|
||||
const CfgParams& params);
|
||||
CfgParamDeviceSelector(const Device &device_ptr,
|
||||
const Context &ctx_ptr,
|
||||
CfgParams params);
|
||||
~CfgParamDeviceSelector();
|
||||
|
||||
DeviceScoreTable select_devices() const override;
|
||||
|
||||
@@ -81,6 +81,42 @@ IDeviceSelector::Score::Type IDeviceSelector::Score::get() const {
|
||||
IDeviceSelector::~IDeviceSelector() {
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
struct DeviceContextCreator : public IDeviceSelector {
|
||||
DeviceScoreTable select_devices() const override { return {};}
|
||||
DeviceContexts select_context() override { return {};}
|
||||
|
||||
template<typename Entity, typename ...Args>
|
||||
static Entity create_entity(Args &&...args) {
|
||||
return IDeviceSelector::create<Entity>(std::forward<Args>(args)...);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Device create_host_device() {
|
||||
return detail::DeviceContextCreator::create_entity<Device>(nullptr,
|
||||
"CPU",
|
||||
AccelType::HOST);
|
||||
}
|
||||
|
||||
Context create_host_context() {
|
||||
return detail::DeviceContextCreator::create_entity<Context>(nullptr,
|
||||
AccelType::HOST);
|
||||
}
|
||||
|
||||
Device create_dx11_device(Device::Ptr device_ptr,
|
||||
const std::string& device_name) {
|
||||
return detail::DeviceContextCreator::create_entity<Device>(device_ptr,
|
||||
device_name,
|
||||
AccelType::DX11);
|
||||
}
|
||||
|
||||
Context create_dx11_context(Context::Ptr ctx_ptr) {
|
||||
return detail::DeviceContextCreator::create_entity<Context>(ctx_ptr,
|
||||
AccelType::DX11);
|
||||
}
|
||||
|
||||
} // namespace onevpl
|
||||
} // namespace wip
|
||||
} // namespace gapi
|
||||
|
||||
@@ -4,30 +4,33 @@
|
||||
//
|
||||
// Copyright (C) 2022 Intel Corporation
|
||||
|
||||
#ifdef HAVE_ONEVPL
|
||||
|
||||
#include <algorithm>
|
||||
#include <exception>
|
||||
|
||||
#include <opencv2/gapi/streaming/onevpl/data_provider_interface.hpp>
|
||||
#include "streaming/onevpl/engine/preproc/preproc_dispatcher.hpp"
|
||||
|
||||
#ifdef HAVE_ONEVPL
|
||||
#include "streaming/onevpl/onevpl_export.hpp"
|
||||
#include "streaming/onevpl/engine/preproc/preproc_engine.hpp"
|
||||
#include "streaming/onevpl/engine/preproc/preproc_session.hpp"
|
||||
#include "streaming/onevpl/engine/preproc/preproc_dispatcher.hpp"
|
||||
|
||||
#include "streaming/onevpl/accelerators/accel_policy_interface.hpp"
|
||||
#include "streaming/onevpl/accelerators/surface/surface.hpp"
|
||||
#include "streaming/onevpl/cfg_params_parser.hpp"
|
||||
#include "logger.hpp"
|
||||
#endif // HAVE_ONEVPL
|
||||
|
||||
#include "logger.hpp"
|
||||
|
||||
namespace cv {
|
||||
namespace gapi {
|
||||
namespace wip {
|
||||
namespace onevpl {
|
||||
#ifdef HAVE_ONEVPL
|
||||
cv::util::optional<pp_params> VPPPreprocDispatcher::is_applicable(const cv::MediaFrame& in_frame) {
|
||||
cv::util::optional<pp_params> param;
|
||||
GAPI_LOG_DEBUG(nullptr, "workers: " << workers.size());
|
||||
bool worker_found = false;
|
||||
for (const auto &w : workers) {
|
||||
param = w->is_applicable(in_frame);
|
||||
if (param.has_value()) {
|
||||
@@ -42,11 +45,12 @@ cv::util::optional<pp_params> VPPPreprocDispatcher::is_applicable(const cv::Medi
|
||||
if (worker_accel_type == adapter->accel_type()){
|
||||
vpp_param.reserved = reinterpret_cast<void *>(w.get());
|
||||
GAPI_LOG_DEBUG(nullptr, "selected worker: " << vpp_param.reserved);
|
||||
worker_found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return param;
|
||||
return worker_found ? param : cv::util::optional<pp_params>{};
|
||||
}
|
||||
|
||||
pp_session VPPPreprocDispatcher::initialize_preproc(const pp_params& initial_frame_param,
|
||||
@@ -78,8 +82,24 @@ cv::MediaFrame VPPPreprocDispatcher::run_sync(const pp_session &session_handle,
|
||||
}
|
||||
GAPI_Assert(false && "Cannot invoke VPP preproc in dispatcher, no suitable worker");
|
||||
}
|
||||
|
||||
#else // HAVE_ONEVPL
|
||||
cv::util::optional<pp_params> VPPPreprocDispatcher::is_applicable(const cv::MediaFrame&) {
|
||||
return cv::util::optional<pp_params>{};
|
||||
}
|
||||
|
||||
pp_session VPPPreprocDispatcher::initialize_preproc(const pp_params&,
|
||||
const GFrameDesc&) {
|
||||
GAPI_Assert(false && "Unsupported: G-API compiled without `WITH_GAPI_ONEVPL=ON`");
|
||||
}
|
||||
|
||||
cv::MediaFrame VPPPreprocDispatcher::run_sync(const pp_session &,
|
||||
const cv::MediaFrame&,
|
||||
const cv::util::optional<cv::Rect> &) {
|
||||
GAPI_Assert(false && "Unsupported: G-API compiled without `WITH_GAPI_ONEVPL=ON`");
|
||||
}
|
||||
#endif // HAVE_ONEVPL
|
||||
} // namespace onevpl
|
||||
} // namespace wip
|
||||
} // namespace gapi
|
||||
} // namespace cv
|
||||
#endif // HAVE_ONEVPL
|
||||
|
||||
@@ -11,10 +11,6 @@
|
||||
#include <vector>
|
||||
|
||||
#include "streaming/onevpl/engine/preproc_engine_interface.hpp"
|
||||
#include "streaming/onevpl/engine/preproc_defines.hpp"
|
||||
|
||||
#ifdef HAVE_ONEVPL
|
||||
#include "streaming/onevpl/onevpl_export.hpp"
|
||||
|
||||
namespace cv {
|
||||
namespace gapi {
|
||||
@@ -49,5 +45,4 @@ private:
|
||||
} // namespace wip
|
||||
} // namespace gapi
|
||||
} // namespace cv
|
||||
#endif // HAVE_ONEVPL
|
||||
#endif // GAPI_STREAMING_ONEVPL_PREPROC_DISPATCHER_HPP
|
||||
|
||||
@@ -51,7 +51,7 @@ void apply_roi(mfxFrameSurface1* surface_handle,
|
||||
|
||||
VPPPreprocEngine::VPPPreprocEngine(std::unique_ptr<VPLAccelerationPolicy>&& accel) :
|
||||
ProcessingEngineBase(std::move(accel)) {
|
||||
GAPI_LOG_INFO(nullptr, "Create VPP preprocessing engine");
|
||||
GAPI_LOG_DEBUG(nullptr, "Create VPP preprocessing engine");
|
||||
preprocessed_frames_count = 0;
|
||||
create_pipeline(
|
||||
// 0) preproc decoded surface with VPP params
|
||||
@@ -455,7 +455,7 @@ ProcessingEngineBase::ExecutionStatus VPPPreprocEngine::process_error(mfxStatus
|
||||
"MFX_ERR_REALLOC_SURFACE is not processed");
|
||||
break;
|
||||
case MFX_WRN_IN_EXECUTION:
|
||||
GAPI_LOG_WARNING(nullptr, "[" << sess.session << "] got MFX_WRN_IN_EXECUTION");
|
||||
GAPI_LOG_DEBUG(nullptr, "[" << sess.session << "] got MFX_WRN_IN_EXECUTION");
|
||||
return ExecutionStatus::Continue;
|
||||
default:
|
||||
GAPI_LOG_WARNING(nullptr, "Unknown status code: " << mfxstatus_to_string(status) <<
|
||||
|
||||
@@ -23,8 +23,8 @@ namespace wip {
|
||||
#else // VPP_PREPROC_ENGINE
|
||||
struct empty_pp_params {};
|
||||
struct empty_pp_session {};
|
||||
#define GAPI_BACKEND_PP_PARAMS cv::gapi::wip::empty_pp_params;
|
||||
#define GAPI_BACKEND_PP_SESSIONS cv::gapi::wip::empty_pp_session;
|
||||
#define GAPI_BACKEND_PP_PARAMS cv::gapi::wip::empty_pp_params
|
||||
#define GAPI_BACKEND_PP_SESSIONS cv::gapi::wip::empty_pp_session
|
||||
#endif // VPP_PREPROC_ENGINE
|
||||
|
||||
struct pp_params {
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
// 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.
|
||||
//
|
||||
// Copyright (C) 2022 Intel Corporation
|
||||
|
||||
#include <opencv2/gapi/streaming/onevpl/device_selector_interface.hpp>
|
||||
#include "streaming/onevpl/engine/preproc_engine_interface.hpp"
|
||||
#include "streaming/onevpl/engine/preproc/preproc_dispatcher.hpp"
|
||||
|
||||
#ifdef HAVE_ONEVPL
|
||||
#include "streaming/onevpl/onevpl_export.hpp"
|
||||
#include "streaming/onevpl/engine/preproc/preproc_engine.hpp"
|
||||
|
||||
#include "streaming/onevpl/accelerators/accel_policy_dx11.hpp"
|
||||
#include "streaming/onevpl/accelerators/accel_policy_cpu.hpp"
|
||||
#include "streaming/onevpl/accelerators/surface/surface.hpp"
|
||||
#include "streaming/onevpl/cfg_param_device_selector.hpp"
|
||||
#include "streaming/onevpl/cfg_params_parser.hpp"
|
||||
|
||||
#endif //HAVE_ONEVPL
|
||||
|
||||
#include "logger.hpp"
|
||||
|
||||
namespace cv {
|
||||
namespace gapi {
|
||||
namespace wip {
|
||||
|
||||
template<typename SpecificPreprocEngine, typename ...PreprocEngineArgs >
|
||||
std::unique_ptr<SpecificPreprocEngine>
|
||||
IPreprocEngine::create_preproc_engine_impl(const PreprocEngineArgs& ...) {
|
||||
GAPI_Assert(false && "Unsupported ");
|
||||
}
|
||||
|
||||
template <>
|
||||
std::unique_ptr<onevpl::VPPPreprocDispatcher>
|
||||
IPreprocEngine::create_preproc_engine_impl(const onevpl::Device &device,
|
||||
const onevpl::Context &context) {
|
||||
using namespace onevpl;
|
||||
cv::util::suppress_unused_warning(device);
|
||||
cv::util::suppress_unused_warning(context);
|
||||
std::unique_ptr<VPPPreprocDispatcher> dispatcher(new VPPPreprocDispatcher);
|
||||
#ifdef HAVE_ONEVPL
|
||||
if (device.get_type() == onevpl::AccelType::DX11) {
|
||||
bool gpu_pp_is_created = false;
|
||||
#ifdef HAVE_DIRECTX
|
||||
#ifdef HAVE_D3D11
|
||||
GAPI_LOG_INFO(nullptr, "Creating DX11 VPP preprocessing engine");
|
||||
// create GPU VPP preproc engine
|
||||
dispatcher->insert_worker<VPPPreprocEngine>(
|
||||
std::unique_ptr<VPLAccelerationPolicy>{
|
||||
new VPLDX11AccelerationPolicy(
|
||||
std::make_shared<CfgParamDeviceSelector>(
|
||||
device, context, CfgParams{}))
|
||||
});
|
||||
GAPI_LOG_INFO(nullptr, "DX11 VPP preprocessing engine created");
|
||||
gpu_pp_is_created = true;
|
||||
#endif
|
||||
#endif
|
||||
GAPI_Assert(gpu_pp_is_created && "VPP preproc for GPU is requested, but it is avaiable only for DX11 at now");
|
||||
} else {
|
||||
GAPI_LOG_INFO(nullptr, "Creating CPU VPP preprocessing engine");
|
||||
dispatcher->insert_worker<VPPPreprocEngine>(
|
||||
std::unique_ptr<VPLAccelerationPolicy>{
|
||||
new VPLCPUAccelerationPolicy(
|
||||
std::make_shared<CfgParamDeviceSelector>(CfgParams{}))});
|
||||
GAPI_LOG_INFO(nullptr, "CPU VPP preprocessing engine created");
|
||||
}
|
||||
#endif // HAVE_ONEVPL
|
||||
return dispatcher;
|
||||
}
|
||||
|
||||
|
||||
// Force instantiation
|
||||
template
|
||||
std::unique_ptr<onevpl::VPPPreprocDispatcher>
|
||||
IPreprocEngine::create_preproc_engine_impl<onevpl::VPPPreprocDispatcher,
|
||||
const onevpl::Device &,const onevpl::Context &>
|
||||
(const onevpl::Device &device,
|
||||
const onevpl::Context &ctx);
|
||||
} // namespace wip
|
||||
} // namespace gapi
|
||||
} // namespace cv
|
||||
@@ -29,6 +29,16 @@ struct IPreprocEngine {
|
||||
virtual cv::MediaFrame
|
||||
run_sync(const pp_session &sess, const cv::MediaFrame& in_frame,
|
||||
const cv::util::optional<cv::Rect> &opt_roi = {}) = 0;
|
||||
|
||||
template<typename SpecificPreprocEngine, typename ...PreprocEngineArgs >
|
||||
static std::unique_ptr<IPreprocEngine> create_preproc_engine(const PreprocEngineArgs& ...args) {
|
||||
static_assert(std::is_base_of<IPreprocEngine, SpecificPreprocEngine>::value,
|
||||
"SpecificPreprocEngine must have reachable ancessor IPreprocEngine");
|
||||
return create_preproc_engine_impl<SpecificPreprocEngine, PreprocEngineArgs...>(args...);
|
||||
}
|
||||
private:
|
||||
template<typename SpecificPreprocEngine, typename ...PreprocEngineArgs >
|
||||
static std::unique_ptr<SpecificPreprocEngine> create_preproc_engine_impl(const PreprocEngineArgs &...args);
|
||||
};
|
||||
} // namespace wip
|
||||
} // namespace gapi
|
||||
|
||||
@@ -33,6 +33,13 @@ GSource::GSource(const std::string& filePath,
|
||||
accel_ctx_ptr, cfg_params)) {
|
||||
}
|
||||
|
||||
GSource::GSource(const std::string& filePath,
|
||||
const CfgParams& cfg_params,
|
||||
const Device &device, const Context &ctx) :
|
||||
GSource(filePath, cfg_params,
|
||||
std::make_shared<CfgParamDeviceSelector>(device, ctx, cfg_params)) {
|
||||
}
|
||||
|
||||
GSource::GSource(const std::string& filePath,
|
||||
const CfgParams& cfg_params,
|
||||
std::shared_ptr<IDeviceSelector> selector) :
|
||||
@@ -74,6 +81,10 @@ GSource::GSource(const std::string&, const CfgParams&, const std::string&,
|
||||
GAPI_Assert(false && "Unsupported: G-API compiled without `WITH_GAPI_ONEVPL=ON`");
|
||||
}
|
||||
|
||||
GSource::GSource(const std::string&, const CfgParams&, const Device &, const Context &) {
|
||||
GAPI_Assert(false && "Unsupported: G-API compiled without `WITH_GAPI_ONEVPL=ON`");
|
||||
}
|
||||
|
||||
GSource::GSource(const std::string&, const CfgParams&, std::shared_ptr<IDeviceSelector>) {
|
||||
GAPI_Assert(false && "Unsupported: G-API compiled without `WITH_GAPI_ONEVPL=ON`");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user