1 // This file is part of OpenCV project.
2 // It is subject to the license terms in the LICENSE file found in the top-level directory
3 // of this distribution and at http://opencv.org/license.html.
5 // Copyright (C) 2018-2019 Intel Corporation
12 #include <ade/util/zip_range.hpp>
14 #include "opencv2/gapi/opencv_includes.hpp"
15 #include "executor/gexecutor.hpp"
16 #include "compiler/passes/passes.hpp"
18 cv::gimpl::GExecutor::GExecutor(std::unique_ptr<ade::Graph> &&g_model)
19 : m_orig_graph(std::move(g_model))
20 , m_island_graph(GModel::Graph(*m_orig_graph).metadata()
21 .get<IslandModel>().model)
23 , m_gim(*m_island_graph)
25 // NB: Right now GIslandModel is acyclic, so for a naive execution,
26 // simple unrolling to a list of triggers is enough
28 // Naive execution model is similar to current CPU (OpenCV) plugin
30 // 1. Allocate all internal resources first (NB - CPU plugin doesn't do it)
31 // 2. Put input/output GComputation arguments to the storage
32 // 3. For every Island, prepare vectors of input/output parameter descs
33 // 4. Iterate over a list of operations (sorted in the topological order)
34 // 5. For every operation, form a list of input/output data objects
35 // 6. Run GIslandExecutable
38 auto sorted = m_gim.metadata().get<ade::passes::TopologicalSortData>();
39 for (auto nh : sorted.nodes())
41 switch (m_gim.metadata(nh).get<NodeKind>().k)
43 case NodeKind::ISLAND:
45 std::vector<RcDesc> input_rcs;
46 std::vector<RcDesc> output_rcs;
47 input_rcs.reserve(nh->inNodes().size());
48 output_rcs.reserve(nh->outNodes().size());
50 auto xtract = [&](ade::NodeHandle slot_nh, std::vector<RcDesc> &vec) {
51 const auto orig_data_nh
52 = m_gim.metadata(slot_nh).get<DataSlot>().original_data_node;
53 const auto &orig_data_info
54 = m_gm.metadata(orig_data_nh).get<Data>();
55 vec.emplace_back(RcDesc{ orig_data_info.rc
56 , orig_data_info.shape
57 , orig_data_info.ctor});
60 for (auto in_slot_nh : nh->inNodes()) xtract(in_slot_nh, input_rcs);
61 for (auto out_slot_nh : nh->outNodes()) xtract(out_slot_nh, output_rcs);
63 m_ops.emplace_back(OpDesc{ std::move(input_rcs)
64 , std::move(output_rcs)
65 , m_gim.metadata(nh).get<IslandExec>().object});
71 const auto orig_data_nh
72 = m_gim.metadata(nh).get<DataSlot>().original_data_node;
74 initResource(orig_data_nh);
75 m_slots.emplace_back(DataDesc{nh, orig_data_nh});
86 void cv::gimpl::GExecutor::initResource(const ade::NodeHandle &orig_nh)
88 const Data &d = m_gm.metadata(orig_nh).get<Data>();
90 if ( d.storage != Data::Storage::INTERNAL
91 && d.storage != Data::Storage::CONST)
94 // INTERNALS+CONST only! no need to allocate/reset output objects
95 // to as it is bound externally (e.g. already in the m_res)
101 const auto desc = util::get<cv::GMatDesc>(d.meta);
102 const auto type = CV_MAKETYPE(desc.depth, desc.chan);
103 m_res.slot<cv::gapi::own::Mat>()[d.rc].create(desc.size, type);
107 case GShape::GSCALAR:
108 if (d.storage == Data::Storage::CONST)
110 auto rc = RcDesc{d.rc, d.shape, d.ctor};
111 magazine::bindInArg(m_res, rc, m_gm.metadata(orig_nh).get<ConstValue>().arg);
116 // Constructed on Reset, do nothing here
124 void cv::gimpl::GExecutor::run(cv::gimpl::GRuntimeArgs &&args)
127 const auto proto = m_gm.metadata().get<Protocol>();
129 // Basic check if input/output arguments are correct
130 // FIXME: Move to GCompiled (do once for all GExecutors)
131 if (proto.inputs.size() != args.inObjs.size()) // TODO: Also check types
133 util::throw_error(std::logic_error
134 ("Computation's input protocol doesn\'t "
135 "match actual arguments!"));
137 if (proto.outputs.size() != args.outObjs.size()) // TODO: Also check types
139 util::throw_error(std::logic_error
140 ("Computation's output protocol doesn\'t "
141 "match actual arguments!"));
144 namespace util = ade::util;
146 //ensure that output Mat parameters are correctly allocated
147 for (auto index : util::iota(proto.out_nhs.size()) ) //FIXME: avoid copy of NodeHandle and GRunRsltComp ?
149 auto& nh = proto.out_nhs.at(index);
150 const Data &d = m_gm.metadata(nh).get<Data>();
151 if (d.shape == GShape::GMAT)
154 const auto desc = get<cv::GMatDesc>(d.meta);
155 const auto type = CV_MAKETYPE(desc.depth, desc.chan);
157 #if !defined(GAPI_STANDALONE)
158 // Building as part of OpenCV - follow OpenCV behavior
159 // if output buffer is not enough to hold the result, reallocate it
160 auto& out_mat = *get<cv::Mat*>(args.outObjs.at(index));
161 out_mat.create(cv::gapi::own::to_ocv(desc.size), type);
163 // Building standalone - output buffer should always exist,
164 // and _exact_ match our inferred metadata
165 auto& out_mat = *get<cv::gapi::own::Mat*>(args.outObjs.at(index));
166 GAPI_Assert( out_mat.type() == type
167 && out_mat.data != nullptr
168 && out_mat.rows == desc.size.height
169 && out_mat.cols == desc.size.width)
170 #endif // !defined(GAPI_STANDALONE)
173 // Update storage with user-passed objects
174 for (auto it : ade::util::zip(ade::util::toRange(proto.inputs),
175 ade::util::toRange(args.inObjs)))
177 magazine::bindInArg(m_res, std::get<0>(it), std::get<1>(it));
179 for (auto it : ade::util::zip(ade::util::toRange(proto.outputs),
180 ade::util::toRange(args.outObjs)))
182 magazine::bindOutArg(m_res, std::get<0>(it), std::get<1>(it));
185 // Reset internal data
186 for (auto &sd : m_slots)
188 const auto& data = m_gm.metadata(sd.data_nh).get<Data>();
189 magazine::resetInternalData(m_res, data);
193 for (auto &op : m_ops)
196 using InObj = GIslandExecutable::InObj;
197 using OutObj = GIslandExecutable::OutObj;
198 std::vector<InObj> in_objs;
199 std::vector<OutObj> out_objs;
200 in_objs.reserve (op.in_objects.size());
201 out_objs.reserve(op.out_objects.size());
203 for (const auto &rc : op.in_objects)
205 in_objs.emplace_back(InObj{rc, magazine::getArg(m_res, rc)});
207 for (const auto &rc : op.out_objects)
209 out_objs.emplace_back(OutObj{rc, magazine::getObjPtr(m_res, rc)});
213 op.isl_exec->run(std::move(in_objs), std::move(out_objs));
217 for (auto it : ade::util::zip(ade::util::toRange(proto.outputs),
218 ade::util::toRange(args.outObjs)))
220 magazine::writeBack(m_res, std::get<0>(it), std::get<1>(it));
224 const cv::gimpl::GModel::Graph& cv::gimpl::GExecutor::model() const
229 bool cv::gimpl::GExecutor::canReshape() const
231 // FIXME: Introduce proper reshaping support on GExecutor level
233 return (m_ops.size() == 1) && m_ops[0].isl_exec->canReshape();
236 void cv::gimpl::GExecutor::reshape(const GMetaArgs& inMetas, const GCompileArgs& args)
238 GAPI_Assert(canReshape());
239 auto& g = *m_orig_graph.get();
240 ade::passes::PassContext ctx{g};
241 passes::initMeta(ctx, inMetas);
242 passes::inferMeta(ctx, true);
243 m_ops[0].isl_exec->reshape(g, args);