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

Merge pull request #20727 from sivanov-work:merge_vpl_accel_impl

G-API: oneVPL (simplification) added CPU, DX11(fallback CPU) accels & surface pool

* Add CPU, DX11(fallback CPU) accels & surface pool

* Fix build for surface_pool

* Apply some comments

* Fix indentation
This commit is contained in:
Sergey Ivanov
2021-09-23 14:34:30 +03:00
committed by GitHub
parent 38b9ec7a18
commit 54386c82fd
8 changed files with 741 additions and 1 deletions
@@ -0,0 +1,225 @@
// 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 <cstdlib>
#include <exception>
#include "streaming/onevpl/accelerators/accel_policy_cpu.hpp"
#include "streaming/onevpl/accelerators/surface/cpu_frame_adapter.hpp"
#include "streaming/onevpl/accelerators/surface/surface.hpp"
#include "logger.hpp"
#ifdef _WIN32
#include <windows.h>
#include <sysinfoapi.h>
#endif
namespace cv {
namespace gapi {
namespace wip {
VPLCPUAccelerationPolicy::VPLCPUAccelerationPolicy() {
GAPI_LOG_INFO(nullptr, "created");
}
VPLCPUAccelerationPolicy::~VPLCPUAccelerationPolicy() {
for (auto& pair : pool_table) {
pair.second.clear();
// do not free key here: last surface will release it
}
GAPI_LOG_INFO(nullptr, "destroyed");
}
void VPLCPUAccelerationPolicy::init(session_t session) {
GAPI_LOG_INFO(nullptr, "initialize session: " << session);
}
void VPLCPUAccelerationPolicy::deinit(session_t session) {
GAPI_LOG_INFO(nullptr, "deinitialize session: " << session);
}
VPLCPUAccelerationPolicy::pool_key_t
VPLCPUAccelerationPolicy::create_surface_pool(size_t pool_size, size_t surface_size_bytes,
surface_ptr_ctr_t creator) {
GAPI_LOG_DEBUG(nullptr, "pool size: " << pool_size << ", surface size bytes: " << surface_size_bytes);
// create empty pool
pool_t pool;
pool.reserve(pool_size);
// allocate workplace memory area
size_t preallocated_raw_bytes = pool_size * surface_size_bytes;
size_t page_size_bytes = 4 * 1024;
void *preallocated_pool_memory_ptr = nullptr;
#ifdef _WIN32
SYSTEM_INFO sysInfo;
GetSystemInfo(&sysInfo);
page_size_bytes = sysInfo.dwPageSize;
GAPI_LOG_DEBUG(nullptr, "page size: " << page_size_bytes << ", preallocated_raw_bytes: " << preallocated_raw_bytes);
preallocated_pool_memory_ptr = _aligned_malloc(preallocated_raw_bytes, page_size_bytes);
#else
GAPI_Assert(false && "Compatibility is not tested for systems differ than \"_WIN32\". "
"Please feel free to set it up under OPENCV contribution policy");
#endif
if (!preallocated_pool_memory_ptr) {
throw std::runtime_error("VPLCPUAccelerationPolicy::create_surface_pool - failed: not enough memory."
"Requested surface count: " + std::to_string(pool_size) +
", surface bytes: " + std::to_string(surface_size_bytes));
}
// fill pool with surfaces
std::shared_ptr<void> workspace_mem_owner (preallocated_pool_memory_ptr, [] (void *ptr){
GAPI_LOG_INFO(nullptr, "Free workspace memory: " << ptr);
#ifdef _WIN32
_aligned_free(ptr);
GAPI_LOG_INFO(nullptr, "Released workspace memory: " << ptr);
ptr = nullptr;
#else
GAPI_Assert(false && "Not implemented for systems differ than \"_WIN32\". "
"Please feel free to set it up under OPENCV contribution policy");
#endif
});
size_t i = 0;
try {
for (; i < pool_size; i++) {
size_t preallocated_mem_offset = static_cast<size_t>(i) * surface_size_bytes;
surface_ptr_t surf_ptr = creator(workspace_mem_owner,
preallocated_mem_offset,
preallocated_raw_bytes);
pool.push_back(std::move(surf_ptr));
}
} catch (const std::exception& ex) {
throw std::runtime_error(std::string("VPLCPUAccelerationPolicy::create_surface_pool - ") +
"cannot construct surface index: " + std::to_string(i) + ", error: " +
ex.what() +
"Requested surface count: " + std::to_string(pool_size) +
", surface bytes: " + std::to_string(surface_size_bytes));
}
// remember pool by key
GAPI_LOG_INFO(nullptr, "New pool allocated, key: " << preallocated_pool_memory_ptr <<
", surface count: " << pool.size() <<
", surface size bytes: " << surface_size_bytes);
if (!pool_table.emplace(preallocated_pool_memory_ptr, std::move(pool)).second) {
GAPI_LOG_WARNING(nullptr, "Cannot insert pool, table size: " + std::to_string(pool_table.size()) <<
", key: " << preallocated_pool_memory_ptr << " exists");
GAPI_Assert(false && "Cannot create pool in VPLCPUAccelerationPolicy");
}
return preallocated_pool_memory_ptr;
}
VPLCPUAccelerationPolicy::surface_weak_ptr_t VPLCPUAccelerationPolicy::get_free_surface(pool_key_t key) {
auto pool_it = pool_table.find(key);
if (pool_it == pool_table.end()) {
throw std::runtime_error("VPLCPUAccelerationPolicy::get_free_surface - "
"key is not found, table size: " +
std::to_string(pool_table.size()));
}
pool_t& requested_pool = pool_it->second;
#ifdef TEST_PERF
return requested_pool.find_free();
#else // TEST_PERF
auto it =
std::find_if(requested_pool.begin(), requested_pool.end(),
[](const surface_ptr_t& val) {
GAPI_DbgAssert(val && "Pool contains empty surface");
return !val->get_locks_count();
});
// Limitation realloc pool might be a future extension
if (it == requested_pool.end()) {
std::stringstream ss;
ss << "cannot get free surface from pool, key: " << key << ", size: " << requested_pool.size();
const std::string& str = ss.str();
GAPI_LOG_WARNING(nullptr, str);
throw std::runtime_error(std::string(__FUNCTION__) + " - " + str);
}
return *it;
#endif // TEST_PERF
}
size_t VPLCPUAccelerationPolicy::get_free_surface_count(pool_key_t key) const {
auto pool_it = pool_table.find(key);
if (pool_it == pool_table.end()) {
GAPI_LOG_WARNING(nullptr, "key is not found: " << key <<
", table size: " << pool_table.size());
return 0;
}
#ifdef TEST_PERF
return 0;
#else // TEST_PERF
const pool_t& requested_pool = pool_it->second;
size_t free_surf_count =
std::count_if(requested_pool.begin(), requested_pool.end(),
[](const surface_ptr_t& val) {
GAPI_Assert(val && "Pool contains empty surface");
return !val->get_locks_count();
});
return free_surf_count;
#endif // TEST_PERF
}
size_t VPLCPUAccelerationPolicy::get_surface_count(pool_key_t key) const {
auto pool_it = pool_table.find(key);
if (pool_it == pool_table.end()) {
GAPI_LOG_DEBUG(nullptr, "key is not found: " << key <<
", table size: " << pool_table.size());
return 0;
}
#ifdef TEST_PERF
return 0;
#else // TEST_PERF
return pool_it->second.size();
#endif // TEST_PERF
}
cv::MediaFrame::AdapterPtr VPLCPUAccelerationPolicy::create_frame_adapter(pool_key_t key,
mfxFrameSurface1* surface) {
auto pool_it = pool_table.find(key);
if (pool_it == pool_table.end()) {
std::stringstream ss;
ss << "key is not found: " << key << ", table size: " << pool_table.size();
const std::string& str = ss.str();
GAPI_LOG_WARNING(nullptr, str);
throw std::runtime_error(std::string(__FUNCTION__) + " - " + str);
}
pool_t& requested_pool = pool_it->second;
#ifdef TEST_PERF
return cv::MediaFrame::AdapterPtr{new VPLMediaFrameCPUAdapter(requested_pool.find_by_handle(surface))};
#else // TEST_PERF
auto it =
std::find_if(requested_pool.begin(), requested_pool.end(),
[surface](const surface_ptr_t& val) {
GAPI_DbgAssert(val && "Pool contains empty surface");
return val->get_handle() == surface;
});
// Limitation realloc pool might be a future extension
if (it == requested_pool.end()) {
std::stringstream ss;
ss << "cannot get requested surface from pool, key: " << key << ", surf: "
<< surface << ", pool size: " << requested_pool.size();
const std::string& str = ss.str();
GAPI_LOG_WARNING(nullptr, str);
throw std::runtime_error(std::string(__FUNCTION__) + " - " + str);
}
return cv::MediaFrame::AdapterPtr{new VPLMediaFrameCPUAdapter(*it)};
#endif // TEST_PERF
}
} // namespace wip
} // namespace gapi
} // namespace cv
#endif // HAVE_ONEVPL
@@ -0,0 +1,55 @@
// 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 GAPI_STREAMING_ONEVPL_ACCELERATORS_ACCEL_POLICY_CPU_HPP
#define GAPI_STREAMING_ONEVPL_ACCELERATORS_ACCEL_POLICY_CPU_HPP
#include <map>
#include <vector>
#include "opencv2/gapi/own/exports.hpp" // GAPI_EXPORTS
#ifdef HAVE_ONEVPL
#include <vpl/mfxvideo.h>
#include "streaming/onevpl/accelerators/accel_policy_interface.hpp"
#ifdef TEST_PERF
#include "streaming/onevpl/accelerators/surface/surface_pool.hpp"
#endif // TEST_PERF
namespace cv {
namespace gapi {
namespace wip {
// GAPI_EXPORTS for tests
struct GAPI_EXPORTS VPLCPUAccelerationPolicy final : public VPLAccelerationPolicy
{
VPLCPUAccelerationPolicy();
~VPLCPUAccelerationPolicy();
#ifdef TEST_PERF
using pool_t = CachedPool;
#else // TEST_PERF
using pool_t = std::vector<surface_ptr_t>;
#endif // TEST_PERF
void init(session_t session) override;
void deinit(session_t session) override;
pool_key_t create_surface_pool(size_t pool_size, size_t surface_size_bytes, surface_ptr_ctr_t creator) override;
surface_weak_ptr_t get_free_surface(pool_key_t key) override;
size_t get_free_surface_count(pool_key_t key) const override;
size_t get_surface_count(pool_key_t key) const override;
cv::MediaFrame::AdapterPtr create_frame_adapter(pool_key_t key,
mfxFrameSurface1* surface) override;
private:
std::map<pool_key_t, pool_t> pool_table;
};
} // namespace wip
} // namespace gapi
} // namespace cv
#endif // HAVE_ONEVPL
#endif // GAPI_STREAMING_ONEVPL_ACCELERATORS_ACCEL_POLICY_CPU_HPP
@@ -0,0 +1,114 @@
// 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/accelerators/accel_policy_dx11.hpp"
#include "streaming/onevpl/accelerators/surface/cpu_frame_adapter.hpp"
#include "streaming/onevpl/accelerators/surface/surface.hpp"
#include "logger.hpp"
#ifdef HAVE_DIRECTX
#ifdef HAVE_D3D11
#pragma comment(lib,"d3d11.lib")
#define D3D11_NO_HELPERS
#include <d3d11.h>
#include <d3d11_4.h>
#include <codecvt>
#include "opencv2/core/directx.hpp"
#ifdef HAVE_OPENCL
#include <CL/cl_d3d11.h>
#endif
namespace cv {
namespace gapi {
namespace wip {
VPLDX11AccelerationPolicy::VPLDX11AccelerationPolicy()
{
#ifdef CPU_ACCEL_ADAPTER
adapter.reset(new VPLCPUAccelerationPolicy);
#endif
}
VPLDX11AccelerationPolicy::~VPLDX11AccelerationPolicy()
{
if (hw_handle)
{
GAPI_LOG_INFO(nullptr, "VPLDX11AccelerationPolicy release ID3D11Device");
hw_handle->Release();
}
}
void VPLDX11AccelerationPolicy::init(session_t session) {
mfxStatus sts = MFXVideoCORE_GetHandle(session, MFX_HANDLE_D3D11_DEVICE, reinterpret_cast<mfxHDL*>(&hw_handle));
if (sts != MFX_ERR_NONE)
{
throw std::logic_error("Cannot create VPLDX11AccelerationPolicy, MFXVideoCORE_GetHandle error");
}
GAPI_LOG_INFO(nullptr, "VPLDX11AccelerationPolicy initialized, session: " << session);
}
void VPLDX11AccelerationPolicy::deinit(session_t session) {
GAPI_LOG_INFO(nullptr, "deinitialize session: " << session);
}
VPLDX11AccelerationPolicy::pool_key_t
VPLDX11AccelerationPolicy::create_surface_pool(size_t pool_size, size_t surface_size_bytes,
surface_ptr_ctr_t creator) {
GAPI_LOG_DEBUG(nullptr, "pool size: " << pool_size << ", surface size bytes: " << surface_size_bytes);
#ifdef CPU_ACCEL_ADAPTER
return adapter->create_surface_pool(pool_size, surface_size_bytes, creator);
#endif
(void)pool_size;
(void)surface_size_bytes;
(void)creator;
throw std::runtime_error("VPLDX11AccelerationPolicy::create_surface_pool() is not implemented");
}
VPLDX11AccelerationPolicy::surface_weak_ptr_t VPLDX11AccelerationPolicy::get_free_surface(pool_key_t key)
{
#ifdef CPU_ACCEL_ADAPTER
return adapter->get_free_surface(key);
#endif
(void)key;
throw std::runtime_error("VPLDX11AccelerationPolicy::get_free_surface() is not implemented");
}
size_t VPLDX11AccelerationPolicy::get_free_surface_count(pool_key_t key) const {
#ifdef CPU_ACCEL_ADAPTER
return adapter->get_free_surface_count(key);
#endif
(void)key;
throw std::runtime_error("get_free_surface_count() is not implemented");
}
size_t VPLDX11AccelerationPolicy::get_surface_count(pool_key_t key) const {
#ifdef CPU_ACCEL_ADAPTER
return adapter->get_surface_count(key);
#endif
(void)key;
throw std::runtime_error("VPLDX11AccelerationPolicy::get_surface_count() is not implemented");
}
cv::MediaFrame::AdapterPtr VPLDX11AccelerationPolicy::create_frame_adapter(pool_key_t key,
mfxFrameSurface1* surface) {
#ifdef CPU_ACCEL_ADAPTER
return adapter->create_frame_adapter(key, surface);
#endif
(void)key;
(void)surface;
throw std::runtime_error("VPLDX11AccelerationPolicy::create_frame_adapter() is not implemented");
}
} // namespace wip
} // namespace gapi
} // namespace cv
#endif // HAVE_D3D11
#endif // HAVE_DIRECTX
#endif // HAVE_ONEVPL
@@ -0,0 +1,67 @@
// 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 GAPI_STREAMING_ONEVPL_ACCELERATORS_ACCEL_POLICY_DX11_HPP
#define GAPI_STREAMING_ONEVPL_ACCELERATORS_ACCEL_POLICY_DX11_HPP
#include "opencv2/gapi/own/exports.hpp" // GAPI_EXPORTS
//TODO Remove the next MACRO right after DX11 implementation
#define CPU_ACCEL_ADAPTER
#ifdef HAVE_ONEVPL
#include <vpl/mfxvideo.h>
#include "streaming/onevpl/accelerators/accel_policy_interface.hpp"
#ifdef CPU_ACCEL_ADAPTER
#include "streaming/onevpl/accelerators/accel_policy_cpu.hpp"
#endif
#ifdef HAVE_DIRECTX
#ifdef HAVE_D3D11
#define D3D11_NO_HELPERS
#include <d3d11.h>
#include <codecvt>
#include "opencv2/core/directx.hpp"
#ifdef HAVE_OPENCL
#include <CL/cl_d3d11.h>
#endif
namespace cv {
namespace gapi {
namespace wip {
// GAPI_EXPORTS for tests
struct GAPI_EXPORTS VPLDX11AccelerationPolicy final: public VPLAccelerationPolicy
{
// GAPI_EXPORTS for tests
VPLDX11AccelerationPolicy();
~VPLDX11AccelerationPolicy();
void init(session_t session) override;
void deinit(session_t session) override;
pool_key_t create_surface_pool(size_t pool_size, size_t surface_size_bytes, surface_ptr_ctr_t creator) override;
surface_weak_ptr_t get_free_surface(pool_key_t key) override;
size_t get_free_surface_count(pool_key_t key) const override;
size_t get_surface_count(pool_key_t key) const override;
cv::MediaFrame::AdapterPtr create_frame_adapter(pool_key_t key,
mfxFrameSurface1* surface) override;
private:
ID3D11Device *hw_handle;
#ifdef CPU_ACCEL_ADAPTER
std::unique_ptr<VPLCPUAccelerationPolicy> adapter;
#endif
};
} // namespace wip
} // namespace gapi
} // namespace cv
#endif // HAVE_D3D11
#endif // HAVE_DIRECTX
#endif // HAVE_ONEVPL
#endif // GAPI_STREAMING_ONEVPL_ACCELERATORS_ACCEL_POLICY_DX11_HPP
@@ -0,0 +1,69 @@
#include "streaming/onevpl/accelerators/surface/surface_pool.hpp"
#include "streaming/onevpl/accelerators/surface/surface.hpp"
#include "logger.hpp"
#ifdef HAVE_ONEVPL
namespace cv {
namespace gapi {
namespace wip {
void CachedPool::reserve(size_t size) {
surfaces.reserve(size);
}
size_t CachedPool::size() const {
return surfaces.size();
}
void CachedPool::clear() {
surfaces.clear();
next_free_it = surfaces.begin();
cache.clear();
}
void CachedPool::push_back(surface_ptr_t &&surf) {
cache.insert(std::make_pair(surf->get_handle(), surf));
surfaces.push_back(std::move(surf));
next_free_it = surfaces.begin();
}
CachedPool::surface_ptr_t CachedPool::find_free() {
auto it =
std::find_if(next_free_it, surfaces.end(),
[](const surface_ptr_t& val) {
GAPI_DbgAssert(val && "Pool contains empty surface");
return !val->get_locks_count();
});
// Limitation realloc pool might be a future extension
if (it == surfaces.end()) {
it = std::find_if(surfaces.begin(), next_free_it,
[](const surface_ptr_t& val) {
GAPI_DbgAssert(val && "Pool contains empty surface");
return !val->get_locks_count();
});
if (it == next_free_it) {
std::stringstream ss;
ss << "cannot get free surface from pool, size: " << surfaces.size();
const std::string& str = ss.str();
GAPI_LOG_WARNING(nullptr, str);
throw std::runtime_error(std::string(__FUNCTION__) + " - " + str);
}
}
next_free_it = it;
++next_free_it;
return *it;
}
CachedPool::surface_ptr_t CachedPool::find_by_handle(mfxFrameSurface1* handle) {
auto it = cache.find(handle);
GAPI_Assert(it != cache.end() && "Cannot find cached surface from pool. Data corruption is possible");
return it->second;
}
} // namespace wip
} // namespace gapi
} // namespace cv
#endif // HAVE_ONEVPL
@@ -0,0 +1,45 @@
#ifndef GAPI_STREAMING_ONEVPL_SURFACE_SURFACE_POOL_HPP
#define GAPI_STREAMING_ONEVPL_SURFACE_SURFACE_POOL_HPP
#include <map>
#include <memory>
#include <vector>
#include "opencv2/gapi/own/exports.hpp" // GAPI_EXPORTS
#ifdef HAVE_ONEVPL
#if (MFX_VERSION >= 2000)
#include <vpl/mfxdispatcher.h>
#endif
#include <vpl/mfx.h>
namespace cv {
namespace gapi {
namespace wip {
class Surface;
// GAPI_EXPORTS for tests
class GAPI_EXPORTS CachedPool {
public:
using surface_ptr_t = std::shared_ptr<Surface>;
using surface_container_t = std::vector<surface_ptr_t>;
using free_surface_iterator_t = typename surface_container_t::iterator;
using cached_surface_container_t = std::map<mfxFrameSurface1*, surface_ptr_t>;
void push_back(surface_ptr_t &&surf);
void reserve(size_t size);
size_t size() const;
void clear();
surface_ptr_t find_free();
surface_ptr_t find_by_handle(mfxFrameSurface1* handle);
private:
surface_container_t surfaces;
free_surface_iterator_t next_free_it;
cached_surface_container_t cache;
};
} // namespace wip
} // namespace gapi
} // namespace cv
#endif // HAVE_ONEVPL
#endif // GAPI_STREAMING_ONEVPL_SURFACE_SURFACE_POOL_HPP