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