1
0
mirror of https://github.com/opencv/opencv.git synced 2026-07-30 15:53:03 +04:00

Merge pull request #21049 from sivanov-work:vpl_dx11_merge

G-API: oneVPL merge DX11 acceleration

* Merge DX11 initial

* Fold conditions row in MACRO in utils

* Inject DeviceSelector

* Turn on DeviceSelector in DX11

* Change sharedLock logic & Move FMT checking in FrameAdapter c-tor

* Move out NumSuggestFrame to configure params

* Drain file source fix

* Fix compilation

* Force zero initializetion of SharedLock

* Fix some compiler warnings

* Fix integer comparison warnings

* Fix integers in sample

* Integrate Demux

* Fix compilation

* Add predefined names for some CfgParam

* Trigger CI

* Fix MultithreadCtx bug, Add Dx11 GetBlobParam(), Get rif of ATL CComPtr

* Fix UT: remove unit test with deprecated video from opencv_extra

* Add creators for most usable CfgParam

* Eliminate some warnings

* Fix warning in GAPI_Assert

* Apply comments

* Add VPL wrapped header with MSVC pragma to get rid of global warning masking
This commit is contained in:
Sergey Ivanov
2021-12-08 10:09:33 +03:00
committed by GitHub
parent 41d108ead6
commit 5c91f5b71d
49 changed files with 3231 additions and 866 deletions
@@ -0,0 +1,86 @@
// 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
#ifndef OPENCV_GAPI_STREAMING_TESTS_COMMON_HPP
#define OPENCV_GAPI_STREAMING_TESTS_COMMON_HPP
#include "gapi_tests_common.hpp"
#include <opencv2/gapi/streaming/onevpl/source.hpp>
#include <opencv2/gapi/streaming/onevpl/data_provider_interface.hpp>
#include "streaming/onevpl/data_provider_defines.hpp"
#ifdef HAVE_ONEVPL
#include "streaming/onevpl/onevpl_export.hpp"
namespace opencv_test {
namespace streaming {
namespace onevpl {
struct StreamDataProvider : public cv::gapi::wip::onevpl::IDataProvider {
StreamDataProvider(std::istream& in) : data_stream (in) {
EXPECT_TRUE(in);
}
mfx_codec_id_type get_mfx_codec_id() const override {
return MFX_CODEC_HEVC;
}
bool fetch_bitstream_data(std::shared_ptr<mfx_bitstream> &out_bitstream) override {
if (empty()) {
return false;
}
if (!out_bitstream) {
out_bitstream = std::make_shared<mfx_bitstream>();
out_bitstream->MaxLength = 2000000;
out_bitstream->Data = (mfxU8 *)calloc(out_bitstream->MaxLength, sizeof(mfxU8));
if(!out_bitstream->Data) {
throw std::runtime_error("Cannot allocate bitstream.Data bytes: " +
std::to_string(out_bitstream->MaxLength * sizeof(mfxU8)));
}
out_bitstream->CodecId = get_mfx_codec_id();
}
mfxU8 *p0 = out_bitstream->Data;
mfxU8 *p1 = out_bitstream->Data + out_bitstream->DataOffset;
EXPECT_FALSE(out_bitstream->DataOffset > out_bitstream->MaxLength - 1);
EXPECT_FALSE(out_bitstream->DataLength + out_bitstream->DataOffset > out_bitstream->MaxLength);
std::copy_n(p1, out_bitstream->DataLength, p0);
out_bitstream->DataOffset = 0;
out_bitstream->DataLength += static_cast<mfxU32>(fetch_data(out_bitstream->MaxLength - out_bitstream->DataLength,
out_bitstream->Data + out_bitstream->DataLength));
return out_bitstream->DataLength != 0;
}
size_t fetch_data(size_t out_data_size, void* out_data_buf) {
data_stream.read(reinterpret_cast<char*>(out_data_buf), out_data_size);
return data_stream.gcount();
}
bool empty() const override {
return data_stream.eof() || data_stream.bad();
}
private:
std::istream& data_stream;
};
static const unsigned char hevc_header[] = {
0x00, 0x00, 0x00, 0x01, 0x40, 0x01, 0x0C, 0x06, 0xFF, 0xFF, 0x01, 0x40, 0x00,
0x00, 0x03, 0x00, 0x80, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x78, 0x00,
0x00, 0x04, 0x02, 0x10, 0x30, 0x00, 0x00, 0x03, 0x00, 0x10, 0x00, 0x00, 0x03,
0x01, 0xE5, 0x00, 0x00, 0x00, 0x01, 0x42, 0x01, 0x06, 0x01, 0x40, 0x00, 0x00,
0x03, 0x00, 0x80, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x78, 0x00, 0x00,
0xA0, 0x10, 0x20, 0x61, 0x63, 0x41, 0x00, 0x86, 0x49, 0x1B, 0x2B, 0x20, 0x00,
0x00, 0x00, 0x01, 0x44, 0x01, 0xC0, 0x71, 0xC0, 0xD9, 0x20, 0x00, 0x00, 0x00,
0x01, 0x26, 0x01, 0xAF, 0x0C
};
} // namespace onevpl
} // namespace streaming
} // namespace opencv_test
#endif // HAVE_ONEVPL
#endif // OPENCV_GAPI_STREAMING_TESTS_HPP
@@ -7,7 +7,7 @@
#include "../test_precomp.hpp"
#include "../common/gapi_tests_common.hpp"
#include "../common/gapi_streaming_tests_common.hpp"
#include <thread> // sleep_for (Delay)
@@ -24,18 +24,8 @@
#include <opencv2/gapi/streaming/cap.hpp>
#include <opencv2/gapi/streaming/desync.hpp>
#include <opencv2/gapi/streaming/format.hpp>
#include <opencv2/gapi/gstreaming.hpp>
#include <opencv2/gapi/streaming/onevpl/source.hpp>
#include "streaming/onevpl/data_provider_defines.hpp"
#ifdef HAVE_ONEVPL
#if (MFX_VERSION >= 2000)
#include <vpl/mfxdispatcher.h>
#endif
#include <vpl/mfx.h>
#endif // HAVE_ONEVPL
namespace opencv_test
{
@@ -116,7 +106,7 @@ struct GAPI_Streaming: public ::testing::TestWithParam<std::tuple<KernelPackage,
using namespace cv::gapi;
auto args = cv::compile_args(use_only{pkg});
if (cap) {
args += cv::compile_args(streaming::queue_capacity{cap.value()});
args += cv::compile_args(cv::gapi::streaming::queue_capacity{cap.value()});
}
return args;
}
@@ -269,57 +259,6 @@ void checkPullOverload(const cv::Mat& ref,
EXPECT_EQ(0., cv::norm(ref, out_mat, cv::NORM_INF));
}
#ifdef HAVE_ONEVPL
struct StreamDataProvider : public cv::gapi::wip::onevpl::IDataProvider {
StreamDataProvider(std::istream& in) : data_stream (in) {
EXPECT_TRUE(in);
}
mfx_codec_id_type get_mfx_codec_id() const override {
return MFX_CODEC_HEVC;
}
bool fetch_bitstream_data(std::shared_ptr<mfx_bitstream> &out_bitstream) override {
if (empty()) {
return false;
}
if (!out_bitstream) {
out_bitstream = std::make_shared<mfx_bitstream>();
out_bitstream->MaxLength = 2000000;
out_bitstream->Data = (mfxU8 *)calloc(out_bitstream->MaxLength, sizeof(mfxU8));
if(!out_bitstream->Data) {
throw std::runtime_error("Cannot allocate bitstream.Data bytes: " +
std::to_string(out_bitstream->MaxLength * sizeof(mfxU8)));
}
out_bitstream->CodecId = get_mfx_codec_id();
}
mfxU8 *p0 = out_bitstream->Data;
mfxU8 *p1 = out_bitstream->Data + out_bitstream->DataOffset;
EXPECT_FALSE(out_bitstream->DataOffset > out_bitstream->MaxLength - 1);
EXPECT_FALSE(out_bitstream->DataLength + out_bitstream->DataOffset > out_bitstream->MaxLength);
std::copy_n(p1, out_bitstream->DataLength, p0);
out_bitstream->DataOffset = 0;
out_bitstream->DataLength += static_cast<mfxU32>(fetch_data(out_bitstream->MaxLength - out_bitstream->DataLength,
out_bitstream->Data + out_bitstream->DataLength));
return out_bitstream->DataLength != 0;
}
size_t fetch_data(size_t out_data_size, void* out_data_buf) {
data_stream.read(reinterpret_cast<char*>(out_data_buf), out_data_size);
return (size_t)data_stream.gcount();
}
bool empty() const override {
return data_stream.eof() || data_stream.bad();
}
private:
std::istream& data_stream;
};
#endif // HAVE_ONEVPL
} // anonymous namespace
TEST_P(GAPI_Streaming, SmokeTest_ConstInput_GMat)
@@ -2244,31 +2183,21 @@ TEST(GAPI_Streaming, TestPythonAPI)
}
#ifdef HAVE_ONEVPL
const unsigned char hevc_header[] = {
0x00, 0x00, 0x00, 0x01, 0x40, 0x01, 0x0C, 0x06, 0xFF, 0xFF, 0x01, 0x40, 0x00,
0x00, 0x03, 0x00, 0x80, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x78, 0x00,
0x00, 0x04, 0x02, 0x10, 0x30, 0x00, 0x00, 0x03, 0x00, 0x10, 0x00, 0x00, 0x03,
0x01, 0xE5, 0x00, 0x00, 0x00, 0x01, 0x42, 0x01, 0x06, 0x01, 0x40, 0x00, 0x00,
0x03, 0x00, 0x80, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x78, 0x00, 0x00,
0xA0, 0x10, 0x20, 0x61, 0x63, 0x41, 0x00, 0x86, 0x49, 0x1B, 0x2B, 0x20, 0x00,
0x00, 0x00, 0x01, 0x44, 0x01, 0xC0, 0x71, 0xC0, 0xD9, 0x20, 0x00, 0x00, 0x00,
0x01, 0x26, 0x01, 0xAF, 0x0C
};
TEST(OneVPL_Source, Init)
{
using CfgParam = cv::gapi::wip::onevpl::CfgParam;
std::vector<CfgParam> src_params;
src_params.push_back(CfgParam::create<uint32_t>("mfxImplDescription.Impl",
MFX_IMPL_TYPE_HARDWARE));
src_params.push_back(CfgParam::create<uint32_t>("mfxImplDescription.AccelerationMode",
MFX_ACCEL_MODE_VIA_D3D11, false));
src_params.push_back(CfgParam::create<uint32_t>("mfxImplDescription.mfxDecoderDescription.decoder.CodecID",
MFX_CODEC_HEVC));
src_params.push_back(CfgParam::create_implementation(MFX_IMPL_TYPE_HARDWARE));
src_params.push_back(CfgParam::create_acceleration_mode(MFX_ACCEL_MODE_VIA_D3D11));
src_params.push_back(CfgParam::create_decoder_id(MFX_CODEC_HEVC));
std::stringstream stream(std::ios_base::in | std::ios_base::out | std::ios_base::binary);
EXPECT_TRUE(stream.write(reinterpret_cast<char*>(const_cast<unsigned char *>(hevc_header)),
sizeof(hevc_header)));
auto stream_data_provider = std::make_shared<StreamDataProvider>(stream);
EXPECT_TRUE(stream.write(reinterpret_cast<char*>(const_cast<unsigned char *>(streaming::onevpl::hevc_header)),
sizeof(streaming::onevpl::hevc_header)));
std::shared_ptr<cv::gapi::wip::onevpl::IDataProvider> stream_data_provider =
std::make_shared<streaming::onevpl::StreamDataProvider>(stream);
cv::Ptr<cv::gapi::wip::IStreamSource> cap;
bool cap_created = false;
@@ -2285,7 +2214,7 @@ TEST(OneVPL_Source, Init)
}
EXPECT_TRUE(stream_data_provider->empty());
}
#endif
#endif // HAVE_ONEVPL
TEST(GAPI_Streaming, TestDesyncRMat) {
cv::GMat in;
@@ -0,0 +1,348 @@
// 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
#include "../test_precomp.hpp"
#include "../common/gapi_streaming_tests_common.hpp"
#include <chrono>
#include <future>
#define private public
#include "streaming/onevpl/accelerators/utils/shared_lock.hpp"
#undef private
#include "streaming/onevpl/accelerators/utils/elastic_barrier.hpp"
namespace opencv_test
{
namespace
{
using cv::gapi::wip::onevpl::SharedLock;
struct TestBarrier : public cv::gapi::wip::onevpl::elastic_barrier<TestBarrier> {
void on_first_in_impl(size_t visitor_id) {
static std::atomic<int> thread_counter{};
thread_counter++;
EXPECT_EQ(thread_counter.load(), 1);
visitors_in.insert(visitor_id);
last_visitor_id = visitor_id;
thread_counter--;
EXPECT_EQ(thread_counter.load(), 0);
}
void on_last_out_impl(size_t visitor_id) {
static std::atomic<int> thread_counter{};
thread_counter++;
EXPECT_EQ(thread_counter.load(), 1);
visitors_out.insert(visitor_id);
last_visitor_id = visitor_id;
thread_counter--;
EXPECT_EQ(thread_counter.load(), 0);
}
size_t last_visitor_id = 0;
std::set<size_t> visitors_in;
std::set<size_t> visitors_out;
};
TEST(OneVPL_SharedLock, Create) {
SharedLock lock;
EXPECT_EQ(lock.shared_counter.load(), size_t{0});
}
TEST(OneVPL_SharedLock, Read_SingleThread)
{
SharedLock lock;
const size_t single_thread_read_count = 100;
for(size_t i = 0; i < single_thread_read_count; i++) {
lock.shared_lock();
EXPECT_FALSE(lock.owns());
}
EXPECT_EQ(lock.shared_counter.load(), single_thread_read_count);
for(size_t i = 0; i < single_thread_read_count; i++) {
lock.unlock_shared();
EXPECT_FALSE(lock.owns());
}
EXPECT_EQ(lock.shared_counter.load(), size_t{0});
}
TEST(OneVPL_SharedLock, TryLock_SingleThread)
{
SharedLock lock;
EXPECT_TRUE(lock.try_lock());
EXPECT_TRUE(lock.owns());
lock.unlock();
EXPECT_FALSE(lock.owns());
EXPECT_EQ(lock.shared_counter.load(), size_t{0});
}
TEST(OneVPL_SharedLock, Write_SingleThread)
{
SharedLock lock;
lock.lock();
EXPECT_TRUE(lock.owns());
lock.unlock();
EXPECT_FALSE(lock.owns());
EXPECT_EQ(lock.shared_counter.load(), size_t{0});
}
TEST(OneVPL_SharedLock, TryLockTryLock_SingleThread)
{
SharedLock lock;
lock.try_lock();
EXPECT_FALSE(lock.try_lock());
lock.unlock();
EXPECT_FALSE(lock.owns());
}
TEST(OneVPL_SharedLock, ReadTryLock_SingleThread)
{
SharedLock lock;
lock.shared_lock();
EXPECT_FALSE(lock.owns());
EXPECT_FALSE(lock.try_lock());
lock.unlock_shared();
EXPECT_TRUE(lock.try_lock());
EXPECT_TRUE(lock.owns());
lock.unlock();
}
TEST(OneVPL_SharedLock, WriteTryLock_SingleThread)
{
SharedLock lock;
lock.lock();
EXPECT_TRUE(lock.owns());
EXPECT_FALSE(lock.try_lock());
lock.unlock();
EXPECT_TRUE(lock.try_lock());
EXPECT_TRUE(lock.owns());
lock.unlock();
}
TEST(OneVPL_SharedLock, Write_MultiThread)
{
SharedLock lock;
std::promise<void> barrier;
std::shared_future<void> sync = barrier.get_future();
static const size_t inc_count = 10000000;
size_t shared_value = 0;
auto work = [&lock, &shared_value](size_t count) {
for (size_t i = 0; i < count; i ++) {
lock.lock();
shared_value ++;
lock.unlock();
}
};
std::thread worker_thread([&barrier, sync, work] () {
std::thread sub_worker([&barrier, work] () {
barrier.set_value();
work(inc_count);
});
sync.wait();
work(inc_count);
sub_worker.join();
});
sync.wait();
work(inc_count);
worker_thread.join();
EXPECT_EQ(shared_value, inc_count * 3);
}
TEST(OneVPL_SharedLock, ReadWrite_MultiThread)
{
SharedLock lock;
std::promise<void> barrier;
std::future<void> sync = barrier.get_future();
static const size_t inc_count = 10000000;
size_t shared_value = 0;
auto write_work = [&lock, &shared_value](size_t count) {
for (size_t i = 0; i < count; i ++) {
lock.lock();
shared_value ++;
lock.unlock();
}
};
auto read_work = [&lock, &shared_value](size_t count) {
auto old_shared_value = shared_value;
for (size_t i = 0; i < count; i ++) {
lock.shared_lock();
EXPECT_TRUE(shared_value >= old_shared_value);
old_shared_value = shared_value;
lock.unlock_shared();
}
};
std::thread writer_thread([&barrier, write_work] () {
barrier.set_value();
write_work(inc_count);
});
sync.wait();
read_work(inc_count);
writer_thread.join();
EXPECT_EQ(shared_value, inc_count);
}
TEST(OneVPL_ElasticBarrier, single_thread_visit)
{
TestBarrier barrier;
const size_t max_visit_count = 10000;
size_t visit_id = 0;
for (visit_id = 0; visit_id < max_visit_count; visit_id++) {
barrier.visit_in(visit_id);
EXPECT_EQ(barrier.visitors_in.size(), size_t{1});
}
EXPECT_EQ(barrier.last_visitor_id, size_t{0});
EXPECT_EQ(barrier.visitors_out.size(), size_t{0});
for (visit_id = 0; visit_id < max_visit_count; visit_id++) {
barrier.visit_out(visit_id);
EXPECT_EQ(barrier.visitors_in.size(), size_t{1});
}
EXPECT_EQ(barrier.last_visitor_id, visit_id - 1);
EXPECT_EQ(barrier.visitors_out.size(), size_t{1});
}
TEST(OneVPL_ElasticBarrier, multi_thread_visit)
{
TestBarrier tested_barrier;
static const size_t max_visit_count = 10000000;
std::atomic<size_t> visit_in_wait_counter{};
std::promise<void> start_sync_barrier;
std::shared_future<void> start_sync = start_sync_barrier.get_future();
std::promise<void> phase_sync_barrier;
std::shared_future<void> phase_sync = phase_sync_barrier.get_future();
auto visit_worker_job = [&tested_barrier,
&visit_in_wait_counter,
start_sync,
phase_sync] (size_t worker_id) {
start_sync.wait();
// first phase
const size_t begin_range = worker_id * max_visit_count;
const size_t end_range = (worker_id + 1) * max_visit_count;
for (size_t visit_id = begin_range; visit_id < end_range; visit_id++) {
tested_barrier.visit_in(visit_id);
}
// notify all worker first phase ready
visit_in_wait_counter.fetch_add(1);
// wait main second phase
phase_sync.wait();
// second phase
for (size_t visit_id = begin_range; visit_id < end_range; visit_id++) {
tested_barrier.visit_out(visit_id);
}
};
auto visit_main_job = [&tested_barrier,
&visit_in_wait_counter,
&phase_sync_barrier] (size_t total_workers_count,
size_t worker_id) {
const size_t begin_range = worker_id * max_visit_count;
const size_t end_range = (worker_id + 1) * max_visit_count;
for (size_t visit_id = begin_range; visit_id < end_range; visit_id++) {
tested_barrier.visit_in(visit_id);
}
// wait all workers first phase done
visit_in_wait_counter.fetch_add(1);
while (visit_in_wait_counter.load() != total_workers_count) {
std::this_thread::yield();
};
// TEST invariant: last_visitor_id MUST be one from any FIRST worker visitor_id
bool one_of_available_ids_matched = false;
for (size_t id = 0; id < total_workers_count; id ++) {
size_t expected_last_visitor_for_id = id * max_visit_count;
one_of_available_ids_matched |=
(tested_barrier.last_visitor_id == expected_last_visitor_for_id) ;
}
EXPECT_TRUE(one_of_available_ids_matched);
// unblock all workers to work out second phase
phase_sync_barrier.set_value();
// continue second phase
for (size_t visit_id = begin_range; visit_id < end_range; visit_id++) {
tested_barrier.visit_out(visit_id);
}
};
size_t max_worker_count = std::thread::hardware_concurrency();
if (max_worker_count < 2) {
max_worker_count = 2; // logical 2 threads required at least
}
std::vector<std::thread> workers;
workers.reserve(max_worker_count);
for (size_t worker_id = 1; worker_id < max_worker_count; worker_id++) {
workers.emplace_back(visit_worker_job, worker_id);
}
// let's go for first phase
start_sync_barrier.set_value();
// utilize main thread as well
visit_main_job(max_worker_count, 0);
// join all threads second phase
for (auto& w : workers) {
w.join();
}
// TEST invariant: last_visitor_id MUST be one from any LATTER worker visitor_id
bool one_of_available_ids_matched = false;
for (size_t id = 0; id < max_worker_count; id ++) {
one_of_available_ids_matched |=
(tested_barrier.last_visitor_id == ((id + 1) * max_visit_count - 1)) ;
}
EXPECT_TRUE(one_of_available_ids_matched);
}
}
} // opencv_test
@@ -7,7 +7,7 @@
#include "../test_precomp.hpp"
#include "../common/gapi_tests_common.hpp"
#include "../common/gapi_streaming_tests_common.hpp"
#include <chrono>
#include <future>
@@ -27,14 +27,16 @@
#include <opencv2/gapi/streaming/desync.hpp>
#include <opencv2/gapi/streaming/format.hpp>
#include <opencv2/gapi/streaming/onevpl/source.hpp>
#ifdef HAVE_ONEVPL
#include <opencv2/gapi/streaming/onevpl/data_provider_interface.hpp>
#include "streaming/onevpl/cfg_param_device_selector.hpp"
#include "streaming/onevpl/accelerators/surface/surface.hpp"
#include "streaming/onevpl/accelerators/surface/cpu_frame_adapter.hpp"
#include "streaming/onevpl/accelerators/accel_policy_cpu.hpp"
#include "streaming/onevpl/accelerators/accel_policy_dx11.hpp"
#include "streaming/onevpl/accelerators/dx11_alloc_resource.hpp"
#include "streaming/onevpl/accelerators/utils/shared_lock.hpp"
#include "streaming/onevpl/engine/processing_engine_base.hpp"
#include "streaming/onevpl/engine/engine_session.hpp"
@@ -60,6 +62,11 @@ struct TestProcessingSession : public cv::gapi::wip::onevpl::EngineSession {
TestProcessingSession(mfxSession mfx_session) :
EngineSession(mfx_session, {}) {
}
const mfxVideoParam& get_video_param() const override {
static mfxVideoParam empty;
return empty;
}
};
struct TestProcessingEngine: public cv::gapi::wip::onevpl::ProcessingEngineBase {
@@ -98,14 +105,66 @@ struct TestProcessingEngine: public cv::gapi::wip::onevpl::ProcessingEngineBase
);
}
void initialize_session(mfxSession mfx_session,
cv::gapi::wip::onevpl::DecoderParams&&,
std::shared_ptr<cv::gapi::wip::onevpl::IDataProvider>) override {
std::shared_ptr<cv::gapi::wip::onevpl::EngineSession>
initialize_session(mfxSession mfx_session,
const std::vector<cv::gapi::wip::onevpl::CfgParam>&,
std::shared_ptr<cv::gapi::wip::onevpl::IDataProvider>) override {
register_session<TestProcessingSession>(mfx_session);
return register_session<TestProcessingSession>(mfx_session);
}
};
template <class LockProcessor, class UnlockProcessor>
class TestLockableAllocator {
public :
using self_t = TestLockableAllocator<LockProcessor, UnlockProcessor>;
mfxFrameAllocator get() {
return m_allocator;
}
private:
TestLockableAllocator(mfxFrameAllocator allocator) :
m_allocator(allocator) {
}
static mfxStatus MFX_CDECL lock_cb(mfxHDL, mfxMemId mid, mfxFrameData *ptr) {
auto it = lock_processor_table.find(mid);
EXPECT_TRUE(it != lock_processor_table.end());
return it->second(mid, ptr);
}
static mfxStatus MFX_CDECL unlock_cb(mfxHDL, mfxMemId mid, mfxFrameData *ptr) {
auto it = unlock_processor_table.find(mid);
EXPECT_TRUE(it != unlock_processor_table.end());
return it->second(mid, ptr);
}
template <class L, class U>
friend TestLockableAllocator<L,U> create_test_allocator(mfxMemId, L, U);
static std::map<mfxMemId, LockProcessor> lock_processor_table;
static std::map<mfxMemId, UnlockProcessor> unlock_processor_table;
mfxFrameAllocator m_allocator;
};
template <class LockProcessor, class UnlockProcessor>
std::map<mfxMemId, UnlockProcessor> TestLockableAllocator<LockProcessor, UnlockProcessor>::lock_processor_table {};
template <class LockProcessor, class UnlockProcessor>
std::map<mfxMemId, UnlockProcessor> TestLockableAllocator<LockProcessor, UnlockProcessor>::unlock_processor_table {};
template <class LockProcessor, class UnlockProcessor>
TestLockableAllocator<LockProcessor, UnlockProcessor>
create_test_allocator(mfxMemId mid, LockProcessor lock_p, UnlockProcessor unlock_p) {
mfxFrameAllocator allocator {};
TestLockableAllocator<LockProcessor, UnlockProcessor>::lock_processor_table[mid] = lock_p;
allocator.Lock = &TestLockableAllocator<LockProcessor, UnlockProcessor>::lock_cb;
TestLockableAllocator<LockProcessor, UnlockProcessor>::unlock_processor_table[mid] = unlock_p;
allocator.Unlock = &TestLockableAllocator<LockProcessor, UnlockProcessor>::unlock_cb;
return TestLockableAllocator<LockProcessor, UnlockProcessor> {allocator};
}
cv::gapi::wip::onevpl::surface_ptr_t create_test_surface(std::shared_ptr<void> out_buf_ptr,
size_t, size_t) {
std::unique_ptr<mfxFrameSurface1> handle(new mfxFrameSurface1{});
@@ -262,8 +321,10 @@ TEST(OneVPL_Source_CPU_Accelerator, InitDestroy)
{
using cv::gapi::wip::onevpl::VPLCPUAccelerationPolicy;
using cv::gapi::wip::onevpl::VPLAccelerationPolicy;
using cv::gapi::wip::onevpl::CfgParamDeviceSelector;
auto acceleration_policy = std::make_shared<VPLCPUAccelerationPolicy>();
auto acceleration_policy =
std::make_shared<VPLCPUAccelerationPolicy>(std::make_shared<CfgParamDeviceSelector>());
size_t surface_count = 10;
size_t surface_size_bytes = 1024;
@@ -292,9 +353,11 @@ TEST(OneVPL_Source_CPU_Accelerator, PoolProduceConsume)
{
using cv::gapi::wip::onevpl::VPLCPUAccelerationPolicy;
using cv::gapi::wip::onevpl::VPLAccelerationPolicy;
using cv::gapi::wip::onevpl::CfgParamDeviceSelector;
using cv::gapi::wip::onevpl::Surface;
auto acceleration_policy = std::make_shared<VPLCPUAccelerationPolicy>();
auto acceleration_policy =
std::make_shared<VPLCPUAccelerationPolicy>(std::make_shared<CfgParamDeviceSelector>());
size_t surface_count = 10;
size_t surface_size_bytes = 1024;
@@ -348,9 +411,11 @@ TEST(OneVPL_Source_CPU_Accelerator, PoolProduceConcurrentConsume)
{
using cv::gapi::wip::onevpl::VPLCPUAccelerationPolicy;
using cv::gapi::wip::onevpl::VPLAccelerationPolicy;
using cv::gapi::wip::onevpl::CfgParamDeviceSelector;
using cv::gapi::wip::onevpl::Surface;
auto acceleration_policy = std::make_shared<VPLCPUAccelerationPolicy>();
auto acceleration_policy =
std::make_shared<VPLCPUAccelerationPolicy>(std::make_shared<CfgParamDeviceSelector>());
size_t surface_count = 10;
size_t surface_size_bytes = 1024;
@@ -416,7 +481,7 @@ TEST(OneVPL_Source_ProcessingEngine, Init)
TestProcessingEngine engine(std::move(accel));
mfxSession mfx_session{};
engine.initialize_session(mfx_session, DecoderParams{}, std::shared_ptr<IDataProvider>{});
engine.initialize_session(mfx_session, {}, std::shared_ptr<IDataProvider>{});
EXPECT_EQ(0, engine.get_ready_frames_count());
ProcessingEngineBase::ExecutionStatus ret = engine.process(mfx_session);
@@ -444,6 +509,181 @@ TEST(OneVPL_Source_ProcessingEngine, Init)
cv::gapi::wip::Data frame;
engine.get_frame(frame);
}
#ifdef HAVE_DIRECTX
#ifdef HAVE_D3D11
TEST(OneVPL_Source_DX11_Accel, Init)
{
using namespace cv::gapi::wip::onevpl;
std::vector<CfgParam> cfg_params_w_dx11;
cfg_params_w_dx11.push_back(CfgParam::create_acceleration_mode(MFX_ACCEL_MODE_VIA_D3D11));
VPLDX11AccelerationPolicy accel(std::make_shared<CfgParamDeviceSelector>(cfg_params_w_dx11));
mfxLoader mfx_handle = MFXLoad();
mfxConfig cfg_inst_0 = MFXCreateConfig(mfx_handle);
EXPECT_TRUE(cfg_inst_0);
mfxVariant mfx_param_0;
mfx_param_0.Type = MFX_VARIANT_TYPE_U32;
mfx_param_0.Data.U32 = MFX_IMPL_TYPE_HARDWARE;
EXPECT_EQ(MFXSetConfigFilterProperty(cfg_inst_0,(mfxU8 *)CfgParam::implementation_name(),
mfx_param_0), MFX_ERR_NONE);
mfxConfig cfg_inst_1 = MFXCreateConfig(mfx_handle);
EXPECT_TRUE(cfg_inst_1);
mfxVariant mfx_param_1;
mfx_param_1.Type = MFX_VARIANT_TYPE_U32;
mfx_param_1.Data.U32 = MFX_ACCEL_MODE_VIA_D3D11;
EXPECT_EQ(MFXSetConfigFilterProperty(cfg_inst_1,(mfxU8 *)CfgParam::acceleration_mode_name(),
mfx_param_1), MFX_ERR_NONE);
mfxConfig cfg_inst_2 = MFXCreateConfig(mfx_handle);
EXPECT_TRUE(cfg_inst_2);
mfxVariant mfx_param_2;
mfx_param_2.Type = MFX_VARIANT_TYPE_U32;
mfx_param_2.Data.U32 = MFX_CODEC_HEVC;
EXPECT_EQ(MFXSetConfigFilterProperty(cfg_inst_2,(mfxU8 *)CfgParam::decoder_id_name(),
mfx_param_2), MFX_ERR_NONE);
// create session
mfxSession mfx_session{};
mfxStatus sts = MFXCreateSession(mfx_handle, 0, &mfx_session);
EXPECT_EQ(MFX_ERR_NONE, sts);
// assign acceleration
EXPECT_NO_THROW(accel.init(mfx_session));
// create proper bitstream
mfxBitstream bitstream{};
const int BITSTREAM_BUFFER_SIZE = 2000000;
bitstream.MaxLength = BITSTREAM_BUFFER_SIZE;
bitstream.Data = (mfxU8 *)calloc(bitstream.MaxLength, sizeof(mfxU8));
EXPECT_TRUE(bitstream.Data);
// simulate read stream
bitstream.DataOffset = 0;
bitstream.DataLength = sizeof(streaming::onevpl::hevc_header) * sizeof(streaming::onevpl::hevc_header[0]);
memcpy(bitstream.Data, streaming::onevpl::hevc_header, bitstream.DataLength);
bitstream.CodecId = MFX_CODEC_HEVC;
// prepare dec params
mfxVideoParam mfxDecParams {};
mfxDecParams.mfx.CodecId = bitstream.CodecId;
mfxDecParams.IOPattern = MFX_IOPATTERN_OUT_VIDEO_MEMORY;
sts = MFXVideoDECODE_DecodeHeader(mfx_session, &bitstream, &mfxDecParams);
EXPECT_EQ(MFX_ERR_NONE, sts);
mfxFrameAllocRequest request{};
memset(&request, 0, sizeof(request));
sts = MFXVideoDECODE_QueryIOSurf(mfx_session, &mfxDecParams, &request);
EXPECT_EQ(MFX_ERR_NONE, sts);
// Allocate surfaces for decoder
VPLAccelerationPolicy::pool_key_t key = accel.create_surface_pool(request,
mfxDecParams);
auto cand_surface = accel.get_free_surface(key).lock();
sts = MFXVideoDECODE_Init(mfx_session, &mfxDecParams);
EXPECT_EQ(MFX_ERR_NONE, sts);
MFXVideoDECODE_Close(mfx_session);
EXPECT_EQ(MFX_ERR_NONE, sts);
EXPECT_NO_THROW(accel.deinit(mfx_session));
MFXClose(mfx_session);
MFXUnload(mfx_handle);
}
#endif // HAVE_DIRECTX
#endif // HAVE_D3D11
TEST(OneVPL_Source_DX11_FrameLockable, LockUnlock_without_Adaptee)
{
using namespace cv::gapi::wip::onevpl;
mfxMemId mid = 0;
int lock_counter = 0;
int unlock_counter = 0;
std::function<mfxStatus(mfxMemId, mfxFrameData *)> lock =
[&lock_counter] (mfxMemId, mfxFrameData *) {
lock_counter ++;
return MFX_ERR_NONE;
};
std::function<mfxStatus(mfxMemId, mfxFrameData *)> unlock =
[&unlock_counter] (mfxMemId, mfxFrameData *) {
unlock_counter++;
return MFX_ERR_NONE;
};
auto test_allocator = create_test_allocator(mid, lock, unlock);
LockAdapter adapter(test_allocator.get());
mfxFrameData data;
const int exec_count = 123;
for (int i = 0; i < exec_count; i ++) {
EXPECT_EQ(adapter.read_lock(mid, data), 0);
adapter.write_lock(mid, data);
EXPECT_EQ(adapter.unlock_read(mid, data), 0);
adapter.unlock_write(mid, data);
}
EXPECT_EQ(lock_counter, exec_count * 2);
EXPECT_EQ(unlock_counter, exec_count * 2);
}
TEST(OneVPL_Source_DX11_FrameLockable, LockUnlock_with_Adaptee)
{
using namespace cv::gapi::wip::onevpl;
mfxMemId mid = 0;
int r_lock_counter = 0;
int r_unlock_counter = 0;
int w_lock_counter = 0;
int w_unlock_counter = 0;
SharedLock adaptee;
std::function<mfxStatus(mfxMemId, mfxFrameData *)> lock =
[&r_lock_counter, &w_lock_counter, &adaptee] (mfxMemId, mfxFrameData *) {
if (adaptee.owns()) {
w_lock_counter ++;
} else {
r_lock_counter ++;
}
return MFX_ERR_NONE;
};
std::function<mfxStatus(mfxMemId, mfxFrameData *)> unlock =
[&r_unlock_counter, &w_unlock_counter, &adaptee] (mfxMemId, mfxFrameData *) {
if (adaptee.owns()) {
w_unlock_counter ++;
} else {
r_unlock_counter ++;
}
return MFX_ERR_NONE;
};
auto test_allocator = create_test_allocator(mid, lock, unlock);
LockAdapter adapter(test_allocator.get());
adapter.set_adaptee(&adaptee);
mfxFrameData data;
const int exec_count = 123;
for (int i = 0; i < exec_count; i ++) {
EXPECT_EQ(adapter.read_lock(mid, data), 0);
EXPECT_FALSE(adaptee.try_lock());
EXPECT_EQ(adapter.unlock_read(mid, data), 1);
EXPECT_TRUE(adaptee.try_lock());
adaptee.unlock();
adapter.write_lock(mid, data);
adapter.unlock_write(mid, data);
}
EXPECT_EQ(r_lock_counter, exec_count);
EXPECT_EQ(r_unlock_counter, exec_count);
EXPECT_EQ(w_lock_counter, exec_count);
EXPECT_EQ(w_unlock_counter, exec_count);
}
}
} // namespace opencv_test
#endif // HAVE_ONEVPL
@@ -39,8 +39,6 @@ array_element_t files[] = {
true, true, true},
array_element_t {"highgui/video/sample_322x242_15frames.yuv420p.libvpx-vp9.mp4",
true, true, true},
array_element_t {"highgui/video/sample_322x242_15frames.yuv420p.libx264.avi",
true, true, true},
array_element_t {"highgui/video/sample_322x242_15frames.yuv420p.libx264.mp4",
true, true, true},
array_element_t {"highgui/video/sample_322x242_15frames.yuv420p.libx265.mp4",
@@ -82,7 +80,7 @@ TEST_P(OneVPL_Source_MFPAsyncDispatcherTest, open_and_decode_file)
mfxVariant mfx_param_0;
mfx_param_0.Type = MFX_VARIANT_TYPE_U32;
mfx_param_0.Data.U32 = provider_ptr->get_mfx_codec_id();
EXPECT_EQ(MFXSetConfigFilterProperty(cfg_inst_0,(mfxU8 *)"mfxImplDescription.mfxDecoderDescription.decoder.CodecID",
EXPECT_EQ(MFXSetConfigFilterProperty(cfg_inst_0,(mfxU8 *)CfgParam::decoder_id_name(),
mfx_param_0), MFX_ERR_NONE);
// create MFX session
@@ -135,7 +133,7 @@ TEST_P(OneVPL_Source_MFPAsyncDispatcherTest, choose_dmux_provider)
EXPECT_FALSE(dd_result);
provider_ptr = DataProviderDispatcher::create(path,
{ CfgParam::create<std::string>(
"mfxImplDescription.mfxDecoderDescription.decoder.CodecID",
CfgParam::decoder_id_name(),
"MFX_CODEC_HEVC") /* Doesn't matter what codec for RAW here*/});
EXPECT_TRUE(std::dynamic_pointer_cast<FileDataProvider>(provider_ptr));
GTEST_SUCCEED();
@@ -30,7 +30,7 @@
#endif // HAVE_DIRECTX
#ifdef HAVE_ONEVPL
#include <vpl/mfxvideo.h>
#include "streaming/onevpl/onevpl_export.hpp"
#include "streaming/onevpl/cfg_param_device_selector.hpp"
namespace opencv_test
@@ -94,8 +94,7 @@ TEST(OneVPL_Source_Device_Selector_CfgParam, DefaultDeviceWithAccelNACfgParam)
{
using namespace cv::gapi::wip::onevpl;
std::vector<CfgParam> cfg_params_w_no_accel;
cfg_params_w_no_accel.push_back(CfgParam::create<uint32_t>("mfxImplDescription.AccelerationMode",
MFX_ACCEL_MODE_NA));
cfg_params_w_no_accel.push_back(CfgParam::create_acceleration_mode(MFX_ACCEL_MODE_NA));
CfgParamDeviceSelector selector(cfg_params_w_no_accel);
IDeviceSelector::DeviceScoreTable devs = selector.select_devices();
EXPECT_EQ(devs.size(), 1);
@@ -126,8 +125,7 @@ TEST(OneVPL_Source_Device_Selector_CfgParam, DefaultDeviceWithDX11AccelCfgParam_
{
using namespace cv::gapi::wip::onevpl;
std::vector<CfgParam> cfg_params_w_dx11;
cfg_params_w_dx11.push_back(CfgParam::create<uint32_t>("mfxImplDescription.AccelerationMode",
MFX_ACCEL_MODE_VIA_D3D11));
cfg_params_w_dx11.push_back(CfgParam::create_acceleration_mode(MFX_ACCEL_MODE_VIA_D3D11));
std::unique_ptr<CfgParamDeviceSelector> selector_ptr;
EXPECT_NO_THROW(selector_ptr.reset(new CfgParamDeviceSelector(cfg_params_w_dx11)));
IDeviceSelector::DeviceScoreTable devs = selector_ptr->select_devices();
@@ -146,8 +144,7 @@ TEST(OneVPL_Source_Device_Selector_CfgParam, NULLDeviceWithDX11AccelCfgParam_DX1
{
using namespace cv::gapi::wip::onevpl;
std::vector<CfgParam> cfg_params_w_dx11;
cfg_params_w_dx11.push_back(CfgParam::create<uint32_t>("mfxImplDescription.AccelerationMode",
MFX_ACCEL_MODE_VIA_D3D11));
cfg_params_w_dx11.push_back(CfgParam::create_acceleration_mode(MFX_ACCEL_MODE_VIA_D3D11));
Device::Ptr empty_device_ptr = nullptr;
Context::Ptr empty_ctx_ptr = nullptr;
EXPECT_THROW(CfgParamDeviceSelector sel(empty_device_ptr, "GPU",
@@ -179,8 +176,7 @@ TEST(OneVPL_Source_Device_Selector_CfgParam, ExternalDeviceWithDX11AccelCfgParam
std::unique_ptr<CfgParamDeviceSelector> selector_ptr;
std::vector<CfgParam> cfg_params_w_dx11;
cfg_params_w_dx11.push_back(CfgParam::create<uint32_t>("mfxImplDescription.AccelerationMode",
MFX_ACCEL_MODE_VIA_D3D11));
cfg_params_w_dx11.push_back(CfgParam::create_acceleration_mode(MFX_ACCEL_MODE_VIA_D3D11));
EXPECT_NO_THROW(selector_ptr.reset(new CfgParamDeviceSelector(device, "GPU",
device_context,
cfg_params_w_dx11)));
@@ -205,8 +201,7 @@ TEST(OneVPL_Source_Device_Selector_CfgParam, DX11DeviceFromCfgParamWithDX11Disab
{
using namespace cv::gapi::wip::onevpl;
std::vector<CfgParam> cfg_params_w_non_existed_dx11;
cfg_params_w_not_existed_dx11.push_back(CfgParam::create<uint32_t>("mfxImplDescription.AccelerationMode",
MFX_ACCEL_MODE_VIA_D3D11));
cfg_params_w_not_existed_dx11.push_back(CfgParam::create_acceleration_mode(MFX_ACCEL_MODE_VIA_D3D11));
EXPECT_THROW(CfgParamDeviceSelector{cfg_params_w_non_existed_dx11},
std::logic_error);
}