mirror of
https://github.com/opencv/opencv.git
synced 2026-07-29 15:23:05 +04:00
Merge pull request #18793 from dmatveev:dm/in_graph_metadata
G-API: Introduce runtime in-graph metadata * G-API: In-graph metadata -- initial implementation * G-API: Finish the in-graph metadata implementation for Streaming * G-API: Fix standalone build & warnings for in-graph metadata * G-API: In-graph meta -- fixed review comments * G-API: Fix issues with desync causing failing tests
This commit is contained in:
@@ -12,6 +12,8 @@
|
||||
#include <ade/util/zip_range.hpp>
|
||||
|
||||
#include <opencv2/gapi/opencv_includes.hpp>
|
||||
|
||||
#include "api/gproto_priv.hpp" // ptr(GRunArgP)
|
||||
#include "executor/gexecutor.hpp"
|
||||
#include "compiler/passes/passes.hpp"
|
||||
|
||||
@@ -105,6 +107,9 @@ void bindInArgExec(Mag& mag, const RcDesc &rc, const GRunArg &arg)
|
||||
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 ?"));
|
||||
}
|
||||
// FIXME: has to take extra care about meta here for this particuluar
|
||||
// case, just because this function exists at all
|
||||
mag.meta<cv::RMat>()[rc.id] = arg.meta;
|
||||
}
|
||||
|
||||
void bindOutArgExec(Mag& mag, const RcDesc &rc, const GRunArgP &arg)
|
||||
@@ -131,7 +136,7 @@ cv::GRunArgP getObjPtrExec(Mag& mag, const RcDesc &rc)
|
||||
{
|
||||
return getObjPtr(mag, rc);
|
||||
}
|
||||
return GRunArgP(&mag.template slot<cv::RMat>()[rc.id]);
|
||||
return GRunArgP(&mag.slot<cv::RMat>()[rc.id]);
|
||||
}
|
||||
|
||||
void writeBackExec(const Mag& mag, const RcDesc &rc, GRunArgP &g_arg)
|
||||
@@ -155,6 +160,25 @@ void writeBackExec(const Mag& mag, const RcDesc &rc, GRunArgP &g_arg)
|
||||
default: util::throw_error(std::logic_error("content type of the runtime argument does not match to resource description ?"));
|
||||
}
|
||||
}
|
||||
|
||||
void assignMetaStubExec(Mag& mag, const RcDesc &rc, const cv::GRunArg::Meta &meta) {
|
||||
switch (rc.shape)
|
||||
{
|
||||
case GShape::GARRAY: mag.meta<cv::detail::VectorRef>()[rc.id] = meta; break;
|
||||
case GShape::GOPAQUE: mag.meta<cv::detail::OpaqueRef>()[rc.id] = meta; break;
|
||||
case GShape::GSCALAR: mag.meta<cv::Scalar>()[rc.id] = meta; break;
|
||||
case GShape::GFRAME: mag.meta<cv::MediaFrame>()[rc.id] = meta; break;
|
||||
case GShape::GMAT:
|
||||
mag.meta<cv::Mat>() [rc.id] = meta;
|
||||
mag.meta<cv::RMat>()[rc.id] = meta;
|
||||
#if !defined(GAPI_STANDALONE)
|
||||
mag.meta<cv::UMat>()[rc.id] = meta;
|
||||
#endif
|
||||
break;
|
||||
default: util::throw_error(std::logic_error("Unsupported GShape type")); break;
|
||||
}
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
}}} // namespace cv::gimpl::magazine
|
||||
|
||||
@@ -231,11 +255,28 @@ public:
|
||||
class cv::gimpl::GExecutor::Output final: public cv::gimpl::GIslandExecutable::IOutput
|
||||
{
|
||||
cv::gimpl::Mag &mag;
|
||||
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
|
||||
std::unordered_map<const void*, int> out_idx;
|
||||
|
||||
GRunArgP get(int idx) override
|
||||
{
|
||||
auto r = magazine::getObjPtrExec(mag, desc()[idx]);
|
||||
// Remember the output port for this output object
|
||||
out_idx[cv::gimpl::proto::ptr(r)] = idx;
|
||||
return r;
|
||||
}
|
||||
void post(GRunArgP&&) override { } // Do nothing here
|
||||
void post(EndOfStream&&) override {} // Do nothing here too
|
||||
void meta(const GRunArgP &out, const GRunArg::Meta &m) override
|
||||
{
|
||||
const auto idx = out_idx.at(cv::gimpl::proto::ptr(out));
|
||||
magazine::assignMetaStubExec(mag, desc()[idx], m);
|
||||
}
|
||||
public:
|
||||
Output(cv::gimpl::Mag &m, const std::vector<RcDesc> &rcs) : mag(m) { set(rcs); }
|
||||
Output(cv::gimpl::Mag &m, const std::vector<RcDesc> &rcs)
|
||||
: mag(m)
|
||||
{
|
||||
set(rcs);
|
||||
}
|
||||
};
|
||||
|
||||
void cv::gimpl::GExecutor::run(cv::gimpl::GRuntimeArgs &&args)
|
||||
@@ -330,7 +371,7 @@ void cv::gimpl::GExecutor::run(cv::gimpl::GRuntimeArgs &&args)
|
||||
// Run the script
|
||||
for (auto &op : m_ops)
|
||||
{
|
||||
// (5)
|
||||
// (5), (6)
|
||||
Input i{m_res, op.in_objects};
|
||||
Output o{m_res, op.out_objects};
|
||||
op.isl_exec->run(i, o);
|
||||
|
||||
@@ -350,16 +350,14 @@ bool QueueReader::getInputVector(std::vector<Q*> &in_queues,
|
||||
// value-initialized scalar)
|
||||
// It can also hold a constant value received with
|
||||
// Stop::Kind::CNST message (see above).
|
||||
// FIXME: Variant move problem
|
||||
isl_inputs[id] = const_cast<const cv::GRunArg&>(in_constants[id]);
|
||||
isl_inputs[id] = in_constants[id];
|
||||
continue;
|
||||
}
|
||||
|
||||
q->pop(m_cmd[id]);
|
||||
if (!cv::util::holds_alternative<Stop>(m_cmd[id]))
|
||||
{
|
||||
// FIXME: Variant move problem
|
||||
isl_inputs[id] = const_cast<const cv::GRunArg &>(cv::util::get<cv::GRunArg>(m_cmd[id]));
|
||||
isl_inputs[id] = cv::util::get<cv::GRunArg>(m_cmd[id]);
|
||||
}
|
||||
else // A Stop sign
|
||||
{
|
||||
@@ -382,7 +380,7 @@ bool QueueReader::getInputVector(std::vector<Q*> &in_queues,
|
||||
// NEXT time (on a next call to getInputVector()), the
|
||||
// "q==nullptr" check above will be triggered, but now
|
||||
// we need to make it manually:
|
||||
isl_inputs[id] = const_cast<const cv::GRunArg&>(in_constants[id]);
|
||||
isl_inputs[id] = in_constants[id];
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -666,8 +664,7 @@ class StreamingOutput final: public cv::gimpl::GIslandExecutable::IOutput
|
||||
Cmd cmd;
|
||||
if (cv::util::holds_alternative<cv::GRunArg>(post_iter->data))
|
||||
{
|
||||
// FIXME: That ugly VARIANT problem
|
||||
cmd = Cmd{const_cast<const cv::GRunArg&>(cv::util::get<cv::GRunArg>(post_iter->data))};
|
||||
cmd = Cmd{cv::util::get<cv::GRunArg>(post_iter->data)};
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -677,8 +674,7 @@ class StreamingOutput final: public cv::gimpl::GIslandExecutable::IOutput
|
||||
}
|
||||
for (auto &&q : m_out_queues[out_idx])
|
||||
{
|
||||
// FIXME: This ugly VARIANT problem
|
||||
q->push(const_cast<const Cmd&>(cmd));
|
||||
q->push(cmd);
|
||||
}
|
||||
post_iter = m_postings[out_idx].erase(post_iter);
|
||||
}
|
||||
@@ -708,6 +704,15 @@ class StreamingOutput final: public cv::gimpl::GIslandExecutable::IOutput
|
||||
}
|
||||
}
|
||||
}
|
||||
void meta(const cv::GRunArgP &out, const cv::GRunArg::Meta &m) override
|
||||
{
|
||||
const auto it = m_postIdx.find(cv::gimpl::proto::ptr(out));
|
||||
GAPI_Assert(it != m_postIdx.end());
|
||||
|
||||
const auto out_iter = it->second.second;
|
||||
cv::util::get<cv::GRunArg>(out_iter->data).meta = m;
|
||||
}
|
||||
|
||||
public:
|
||||
explicit StreamingOutput(const cv::GMetaArgs &metas,
|
||||
std::vector< std::vector<Q*> > &out_queues,
|
||||
@@ -769,6 +774,7 @@ void islandActorThread(std::vector<cv::gimpl::RcDesc> in_rcs, //
|
||||
void collectorThread(std::vector<Q*> in_queues,
|
||||
std::vector<int> in_mapping,
|
||||
const std::size_t out_size,
|
||||
const bool handle_stop,
|
||||
Q& out_queue)
|
||||
{
|
||||
// These flags are static now: regardless if the sync or
|
||||
@@ -783,9 +789,14 @@ void collectorThread(std::vector<Q*> in_queues,
|
||||
while (true)
|
||||
{
|
||||
cv::GRunArgs this_result(out_size);
|
||||
if (!qr.getResultsVector(in_queues, in_mapping, out_size, this_result))
|
||||
const bool ok = qr.getResultsVector(in_queues, in_mapping, out_size, this_result);
|
||||
if (!ok)
|
||||
{
|
||||
out_queue.push(Cmd{Stop{}});
|
||||
if (handle_stop)
|
||||
{
|
||||
out_queue.push(Cmd{Stop{}});
|
||||
}
|
||||
// Terminate the thread anyway
|
||||
return;
|
||||
}
|
||||
out_queue.push(Cmd{Result{std::move(this_result), flags}});
|
||||
@@ -1263,12 +1274,22 @@ void cv::gimpl::GStreamingExecutor::setSource(GRunArgs &&ins)
|
||||
// If there are desynchronized parts in the graph, there may be
|
||||
// multiple theads polling every separate (desynchronized)
|
||||
// branch in the graph individually.
|
||||
const bool has_main_path = m_sink_sync.end() !=
|
||||
std::find(m_sink_sync.begin(), m_sink_sync.end(), -1);
|
||||
for (auto &&info : m_collector_map) {
|
||||
m_threads.emplace_back(collectorThread,
|
||||
info.second.queues,
|
||||
info.second.mapping,
|
||||
m_sink_queues.size(),
|
||||
has_main_path ? info.first == -1 : true, // see below (*)
|
||||
std::ref(m_out_queue));
|
||||
|
||||
// (*) - there may be a problem with desynchronized paths when those work
|
||||
// faster than the main path. In this case, the desync paths get "Stop" message
|
||||
// earlier and thus broadcast it down to pipeline gets stopped when there is
|
||||
// some "main path" data to process. This new collectorThread's flag regulates it:
|
||||
// - desync paths should never post Stop message if there is a main path.
|
||||
// - if there is no main path, than any desync path can terminate the execution.
|
||||
}
|
||||
state = State::READY;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user