mirror of
https://github.com/opencv/opencv.git
synced 2026-07-31 08:13:04 +04:00
Merge pull request #18339 from rgarnov:rg/rmat_integration
[GAPI] RMat integration into the framework * RMat integration * Added initialization of input mat in GArray initialization tests * Fixed klocwork warnings in RMat tests, changed argument order in EXPECT_EQ
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
// 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) 2018 Intel Corporation
|
||||
// Copyright (C) 2018-2020 Intel Corporation
|
||||
|
||||
|
||||
#include "precomp.hpp"
|
||||
@@ -103,38 +103,34 @@ namespace cv {
|
||||
namespace gimpl {
|
||||
namespace magazine {
|
||||
|
||||
// FIXME implement the below functions with visit()?
|
||||
namespace {
|
||||
// Utility function, used in both bindInArg and bindOutArg,
|
||||
// implements default RMat bind behaviour (if backend doesn't handle RMats in specific way):
|
||||
// view + wrapped cv::Mat are placed into the magazine
|
||||
void bindRMat(Mag& mag, const RcDesc& rc, const cv::RMat& rmat, RMat::Access a)
|
||||
{
|
||||
auto& matv = mag.template slot<RMat::View>()[rc.id];
|
||||
matv = rmat.access(a);
|
||||
mag.template slot<cv::Mat>()[rc.id] = asMat(matv);
|
||||
}
|
||||
} // anonymous namespace
|
||||
|
||||
void bindInArg(Mag& mag, const RcDesc &rc, const GRunArg &arg, bool is_umat)
|
||||
// FIXME implement the below functions with visit()?
|
||||
void bindInArg(Mag& mag, const RcDesc &rc, const GRunArg &arg, HandleRMat handleRMat)
|
||||
{
|
||||
switch (rc.shape)
|
||||
{
|
||||
case GShape::GMAT:
|
||||
{
|
||||
switch (arg.index())
|
||||
{
|
||||
case GRunArg::index_of<cv::Mat>() :
|
||||
if (is_umat)
|
||||
{
|
||||
#if !defined(GAPI_STANDALONE)
|
||||
auto& mag_umat = mag.template slot<cv::UMat>()[rc.id];
|
||||
mag_umat = util::get<cv::Mat>(arg).getUMat(ACCESS_READ);
|
||||
#else
|
||||
util::throw_error(std::logic_error("UMat is not supported in standalone build"));
|
||||
#endif // !defined(GAPI_STANDALONE)
|
||||
}
|
||||
else
|
||||
{
|
||||
auto& mag_mat = mag.template slot<cv::Mat>()[rc.id];
|
||||
mag_mat = util::get<cv::Mat>(arg);
|
||||
}
|
||||
break;
|
||||
default: util::throw_error(std::logic_error("content type of the runtime argument does not match to resource description ?"));
|
||||
}
|
||||
// In case of handleRMat == SKIP
|
||||
// We assume that backend can work with some device-specific RMats
|
||||
// and will handle them in some specific way, so just return
|
||||
if (handleRMat == HandleRMat::SKIP) return;
|
||||
GAPI_Assert(arg.index() == GRunArg::index_of<cv::RMat>());
|
||||
bindRMat(mag, rc, util::get<cv::RMat>(arg), RMat::Access::R);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
case GShape::GSCALAR:
|
||||
{
|
||||
auto& mag_scalar = mag.template slot<cv::Scalar>()[rc.id];
|
||||
@@ -159,32 +155,18 @@ void bindInArg(Mag& mag, const RcDesc &rc, const GRunArg &arg, bool is_umat)
|
||||
}
|
||||
}
|
||||
|
||||
void bindOutArg(Mag& mag, const RcDesc &rc, const GRunArgP &arg, bool is_umat)
|
||||
void bindOutArg(Mag& mag, const RcDesc &rc, const GRunArgP &arg, HandleRMat handleRMat)
|
||||
{
|
||||
switch (rc.shape)
|
||||
{
|
||||
case GShape::GMAT:
|
||||
{
|
||||
switch (arg.index())
|
||||
{
|
||||
case GRunArgP::index_of<cv::Mat*>() :
|
||||
if (is_umat)
|
||||
{
|
||||
#if !defined(GAPI_STANDALONE)
|
||||
auto& mag_umat = mag.template slot<cv::UMat>()[rc.id];
|
||||
mag_umat = util::get<cv::Mat*>(arg)->getUMat(ACCESS_RW);
|
||||
#else
|
||||
util::throw_error(std::logic_error("UMat is not supported in standalone build"));
|
||||
#endif // !defined(GAPI_STANDALONE)
|
||||
}
|
||||
else
|
||||
{
|
||||
auto& mag_mat = mag.template slot<cv::Mat>()[rc.id];
|
||||
mag_mat = *util::get<cv::Mat*>(arg);
|
||||
}
|
||||
break;
|
||||
default: util::throw_error(std::logic_error("content type of the runtime argument does not match to resource description ?"));
|
||||
}
|
||||
// In case of handleRMat == SKIP
|
||||
// We assume that backend can work with some device-specific RMats
|
||||
// and will handle them in some specific way, so just return
|
||||
if (handleRMat == HandleRMat::SKIP) return;
|
||||
GAPI_Assert(arg.index() == GRunArgP::index_of<cv::RMat*>());
|
||||
bindRMat(mag, rc, *util::get<cv::RMat*>(arg), RMat::Access::W);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -248,7 +230,7 @@ cv::GRunArg getArg(const Mag& mag, const RcDesc &ref)
|
||||
// Wrap associated CPU object (either host or an internal one)
|
||||
switch (ref.shape)
|
||||
{
|
||||
case GShape::GMAT: return GRunArg(mag.template slot<cv::Mat>().at(ref.id));
|
||||
case GShape::GMAT: return GRunArg(mag.template slot<cv::RMat>().at(ref.id));
|
||||
case GShape::GSCALAR: return GRunArg(mag.template slot<cv::Scalar>().at(ref.id));
|
||||
// Note: .at() is intentional for GArray and GOpaque as objects MUST be already there
|
||||
// (and constructed by either bindIn/Out or resetInternal)
|
||||
@@ -300,46 +282,15 @@ cv::GRunArgP getObjPtr(Mag& mag, const RcDesc &rc, bool is_umat)
|
||||
}
|
||||
}
|
||||
|
||||
void writeBack(const Mag& mag, const RcDesc &rc, GRunArgP &g_arg, bool is_umat)
|
||||
void writeBack(const Mag& mag, const RcDesc &rc, GRunArgP &g_arg)
|
||||
{
|
||||
switch (rc.shape)
|
||||
{
|
||||
case GShape::GARRAY:
|
||||
// Do nothing - should we really do anything here?
|
||||
break;
|
||||
case GShape::GOPAQUE:
|
||||
// Do nothing - should we really do anything here?
|
||||
break;
|
||||
|
||||
case GShape::GMAT:
|
||||
{
|
||||
//simply check that memory was not reallocated, i.e.
|
||||
//both instances of Mat pointing to the same memory
|
||||
uchar* out_arg_data = nullptr;
|
||||
switch (g_arg.index())
|
||||
{
|
||||
case GRunArgP::index_of<cv::Mat*>() : out_arg_data = util::get<cv::Mat*>(g_arg)->data; break;
|
||||
#if !defined(GAPI_STANDALONE)
|
||||
case GRunArgP::index_of<cv::UMat*>() : out_arg_data = (util::get<cv::UMat*>(g_arg))->getMat(ACCESS_RW).data; break;
|
||||
#endif // !defined(GAPI_STANDALONE)
|
||||
default: util::throw_error(std::logic_error("content type of the runtime argument does not match to resource description ?"));
|
||||
}
|
||||
if (is_umat)
|
||||
{
|
||||
#if !defined(GAPI_STANDALONE)
|
||||
auto& in_mag = mag.template slot<cv::UMat>().at(rc.id);
|
||||
GAPI_Assert((out_arg_data == (in_mag.getMat(ACCESS_RW).data)) && " data for output parameters was reallocated ?");
|
||||
#else
|
||||
util::throw_error(std::logic_error("UMat is not supported in standalone build"));
|
||||
#endif // !defined(GAPI_STANDALONE)
|
||||
}
|
||||
else
|
||||
{
|
||||
auto& in_mag = mag.template slot<cv::Mat>().at(rc.id);
|
||||
GAPI_Assert((out_arg_data == in_mag.data) && " data for output parameters was reallocated ?");
|
||||
}
|
||||
case GShape::GOPAQUE:
|
||||
// Do nothing - should we really do anything here?
|
||||
break;
|
||||
}
|
||||
|
||||
case GShape::GSCALAR:
|
||||
{
|
||||
@@ -357,6 +308,32 @@ void writeBack(const Mag& mag, const RcDesc &rc, GRunArgP &g_arg, bool is_umat)
|
||||
}
|
||||
}
|
||||
|
||||
void unbind(Mag& mag, const RcDesc &rc)
|
||||
{
|
||||
switch (rc.shape)
|
||||
{
|
||||
case GShape::GARRAY:
|
||||
case GShape::GOPAQUE:
|
||||
case GShape::GSCALAR:
|
||||
// TODO: Do nothing - should we really do anything here?
|
||||
break;
|
||||
|
||||
case GShape::GMAT:
|
||||
// Clean-up everything - a cv::Mat, cv::RMat::View, a cv::UMat, and cv::RMat
|
||||
// if applicable
|
||||
mag.slot<cv::Mat>().erase(rc.id);
|
||||
#if !defined(GAPI_STANDALONE)
|
||||
mag.slot<cv::UMat>().erase(rc.id);
|
||||
#endif
|
||||
mag.slot<cv::RMat::View>().erase(rc.id);
|
||||
mag.slot<cv::RMat>().erase(rc.id);
|
||||
break;
|
||||
|
||||
default:
|
||||
GAPI_Assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace magazine
|
||||
|
||||
void createMat(const cv::GMatDesc &desc, cv::Mat& mat)
|
||||
|
||||
@@ -95,6 +95,11 @@ cv::GMetaArgs cv::gapi::own::descrs_of(const std::vector<Mat> &vec)
|
||||
return vec_descr_of(vec);
|
||||
}
|
||||
|
||||
cv::GMatDesc cv::descr_of(const cv::RMat &mat)
|
||||
{
|
||||
return mat.desc();
|
||||
}
|
||||
|
||||
namespace cv {
|
||||
std::ostream& operator<<(std::ostream& os, const cv::GMatDesc &desc)
|
||||
{
|
||||
@@ -137,4 +142,9 @@ bool GMatDesc::canDescribe(const cv::Mat& mat) const
|
||||
return canDescribeHelper(*this, mat);
|
||||
}
|
||||
|
||||
bool GMatDesc::canDescribe(const cv::RMat& mat) const
|
||||
{
|
||||
return *this == mat.desc();
|
||||
}
|
||||
|
||||
}// namespace cv
|
||||
|
||||
@@ -119,6 +119,9 @@ cv::GMetaArg cv::descr_of(const cv::GRunArg &arg)
|
||||
case GRunArg::index_of<cv::gapi::wip::IStreamSource::Ptr>():
|
||||
return cv::util::get<cv::gapi::wip::IStreamSource::Ptr>(arg)->descr_of();
|
||||
|
||||
case GRunArg::index_of<cv::RMat>():
|
||||
return cv::GMetaArg(cv::util::get<cv::RMat>(arg).desc());
|
||||
|
||||
default: util::throw_error(std::logic_error("Unsupported GRunArg type"));
|
||||
}
|
||||
}
|
||||
@@ -174,6 +177,8 @@ bool cv::can_describe(const GMetaArg& meta, const GRunArg& arg)
|
||||
case GRunArg::index_of<cv::detail::VectorRef>(): return meta == cv::GMetaArg(util::get<cv::detail::VectorRef>(arg).descr_of());
|
||||
case GRunArg::index_of<cv::detail::OpaqueRef>(): return meta == cv::GMetaArg(util::get<cv::detail::OpaqueRef>(arg).descr_of());
|
||||
case GRunArg::index_of<cv::gapi::wip::IStreamSource::Ptr>(): return util::holds_alternative<GMatDesc>(meta); // FIXME(?) may be not the best option
|
||||
case GRunArg::index_of<cv::RMat>(): return util::holds_alternative<GMatDesc>(meta) &&
|
||||
util::get<GMatDesc>(meta).canDescribe(cv::util::get<cv::RMat>(arg));
|
||||
default: util::throw_error(std::logic_error("Unsupported GRunArg type"));
|
||||
}
|
||||
}
|
||||
@@ -263,6 +268,8 @@ const void* cv::gimpl::proto::ptr(const GRunArgP &arg)
|
||||
return static_cast<const void*>(cv::util::get<cv::Mat*>(arg));
|
||||
case GRunArgP::index_of<cv::Scalar*>():
|
||||
return static_cast<const void*>(cv::util::get<cv::Scalar*>(arg));
|
||||
case GRunArgP::index_of<cv::RMat*>():
|
||||
return static_cast<const void*>(cv::util::get<cv::RMat*>(arg));
|
||||
case GRunArgP::index_of<cv::detail::VectorRef>():
|
||||
return cv::util::get<cv::detail::VectorRef>(arg).ptr();
|
||||
case GRunArgP::index_of<cv::detail::OpaqueRef>():
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
// 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) 2020 Intel Corporation
|
||||
|
||||
#include <opencv2/gapi/rmat.hpp>
|
||||
|
||||
using View = cv::RMat::View;
|
||||
|
||||
// There is an issue with default generated operator=(View&&) on Mac:
|
||||
// it doesn't nullify m_cb of a moved object
|
||||
View& View::operator=(View&& v) {
|
||||
m_desc = v.m_desc;
|
||||
m_data = v.m_data;
|
||||
m_step = v.m_step;
|
||||
m_cb = v.m_cb;
|
||||
v.m_desc = {};
|
||||
v.m_data = nullptr;
|
||||
v.m_step = 0u;
|
||||
v.m_cb = nullptr;
|
||||
return *this;
|
||||
}
|
||||
@@ -22,6 +22,23 @@
|
||||
namespace cv {
|
||||
namespace gimpl {
|
||||
|
||||
inline cv::Mat asMat(RMat::View& v) {
|
||||
return v.dims().empty() ? cv::Mat(v.rows(), v.cols(), v.type(), v.ptr(), v.step())
|
||||
: cv::Mat(v.dims(), v.type(), v.ptr());
|
||||
}
|
||||
inline RMat::View asView(const Mat& m, RMat::View::DestroyCallback&& cb = nullptr) {
|
||||
return RMat::View(cv::descr_of(m), m.data, m.step, std::move(cb));
|
||||
}
|
||||
|
||||
class RMatAdapter : public RMat::Adapter {
|
||||
cv::Mat m_mat;
|
||||
public:
|
||||
const void* data() const { return m_mat.data; }
|
||||
RMatAdapter(cv::Mat m) : m_mat(m) {}
|
||||
virtual RMat::View access(RMat::Access) override { return asView(m_mat); }
|
||||
virtual cv::GMatDesc desc() const override { return cv::descr_of(m_mat); }
|
||||
};
|
||||
|
||||
// Forward declarations
|
||||
struct Data;
|
||||
struct RcDesc;
|
||||
@@ -44,20 +61,39 @@ namespace magazine {
|
||||
|
||||
} // namespace magazine
|
||||
#if !defined(GAPI_STANDALONE)
|
||||
using Mag = magazine::Class<cv::Mat, cv::UMat, cv::Scalar, cv::detail::VectorRef, cv::detail::OpaqueRef>;
|
||||
using Mag = magazine::Class<cv::Mat, cv::UMat, cv::Scalar, cv::detail::VectorRef, cv::detail::OpaqueRef, cv::RMat, cv::RMat::View>;
|
||||
#else
|
||||
using Mag = magazine::Class<cv::Mat, cv::Scalar, cv::detail::VectorRef, cv::detail::OpaqueRef>;
|
||||
using Mag = magazine::Class<cv::Mat, cv::Scalar, cv::detail::VectorRef, cv::detail::OpaqueRef, cv::RMat, cv::RMat::View>;
|
||||
#endif
|
||||
|
||||
namespace magazine
|
||||
{
|
||||
void GAPI_EXPORTS bindInArg (Mag& mag, const RcDesc &rc, const GRunArg &arg, bool is_umat = false);
|
||||
void GAPI_EXPORTS bindOutArg(Mag& mag, const RcDesc &rc, const GRunArgP &arg, bool is_umat = false);
|
||||
enum class HandleRMat { BIND, SKIP };
|
||||
// Extracts a memory object from GRunArg, stores it in appropriate slot in a magazine
|
||||
// Note:
|
||||
// Only RMats are expected here as a memory object for GMat shape.
|
||||
// If handleRMat is BIND, RMat will be accessed, and RMat::View and wrapping cv::Mat
|
||||
// will be placed into the magazine.
|
||||
// If handleRMat is SKIP, this function skips'RMat handling assuming that backend will do it on its own.
|
||||
// FIXME?
|
||||
// handleRMat parameter might be redundant if all device specific backends implement own bind routines
|
||||
// without utilizing magazine at all
|
||||
void GAPI_EXPORTS bindInArg (Mag& mag, const RcDesc &rc, const GRunArg &arg, HandleRMat handleRMat = HandleRMat::BIND);
|
||||
|
||||
// Extracts a memory object reference fro GRunArgP, stores it in appropriate slot in a magazine
|
||||
// Note on RMat handling from bindInArg above is also applied here
|
||||
void GAPI_EXPORTS bindOutArg(Mag& mag, const RcDesc &rc, const GRunArgP &arg, HandleRMat handleRMat = HandleRMat::BIND);
|
||||
|
||||
void resetInternalData(Mag& mag, const Data &d);
|
||||
cv::GRunArg getArg (const Mag& mag, const RcDesc &ref);
|
||||
cv::GRunArgP getObjPtr ( Mag& mag, const RcDesc &rc, bool is_umat = false);
|
||||
void writeBack (const Mag& mag, const RcDesc &rc, GRunArgP &g_arg, bool is_umat = false);
|
||||
void writeBack (const Mag& mag, const RcDesc &rc, GRunArgP &g_arg);
|
||||
|
||||
// A mandatory clean-up procedure to force proper lifetime of wrappers (cv::Mat, cv::RMat::View)
|
||||
// over not-owned data
|
||||
// FIXME? Add an RAII wrapper for that?
|
||||
// Or put objects which need to be cleaned-up into a separate stack allocated magazine?
|
||||
void unbind(Mag &mag, const RcDesc &rc);
|
||||
} // namespace magazine
|
||||
|
||||
namespace detail
|
||||
|
||||
@@ -165,6 +165,14 @@ IOStream& operator<< (IOStream& os, const cv::Scalar &s) {
|
||||
IIStream& operator>> (IIStream& is, cv::Scalar& s) {
|
||||
return is >> s.val[0] >> s.val[1] >> s.val[2] >> s.val[3];
|
||||
}
|
||||
IOStream& operator<< (IOStream& os, const cv::RMat&) {
|
||||
util::throw_error(std::logic_error("Serialization of RMat is not supported"));
|
||||
return os;
|
||||
}
|
||||
IIStream& operator>> (IIStream& is, cv::RMat&) {
|
||||
util::throw_error(std::logic_error("Serialization of RMat is not supported"));
|
||||
return is;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
@@ -88,6 +88,9 @@ GAPI_EXPORTS IOStream& operator<< (IOStream& os, const cv::UMat &);
|
||||
GAPI_EXPORTS IIStream& operator>> (IIStream& is, cv::UMat &);
|
||||
#endif // !defined(GAPI_STANDALONE)
|
||||
|
||||
GAPI_EXPORTS IOStream& operator<< (IOStream& os, const cv::RMat &r);
|
||||
GAPI_EXPORTS IIStream& operator>> (IIStream& is, cv::RMat &r);
|
||||
|
||||
GAPI_EXPORTS IOStream& operator<< (IOStream& os, const cv::gapi::wip::IStreamSource::Ptr &);
|
||||
GAPI_EXPORTS IIStream& operator>> (IIStream& is, cv::gapi::wip::IStreamSource::Ptr &);
|
||||
|
||||
|
||||
@@ -276,4 +276,8 @@ void cv::gimpl::GCPUExecutable::run(std::vector<InObj> &&input_objs,
|
||||
} // for(m_script)
|
||||
|
||||
for (auto &it : output_objs) magazine::writeBack(m_res, it.first, it.second);
|
||||
|
||||
// In/Out args clean-up is mandatory now with RMat
|
||||
for (auto &it : input_objs) magazine::unbind(m_res, it.first);
|
||||
for (auto &it : output_objs) magazine::unbind(m_res, it.first);
|
||||
}
|
||||
|
||||
@@ -1243,41 +1243,25 @@ void cv::gimpl::GFluidExecutable::reshape(ade::Graph &g, const GCompileArgs &arg
|
||||
// FIXME: Document what it does
|
||||
void cv::gimpl::GFluidExecutable::bindInArg(const cv::gimpl::RcDesc &rc, const GRunArg &arg)
|
||||
{
|
||||
switch (rc.shape)
|
||||
{
|
||||
case GShape::GMAT: m_buffers[m_id_map.at(rc.id)].priv().bindTo(util::get<cv::Mat>(arg), true); break;
|
||||
case GShape::GSCALAR: m_res.slot<cv::Scalar>()[rc.id] = util::get<cv::Scalar>(arg); break;
|
||||
case GShape::GARRAY: m_res.slot<cv::detail::VectorRef>()[rc.id] = util::get<cv::detail::VectorRef>(arg); break;
|
||||
case GShape::GOPAQUE: m_res.slot<cv::detail::OpaqueRef>()[rc.id] = util::get<cv::detail::OpaqueRef>(arg); break;
|
||||
default: util::throw_error(std::logic_error("Unsupported input GShape type"));
|
||||
magazine::bindInArg(m_res, rc, arg);
|
||||
if (rc.shape == GShape::GMAT) {
|
||||
auto& mat = m_res.slot<cv::Mat>()[rc.id];
|
||||
// fluid::Buffer::bindTo() is not connected to magazine::bindIn/OutArg and unbind() calls,
|
||||
// it's simply called each run() without any requirement to call some fluid-specific
|
||||
// unbind() at the end of run()
|
||||
m_buffers[m_id_map.at(rc.id)].priv().bindTo(mat, true);
|
||||
}
|
||||
}
|
||||
|
||||
void cv::gimpl::GFluidExecutable::bindOutArg(const cv::gimpl::RcDesc &rc, const GRunArgP &arg)
|
||||
{
|
||||
// Only GMat is supported as return type
|
||||
using T = GRunArgP;
|
||||
switch (rc.shape)
|
||||
{
|
||||
case GShape::GMAT:
|
||||
{
|
||||
cv::GMatDesc desc = m_buffers[m_id_map.at(rc.id)].meta();
|
||||
auto &bref = m_buffers[m_id_map.at(rc.id)].priv();
|
||||
|
||||
switch (arg.index()) {
|
||||
// FIXME: See the bindInArg comment on Streaming-related changes
|
||||
case T::index_of<cv::Mat*>(): {
|
||||
auto &outMat = *util::get<cv::Mat*>(arg);
|
||||
GAPI_Assert(outMat.data != nullptr);
|
||||
GAPI_Assert(cv::descr_of(outMat) == desc && "Output argument was not preallocated as it should be ?");
|
||||
bref.bindTo(outMat, false);
|
||||
} break;
|
||||
default: GAPI_Assert(false);
|
||||
} // switch(arg.index())
|
||||
break;
|
||||
}
|
||||
default: util::throw_error(std::logic_error("Unsupported return GShape type"));
|
||||
if (rc.shape != GShape::GMAT) {
|
||||
util::throw_error(std::logic_error("Unsupported return GShape type"));
|
||||
}
|
||||
magazine::bindOutArg(m_res, rc, arg);
|
||||
auto& mat = m_res.slot<cv::Mat>()[rc.id];
|
||||
m_buffers[m_id_map.at(rc.id)].priv().bindTo(mat, false);
|
||||
}
|
||||
|
||||
void cv::gimpl::GFluidExecutable::packArg(cv::GArg &in_arg, const cv::GArg &op_arg)
|
||||
@@ -1383,6 +1367,10 @@ void cv::gimpl::GFluidExecutable::run(std::vector<InObj> &input_objs,
|
||||
agent->doWork();
|
||||
}
|
||||
}
|
||||
|
||||
// In/Out args clean-up is mandatory now with RMat
|
||||
for (auto &it : input_objs) magazine::unbind(m_res, it.first);
|
||||
for (auto &it : output_objs) magazine::unbind(m_res, it.first);
|
||||
}
|
||||
|
||||
cv::gimpl::GParallelFluidExecutable::GParallelFluidExecutable(const ade::Graph &g,
|
||||
|
||||
@@ -128,8 +128,7 @@ class GFluidExecutable final: public GIslandExecutable
|
||||
|
||||
std::vector<FluidAgent*> m_script;
|
||||
|
||||
using Magazine = detail::magazine<cv::Scalar, cv::detail::VectorRef, cv::detail::OpaqueRef>;
|
||||
Magazine m_res;
|
||||
cv::gimpl::Mag m_res;
|
||||
|
||||
std::size_t m_num_int_buffers; // internal buffers counter (m_buffers - num_scratch)
|
||||
std::vector<std::size_t> m_scratch_users;
|
||||
|
||||
@@ -397,6 +397,10 @@ void cv::gimpl::ie::GIEExecutable::run(std::vector<InObj> &&input_objs,
|
||||
kk.run(this_iec, uu, context);
|
||||
|
||||
for (auto &it : output_objs) magazine::writeBack(m_res, it.first, it.second);
|
||||
|
||||
// In/Out args clean-up is mandatory now with RMat
|
||||
for (auto &it : input_objs) magazine::unbind(m_res, it.first);
|
||||
for (auto &it : output_objs) magazine::unbind(m_res, it.first);
|
||||
}
|
||||
|
||||
namespace cv {
|
||||
|
||||
@@ -165,12 +165,31 @@ void cv::gimpl::GOCLExecutable::run(std::vector<InObj> &&input_objs,
|
||||
// NB: avoid clearing the whole magazine, there's also pre-allocated internal data
|
||||
for (auto& it : input_objs) umats.erase(it.first.id);
|
||||
for (auto& it : output_objs) umats.erase(it.first.id);
|
||||
|
||||
// In/Out args clean-up is mandatory now with RMat
|
||||
for (auto &it : input_objs) magazine::unbind(*p, it.first);
|
||||
for (auto &it : output_objs) magazine::unbind(*p, it.first);
|
||||
};
|
||||
// RAII wrapper to clean-up m_res
|
||||
std::unique_ptr<cv::gimpl::Mag, decltype(clean_up)> cleaner(&m_res, clean_up);
|
||||
|
||||
for (auto& it : input_objs) magazine::bindInArg (m_res, it.first, it.second, true);
|
||||
for (auto& it : output_objs) magazine::bindOutArg(m_res, it.first, it.second, true);
|
||||
const auto bindUMat = [this](const RcDesc& rc) {
|
||||
auto& mag_umat = m_res.template slot<cv::UMat>()[rc.id];
|
||||
mag_umat = m_res.template slot<cv::Mat>()[rc.id].getUMat(ACCESS_READ);
|
||||
};
|
||||
|
||||
for (auto& it : input_objs) {
|
||||
const auto& rc = it.first;
|
||||
magazine::bindInArg (m_res, rc, it.second);
|
||||
// There is already cv::Mat in the magazine after bindInArg call,
|
||||
// extract UMat from it, put into the magazine
|
||||
if (rc.shape == GShape::GMAT) bindUMat(rc);
|
||||
}
|
||||
for (auto& it : output_objs) {
|
||||
const auto& rc = it.first;
|
||||
magazine::bindOutArg(m_res, rc, it.second);
|
||||
if (rc.shape == GShape::GMAT) bindUMat(rc);
|
||||
}
|
||||
|
||||
// Initialize (reset) internal data nodes with user structures
|
||||
// before processing a frame (no need to do it for external data structures)
|
||||
@@ -241,5 +260,16 @@ void cv::gimpl::GOCLExecutable::run(std::vector<InObj> &&input_objs,
|
||||
}
|
||||
} // for(m_script)
|
||||
|
||||
for (auto &it : output_objs) magazine::writeBack(m_res, it.first, it.second, true);
|
||||
for (auto &it : output_objs)
|
||||
{
|
||||
auto& rc = it.first;
|
||||
auto& g_arg = it.second;
|
||||
magazine::writeBack(m_res, rc, g_arg);
|
||||
if (rc.shape == GShape::GMAT)
|
||||
{
|
||||
uchar* out_arg_data = m_res.template slot<cv::Mat>()[rc.id].data;
|
||||
auto& mag_mat = m_res.template slot<cv::UMat>().at(rc.id);
|
||||
GAPI_Assert((out_arg_data == (mag_mat.getMat(ACCESS_RW).data)) && " data for output parameters was reallocated ?");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -198,6 +198,9 @@ void cv::gimpl::GPlaidMLExecutable::run(std::vector<InObj> &&input_objs,
|
||||
exec_->run();
|
||||
|
||||
for (auto& it : output_objs) bindOutArg(it.first, it.second);
|
||||
|
||||
// FIXME:
|
||||
// PlaidML backend haven't been updated with RMat support
|
||||
}
|
||||
|
||||
void cv::gimpl::GPlaidMLExecutable::bindInArg(const RcDesc &rc, const GRunArg &arg)
|
||||
|
||||
@@ -96,6 +96,10 @@ void cv::gimpl::render::ocv::GRenderExecutable::run(std::vector<InObj> &&input_
|
||||
k.m_runF(context);
|
||||
|
||||
for (auto &it : output_objs) magazine::writeBack(m_res, it.first, it.second);
|
||||
|
||||
// In/Out args clean-up is mandatory now with RMat
|
||||
for (auto &it : input_objs) magazine::unbind(m_res, it.first);
|
||||
for (auto &it : output_objs) magazine::unbind(m_res, it.first);
|
||||
}
|
||||
|
||||
cv::GArg cv::gimpl::render::ocv::GRenderExecutable::packArg(const cv::GArg &arg) {
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "compiler/gmodel.hpp"
|
||||
#include "compiler/gislandmodel.hpp"
|
||||
#include "compiler/gmodel.hpp"
|
||||
#include "backends/common/gbackend.hpp" // RMatAdapter
|
||||
|
||||
#include "logger.hpp" // GAPI_LOG
|
||||
|
||||
@@ -348,7 +349,7 @@ void GIslandExecutable::run(GIslandExecutable::IInput &in, GIslandExecutable::IO
|
||||
switch (in_data_orig.index())
|
||||
{
|
||||
case cv::GRunArg::index_of<cv::Mat>():
|
||||
in_data = cv::GRunArg{cv::util::get<cv::Mat>(in_data_orig)};
|
||||
in_data = cv::GRunArg{cv::make_rmat<cv::gimpl::RMatAdapter>(cv::util::get<cv::Mat>(in_data_orig))};
|
||||
break;
|
||||
case cv::GRunArg::index_of<cv::Scalar>():
|
||||
in_data = cv::GRunArg{(cv::util::get<cv::Scalar>(in_data_orig))};
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
|
||||
namespace cv { namespace gimpl {
|
||||
|
||||
|
||||
// FIXME: GAPI_EXPORTS only because of tests!
|
||||
class GAPI_EXPORTS GIsland
|
||||
{
|
||||
@@ -122,6 +121,8 @@ public:
|
||||
|
||||
virtual bool canReshape() const = 0;
|
||||
virtual void reshape(ade::Graph& g, const GCompileArgs& args) = 0;
|
||||
virtual bool allocatesOutputs() const { return false; }
|
||||
virtual cv::RMat allocate(const cv::GMatDesc&) const { GAPI_Assert(false && "should never be called"); }
|
||||
|
||||
// This method is called when the GStreamingCompiled gets a new
|
||||
// input source to process. Normally this method is called once
|
||||
|
||||
@@ -72,7 +72,7 @@ cv::gimpl::GExecutor::GExecutor(std::unique_ptr<ade::Graph> &&g_model)
|
||||
const auto orig_data_nh
|
||||
= m_gim.metadata(nh).get<DataSlot>().original_data_node;
|
||||
// (1)
|
||||
initResource(orig_data_nh);
|
||||
initResource(nh, orig_data_nh);
|
||||
m_slots.emplace_back(DataDesc{nh, orig_data_nh});
|
||||
}
|
||||
break;
|
||||
@@ -84,7 +84,82 @@ cv::gimpl::GExecutor::GExecutor(std::unique_ptr<ade::Graph> &&g_model)
|
||||
} // for(gim nodes)
|
||||
}
|
||||
|
||||
void cv::gimpl::GExecutor::initResource(const ade::NodeHandle &orig_nh)
|
||||
namespace cv {
|
||||
namespace gimpl {
|
||||
namespace magazine {
|
||||
namespace {
|
||||
|
||||
void bindInArgExec(Mag& mag, const RcDesc &rc, const GRunArg &arg)
|
||||
{
|
||||
if (rc.shape != GShape::GMAT)
|
||||
{
|
||||
bindInArg(mag, rc, arg);
|
||||
return;
|
||||
}
|
||||
auto& mag_rmat = mag.template slot<cv::RMat>()[rc.id];
|
||||
switch (arg.index())
|
||||
{
|
||||
case GRunArg::index_of<Mat>() :
|
||||
mag_rmat = make_rmat<RMatAdapter>(util::get<Mat>(arg)); break;
|
||||
case GRunArg::index_of<cv::RMat>() :
|
||||
mag_rmat = util::get<cv::RMat>(arg); break;
|
||||
default: util::throw_error(std::logic_error("content type of the runtime argument does not match to resource description ?"));
|
||||
}
|
||||
}
|
||||
|
||||
void bindOutArgExec(Mag& mag, const RcDesc &rc, const GRunArgP &arg)
|
||||
{
|
||||
if (rc.shape != GShape::GMAT)
|
||||
{
|
||||
bindOutArg(mag, rc, arg);
|
||||
return;
|
||||
}
|
||||
auto& mag_rmat = mag.template slot<cv::RMat>()[rc.id];
|
||||
switch (arg.index())
|
||||
{
|
||||
case GRunArgP::index_of<Mat*>() :
|
||||
mag_rmat = make_rmat<RMatAdapter>(*util::get<Mat*>(arg)); break;
|
||||
case GRunArgP::index_of<cv::RMat*>() :
|
||||
mag_rmat = *util::get<cv::RMat*>(arg); break;
|
||||
default: util::throw_error(std::logic_error("content type of the runtime argument does not match to resource description ?"));
|
||||
}
|
||||
}
|
||||
|
||||
cv::GRunArgP getObjPtrExec(Mag& mag, const RcDesc &rc)
|
||||
{
|
||||
if (rc.shape != GShape::GMAT)
|
||||
{
|
||||
return getObjPtr(mag, rc);
|
||||
}
|
||||
return GRunArgP(&mag.template slot<cv::RMat>()[rc.id]);
|
||||
}
|
||||
|
||||
void writeBackExec(const Mag& mag, const RcDesc &rc, GRunArgP &g_arg)
|
||||
{
|
||||
if (rc.shape != GShape::GMAT)
|
||||
{
|
||||
writeBack(mag, rc, g_arg);
|
||||
return;
|
||||
}
|
||||
auto checkOutArgData = [&](const uchar* out_arg_data) {
|
||||
//simply check that memory was not reallocated, i.e.
|
||||
//both Mat and View pointing to the same memory
|
||||
auto mag_data = mag.template slot<cv::RMat>().at(rc.id).get<RMatAdapter>()->data();
|
||||
GAPI_Assert((out_arg_data == mag_data) && " data for output parameters was reallocated ?");
|
||||
};
|
||||
|
||||
switch (g_arg.index())
|
||||
{
|
||||
case GRunArgP::index_of<cv::Mat*>() : checkOutArgData(util::get<cv::Mat*>(g_arg)->data); break;
|
||||
case GRunArgP::index_of<cv::RMat*>() : /* do nothing */ break;
|
||||
default: util::throw_error(std::logic_error("content type of the runtime argument does not match to resource description ?"));
|
||||
}
|
||||
}
|
||||
} // anonymous namespace
|
||||
}}} // namespace cv::gimpl::magazine
|
||||
|
||||
|
||||
void cv::gimpl::GExecutor::initResource(const ade::NodeHandle & nh, const ade::NodeHandle &orig_nh)
|
||||
{
|
||||
const Data &d = m_gm.metadata(orig_nh).get<Data>();
|
||||
|
||||
@@ -99,9 +174,19 @@ void cv::gimpl::GExecutor::initResource(const ade::NodeHandle &orig_nh)
|
||||
{
|
||||
case GShape::GMAT:
|
||||
{
|
||||
// Let island allocate it's outputs if it can,
|
||||
// allocate cv::Mat and wrap it with RMat otherwise
|
||||
GAPI_Assert(!nh->inNodes().empty());
|
||||
const auto desc = util::get<cv::GMatDesc>(d.meta);
|
||||
auto& mat = m_res.slot<cv::Mat>()[d.rc];
|
||||
createMat(desc, mat);
|
||||
auto& exec = m_gim.metadata(nh->inNodes().front()).get<IslandExec>().object;
|
||||
auto& rmat = m_res.slot<cv::RMat>()[d.rc];
|
||||
if (exec->allocatesOutputs()) {
|
||||
rmat = exec->allocate(desc);
|
||||
} else {
|
||||
Mat mat;
|
||||
createMat(desc, mat);
|
||||
rmat = make_rmat<RMatAdapter>(mat);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -146,7 +231,7 @@ public:
|
||||
class cv::gimpl::GExecutor::Output final: public cv::gimpl::GIslandExecutable::IOutput
|
||||
{
|
||||
cv::gimpl::Mag &mag;
|
||||
virtual GRunArgP get(int idx) override { return magazine::getObjPtr(mag, desc()[idx]); }
|
||||
virtual GRunArgP get(int idx) override { return magazine::getObjPtrExec(mag, desc()[idx]); }
|
||||
virtual void post(GRunArgP&&) override { } // Do nothing here
|
||||
virtual void post(EndOfStream&&) override {} // Do nothing here too
|
||||
public:
|
||||
@@ -186,11 +271,10 @@ void cv::gimpl::GExecutor::run(cv::gimpl::GRuntimeArgs &&args)
|
||||
using cv::util::get;
|
||||
const auto desc = get<cv::GMatDesc>(d.meta);
|
||||
|
||||
auto check_own_mat = [&desc, &args, &index]()
|
||||
auto check_rmat = [&desc, &args, &index]()
|
||||
{
|
||||
auto& out_mat = *get<cv::Mat*>(args.outObjs.at(index));
|
||||
GAPI_Assert(out_mat.data != nullptr &&
|
||||
desc.canDescribe(out_mat));
|
||||
auto& out_mat = *get<cv::RMat*>(args.outObjs.at(index));
|
||||
GAPI_Assert(desc.canDescribe(out_mat));
|
||||
};
|
||||
|
||||
#if !defined(GAPI_STANDALONE)
|
||||
@@ -202,15 +286,25 @@ void cv::gimpl::GExecutor::run(cv::gimpl::GRuntimeArgs &&args)
|
||||
auto& out_mat = *get<cv::Mat*>(args.outObjs.at(index));
|
||||
createMat(desc, out_mat);
|
||||
}
|
||||
// In the case of own::Mat never reallocated, checked to perfectly fit required meta
|
||||
// In the case of RMat check to fit required meta
|
||||
else
|
||||
{
|
||||
check_own_mat();
|
||||
check_rmat();
|
||||
}
|
||||
#else
|
||||
// Building standalone - output buffer should always exist,
|
||||
// and _exact_ match our inferred metadata
|
||||
check_own_mat();
|
||||
if (cv::util::holds_alternative<cv::Mat*>(args.outObjs.at(index)))
|
||||
{
|
||||
auto& out_mat = *get<cv::Mat*>(args.outObjs.at(index));
|
||||
GAPI_Assert(out_mat.data != nullptr &&
|
||||
desc.canDescribe(out_mat));
|
||||
}
|
||||
// In the case of RMat check to fit required meta
|
||||
else
|
||||
{
|
||||
check_rmat();
|
||||
}
|
||||
#endif // !defined(GAPI_STANDALONE)
|
||||
}
|
||||
}
|
||||
@@ -218,12 +312,12 @@ void cv::gimpl::GExecutor::run(cv::gimpl::GRuntimeArgs &&args)
|
||||
for (auto it : ade::util::zip(ade::util::toRange(proto.inputs),
|
||||
ade::util::toRange(args.inObjs)))
|
||||
{
|
||||
magazine::bindInArg(m_res, std::get<0>(it), std::get<1>(it));
|
||||
magazine::bindInArgExec(m_res, std::get<0>(it), std::get<1>(it));
|
||||
}
|
||||
for (auto it : ade::util::zip(ade::util::toRange(proto.outputs),
|
||||
ade::util::toRange(args.outObjs)))
|
||||
{
|
||||
magazine::bindOutArg(m_res, std::get<0>(it), std::get<1>(it));
|
||||
magazine::bindOutArgExec(m_res, std::get<0>(it), std::get<1>(it));
|
||||
}
|
||||
|
||||
// Reset internal data
|
||||
@@ -246,7 +340,7 @@ void cv::gimpl::GExecutor::run(cv::gimpl::GRuntimeArgs &&args)
|
||||
for (auto it : ade::util::zip(ade::util::toRange(proto.outputs),
|
||||
ade::util::toRange(args.outObjs)))
|
||||
{
|
||||
magazine::writeBack(m_res, std::get<0>(it), std::get<1>(it));
|
||||
magazine::writeBackExec(m_res, std::get<0>(it), std::get<1>(it));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -54,6 +54,7 @@ namespace gimpl {
|
||||
class GExecutor
|
||||
{
|
||||
protected:
|
||||
Mag m_res;
|
||||
std::unique_ptr<ade::Graph> m_orig_graph;
|
||||
std::shared_ptr<ade::Graph> m_island_graph;
|
||||
|
||||
@@ -80,9 +81,7 @@ protected:
|
||||
class Input;
|
||||
class Output;
|
||||
|
||||
Mag m_res;
|
||||
|
||||
void initResource(const ade::NodeHandle &orig_nh); // FIXME: shouldn't it be RcDesc?
|
||||
void initResource(const ade::NodeHandle &nh, const ade::NodeHandle &orig_nh); // FIXME: shouldn't it be RcDesc?
|
||||
|
||||
public:
|
||||
explicit GExecutor(std::unique_ptr<ade::Graph> &&g_model);
|
||||
|
||||
@@ -109,7 +109,13 @@ void sync_data(cv::GRunArgs &results, cv::GRunArgsP &outputs)
|
||||
switch (out_obj.index())
|
||||
{
|
||||
case T::index_of<cv::Mat*>():
|
||||
*cv::util::get<cv::Mat*>(out_obj) = std::move(cv::util::get<cv::Mat>(res_obj));
|
||||
{
|
||||
auto out_mat_p = cv::util::get<cv::Mat*>(out_obj);
|
||||
auto view = cv::util::get<cv::RMat>(res_obj).access(cv::RMat::Access::R);
|
||||
*out_mat_p = cv::gimpl::asMat(view).clone();
|
||||
} break;
|
||||
case T::index_of<cv::RMat*>():
|
||||
*cv::util::get<cv::RMat*>(out_obj) = std::move(cv::util::get<cv::RMat>(res_obj));
|
||||
break;
|
||||
case T::index_of<cv::Scalar*>():
|
||||
*cv::util::get<cv::Scalar*>(out_obj) = std::move(cv::util::get<cv::Scalar>(res_obj));
|
||||
@@ -408,6 +414,7 @@ class StreamingOutput final: public cv::gimpl::GIslandExecutable::IOutput
|
||||
// These objects are owned externally
|
||||
const cv::GMetaArgs &m_metas;
|
||||
std::vector< std::vector<Q*> > &m_out_queues;
|
||||
std::shared_ptr<cv::gimpl::GIslandExecutable> m_island;
|
||||
|
||||
// Allocate a new data object for output under idx
|
||||
// Prepare this object for posting
|
||||
@@ -430,10 +437,19 @@ class StreamingOutput final: public cv::gimpl::GIslandExecutable::IOutput
|
||||
// FIXME: This is absolutely ugly but seem to work perfectly for its purpose.
|
||||
case cv::GShape::GMAT:
|
||||
{
|
||||
MatType newMat;
|
||||
cv::gimpl::createMat(cv::util::get<cv::GMatDesc>(m_metas[idx]), newMat);
|
||||
out_arg = cv::GRunArg(std::move(newMat));
|
||||
ret_val = cv::GRunArgP(&cv::util::get<MatType>(out_arg));
|
||||
auto desc = cv::util::get<cv::GMatDesc>(m_metas[idx]);
|
||||
if (m_island->allocatesOutputs())
|
||||
{
|
||||
out_arg = cv::GRunArg(m_island->allocate(desc));
|
||||
}
|
||||
else
|
||||
{
|
||||
MatType newMat;
|
||||
cv::gimpl::createMat(desc, newMat);
|
||||
auto rmat = cv::make_rmat<cv::gimpl::RMatAdapter>(newMat);
|
||||
out_arg = cv::GRunArg(std::move(rmat));
|
||||
}
|
||||
ret_val = cv::GRunArgP(&cv::util::get<cv::RMat>(out_arg));
|
||||
}
|
||||
break;
|
||||
case cv::GShape::GSCALAR:
|
||||
@@ -538,9 +554,11 @@ class StreamingOutput final: public cv::gimpl::GIslandExecutable::IOutput
|
||||
public:
|
||||
explicit StreamingOutput(const cv::GMetaArgs &metas,
|
||||
std::vector< std::vector<Q*> > &out_queues,
|
||||
const std::vector<cv::gimpl::RcDesc> &out_descs)
|
||||
const std::vector<cv::gimpl::RcDesc> &out_descs,
|
||||
std::shared_ptr<cv::gimpl::GIslandExecutable> island)
|
||||
: m_metas(metas)
|
||||
, m_out_queues(out_queues)
|
||||
, m_island(island)
|
||||
{
|
||||
set(out_descs);
|
||||
m_postings.resize(out_descs.size());
|
||||
@@ -573,7 +591,7 @@ void islandActorThread(std::vector<cv::gimpl::RcDesc> in_rcs, //
|
||||
GAPI_Assert(out_queues.size() == out_metas.size());
|
||||
QueueReader qr;
|
||||
StreamingInput input(qr, in_queues, in_constants, in_rcs);
|
||||
StreamingOutput output(out_metas, out_queues, out_rcs);
|
||||
StreamingOutput output(out_metas, out_queues, out_rcs, island);
|
||||
while (!output.done())
|
||||
{
|
||||
island->run(input, output);
|
||||
|
||||
Reference in New Issue
Block a user