Path: blob/master/modules/gapi/src/backends/cpu/gcpubackend.cpp
16344 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 <functional>10#include <unordered_set>1112#include <ade/util/algorithm.hpp>1314#include <ade/util/range.hpp>15#include <ade/util/zip_range.hpp>16#include <ade/util/chain_range.hpp>1718#include <ade/typed_graph.hpp>1920#include "opencv2/gapi/gcommon.hpp"21#include "opencv2/gapi/util/any.hpp"22#include "opencv2/gapi/gtype_traits.hpp"2324#include "compiler/gobjref.hpp"25#include "compiler/gmodel.hpp"2627#include "backends/cpu/gcpubackend.hpp"28#include "backends/cpu/gcpuimgproc.hpp"29#include "backends/cpu/gcpucore.hpp"3031#include "api/gbackend_priv.hpp" // FIXME: Make it part of Backend SDK!3233// FIXME: Is there a way to take a typed graph (our GModel),34// and create a new typed graph _ATOP_ of that (by extending with a couple of35// new types?).36// Alternatively, is there a way to compose types graphs?37//38// If not, we need to introduce that!39using GCPUModel = ade::TypedGraph40< cv::gimpl::Unit41, cv::gimpl::Protocol42>;4344// FIXME: Same issue with Typed and ConstTyped45using GConstGCPUModel = ade::ConstTypedGraph46< cv::gimpl::Unit47, cv::gimpl::Protocol48>;4950namespace51{52class GCPUBackendImpl final: public cv::gapi::GBackend::Priv53{54virtual void unpackKernel(ade::Graph &graph,55const ade::NodeHandle &op_node,56const cv::GKernelImpl &impl) override57{58GCPUModel gm(graph);59auto cpu_impl = cv::util::any_cast<cv::GCPUKernel>(impl.opaque);60gm.metadata(op_node).set(cv::gimpl::Unit{cpu_impl});61}6263virtual EPtr compile(const ade::Graph &graph,64const cv::GCompileArgs &,65const std::vector<ade::NodeHandle> &nodes) const override66{67return EPtr{new cv::gimpl::GCPUExecutable(graph, nodes)};68}69};70}7172cv::gapi::GBackend cv::gapi::cpu::backend()73{74static cv::gapi::GBackend this_backend(std::make_shared<GCPUBackendImpl>());75return this_backend;76}7778// GCPUExcecutable implementation //////////////////////////////////////////////79cv::gimpl::GCPUExecutable::GCPUExecutable(const ade::Graph &g,80const std::vector<ade::NodeHandle> &nodes)81: m_g(g), m_gm(m_g)82{83// Convert list of operations (which is topologically sorted already)84// into an execution script.85for (auto &nh : nodes)86{87switch (m_gm.metadata(nh).get<NodeType>().t)88{89case NodeType::OP: m_script.push_back({nh, GModel::collectOutputMeta(m_gm, nh)}); break;90case NodeType::DATA:91{92m_dataNodes.push_back(nh);93const auto &desc = m_gm.metadata(nh).get<Data>();94if (desc.storage == Data::Storage::CONST)95{96auto rc = RcDesc{desc.rc, desc.shape, desc.ctor};97magazine::bindInArg(m_res, rc, m_gm.metadata(nh).get<ConstValue>().arg);98}99//preallocate internal Mats in advance100if (desc.storage == Data::Storage::INTERNAL && desc.shape == GShape::GMAT)101{102const auto mat_desc = util::get<cv::GMatDesc>(desc.meta);103const auto type = CV_MAKETYPE(mat_desc.depth, mat_desc.chan);104m_res.slot<cv::gapi::own::Mat>()[desc.rc].create(mat_desc.size, type);105}106break;107}108default: util::throw_error(std::logic_error("Unsupported NodeType type"));109}110}111}112113// FIXME: Document what it does114cv::GArg cv::gimpl::GCPUExecutable::packArg(const GArg &arg)115{116// No API placeholders allowed at this point117// FIXME: this check has to be done somewhere in compilation stage.118GAPI_Assert( arg.kind != cv::detail::ArgKind::GMAT119&& arg.kind != cv::detail::ArgKind::GSCALAR120&& arg.kind != cv::detail::ArgKind::GARRAY);121122if (arg.kind != cv::detail::ArgKind::GOBJREF)123{124// All other cases - pass as-is, with no transformations to GArg contents.125return arg;126}127GAPI_Assert(arg.kind == cv::detail::ArgKind::GOBJREF);128129// Wrap associated CPU object (either host or an internal one)130// FIXME: object can be moved out!!! GExecutor faced that.131const cv::gimpl::RcDesc &ref = arg.get<cv::gimpl::RcDesc>();132switch (ref.shape)133{134case GShape::GMAT: return GArg(m_res.slot<cv::gapi::own::Mat>() [ref.id]);135case GShape::GSCALAR: return GArg(m_res.slot<cv::gapi::own::Scalar>()[ref.id]);136// Note: .at() is intentional for GArray as object MUST be already there137// (and constructed by either bindIn/Out or resetInternal)138case GShape::GARRAY: return GArg(m_res.slot<cv::detail::VectorRef>().at(ref.id));139default:140util::throw_error(std::logic_error("Unsupported GShape type"));141break;142}143}144145void cv::gimpl::GCPUExecutable::run(std::vector<InObj> &&input_objs,146std::vector<OutObj> &&output_objs)147{148// Update resources with run-time information - what this Island149// has received from user (or from another Island, or mix...)150// FIXME: Check input/output objects against GIsland protocol151152for (auto& it : input_objs) magazine::bindInArg (m_res, it.first, it.second);153for (auto& it : output_objs) magazine::bindOutArg(m_res, it.first, it.second);154155// Initialize (reset) internal data nodes with user structures156// before processing a frame (no need to do it for external data structures)157GModel::ConstGraph gm(m_g);158for (auto nh : m_dataNodes)159{160const auto &desc = gm.metadata(nh).get<Data>();161162if ( desc.storage == Data::Storage::INTERNAL163&& !util::holds_alternative<util::monostate>(desc.ctor))164{165// FIXME: Note that compile-time constant data objects (like166// a value-initialized GArray<T>) also satisfy this condition167// and should be excluded, but now we just don't support it168magazine::resetInternalData(m_res, desc);169}170}171172// OpenCV backend execution is not a rocket science at all.173// Simply invoke our kernels in the proper order.174GConstGCPUModel gcm(m_g);175for (auto &op_info : m_script)176{177const auto &op = m_gm.metadata(op_info.nh).get<Op>();178179// Obtain our real execution unit180// TODO: Should kernels be copyable?181GCPUKernel k = gcm.metadata(op_info.nh).get<Unit>().k;182183// Initialize kernel's execution context:184// - Input parameters185GCPUContext context;186context.m_args.reserve(op.args.size());187188using namespace std::placeholders;189ade::util::transform(op.args,190std::back_inserter(context.m_args),191std::bind(&GCPUExecutable::packArg, this, _1));192193// - Output parameters.194// FIXME: pre-allocate internal Mats, etc, according to the known meta195for (const auto &out_it : ade::util::indexed(op.outs))196{197// FIXME: Can the same GArg type resolution mechanism be reused here?198const auto out_port = ade::util::index(out_it);199const auto out_desc = ade::util::value(out_it);200context.m_results[out_port] = magazine::getObjPtr(m_res, out_desc);201}202203// Now trigger the executable unit204k.apply(context);205206//As Kernels are forbidden to allocate memory for (Mat) outputs,207//this code seems redundant, at least for Mats208//FIXME: unify with cv::detail::ensure_out_mats_not_reallocated209for (const auto &out_it : ade::util::indexed(op_info.expected_out_metas))210{211const auto out_index = ade::util::index(out_it);212const auto expected_meta = ade::util::value(out_it);213const auto out_meta = descr_of(context.m_results[out_index]);214215if (expected_meta != out_meta)216{217util::throw_error218(std::logic_error219("Output meta doesn't "220"coincide with the generated meta\n"221"Expected: " + ade::util::to_string(expected_meta) + "\n"222"Actual : " + ade::util::to_string(out_meta)));223}224}225} // for(m_script)226227for (auto &it : output_objs) magazine::writeBack(m_res, it.first, it.second);228}229230231