Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Tetragramm
GitHub Repository: Tetragramm/opencv
Path: blob/master/modules/gapi/src/compiler/passes/kernels.cpp
16354 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 <ade/util/zip_range.hpp> // util::indexed
11
#include <ade/graph.hpp>
12
#include <ade/passes/check_cycles.hpp>
13
14
#include "opencv2/gapi/gcompoundkernel.hpp" // compound::backend()
15
16
#include "compiler/gmodel.hpp"
17
#include "compiler/passes/passes.hpp"
18
19
#include "api/gbackend_priv.hpp"
20
#include "backends/common/gbackend.hpp"
21
#include "compiler/gmodelbuilder.hpp"
22
#include "logger.hpp" // GAPI_LOG
23
24
namespace
25
{
26
struct ImplInfo
27
{
28
cv::GKernelImpl impl;
29
cv::GArgs in_args;
30
};
31
32
// Generaly the algorithm is following
33
//
34
// 1. Get GCompoundKernel implementation
35
// 2. Create GCompoundContext
36
// 3. Run GCompoundKernel with GCompoundContext
37
// 4. Build subgraph from imputs/outputs GCompoundKernel
38
// 5. Replace compound node to subgraph
39
40
void expand(ade::Graph& g, ade::NodeHandle nh, const ImplInfo& impl_info)
41
{
42
cv::gimpl::GModel::Graph gr(g);
43
auto compound_impl = cv::util::any_cast<cv::detail::GCompoundKernel>(impl_info.impl.opaque);
44
45
// GCompoundContext instantiates its own objects
46
// in accordance with the RcDescs from in_args
47
cv::detail::GCompoundContext context(impl_info.in_args);
48
compound_impl.apply(context);
49
50
cv::GProtoArgs ins, outs;
51
ins.reserve(context.m_args.size());
52
outs.reserve(context.m_results.size());
53
54
// Inputs can be non-dynamic types.
55
// Such inputs are not used when building a graph
56
for (const auto& arg : context.m_args)
57
{
58
if (cv::gimpl::proto::is_dynamic(arg))
59
{
60
ins.emplace_back(cv::gimpl::proto::rewrap(arg));
61
}
62
}
63
64
ade::util::transform(context.m_results, std::back_inserter(outs), &cv::gimpl::proto::rewrap);
65
66
cv::gimpl::GModelBuilder builder(g);
67
68
// Build the subgraph graph which will need to replace the compound node
69
const auto& proto_slots = builder.put(ins, outs);
70
71
const auto& in_nhs = std::get<2>(proto_slots);
72
const auto& out_nhs = std::get<3>(proto_slots);
73
74
auto sorted_in_nhs = cv::gimpl::GModel::orderedInputs(gr, nh);
75
auto sorted_out_nhs = cv::gimpl::GModel::orderedOutputs(gr, nh);
76
77
// Reconnect expanded kernels from graph data objects
78
// to subgraph data objects, then drop that graph data objects
79
for (const auto& it : ade::util::zip(in_nhs, sorted_in_nhs))
80
{
81
const auto& subgr_in_nh = std::get<0>(it);
82
const auto& comp_in_nh = std::get<1>(it);
83
84
cv::gimpl::GModel::redirectReaders(gr, subgr_in_nh, comp_in_nh);
85
gr.erase(subgr_in_nh);
86
}
87
88
gr.erase(nh);
89
90
for (const auto& it : ade::util::zip(out_nhs, sorted_out_nhs))
91
{
92
const auto& subgr_out_nh = std::get<0>(it);
93
const auto& comp_out_nh = std::get<1>(it);
94
95
cv::gimpl::GModel::redirectWriter(gr, subgr_out_nh, comp_out_nh);
96
gr.erase(subgr_out_nh);
97
}
98
}
99
}
100
// This pass, given the kernel package, selects a kernel implementation
101
// for every operation in the graph
102
void cv::gimpl::passes::resolveKernels(ade::passes::PassContext &ctx,
103
const gapi::GKernelPackage &kernels,
104
const gapi::GLookupOrder &order)
105
{
106
std::unordered_set<cv::gapi::GBackend> active_backends;
107
108
GModel::Graph gr(ctx.graph);
109
for (const auto &nh : gr.nodes())
110
{
111
if (gr.metadata(nh).get<NodeType>().t == NodeType::OP)
112
{
113
auto &op = gr.metadata(nh).get<Op>();
114
cv::gapi::GBackend selected_backend;
115
cv::GKernelImpl selected_impl;
116
std::tie(selected_backend, selected_impl)
117
= kernels.lookup(op.k.name, order);
118
119
selected_backend.priv().unpackKernel(ctx.graph, nh, selected_impl);
120
op.backend = selected_backend;
121
active_backends.insert(selected_backend);
122
}
123
}
124
gr.metadata().set(ActiveBackends{active_backends});
125
}
126
127
void cv::gimpl::passes::expandKernels(ade::passes::PassContext &ctx, const gapi::GKernelPackage &kernels)
128
{
129
GModel::Graph gr(ctx.graph);
130
131
// Repeat the loop while there are compound kernels.
132
// Restart procedure after every successfull unrolling
133
bool has_compound_kernel = true;
134
while (has_compound_kernel)
135
{
136
has_compound_kernel = false;
137
for (const auto& nh : gr.nodes())
138
{
139
if (gr.metadata(nh).get<NodeType>().t == NodeType::OP)
140
{
141
const auto& op = gr.metadata(nh).get<Op>();
142
143
cv::gapi::GBackend selected_backend;
144
cv::GKernelImpl selected_impl;
145
std::tie(selected_backend, selected_impl) = kernels.lookup(op.k.name);
146
147
if (selected_backend == cv::gapi::compound::backend())
148
{
149
has_compound_kernel = true;
150
expand(ctx.graph, nh, ImplInfo{selected_impl, op.args});
151
break;
152
}
153
}
154
}
155
}
156
GAPI_LOG_INFO(NULL, "Final graph: " << ctx.graph.nodes().size() << " nodes" << std::endl);
157
}
158
159