/
Alx89
/
OpenCV
Обзор
Документация
Войти
/
Alx89
/
OpenCV
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
4.x
modules/gapi/src/streaming/onevpl/cfg_param_device_selector.cpp
475 строк
20 KB
Alexander Alekhin
Merge pull request #22935 from alalek:gapi_error
19 дек 2022, 09:05
Не верифицирован
19 дек 2022, 09:05
91998d6
Код
Авторство
О чём код?
// 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) 2021 Intel Corporation #ifdef HAVE_ONEVPL #include "streaming/onevpl/onevpl_export.hpp" #include <opencv2/gapi/own/assert.hpp> #include <opencv2/gapi/util/variant.hpp> #include <opencv2/gapi/streaming/onevpl/device_selector_interface.hpp> #include "streaming/onevpl/cfg_param_device_selector.hpp" #include "streaming/onevpl/cfg_params_parser.hpp" #include "streaming/onevpl/utils.hpp" #include "logger.hpp" #ifdef HAVE_DIRECTX #ifdef HAVE_D3D11 // get rid of generate macro max/min/etc from DX side #define D3D11_NO_HELPERS #define NOMINMAX #include <d3d11.h> #include <d3d11_4.h> #undef D3D11_NO_HELPERS #undef NOMINMAX #endif // HAVE_D3D11 #endif // HAVE_DIRECTX #ifdef __linux__ #include <fcntl.h> #include <unistd.h> #if defined(HAVE_VA) || defined(HAVE_VA_INTEL) #include "va/va.h" #include "va/va_drm.h" #endif // defined(HAVE_VA) || defined(HAVE_VA_INTEL) #endif // __linux__ #include <codecvt> #include "opencv2/core/directx.hpp" namespace cv { namespace gapi { namespace wip { namespace onevpl { #ifdef __linux__ struct PlatformSpecificParams { ~PlatformSpecificParams() { for (int fd : fds) { close(fd); } } void track_fd(int fd) { fds.insert(fd); } private: std::set<int> fds; }; #else struct PlatformSpecificParams {}; #endif std::vector<CfgParam> update_param_with_accel_type(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; case AccelType::VAAPI: param_array.push_back(CfgParam::create_acceleration_mode(MFX_IMPL_VIA_VAAPI)); 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)) { auto accel_mode_it = std::find_if(cfg_params.begin(), cfg_params.end(), [] (const CfgParam& value) { return value.get_name() == CfgParam::acceleration_mode_name(); }); if (accel_mode_it == cfg_params.end()) { GAPI_LOG_DEBUG(nullptr, "No HW Accel requested. Use default CPU"); return; } GAPI_LOG_DEBUG(nullptr, "Add HW acceleration support"); mfxVariant accel_mode = cfg_param_to_mfx_variant(*accel_mode_it); switch(accel_mode.Data.U32) { case MFX_ACCEL_MODE_VIA_D3D11: { #if defined(HAVE_DIRECTX) && defined(HAVE_D3D11) ID3D11Device *hw_handle = nullptr; ID3D11DeviceContext* device_context = nullptr; //Create device UINT creationFlags = 0;//D3D11_CREATE_DEVICE_BGRA_SUPPORT; #if defined _DEBUG || defined CV_STATIC_ANALYSIS // If the project is in a debug build, enable debugging via SDK Layers with this flag. creationFlags |= D3D11_CREATE_DEVICE_DEBUG; #endif D3D_FEATURE_LEVEL featureLevels[] = { D3D_FEATURE_LEVEL_11_1, D3D_FEATURE_LEVEL_11_0, }; D3D_FEATURE_LEVEL featureLevel; auto adapter_factory = createCOMPtrGuard<IDXGIFactory>(); { IDXGIFactory* out_factory = nullptr; HRESULT err = CreateDXGIFactory(__uuidof(IDXGIFactory), reinterpret_cast<void**>(&out_factory)); if (FAILED(err)) { throw std::runtime_error("Cannot create CreateDXGIFactory, error: " + std::to_string(HRESULT_CODE(err))); } adapter_factory = createCOMPtrGuard(out_factory); } auto intel_adapter = createCOMPtrGuard<IDXGIAdapter>(); UINT adapter_index = 0; const unsigned int refIntelVendorID = 0x8086; IDXGIAdapter* out_adapter = nullptr; while (adapter_factory->EnumAdapters(adapter_index, &out_adapter) != DXGI_ERROR_NOT_FOUND) { DXGI_ADAPTER_DESC desc{}; out_adapter->GetDesc(&desc); if (desc.VendorId == refIntelVendorID) { intel_adapter = createCOMPtrGuard(out_adapter); break; } ++adapter_index; } if (!intel_adapter) { throw std::runtime_error("No Intel GPU adapter on aboard"); } // Create the Direct3D 11 API device object and a corresponding context. HRESULT err = D3D11CreateDevice(intel_adapter.get(), D3D_DRIVER_TYPE_UNKNOWN, nullptr, creationFlags, featureLevels, ARRAYSIZE(featureLevels), D3D11_SDK_VERSION, &hw_handle, &featureLevel, &device_context); if(FAILED(err)) { throw std::logic_error("Cannot create D3D11CreateDevice, error: " + std::to_string(HRESULT_CODE(err))); } // oneVPL recommendation { ID3D11Multithread *pD11Multithread = nullptr; device_context->QueryInterface(IID_PPV_ARGS(&pD11Multithread)); pD11Multithread->SetMultithreadProtected(true); pD11Multithread->Release(); } suggested_device = IDeviceSelector::create<Device>(hw_handle, "GPU", AccelType::DX11); suggested_context = IDeviceSelector::create<Context>(device_context, AccelType::DX11); #else // defined(HAVE_DIRECTX) && defined(HAVE_D3D11) 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 // defined(HAVE_DIRECTX) && defined(HAVE_D3D11) break; } case MFX_IMPL_VIA_VAAPI : { #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 `PlatformSpecificParams` which // represent some kind of 'platform specific data' and which will store opened FD for // future utilization platform_specific_data.reset (new PlatformSpecificParams); platform_specific_data->track_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_Error("VPLVAAPIAccelerationPolicy unavailable in current linux configuration"); #endif // defined(HAVE_VA) || defined(HAVE_VA_INTEL) #else // #ifdef __linux__ GAPI_Error("MFX_IMPL_VIA_VAAPI is supported on linux only"); #endif // #ifdef __linux__ break; } case MFX_ACCEL_MODE_NA: { // nothing to do break; } default: throw std::logic_error(std::string("Unsupported \"") + CfgParam::acceleration_mode_name() +"\" requested: " + std::to_string(accel_mode.Data.U32)); break; } } CfgParamDeviceSelector::CfgParamDeviceSelector(Device::Ptr device_ptr, const std::string& device_id, Context::Ptr ctx_ptr, const CfgParams& cfg_params) : suggested_device(IDeviceSelector::create<Device>(nullptr, "CPU", AccelType::HOST)), suggested_context(IDeviceSelector::create<Context>(nullptr, AccelType::HOST)) { auto accel_mode_it = std::find_if(cfg_params.begin(), cfg_params.end(), [] (const CfgParam& value) { return value.get_name() == CfgParam::acceleration_mode_name(); }); if (accel_mode_it == cfg_params.end()) { GAPI_LOG_WARNING(nullptr, "Cannot deternime \"device_ptr\" type. " "Make sure a param \"" << CfgParam::acceleration_mode_name() << "\" " "presents in configurations and has correct value according to " "\"device_ptr\" type"); throw std::logic_error(std::string("Missing \"") + CfgParam::acceleration_mode_name() + "\" param"); } GAPI_LOG_DEBUG(nullptr, "Turn on HW acceleration support for device: " << device_ptr << ", context: " << ctx_ptr); if (!device_ptr) { GAPI_LOG_WARNING(nullptr, "Empty \"device_ptr\" is not allowed when " "param \"" << CfgParam::acceleration_mode_name() << "\" existed"); throw std::logic_error("Invalid param: \"device_ptr\""); } if (!ctx_ptr) { GAPI_LOG_WARNING(nullptr, "Empty \"ctx_ptr\" is not allowed"); throw std::logic_error("Invalid param: \"ctx_ptr\""); } mfxVariant accel_mode = cfg_param_to_mfx_variant(*accel_mode_it); cv::util::suppress_unused_warning(device_id); switch(accel_mode.Data.U32) { case MFX_ACCEL_MODE_VIA_D3D11: { #if defined(HAVE_DIRECTX) && defined(HAVE_D3D11) suggested_device = IDeviceSelector::create<Device>(device_ptr, device_id, AccelType::DX11); ID3D11Device* dx_device_ptr = reinterpret_cast<ID3D11Device*>(suggested_device.get_ptr()); dx_device_ptr->AddRef(); suggested_context = IDeviceSelector::create<Context>(ctx_ptr, AccelType::DX11); 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(); #else // defined(HAVE_DIRECTX) && defined(HAVE_D3D11) 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 // #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_Error("VPLVAAPIAccelerationPolicy unavailable in current linux configuration"); #endif // defined(HAVE_VA) || defined(HAVE_VA_INTEL) #else // #ifdef __linux__ GAPI_Error("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 " "\"device_ptr\" and \"ctx_ptr\" arguments. " "You should not clarify these arguments with \"MFX_ACCEL_MODE_NA\" mode"); throw std::logic_error("Incompatible param: MFX_ACCEL_MODE_NA"); } default: throw std::logic_error(std::string("Unsupported \"") + CfgParam::acceleration_mode_name() + "\" requested: " + std::to_string(accel_mode.Data.U32)); break; } } CfgParamDeviceSelector::CfgParamDeviceSelector(const Device &device, const Context &ctx, CfgParams) : suggested_device(device), suggested_context(ctx) { switch(device.get_type()) { case AccelType::DX11: { #if defined(HAVE_DIRECTX) && defined(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 // defined(HAVE_DIRECTX) && defined(HAVE_D3D11) 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 // defined(HAVE_DIRECTX) && defined(HAVE_D3D11) } case AccelType::VAAPI: #ifdef __linux__ #if !defined(HAVE_VA) || !defined(HAVE_VA_INTEL) GAPI_Error("VPLVAAPIAccelerationPolicy unavailable in current linux configuration"); #endif // defined(HAVE_VA) || defined(HAVE_VA_INTEL) #else // #ifdef __linux__ GAPI_Error("MFX_IMPL_VIA_VAAPI is supported on linux only"); #endif // #ifdef __linux__ break; 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(); switch(ctype) { case AccelType::HOST: //nothing to do break; case AccelType::DX11: { #if defined(HAVE_DIRECTX) && defined(HAVE_D3D11) ID3D11DeviceContext* device_ctx_ptr = reinterpret_cast<ID3D11DeviceContext*>(suggested_context.get_ptr()); device_ctx_ptr->Release(); device_ctx_ptr = nullptr; #endif // defined(HAVE_DIRECTX) && defined(HAVE_D3D11) break; } default: break; } GAPI_LOG_INFO(nullptr, "release device by name: " << suggested_device.get_name() << ", ptr: " << suggested_device.get_ptr()); AccelType dtype = suggested_device.get_type(); switch(dtype) { case AccelType::HOST: //nothing to do break; case AccelType::DX11: { #if defined(HAVE_DIRECTX) && defined(HAVE_D3D11) ID3D11Device* device_ptr = reinterpret_cast<ID3D11Device*>(suggested_device.get_ptr()); device_ptr->Release(); device_ptr = nullptr; #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; } } CfgParamDeviceSelector::DeviceScoreTable CfgParamDeviceSelector::select_devices() const { return {std::make_pair(Score::Type(Score::MaxActivePriority), suggested_device)}; } CfgParamDeviceSelector::DeviceContexts CfgParamDeviceSelector::select_context() { return {suggested_context}; } } // namespace onevpl } // namespace wip } // namespace gapi } // namespace cv #endif // HAVE_ONEVPL