Path: blob/master/modules/gapi/src/compiler/passes/kernels.cpp
16354 views
// This file is part of OpenCV project.1// It is subject to the license terms in the LICENSE file found in the top-level directory2// of this distribution and at http://opencv.org/license.html.3//4// Copyright (C) 2018 Intel Corporation567#include "precomp.hpp"89#include <ade/util/zip_range.hpp> // util::indexed10#include <ade/graph.hpp>11#include <ade/passes/check_cycles.hpp>1213#include "opencv2/gapi/gcompoundkernel.hpp" // compound::backend()1415#include "compiler/gmodel.hpp"16#include "compiler/passes/passes.hpp"1718#include "api/gbackend_priv.hpp"19#include "backends/common/gbackend.hpp"20#include "compiler/gmodelbuilder.hpp"21#include "logger.hpp" // GAPI_LOG2223namespace24{25struct ImplInfo26{27cv::GKernelImpl impl;28cv::GArgs in_args;29};3031// Generaly the algorithm is following32//33// 1. Get GCompoundKernel implementation34// 2. Create GCompoundContext35// 3. Run GCompoundKernel with GCompoundContext36// 4. Build subgraph from imputs/outputs GCompoundKernel37// 5. Replace compound node to subgraph3839void expand(ade::Graph& g, ade::NodeHandle nh, const ImplInfo& impl_info)40{41cv::gimpl::GModel::Graph gr(g);42auto compound_impl = cv::util::any_cast<cv::detail::GCompoundKernel>(impl_info.impl.opaque);4344// GCompoundContext instantiates its own objects45// in accordance with the RcDescs from in_args46cv::detail::GCompoundContext context(impl_info.in_args);47compound_impl.apply(context);4849cv::GProtoArgs ins, outs;50ins.reserve(context.m_args.size());51outs.reserve(context.m_results.size());5253// Inputs can be non-dynamic types.54// Such inputs are not used when building a graph55for (const auto& arg : context.m_args)56{57if (cv::gimpl::proto::is_dynamic(arg))58{59ins.emplace_back(cv::gimpl::proto::rewrap(arg));60}61}6263ade::util::transform(context.m_results, std::back_inserter(outs), &cv::gimpl::proto::rewrap);6465cv::gimpl::GModelBuilder builder(g);6667// Build the subgraph graph which will need to replace the compound node68const auto& proto_slots = builder.put(ins, outs);6970const auto& in_nhs = std::get<2>(proto_slots);71const auto& out_nhs = std::get<3>(proto_slots);7273auto sorted_in_nhs = cv::gimpl::GModel::orderedInputs(gr, nh);74auto sorted_out_nhs = cv::gimpl::GModel::orderedOutputs(gr, nh);7576// Reconnect expanded kernels from graph data objects77// to subgraph data objects, then drop that graph data objects78for (const auto& it : ade::util::zip(in_nhs, sorted_in_nhs))79{80const auto& subgr_in_nh = std::get<0>(it);81const auto& comp_in_nh = std::get<1>(it);8283cv::gimpl::GModel::redirectReaders(gr, subgr_in_nh, comp_in_nh);84gr.erase(subgr_in_nh);85}8687gr.erase(nh);8889for (const auto& it : ade::util::zip(out_nhs, sorted_out_nhs))90{91const auto& subgr_out_nh = std::get<0>(it);92const auto& comp_out_nh = std::get<1>(it);9394cv::gimpl::GModel::redirectWriter(gr, subgr_out_nh, comp_out_nh);95gr.erase(subgr_out_nh);96}97}98}99// This pass, given the kernel package, selects a kernel implementation100// for every operation in the graph101void cv::gimpl::passes::resolveKernels(ade::passes::PassContext &ctx,102const gapi::GKernelPackage &kernels,103const gapi::GLookupOrder &order)104{105std::unordered_set<cv::gapi::GBackend> active_backends;106107GModel::Graph gr(ctx.graph);108for (const auto &nh : gr.nodes())109{110if (gr.metadata(nh).get<NodeType>().t == NodeType::OP)111{112auto &op = gr.metadata(nh).get<Op>();113cv::gapi::GBackend selected_backend;114cv::GKernelImpl selected_impl;115std::tie(selected_backend, selected_impl)116= kernels.lookup(op.k.name, order);117118selected_backend.priv().unpackKernel(ctx.graph, nh, selected_impl);119op.backend = selected_backend;120active_backends.insert(selected_backend);121}122}123gr.metadata().set(ActiveBackends{active_backends});124}125126void cv::gimpl::passes::expandKernels(ade::passes::PassContext &ctx, const gapi::GKernelPackage &kernels)127{128GModel::Graph gr(ctx.graph);129130// Repeat the loop while there are compound kernels.131// Restart procedure after every successfull unrolling132bool has_compound_kernel = true;133while (has_compound_kernel)134{135has_compound_kernel = false;136for (const auto& nh : gr.nodes())137{138if (gr.metadata(nh).get<NodeType>().t == NodeType::OP)139{140const auto& op = gr.metadata(nh).get<Op>();141142cv::gapi::GBackend selected_backend;143cv::GKernelImpl selected_impl;144std::tie(selected_backend, selected_impl) = kernels.lookup(op.k.name);145146if (selected_backend == cv::gapi::compound::backend())147{148has_compound_kernel = true;149expand(ctx.graph, nh, ImplInfo{selected_impl, op.args});150break;151}152}153}154}155GAPI_LOG_INFO(NULL, "Final graph: " << ctx.graph.nodes().size() << " nodes" << std::endl);156}157158159