// This file is part of OpenCV project. // It is subject to the license terms in the LICENSE file found in the top-level directory // of this distribution and at http://opencv.org/license.html. // // Copyright (C) 2018-2020 Intel Corporation #include "precomp.hpp" #include // unique_ptr #include // multiplies #include #include "api/gbackend_priv.hpp" #include "backends/common/gbackend.hpp" #include "compiler/gobjref.hpp" #include "compiler/gislandmodel.hpp" // GBackend private implementation ///////////////////////////////////////////// void cv::gapi::GBackend::Priv::unpackKernel(ade::Graph & /*graph */ , const ade::NodeHandle & /*op_node*/ , const GKernelImpl & /*impl */ ) { // Default implementation is still there as Priv // is instantiated by some tests. // Priv is even instantiated as a mock object in a number of tests // as a backend and this method is called for mock objects (doing nothing). // FIXME: add a warning message here // FIXME: Do something with this! Ideally this function should be "=0"; } std::unique_ptr cv::gapi::GBackend::Priv::compile(const ade::Graph&, const GCompileArgs&, const std::vector &) const { // ...and this method is here for the same reason! GAPI_Assert(false); return {}; } std::unique_ptr cv::gapi::GBackend::Priv::compile(const ade::Graph& graph, const GCompileArgs& args, const std::vector& nodes, const std::vector&, const std::vector&) const { return compile(graph, args, nodes); } void cv::gapi::GBackend::Priv::addBackendPasses(ade::ExecutionEngineSetupContext &) { // Do nothing by default, plugins may override this to // add custom (backend-specific) graph transformations } void cv::gapi::GBackend::Priv::addMetaSensitiveBackendPasses(ade::ExecutionEngineSetupContext &) { // Do nothing by default, plugins may override this to // add custom (backend-specific) graph transformations // which are sensitive to metadata } cv::gapi::GKernelPackage cv::gapi::GBackend::Priv::auxiliaryKernels() const { return {}; } // GBackend public implementation ////////////////////////////////////////////// cv::gapi::GBackend::GBackend() { } cv::gapi::GBackend::GBackend(std::shared_ptr &&p) : m_priv(std::move(p)) { } cv::gapi::GBackend::Priv& cv::gapi::GBackend::priv() { return *m_priv; } const cv::gapi::GBackend::Priv& cv::gapi::GBackend::priv() const { return *m_priv; } std::size_t cv::gapi::GBackend::hash() const { return std::hash{}(m_priv.get()); } bool cv::gapi::GBackend::operator== (const cv::gapi::GBackend &rhs) const { return m_priv == rhs.m_priv; } // Abstract Host-side data manipulation //////////////////////////////////////// // Reused between CPU backend and more generic GExecutor namespace cv { namespace gimpl { namespace magazine { namespace { // Utility function, used in both bindInArg and bindOutArg, // implements default RMat bind behaviour (if backend doesn't handle RMats in specific way): // view + wrapped cv::Mat are placed into the magazine void bindRMat(Mag& mag, const RcDesc& rc, const cv::RMat& rmat, RMat::Access a) { auto& matv = mag.template slot()[rc.id]; matv = rmat.access(a); mag.template slot()[rc.id] = asMat(matv); } } // anonymous namespace // FIXME implement the below functions with visit()? void bindInArg(Mag& mag, const RcDesc &rc, const GRunArg &arg, HandleRMat handleRMat) { switch (rc.shape) { case GShape::GMAT: { // In case of handleRMat == SKIP // We assume that backend can work with some device-specific RMats // and will handle them in some specific way, so just return if (handleRMat == HandleRMat::SKIP) return; GAPI_Assert(arg.index() == GRunArg::index_of()); bindRMat(mag, rc, util::get(arg), RMat::Access::R); break; } case GShape::GSCALAR: { auto& mag_scalar = mag.template slot()[rc.id]; switch (arg.index()) { case GRunArg::index_of() : mag_scalar = util::get(arg); break; default: util::throw_error(std::logic_error("content type of the runtime argument does not match to resource description ?")); } break; } case GShape::GARRAY: mag.template slot()[rc.id] = util::get(arg); break; case GShape::GOPAQUE: mag.template slot()[rc.id] = util::get(arg); break; default: util::throw_error(std::logic_error("Unsupported GShape type")); } } void bindOutArg(Mag& mag, const RcDesc &rc, const GRunArgP &arg, HandleRMat handleRMat) { switch (rc.shape) { case GShape::GMAT: { // In case of handleRMat == SKIP // We assume that backend can work with some device-specific RMats // and will handle them in some specific way, so just return if (handleRMat == HandleRMat::SKIP) return; GAPI_Assert(arg.index() == GRunArgP::index_of()); bindRMat(mag, rc, *util::get(arg), RMat::Access::W); break; } case GShape::GSCALAR: { auto& mag_scalar = mag.template slot()[rc.id]; switch (arg.index()) { case GRunArgP::index_of() : mag_scalar = *util::get(arg); break; default: util::throw_error(std::logic_error("content type of the runtime argument does not match to resource description ?")); } break; } case GShape::GARRAY: mag.template slot()[rc.id] = util::get(arg); break; case GShape::GOPAQUE: mag.template slot()[rc.id] = util::get(arg); break; default: util::throw_error(std::logic_error("Unsupported GShape type")); break; } } void resetInternalData(Mag& mag, const Data &d) { if (d.storage != Data::Storage::INTERNAL) return; switch (d.shape) { case GShape::GARRAY: util::get(d.ctor) (mag.template slot()[d.rc]); break; case GShape::GOPAQUE: util::get(d.ctor) (mag.template slot()[d.rc]); break; case GShape::GSCALAR: mag.template slot()[d.rc] = cv::Scalar(); break; case GShape::GMAT: // Do nothing here - FIXME unify with initInternalData? break; default: util::throw_error(std::logic_error("Unsupported GShape type")); break; } } cv::GRunArg getArg(const Mag& mag, const RcDesc &ref) { // Wrap associated CPU object (either host or an internal one) switch (ref.shape) { case GShape::GMAT: return GRunArg(mag.template slot().at(ref.id)); case GShape::GSCALAR: return GRunArg(mag.template slot().at(ref.id)); // Note: .at() is intentional for GArray and GOpaque as objects MUST be already there // (and constructed by either bindIn/Out or resetInternal) case GShape::GARRAY: return GRunArg(mag.template slot().at(ref.id)); case GShape::GOPAQUE: return GRunArg(mag.template slot().at(ref.id)); default: util::throw_error(std::logic_error("Unsupported GShape type")); break; } } cv::GRunArgP getObjPtr(Mag& mag, const RcDesc &rc, bool is_umat) { switch (rc.shape) { case GShape::GMAT: if (is_umat) { #if !defined(GAPI_STANDALONE) return GRunArgP(&mag.template slot()[rc.id]); #else util::throw_error(std::logic_error("UMat is not supported in standalone build")); #endif // !defined(GAPI_STANDALONE) } else return GRunArgP(&mag.template slot()[rc.id]); case GShape::GSCALAR: return GRunArgP(&mag.template slot()[rc.id]); // Note: .at() is intentional for GArray and GOpaque as objects MUST be already there // (and constructor by either bindIn/Out or resetInternal) case GShape::GARRAY: // FIXME(DM): For some absolutely unknown to me reason, move // semantics is involved here without const_cast to const (and // value from map is moved into return value GRunArgP, leaving // map with broken value I've spent few late Friday hours // debugging this!!!1 return GRunArgP(const_cast(mag) .template slot().at(rc.id)); case GShape::GOPAQUE: // FIXME(DM): For some absolutely unknown to me reason, move // semantics is involved here without const_cast to const (and // value from map is moved into return value GRunArgP, leaving // map with broken value I've spent few late Friday hours // debugging this!!!1 return GRunArgP(const_cast(mag) .template slot().at(rc.id)); default: util::throw_error(std::logic_error("Unsupported GShape type")); break; } } void writeBack(const Mag& mag, const RcDesc &rc, GRunArgP &g_arg) { switch (rc.shape) { case GShape::GARRAY: case GShape::GMAT: case GShape::GOPAQUE: // Do nothing - should we really do anything here? break; case GShape::GSCALAR: { switch (g_arg.index()) { case GRunArgP::index_of() : *util::get(g_arg) = mag.template slot().at(rc.id); break; default: util::throw_error(std::logic_error("content type of the runtime argument does not match to resource description ?")); } break; } default: util::throw_error(std::logic_error("Unsupported GShape type")); break; } } void unbind(Mag& mag, const RcDesc &rc) { switch (rc.shape) { case GShape::GARRAY: case GShape::GOPAQUE: case GShape::GSCALAR: // TODO: Do nothing - should we really do anything here? break; case GShape::GMAT: // Clean-up everything - a cv::Mat, cv::RMat::View, a cv::UMat, and cv::RMat // if applicable mag.slot().erase(rc.id); #if !defined(GAPI_STANDALONE) mag.slot().erase(rc.id); #endif mag.slot().erase(rc.id); mag.slot().erase(rc.id); break; default: GAPI_Assert(false); } } } // namespace magazine void createMat(const cv::GMatDesc &desc, cv::Mat& mat) { // FIXME: Refactor (probably start supporting N-Dimensional blobs natively if (desc.dims.empty()) { const auto type = desc.planar ? desc.depth : CV_MAKETYPE(desc.depth, desc.chan); const auto size = desc.planar ? cv::Size{desc.size.width, desc.size.height*desc.chan} : desc.size; mat.create(size, type); } else { GAPI_Assert(!desc.planar); mat.create(desc.dims, desc.depth); } } } // namespace gimpl } // namespace cv