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
10 #include <ade/util/zip_range.hpp> // util::indexed
11 #include <ade/graph.hpp>
12 #include <ade/passes/check_cycles.hpp>
14 #include "opencv2/gapi/gcompoundkernel.hpp" // compound::backend()
16 #include "compiler/gmodel.hpp"
17 #include "compiler/passes/passes.hpp"
19 #include "api/gbackend_priv.hpp"
20 #include "backends/common/gbackend.hpp"
21 #include "compiler/gmodelbuilder.hpp"
22 #include "logger.hpp" // GAPI_LOG
32 // Generaly the algorithm is following
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
40 void expand(ade::Graph& g, ade::NodeHandle nh, const ImplInfo& impl_info)
42 cv::gimpl::GModel::Graph gr(g);
43 auto compound_impl = cv::util::any_cast<cv::detail::GCompoundKernel>(impl_info.impl.opaque);
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);
50 cv::GProtoArgs ins, outs;
51 ins.reserve(context.m_args.size());
52 outs.reserve(context.m_results.size());
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)
58 if (cv::gimpl::proto::is_dynamic(arg))
60 ins.emplace_back(cv::gimpl::proto::rewrap(arg));
64 ade::util::transform(context.m_results, std::back_inserter(outs), &cv::gimpl::proto::rewrap);
66 cv::gimpl::GModelBuilder builder(g);
68 // Build the subgraph graph which will need to replace the compound node
69 const auto& proto_slots = builder.put(ins, outs);
71 const auto& in_nhs = std::get<2>(proto_slots);
72 const auto& out_nhs = std::get<3>(proto_slots);
74 auto sorted_in_nhs = cv::gimpl::GModel::orderedInputs(gr, nh);
75 auto sorted_out_nhs = cv::gimpl::GModel::orderedOutputs(gr, nh);
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))
81 const auto& subgr_in_nh = std::get<0>(it);
82 const auto& comp_in_nh = std::get<1>(it);
84 cv::gimpl::GModel::redirectReaders(gr, subgr_in_nh, comp_in_nh);
85 gr.erase(subgr_in_nh);
90 for (const auto& it : ade::util::zip(out_nhs, sorted_out_nhs))
92 const auto& subgr_out_nh = std::get<0>(it);
93 const auto& comp_out_nh = std::get<1>(it);
95 cv::gimpl::GModel::redirectWriter(gr, subgr_out_nh, comp_out_nh);
96 gr.erase(subgr_out_nh);
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)
106 std::unordered_set<cv::gapi::GBackend> active_backends;
108 GModel::Graph gr(ctx.graph);
109 for (const auto &nh : gr.nodes())
111 if (gr.metadata(nh).get<NodeType>().t == NodeType::OP)
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);
119 selected_backend.priv().unpackKernel(ctx.graph, nh, selected_impl);
120 op.backend = selected_backend;
121 active_backends.insert(selected_backend);
124 gr.metadata().set(ActiveBackends{active_backends});
127 void cv::gimpl::passes::expandKernels(ade::passes::PassContext &ctx, const gapi::GKernelPackage &kernels)
129 GModel::Graph gr(ctx.graph);
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)
136 has_compound_kernel = false;
137 for (const auto& nh : gr.nodes())
139 if (gr.metadata(nh).get<NodeType>().t == NodeType::OP)
141 const auto& op = gr.metadata(nh).get<Op>();
143 cv::gapi::GBackend selected_backend;
144 cv::GKernelImpl selected_impl;
145 std::tie(selected_backend, selected_impl) = kernels.lookup(op.k.name);
147 if (selected_backend == cv::gapi::compound::backend())
149 has_compound_kernel = true;
150 expand(ctx.graph, nh, ImplInfo{selected_impl, op.args});
156 GAPI_LOG_INFO(NULL, "Final graph: " << ctx.graph.nodes().size() << " nodes" << std::endl);