Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Tetragramm
GitHub Repository: Tetragramm/opencv
Path: blob/master/modules/gapi/src/executor/gexecutor.cpp
16339 views
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.
4
//
5
// Copyright (C) 2018 Intel Corporation
6
7
8
#include "precomp.hpp"
9
10
#include <iostream>
11
12
#include <ade/util/zip_range.hpp>
13
14
#include "opencv2/gapi/opencv_includes.hpp"
15
#include "executor/gexecutor.hpp"
16
17
cv::gimpl::GExecutor::GExecutor(std::unique_ptr<ade::Graph> &&g_model)
18
: m_orig_graph(std::move(g_model))
19
, m_island_graph(GModel::Graph(*m_orig_graph).metadata()
20
.get<IslandModel>().model)
21
, m_gm(*m_orig_graph)
22
, m_gim(*m_island_graph)
23
{
24
// NB: Right now GIslandModel is acyclic, so for a naive execution,
25
// simple unrolling to a list of triggers is enough
26
27
// Naive execution model is similar to current CPU (OpenCV) plugin
28
// execution model:
29
// 1. Allocate all internal resources first (NB - CPU plugin doesn't do it)
30
// 2. Put input/output GComputation arguments to the storage
31
// 3. For every Island, prepare vectors of input/output parameter descs
32
// 4. Iterate over a list of operations (sorted in the topological order)
33
// 5. For every operation, form a list of input/output data objects
34
// 6. Run GIslandExecutable
35
// 7. writeBack
36
37
m_ops.reserve(m_gim.nodes().size());
38
auto sorted = m_gim.metadata().get<ade::passes::TopologicalSortData>();
39
for (auto nh : sorted.nodes())
40
{
41
switch (m_gim.metadata(nh).get<NodeKind>().k)
42
{
43
case NodeKind::ISLAND:
44
{
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());
49
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});
58
};
59
// (3)
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);
62
m_ops.emplace_back(OpDesc{ std::move(input_rcs)
63
, std::move(output_rcs)
64
, m_gim.metadata(nh).get<IslandExec>().object});
65
}
66
break;
67
68
case NodeKind::SLOT:
69
{
70
const auto orig_data_nh
71
= m_gim.metadata(nh).get<DataSlot>().original_data_node;
72
// (1)
73
initResource(orig_data_nh);
74
m_slots.emplace_back(DataDesc{nh, orig_data_nh});
75
}
76
break;
77
78
default:
79
GAPI_Assert(false);
80
break;
81
} // switch(kind)
82
} // for(gim nodes)
83
}
84
85
void cv::gimpl::GExecutor::initResource(const ade::NodeHandle &orig_nh)
86
{
87
const Data &d = m_gm.metadata(orig_nh).get<Data>();
88
89
if ( d.storage != Data::Storage::INTERNAL
90
&& d.storage != Data::Storage::CONST)
91
return;
92
93
// INTERNALS+CONST only! no need to allocate/reset output objects
94
// to as it is bound externally (e.g. already in the m_res)
95
96
switch (d.shape)
97
{
98
case GShape::GMAT:
99
{
100
const auto desc = util::get<cv::GMatDesc>(d.meta);
101
const auto type = CV_MAKETYPE(desc.depth, desc.chan);
102
m_res.slot<cv::gapi::own::Mat>()[d.rc].create(desc.size, type);
103
}
104
break;
105
106
case GShape::GSCALAR:
107
if (d.storage == Data::Storage::CONST)
108
{
109
auto rc = RcDesc{d.rc, d.shape, d.ctor};
110
magazine::bindInArg(m_res, rc, m_gm.metadata(orig_nh).get<ConstValue>().arg);
111
}
112
break;
113
114
case GShape::GARRAY:
115
// Constructed on Reset, do nothing here
116
break;
117
118
default:
119
GAPI_Assert(false);
120
}
121
}
122
123
void cv::gimpl::GExecutor::run(cv::gimpl::GRuntimeArgs &&args)
124
{
125
// (2)
126
const auto proto = m_gm.metadata().get<Protocol>();
127
128
// Basic check if input/output arguments are correct
129
// FIXME: Move to GCompiled (do once for all GExecutors)
130
if (proto.inputs.size() != args.inObjs.size()) // TODO: Also check types
131
{
132
util::throw_error(std::logic_error
133
("Computation's input protocol doesn\'t "
134
"match actual arguments!"));
135
}
136
if (proto.outputs.size() != args.outObjs.size()) // TODO: Also check types
137
{
138
util::throw_error(std::logic_error
139
("Computation's output protocol doesn\'t "
140
"match actual arguments!"));
141
}
142
143
namespace util = ade::util;
144
145
//ensure that output Mat parameters are correctly allocated
146
for (auto index : util::iota(proto.out_nhs.size()) ) //FIXME: avoid copy of NodeHandle and GRunRsltComp ?
147
{
148
auto& nh = proto.out_nhs.at(index);
149
const Data &d = m_gm.metadata(nh).get<Data>();
150
if (d.shape == GShape::GMAT)
151
{
152
using cv::util::get;
153
const auto desc = get<cv::GMatDesc>(d.meta);
154
const auto type = CV_MAKETYPE(desc.depth, desc.chan);
155
156
#if !defined(GAPI_STANDALONE)
157
// Building as part of OpenCV - follow OpenCV behavior
158
// if output buffer is not enough to hold the result, reallocate it
159
auto& out_mat = *get<cv::Mat*>(args.outObjs.at(index));
160
out_mat.create(cv::gapi::own::to_ocv(desc.size), type);
161
#else
162
// Building standalone - output buffer should always exist,
163
// and _exact_ match our inferred metadata
164
auto& out_mat = *get<cv::gapi::own::Mat*>(args.outObjs.at(index));
165
GAPI_Assert( out_mat.type() == type
166
&& out_mat.data != nullptr
167
&& out_mat.rows == desc.size.height
168
&& out_mat.cols == desc.size.width)
169
#endif // !defined(GAPI_STANDALONE)
170
}
171
}
172
// Update storage with user-passed objects
173
for (auto it : ade::util::zip(ade::util::toRange(proto.inputs),
174
ade::util::toRange(args.inObjs)))
175
{
176
magazine::bindInArg(m_res, std::get<0>(it), std::get<1>(it));
177
}
178
for (auto it : ade::util::zip(ade::util::toRange(proto.outputs),
179
ade::util::toRange(args.outObjs)))
180
{
181
magazine::bindOutArg(m_res, std::get<0>(it), std::get<1>(it));
182
}
183
184
// Reset internal data
185
for (auto &sd : m_slots)
186
{
187
const auto& data = m_gm.metadata(sd.data_nh).get<Data>();
188
magazine::resetInternalData(m_res, data);
189
}
190
191
// Run the script
192
for (auto &op : m_ops)
193
{
194
// (5)
195
using InObj = GIslandExecutable::InObj;
196
using OutObj = GIslandExecutable::OutObj;
197
std::vector<InObj> in_objs;
198
std::vector<OutObj> out_objs;
199
in_objs.reserve (op.in_objects.size());
200
out_objs.reserve(op.out_objects.size());
201
202
for (const auto &rc : op.in_objects)
203
{
204
in_objs.emplace_back(InObj{rc, magazine::getArg(m_res, rc)});
205
}
206
for (const auto &rc : op.out_objects)
207
{
208
out_objs.emplace_back(OutObj{rc, magazine::getObjPtr(m_res, rc)});
209
}
210
211
// (6)
212
op.isl_exec->run(std::move(in_objs), std::move(out_objs));
213
}
214
215
// (7)
216
for (auto it : ade::util::zip(ade::util::toRange(proto.outputs),
217
ade::util::toRange(args.outObjs)))
218
{
219
magazine::writeBack(m_res, std::get<0>(it), std::get<1>(it));
220
}
221
}
222
223
const cv::gimpl::GModel::Graph& cv::gimpl::GExecutor::model() const
224
{
225
return m_gm;
226
}
227
228