1
0
mirror of https://github.com/opencv/opencv.git synced 2026-07-31 08:13:04 +04:00

Add VAAPI into tests & VPL sample

This commit is contained in:
SergeyIvanov87
2022-07-08 11:40:25 +03:00
parent 139c443770
commit f562264674
14 changed files with 588 additions and 120 deletions
+33 -44
View File
@@ -300,6 +300,7 @@ struct IEUnit {
cv::util::any_cast<InferenceEngine::ParamMap>(&params.context_config);
if (ctx_params != nullptr) {
auto ie_core = cv::gimpl::ie::wrap::getCore();
GAPI_LOG_DEBUG(nullptr, "create IE remote ctx for device id: " << params.device_id);
rctx = ie_core.CreateContext(params.device_id, *ctx_params);
}
@@ -703,45 +704,6 @@ cv::MediaFrame preprocess_frame_impl(cv::MediaFrame &&in_frame, const std::strin
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);
}
// 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>;
NV12ParamType* blob_params = cv::util::any_cast<NV12ParamType>(&any_blob_params);
if (blob_params == nullptr) {
GAPI_Assert(false && "Incorrect type of blobParams:"
"expected std::pair<ParamType, ParamType>,"
"with ParamType std::pair<InferenceEngine::TensorDesc,"
"InferenceEngine::ParamMap >>");
}
//The parameters are TensorDesc and ParamMap for both y and uv blobs
auto y_blob = ctx.uu.rctx->CreateBlob(blob_params->first.first, blob_params->first.second);
auto uv_blob = ctx.uu.rctx->CreateBlob(blob_params->second.first, blob_params->second.second);
#if INF_ENGINE_RELEASE >= 2021010000
return IE::make_shared_blob<IE::NV12Blob>(y_blob, uv_blob);
#else
return IE::make_shared_blob<InferenceEngine::NV12Blob>(y_blob, uv_blob);
#endif
}
inline IE::Blob::Ptr extractBlob(IECallContext& ctx,
std::size_t i,
cv::gapi::ie::TraitAs hint,
@@ -749,11 +711,6 @@ inline IE::Blob::Ptr extractBlob(IECallContext& ctx,
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, layer_name, opt_roi,
out_keep_alive_frame, out_is_preprocessed);
}
switch (ctx.inShape(i)) {
case cv::GShape::GFRAME: {
auto frame = ctx.inFrame(i);
@@ -762,6 +719,37 @@ inline IE::Blob::Ptr extractBlob(IECallContext& ctx,
frame = preprocess_frame_impl(std::move(frame), layer_name, ctx, opt_roi,
out_keep_alive_frame, out_is_preprocessed);
}
// NB: check OV remote device context availability.
// if it exist and MediaFrame shares the same device context
// then we create a remote blob without memory copy
if (ctx.uu.rctx != nullptr) {
// 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>;
NV12ParamType* blob_params = cv::util::any_cast<NV12ParamType>(&any_blob_params);
if (blob_params == nullptr) {
GAPI_Assert(false && "Incorrect type of blobParams:"
"expected std::pair<ParamType, ParamType>,"
"with ParamType std::pair<InferenceEngine::TensorDesc,"
"InferenceEngine::ParamMap >>");
}
//The parameters are TensorDesc and ParamMap for both y and uv blobs
auto y_blob = ctx.uu.rctx->CreateBlob(blob_params->first.first, blob_params->first.second);
auto uv_blob = ctx.uu.rctx->CreateBlob(blob_params->second.first, blob_params->second.second);
#if INF_ENGINE_RELEASE >= 2021010000
return IE::make_shared_blob<IE::NV12Blob>(y_blob, uv_blob);
#else
return IE::make_shared_blob<InferenceEngine::NV12Blob>(y_blob, uv_blob);
#endif
}
// NB: If no OV remote context created then use default MediaFrame accessor approach:
// it invokes memory copying operation If GPU MediaFrame come
ctx.views.emplace_back(new cv::MediaFrame::View(frame.access(cv::MediaFrame::Access::R)));
return wrapIE(*(ctx.views.back()), frame.desc());
}
@@ -1158,6 +1146,7 @@ static void PostOutputs(InferenceEngine::InferRequest &request,
ctx->out.post(std::move(output), ctx->eptr);
}
ctx->views.clear();
ctx->releaseKeepAliveFrame(&request);
}
@@ -178,8 +178,8 @@ VPLCPUAccelerationPolicy::create_surface_pool(size_t pool_size, size_t surface_s
GAPI_LOG_INFO(nullptr, "Released workspace memory: " << ptr);
ptr = nullptr;
#else
GAPI_LOG_INFO(nullptr, "Workspace memory to release: " << ptr);
free(ptr);
GAPI_LOG_INFO(nullptr, "Released workspace memory: " << ptr);
ptr = nullptr;
#endif
@@ -27,30 +27,16 @@ namespace onevpl {
VPLVAAPIAccelerationPolicy::VPLVAAPIAccelerationPolicy(device_selector_ptr_t selector) :
VPLAccelerationPolicy(selector),
cpu_dispatcher(new VPLCPUAccelerationPolicy(selector)),
va_handle(),
device_fd(-1) {
va_handle() {
#if defined(HAVE_VA) || defined(HAVE_VA_INTEL)
// TODO Move it out in device selector
device_fd = open("/dev/dri/renderD128", O_RDWR);
if (device_fd < 0) {
GAPI_LOG_WARNING(nullptr, "VAAPI device descriptor \"/dev/dri/renderD128\" has not found");
throw std::runtime_error("cannot open VAAPI device");
}
va_handle = vaGetDisplayDRM(device_fd);
if (!va_handle) {
GAPI_LOG_WARNING(nullptr, "VAAPI device vaGetDisplayDRM failed, error: " << strerror(errno));
close(device_fd);
throw std::runtime_error("vaGetDisplayDRM failed");
}
int major_version = 0, minor_version = 0;
VAStatus status {};
status = vaInitialize(va_handle, &major_version, &minor_version);
if (VA_STATUS_SUCCESS != status) {
GAPI_LOG_WARNING(nullptr, "Cannot initialize VAAPI device, error: " << vaErrorStr(status));
close(device_fd);
throw std::runtime_error("vaInitialize failed");
}
GAPI_LOG_INFO(nullptr, "created");
// setup VAAPI device
IDeviceSelector::DeviceScoreTable devices = get_device_selector()->select_devices();
GAPI_Assert(devices.size() == 1 && "Multiple(or zero) acceleration VAAPI devices are not unsupported");
AccelType accel_type = devices.begin()->second.get_type();
GAPI_Assert(accel_type == AccelType::VAAPI &&
"Unexpected device AccelType while is waiting AccelType::VAAPI");
va_handle = reinterpret_cast<VADisplay>(devices.begin()->second.get_ptr());
#else // defined(HAVE_VA) || defined(HAVE_VA_INTEL)
GAPI_Assert(false && "VPLVAAPIAccelerationPolicy unavailable in current configuration");
#endif // defined(HAVE_VA) || defined(HAVE_VA_INTEL)
@@ -58,7 +44,6 @@ VPLVAAPIAccelerationPolicy::VPLVAAPIAccelerationPolicy(device_selector_ptr_t sel
VPLVAAPIAccelerationPolicy::~VPLVAAPIAccelerationPolicy() {
vaTerminate(va_handle);
close(device_fd);
GAPI_LOG_INFO(nullptr, "destroyed");
}
@@ -50,7 +50,6 @@ private:
std::unique_ptr<VPLAccelerationPolicy> cpu_dispatcher;
#ifdef __linux__
VADisplay va_handle;
int device_fd; // TODO Move it out in device selector
#endif // __linux__
};
} // namespace onevpl
@@ -96,6 +96,8 @@ void LockAdapter::unlock_write(mfxMemId mid, mfxFrameData &data) {
SharedLock* LockAdapter::set_adaptee(SharedLock* new_impl) {
SharedLock* old_impl = impl;
GAPI_LOG_DEBUG(nullptr, "this: " << this <<
", old: " << old_impl << ", new: " << new_impl);
GAPI_DbgAssert(old_impl == nullptr || new_impl == nullptr && "Must not be previous impl");
impl = new_impl;
return old_impl;
@@ -184,6 +186,8 @@ void DX11AllocationItem::on_first_in_impl(mfxFrameData *ptr) {
D3D11_MAP mapType = D3D11_MAP_READ;
UINT mapFlags = D3D11_MAP_FLAG_DO_NOT_WAIT;
GAPI_LOG_DEBUG(nullptr, "texture: " << get_texture_ptr() <<
", subresorce: " << get_subresource());
shared_device_context->CopySubresourceRegion(get_staging_texture_ptr(), 0,
0, 0, 0,
get_texture_ptr(),
@@ -245,8 +249,8 @@ mfxStatus DX11AllocationItem::release_access(mfxFrameData *ptr) {
}
mfxStatus DX11AllocationItem::shared_access_acquire_unsafe(mfxFrameData *ptr) {
GAPI_LOG_DEBUG(nullptr, "acquire READ lock: " << this);
GAPI_LOG_DEBUG(nullptr, "texture: " << get_texture_ptr() <<
GAPI_LOG_DEBUG(nullptr, "acquire READ lock: " << this <<
", texture: " << get_texture_ptr() <<
", sub id: " << get_subresource());
// shared access requires elastic barrier
// first-in visited thread uses resource mapping on host memory
@@ -257,6 +261,7 @@ mfxStatus DX11AllocationItem::shared_access_acquire_unsafe(mfxFrameData *ptr) {
if (!(ptr->Y && (ptr->UV || (ptr->U && ptr->V)))) {
GAPI_LOG_WARNING(nullptr, "No any data obtained: " << this);
GAPI_DbgAssert(false && "shared access must provide data");
return MFX_ERR_LOCK_MEMORY;
}
GAPI_LOG_DEBUG(nullptr, "READ access granted: " << this);
@@ -264,8 +269,8 @@ mfxStatus DX11AllocationItem::shared_access_acquire_unsafe(mfxFrameData *ptr) {
}
mfxStatus DX11AllocationItem::shared_access_release_unsafe(mfxFrameData *ptr) {
GAPI_LOG_DEBUG(nullptr, "releasing READ lock: " << this);
GAPI_LOG_DEBUG(nullptr, "texture: " << get_texture_ptr() <<
GAPI_LOG_DEBUG(nullptr, "releasing READ lock: " << this <<
", texture: " << get_texture_ptr() <<
", sub id: " << get_subresource());
// releasing shared access requires elastic barrier
// last-out thread must make memory unmapping then and only then no more
@@ -278,8 +283,8 @@ mfxStatus DX11AllocationItem::shared_access_release_unsafe(mfxFrameData *ptr) {
}
mfxStatus DX11AllocationItem::exclusive_access_acquire_unsafe(mfxFrameData *ptr) {
GAPI_LOG_DEBUG(nullptr, "acquire WRITE lock: " << this);
GAPI_LOG_DEBUG(nullptr, "texture: " << get_texture_ptr() <<
GAPI_LOG_DEBUG(nullptr, "acquire WRITE lock: " << this <<
", texture: " << get_texture_ptr() <<
", sub id: " << get_subresource());
D3D11_MAP mapType = D3D11_MAP_WRITE;
UINT mapFlags = D3D11_MAP_FLAG_DO_NOT_WAIT;
@@ -321,8 +326,8 @@ mfxStatus DX11AllocationItem::exclusive_access_acquire_unsafe(mfxFrameData *ptr)
}
mfxStatus DX11AllocationItem::exclusive_access_release_unsafe(mfxFrameData *ptr) {
GAPI_LOG_DEBUG(nullptr, "releasing WRITE lock: " << this);
GAPI_LOG_DEBUG(nullptr, "texture: " << get_texture_ptr() <<
GAPI_LOG_DEBUG(nullptr, "releasing WRITE lock: " << this <<
", texture: " << get_texture_ptr() <<
", sub id: " << get_subresource());
get_device_ctx_ptr()->Unmap(get_staging_texture_ptr(), 0);
@@ -64,7 +64,7 @@ MediaFrame::View VPLMediaFrameCPUAdapter::access(MediaFrame::Access) {
}
cv::util::any VPLMediaFrameCPUAdapter::blobParams() const {
GAPI_Assert("VPLMediaFrameCPUAdapter::blobParams() is not implemented");
throw std::runtime_error("VPLMediaFrameCPUAdapter::blobParams() is not implemented");
return {};
}
@@ -30,6 +30,16 @@
#endif // HAVE_D3D11
#endif // HAVE_DIRECTX
#ifdef __linux__
#if defined(HAVE_VA) || defined(HAVE_VA_INTEL)
#include "va/va.h"
#include "va/va_drm.h"
#include <fcntl.h>
#include <unistd.h>
#endif // defined(HAVE_VA) || defined(HAVE_VA_INTEL)
#endif // __linux__
#include <codecvt>
#include "opencv2/core/directx.hpp"
@@ -37,6 +47,23 @@ namespace cv {
namespace gapi {
namespace wip {
namespace onevpl {
#ifdef __linux__
struct Aux {
~Aux() {
for (int fd : fds) {
close(fd);
}
}
void remember_fd(int fd) {
fds.insert(fd);
}
private:
std::set<int> fds;
};
#else
struct Aux {};
#endif
static std::vector<CfgParam> insertCfgparam(std::vector<CfgParam> &&param_array, AccelType type) {
switch (type) {
@@ -153,7 +180,78 @@ CfgParamDeviceSelector::CfgParamDeviceSelector(const CfgParams& cfg_params) :
break;
}
case MFX_IMPL_VIA_VAAPI : {
GAPI_LOG_WARNING(nullptr, "TODO MFX_IMPL_VIA_VAAPI falls back to CPU case")
#ifdef __linux__
#if defined(HAVE_VA) || defined(HAVE_VA_INTEL)
static const char *predefined_vaapi_devices_list[] {"/dev/dri/renderD128",
"/dev/dri/renderD129",
"/dev/dri/card0",
"/dev/dri/card1",
nullptr};
std::stringstream ss;
int device_fd = -1;
VADisplay va_handle;va_handle = nullptr;
for (const char **device_path = predefined_vaapi_devices_list;
*device_path != nullptr; device_path++) {
device_fd = open(*device_path, O_RDWR);
if (device_fd < 0) {
std::string info("Cannot open GPU file: \"");
info = info + *device_path + "\", error: " + strerror(errno);
GAPI_LOG_DEBUG(nullptr, info);
ss << info << std::endl;
continue;
}
va_handle = vaGetDisplayDRM(device_fd);
if (!va_handle) {
close(device_fd);
std::string info("VAAPI device vaGetDisplayDRM failed, error: ");
info += strerror(errno);
GAPI_LOG_DEBUG(nullptr, info);
ss << info << std::endl;
continue;
}
int major_version = 0, minor_version = 0;
VAStatus status {};
status = vaInitialize(va_handle, &major_version, &minor_version);
if (VA_STATUS_SUCCESS != status) {
close(device_fd);
va_handle = nullptr;
std::string info("Cannot initialize VAAPI device, error: ");
info += vaErrorStr(status);
GAPI_LOG_DEBUG(nullptr, info);
ss << info << std::endl;
continue;
}
GAPI_LOG_INFO(nullptr, "VAAPI created for device: " << *device_path);
break;
}
// check device creation
if (!va_handle) {
GAPI_LOG_WARNING(nullptr, "Cannot create VAAPI device. Log:\n" << ss.str());
throw std::logic_error(std::string("Cannot create device for \"") +
CfgParam::acceleration_mode_name() +
": MFX_IMPL_VIA_VAAPI\"");
}
// Unfortunately VAAPI doesn't provide API for extracting initial FD value from VADisplay, which
// value is stored as VADisplay fields, by the way. But, because we here are only one creator
// of VAAPI device then we will need make cleanup for all allocated resources by ourselfs
//and FD is definitely must be utilized. So, let's use complementary struct `Aux` which
// represent some kind of 'platform specific data' and which will store opened FD for
// future utilization
platform_specific_data.reset (new Aux);
platform_specific_data->remember_fd(device_fd);
suggested_device = IDeviceSelector::create<Device>(va_handle, "GPU", AccelType::VAAPI);
suggested_context = IDeviceSelector::create<Context>(nullptr, AccelType::VAAPI);
#else // defined(HAVE_VA) || defined(HAVE_VA_INTEL)
GAPI_Assert(false && "VPLVAAPIAccelerationPolicy unavailable in current linux configuration");
#endif // defined(HAVE_VA) || defined(HAVE_VA_INTEL)
#else // #ifdef __linux__
GAPI_Assert(false && "MFX_IMPL_VIA_VAAPI is supported on linux only")
#endif // #ifdef __linux__
break;
}
case MFX_ACCEL_MODE_NA: {
@@ -234,6 +332,19 @@ CfgParamDeviceSelector::CfgParamDeviceSelector(Device::Ptr device_ptr,
#endif // #if defined(HAVE_DIRECTX) && defined(HAVE_D3D11)
break;
}
case MFX_IMPL_VIA_VAAPI : {
#ifdef __linux__
#if defined(HAVE_VA) || defined(HAVE_VA_INTEL)
suggested_device = IDeviceSelector::create<Device>(device_ptr, device_id, AccelType::VAAPI);
suggested_context = IDeviceSelector::create<Context>(nullptr, AccelType::VAAPI);
#else // defined(HAVE_VA) || defined(HAVE_VA_INTEL)
GAPI_Assert(false && "VPLVAAPIAccelerationPolicy unavailable in current linux configuration");
#endif // defined(HAVE_VA) || defined(HAVE_VA_INTEL)
#else // #ifdef __linux__
GAPI_Assert(false && "MFX_IMPL_VIA_VAAPI is supported on linux only")
#endif // #ifdef __linux__
break;
}
case MFX_ACCEL_MODE_NA: {
GAPI_LOG_WARNING(nullptr, "Incompatible \"" << CfgParam::acceleration_mode_name() <<
": MFX_ACCEL_MODE_NA\" with "
@@ -284,7 +395,13 @@ CfgParamDeviceSelector::CfgParamDeviceSelector(const Device &device,
#endif // defined(HAVE_DIRECTX) && defined(HAVE_D3D11)
}
case AccelType::VAAPI:
GAPI_LOG_WARNING(nullptr, "TODO MFX_IMPL_VIA_VAAPI falls back to CPU case")
#ifdef __linux__
#if !defined(HAVE_VA) || !defined(HAVE_VA_INTEL)
GAPI_Assert(false && "VPLVAAPIAccelerationPolicy unavailable in current linux configuration");
#endif // defined(HAVE_VA) || defined(HAVE_VA_INTEL)
#else // #ifdef __linux__
GAPI_Assert(false && "MFX_IMPL_VIA_VAAPI is supported on linux only")
#endif // #ifdef __linux__
break;
case AccelType::HOST:
break;
@@ -332,6 +449,15 @@ CfgParamDeviceSelector::~CfgParamDeviceSelector() {
#endif // defined(HAVE_DIRECTX) && defined(HAVE_D3D11)
break;
}
case AccelType::VAAPI: {
#ifdef __linux__
#if defined(HAVE_VA) || defined(HAVE_VA_INTEL)
VADisplay va_handle = reinterpret_cast<VADisplay>(suggested_device.get_ptr());
vaTerminate(va_handle);
platform_specific_data.reset();
#endif // defined(HAVE_VA) || defined(HAVE_VA_INTEL)
#endif // #ifdef __linux__
}
default:
break;
}
@@ -20,6 +20,7 @@ namespace gapi {
namespace wip {
namespace onevpl {
class Aux;
struct GAPI_EXPORTS CfgParamDeviceSelector final: public IDeviceSelector {
CfgParamDeviceSelector(const CfgParams& params = {});
CfgParamDeviceSelector(Device::Ptr device_ptr,
@@ -37,6 +38,7 @@ struct GAPI_EXPORTS CfgParamDeviceSelector final: public IDeviceSelector {
private:
Device suggested_device;
Context suggested_context;
std::unique_ptr<Aux> platform_specific_data;
};
} // namespace onevpl
} // namespace wip
@@ -119,6 +119,19 @@ Context create_dx11_context(Context::Ptr ctx_ptr) {
AccelType::DX11);
}
Device create_vaapi_device(Device::Ptr device_ptr,
const std::string& device_name,
int file_description) {
return detail::DeviceContextCreator::create_entity<Device>(device_ptr,
device_name,
AccelType::VAAPI);
}
Context create_vaapi_context(Context::Ptr ctx_ptr) {
return detail::DeviceContextCreator::create_entity<Context>(ctx_ptr,
AccelType::VAAPI);
}
} // namespace onevpl
} // namespace wip
} // namespace gapi
@@ -321,11 +321,16 @@ std::unique_ptr<VPLAccelerationPolicy> GSource::Priv::initializeHWAccel(std::sha
const std::vector<CfgParam>& GSource::Priv::getDefaultCfgParams()
{
#ifdef __WIN32__
static const std::vector<CfgParam> def_params =
get_params_from_string<CfgParam>(
"mfxImplDescription.Impl: MFX_IMPL_TYPE_HARDWARE\n"
"mfxImplDescription.AccelerationMode: MFX_ACCEL_MODE_VIA_D3D11\n");
#else
static const std::vector<CfgParam> def_params =
get_params_from_string<CfgParam>(
"mfxImplDescription.Impl: MFX_IMPL_TYPE_HARDWARE\n");
#endif
return def_params;
}