diff --git a/modules/gapi/CMakeLists.txt b/modules/gapi/CMakeLists.txt index 1fb6d38420..1f14b2a611 100644 --- a/modules/gapi/CMakeLists.txt +++ b/modules/gapi/CMakeLists.txt @@ -44,6 +44,7 @@ set(gapi_srcs src/api/gorigin.cpp src/api/gmat.cpp src/api/garray.cpp + src/api/gopaque.cpp src/api/gscalar.cpp src/api/gkernel.cpp src/api/gbackend.cpp diff --git a/modules/gapi/include/opencv2/gapi/cpu/gcpukernel.hpp b/modules/gapi/include/opencv2/gapi/cpu/gcpukernel.hpp index 85a90ce797..e9c6e2618c 100644 --- a/modules/gapi/include/opencv2/gapi/cpu/gcpukernel.hpp +++ b/modules/gapi/include/opencv2/gapi/cpu/gcpukernel.hpp @@ -94,9 +94,14 @@ public: { return outVecRef(output).wref(); } + template T& outOpaqueR(int output) // FIXME: the same issue + { + return outOpaqueRef(output).wref(); + } protected: detail::VectorRef& outVecRef(int output); + detail::OpaqueRef& outOpaqueRef(int output); std::vector m_args; @@ -145,12 +150,31 @@ template struct get_in > { static const std::vector& get(GCPUContext &ctx, int idx) { return ctx.inArg(idx).rref(); } }; +template struct get_in > +{ + static const U& get(GCPUContext &ctx, int idx) { return ctx.inArg(idx).rref(); } +}; //FIXME(dm): GArray/GArray conversion should be done more gracefully in the system template<> struct get_in >: public get_in > { }; +//FIXME(dm): GArray/GArray conversion should be done more gracefully in the system +template<> struct get_in >: public get_in > +{ +}; + +//FIXME(dm): GOpaque/GOpaque conversion should be done more gracefully in the system +template<> struct get_in >: public get_in > +{ +}; + +//FIXME(dm): GOpaque/GOpaque conversion should be done more gracefully in the system +template<> struct get_in >: public get_in > +{ +}; + template struct get_in { static T get(GCPUContext &ctx, int idx) { return ctx.inArg(idx); } @@ -229,6 +253,13 @@ template struct get_out> return ctx.outVecR(idx); } }; +template struct get_out> +{ + static U& get(GCPUContext &ctx, int idx) + { + return ctx.outOpaqueR(idx); + } +}; template struct OCVCallHelper; diff --git a/modules/gapi/include/opencv2/gapi/fluid/gfluidkernel.hpp b/modules/gapi/include/opencv2/gapi/fluid/gfluidkernel.hpp index 3f7a0f811c..4d2e4a6525 100644 --- a/modules/gapi/include/opencv2/gapi/fluid/gfluidkernel.hpp +++ b/modules/gapi/include/opencv2/gapi/fluid/gfluidkernel.hpp @@ -200,6 +200,14 @@ template struct fluid_get_in> } }; +template struct fluid_get_in> +{ + static const U& get(const cv::GArgs &in_args, int idx) + { + return in_args.at(idx).unsafe_get().rref(); + } +}; + template struct fluid_get_in { static const T& get(const cv::GArgs &in_args, int idx) diff --git a/modules/gapi/include/opencv2/gapi/garg.hpp b/modules/gapi/include/opencv2/gapi/garg.hpp index 9b835d9567..7228ac6daf 100644 --- a/modules/gapi/include/opencv2/gapi/garg.hpp +++ b/modules/gapi/include/opencv2/gapi/garg.hpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -96,7 +97,8 @@ using GRunArg = util::variant< cv::gapi::wip::IStreamSource::Ptr, cv::gapi::own::Mat, cv::gapi::own::Scalar, - cv::detail::VectorRef + cv::detail::VectorRef, + cv::detail::OpaqueRef >; using GRunArgs = std::vector; @@ -128,7 +130,8 @@ using GRunArgP = util::variant< #endif // !defined(GAPI_STANDALONE) cv::gapi::own::Mat*, cv::gapi::own::Scalar*, - cv::detail::VectorRef + cv::detail::VectorRef, + cv::detail::OpaqueRef >; using GRunArgsP = std::vector; diff --git a/modules/gapi/include/opencv2/gapi/gcall.hpp b/modules/gapi/include/opencv2/gapi/gcall.hpp index 87cba52971..ed5ba5fde8 100644 --- a/modules/gapi/include/opencv2/gapi/gcall.hpp +++ b/modules/gapi/include/opencv2/gapi/gcall.hpp @@ -12,6 +12,7 @@ #include // GMat #include // GScalar #include // GArray +#include // GOpaque namespace cv { @@ -46,6 +47,11 @@ public: return GArray(yieldArray(output)); } + template GOpaque yieldOpaque(int output = 0) + { + return GOpaque(yieldOpaque(output)); + } + // Internal use only Priv& priv(); const Priv& priv() const; @@ -55,8 +61,9 @@ protected: void setArgs(std::vector &&args); - // Public version returns a typed array, this one is implementation detail + // Public versions return a typed array or opaque, those are implementation details detail::GArrayU yieldArray(int output = 0); + detail::GOpaqueU yieldOpaque(int output = 0); }; } // namespace cv diff --git a/modules/gapi/include/opencv2/gapi/gcommon.hpp b/modules/gapi/include/opencv2/gapi/gcommon.hpp index 40c6d36af0..9ee75f7dec 100644 --- a/modules/gapi/include/opencv2/gapi/gcommon.hpp +++ b/modules/gapi/include/opencv2/gapi/gcommon.hpp @@ -44,6 +44,7 @@ enum class GShape: int GMAT, GSCALAR, GARRAY, + GOPAQUE, }; struct GCompileArg; diff --git a/modules/gapi/include/opencv2/gapi/gcompoundkernel.hpp b/modules/gapi/include/opencv2/gapi/gcompoundkernel.hpp index 84b8780251..2f17064bbf 100644 --- a/modules/gapi/include/opencv2/gapi/gcompoundkernel.hpp +++ b/modules/gapi/include/opencv2/gapi/gcompoundkernel.hpp @@ -65,6 +65,16 @@ template struct get_compound_in> } }; +template struct get_compound_in> +{ + static cv::GOpaque get(GCompoundContext &ctx, int idx) + { + auto opaq = cv::GOpaque(); + ctx.m_args[idx] = GArg(opaq); + return opaq; + } +}; + template struct GCompoundCallHelper; diff --git a/modules/gapi/include/opencv2/gapi/gkernel.hpp b/modules/gapi/include/opencv2/gapi/gkernel.hpp index 91f57318ff..b7ff883c66 100644 --- a/modules/gapi/include/opencv2/gapi/gkernel.hpp +++ b/modules/gapi/include/opencv2/gapi/gkernel.hpp @@ -74,6 +74,10 @@ namespace detail { static inline cv::GArray yield(cv::GCall &call, int i) { return call.yieldArray(i); } }; + template struct Yield > + { + static inline cv::GOpaque yield(cv::GCall &call, int i) { return call.yieldOpaque(i); } + }; } // anonymous namespace //////////////////////////////////////////////////////////////////////////// @@ -87,7 +91,8 @@ namespace detail template<> struct MetaType { using type = GMatDesc; }; template<> struct MetaType { using type = GMatDesc; }; template<> struct MetaType { using type = GScalarDesc; }; - template struct MetaType > { using type = GArrayDesc; }; + template struct MetaType > { using type = GArrayDesc; }; + template struct MetaType > { using type = GOpaqueDesc; }; template struct MetaType { using type = T; }; // opaque args passed as-is // 2. Hacky test based on MetaType to check if we operate on G-* type or not diff --git a/modules/gapi/include/opencv2/gapi/gmat.hpp b/modules/gapi/include/opencv2/gapi/gmat.hpp index 4f67126a90..d05d151698 100644 --- a/modules/gapi/include/opencv2/gapi/gmat.hpp +++ b/modules/gapi/include/opencv2/gapi/gmat.hpp @@ -46,6 +46,7 @@ struct GOrigin; * cv::GMat | cv::Mat * cv::GScalar | cv::Scalar * `cv::GArray` | std::vector + * `cv::GOpaque` | T */ class GAPI_EXPORTS GMat { diff --git a/modules/gapi/include/opencv2/gapi/gmetaarg.hpp b/modules/gapi/include/opencv2/gapi/gmetaarg.hpp index 0bd6767b7e..39f087f806 100644 --- a/modules/gapi/include/opencv2/gapi/gmetaarg.hpp +++ b/modules/gapi/include/opencv2/gapi/gmetaarg.hpp @@ -17,6 +17,7 @@ #include #include #include +#include namespace cv { @@ -36,6 +37,7 @@ using GMetaArg = util::variant , GMatDesc , GScalarDesc , GArrayDesc + , GOpaqueDesc >; GAPI_EXPORTS std::ostream& operator<<(std::ostream& os, const GMetaArg &); @@ -52,6 +54,7 @@ namespace detail template<> struct is_meta_descr : std::true_type {}; template<> struct is_meta_descr : std::true_type {}; template<> struct is_meta_descr : std::true_type {}; + template<> struct is_meta_descr : std::true_type {}; template using are_meta_descrs = all_satisfy; diff --git a/modules/gapi/include/opencv2/gapi/gopaque.hpp b/modules/gapi/include/opencv2/gapi/gopaque.hpp new file mode 100644 index 0000000000..a8b0c595e1 --- /dev/null +++ b/modules/gapi/include/opencv2/gapi/gopaque.hpp @@ -0,0 +1,289 @@ +// 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) 2019 Intel Corporation + + +#ifndef OPENCV_GAPI_GOPAQUE_HPP +#define OPENCV_GAPI_GOPAQUE_HPP + +#include +#include +#include + +#include +#include + +#include +#include +#include + +namespace cv +{ +// Forward declaration; GNode and GOrigin are an internal +// (user-inaccessible) classes. +class GNode; +struct GOrigin; + +template class GOpaque; + +/** + * \addtogroup gapi_meta_args + * @{ + */ +struct GOpaqueDesc +{ + // FIXME: Body + // FIXME: Also implement proper operator== then + bool operator== (const GOpaqueDesc&) const { return true; } +}; +template GOpaqueDesc descr_of(const U &) { return {};} +static inline GOpaqueDesc empty_gopaque_desc() {return {}; } +/** @} */ + +std::ostream& operator<<(std::ostream& os, const cv::GOpaqueDesc &desc); + +namespace detail +{ + // ConstructOpaque is a callback which stores information about T and is used by + // G-API runtime to construct an object in host memory (T remains opaque for G-API). + // ConstructOpaque is carried into G-API internals by GOpaqueU. + // Currently it is suitable for Host (CPU) plugins only, real offload may require + // more information for manual memory allocation on-device. + class OpaqueRef; + using ConstructOpaque = std::function; + + // FIXME: garray.hpp already contains hint classes (for actual T type verification), + // need to think where it can be moved (currently opaque uses it from garray) + + // This class strips type information from GOpaque and makes it usable + // in the G-API graph compiler (expression unrolling, graph generation, etc). + // Part of GProtoArg. + class GAPI_EXPORTS GOpaqueU + { + public: + GOpaqueU(const GNode &n, std::size_t out); // Operation result constructor + + template + bool holds() const; // Check if was created from GOpaque + + GOrigin& priv(); // Internal use only + const GOrigin& priv() const; // Internal use only + + protected: + GOpaqueU(); // Default constructor + template friend class cv::GOpaque; // (available for GOpaque only) + + void setConstructFcn(ConstructOpaque &&cv); // Store T-aware constructor + + template + void specifyType(); // Store type of initial GOpaque + + std::shared_ptr m_priv; + std::shared_ptr m_hint; + }; + + template + bool GOpaqueU::holds() const{ + GAPI_Assert(m_hint != nullptr); + using U = typename std::decay::type; + return dynamic_cast*>(m_hint.get()) != nullptr; + }; + + template + void GOpaqueU::specifyType(){ + m_hint.reset(new TypeHint::type>); + }; + + // This class represents a typed object reference. + // Depending on origins, this reference may be either "just a" reference to + // an object created externally, OR actually own the underlying object + // (be value holder). + class BasicOpaqueRef + { + public: + cv::GOpaqueDesc m_desc; + virtual ~BasicOpaqueRef() {} + + virtual void mov(BasicOpaqueRef &ref) = 0; + }; + + template class OpaqueRefT final: public BasicOpaqueRef + { + using empty_t = util::monostate; + using ro_ext_t = const T *; + using rw_ext_t = T *; + using rw_own_t = T ; + util::variant m_ref; + + inline bool isEmpty() const { return util::holds_alternative(m_ref); } + inline bool isROExt() const { return util::holds_alternative(m_ref); } + inline bool isRWExt() const { return util::holds_alternative(m_ref); } + inline bool isRWOwn() const { return util::holds_alternative(m_ref); } + + void init(const T* obj = nullptr) + { + if (obj) m_desc = cv::descr_of(*obj); + } + + public: + OpaqueRefT() { init(); } + virtual ~OpaqueRefT() {} + + explicit OpaqueRefT(const T& obj) : m_ref(&obj) { init(&obj); } + explicit OpaqueRefT( T& obj) : m_ref(&obj) { init(&obj); } + explicit OpaqueRefT( T&& obj) : m_ref(std::move(obj)) { init(&obj); } + + // Reset a OpaqueRefT. Called only for objects instantiated + // internally in G-API (e.g. temporary GOpaque's within a + // computation). Reset here means both initialization + // (creating an object) and reset (discarding its existing + // content before the next execution). Must never be called + // for external OpaqueRefTs. + void reset() + { + if (isEmpty()) + { + T empty_obj{}; + m_desc = cv::descr_of(empty_obj); + m_ref = std::move(empty_obj); + GAPI_Assert(isRWOwn()); + } + else if (isRWOwn()) + { + util::get(m_ref) = {}; + } + else GAPI_Assert(false); // shouldn't be called in *EXT modes + } + + // Obtain a WRITE reference to underlying object + // Used by CPU kernel API wrappers when a kernel execution frame + // is created + T& wref() + { + GAPI_Assert(isRWExt() || isRWOwn()); + if (isRWExt()) return *util::get(m_ref); + if (isRWOwn()) return util::get(m_ref); + util::throw_error(std::logic_error("Impossible happened")); + } + + // Obtain a READ reference to underlying object + // Used by CPU kernel API wrappers when a kernel execution frame + // is created + const T& rref() const + { + // ANY object can be accessed for reading, even if it declared for + // output. Example -- a GComputation from [in] to [out1,out2] + // where [out2] is a result of operation applied to [out1]: + // + // GComputation boundary + // . . . . . . . + // . . + // [in] ----> foo() ----> [out1] + // . . : + // . . . .:. . . + // . V . + // . bar() ---> [out2] + // . . . . . . . . . . . . + // + if (isROExt()) return *util::get(m_ref); + if (isRWExt()) return *util::get(m_ref); + if (isRWOwn()) return util::get(m_ref); + util::throw_error(std::logic_error("Impossible happened")); + } + + virtual void mov(BasicOpaqueRef &v) override { + OpaqueRefT *tv = dynamic_cast*>(&v); + GAPI_Assert(tv != nullptr); + wref() = std::move(tv->wref()); + } + }; + + // This class strips type information from OpaqueRefT<> and makes it usable + // in the G-API executables (carrying run-time data/information to kernels). + // Part of GRunArg. + // Its methods are typed proxies to OpaqueRefT. + // OpaqueRef maintains "reference" semantics so two copies of OpaqueRef refer + // to the same underlying object. + class OpaqueRef + { + std::shared_ptr m_ref; + + template inline void check() const + { + GAPI_DbgAssert(dynamic_cast*>(m_ref.get()) != nullptr); + } + + public: + OpaqueRef() = default; + + template explicit OpaqueRef(T&& obj) : + m_ref(new OpaqueRefT::type>(std::forward(obj))) {} + + template void reset() + { + if (!m_ref) m_ref.reset(new OpaqueRefT()); + + check(); + static_cast&>(*m_ref).reset(); + } + + template T& wref() + { + check(); + return static_cast&>(*m_ref).wref(); + } + + template const T& rref() const + { + check(); + return static_cast&>(*m_ref).rref(); + } + + void mov(OpaqueRef &v) + { + m_ref->mov(*v.m_ref); + } + + cv::GOpaqueDesc descr_of() const + { + return m_ref->m_desc; + } + }; +} // namespace detail + +/** \addtogroup gapi_data_objects + * @{ + */ + +template class GOpaque +{ +public: + GOpaque() { putDetails(); } // Empty constructor + explicit GOpaque(detail::GOpaqueU &&ref) // GOpaqueU-based constructor + : m_ref(ref) { putDetails(); } // (used by GCall, not for users) + + detail::GOpaqueU strip() const { return m_ref; } + +private: + // Host type (or Flat type) - the type this GOpaque is actually + // specified to. + using HT = typename detail::flatten_g::type>::type; + + static void CTor(detail::OpaqueRef& ref) { + ref.reset(); + } + void putDetails() { + m_ref.setConstructFcn(&CTor); + m_ref.specifyType(); + } + + detail::GOpaqueU m_ref; +}; + +/** @} */ + +} // namespace cv + +#endif // OPENCV_GAPI_GOPAQUE_HPP diff --git a/modules/gapi/include/opencv2/gapi/gproto.hpp b/modules/gapi/include/opencv2/gapi/gproto.hpp index b9e206ac9e..fe4d3dcb78 100644 --- a/modules/gapi/include/opencv2/gapi/gproto.hpp +++ b/modules/gapi/include/opencv2/gapi/gproto.hpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -36,7 +37,8 @@ using GProtoArg = util::variant < GMat , GMatP , GScalar - , detail::GArrayU // instead of GArray + , detail::GArrayU // instead of GArray + , detail::GOpaqueU // instead of GOpaque >; using GProtoArgs = std::vector; diff --git a/modules/gapi/include/opencv2/gapi/gtype_traits.hpp b/modules/gapi/include/opencv2/gapi/gtype_traits.hpp index a1373f3f85..fa871d1fed 100644 --- a/modules/gapi/include/opencv2/gapi/gtype_traits.hpp +++ b/modules/gapi/include/opencv2/gapi/gtype_traits.hpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -36,7 +37,8 @@ namespace detail GMAT, // a cv::GMat GMATP, // a cv::GMatP GSCALAR, // a cv::GScalar - GARRAY, // a cv::GArrayU (note - exactly GArrayU, not GArray!) + GARRAY, // a cv::GArrayU (note - exactly GArrayU, not GArray!) + GOPAQUE, // a cv::GOpaqueU (note - exactly GOpaqueU, not GOpaque!) }; // Describe G-API types (G-types) with traits. Mostly used by @@ -73,6 +75,16 @@ namespace detail static cv::detail::VectorRef wrap_in (const std::vector &t) { return detail::VectorRef(t); } static cv::detail::VectorRef wrap_out ( std::vector &t) { return detail::VectorRef(t); } }; + template struct GTypeTraits > + { + static constexpr const ArgKind kind = ArgKind::GOPAQUE; + static constexpr const GShape shape = GShape::GOPAQUE; + using host_type = T; + using strip_type = cv::detail::OpaqueRef; + static cv::detail::GOpaqueU wrap_value(const cv::GOpaque &t) { return t.strip();} + static cv::detail::OpaqueRef wrap_in (const T &t) { return detail::OpaqueRef(t); } + static cv::detail::OpaqueRef wrap_out ( T &t) { return detail::OpaqueRef(t); } + }; // Tests if Trait for type T requires extra marshalling ("custom wrap") or not. // If Traits has wrap_value() defined, it does. @@ -100,6 +112,7 @@ namespace detail template<> struct GTypeOf { using type = cv::GMat; }; template<> struct GTypeOf { using type = cv::GScalar; }; template struct GTypeOf > { using type = cv::GArray; }; + template struct GTypeOf { using type = cv::GOpaque;}; // FIXME: This is not quite correct since IStreamSource may produce not only Mat but also Scalar // and vector data. TODO: Extend the type dispatching on these types too. template<> struct GTypeOf { using type = cv::GMat;}; @@ -164,7 +177,6 @@ namespace detail template using wrap_gapi_helper = WrapValue::type>; template using wrap_host_helper = WrapValue >::type>; - } // namespace detail } // namespace cv diff --git a/modules/gapi/include/opencv2/gapi/gtyped.hpp b/modules/gapi/include/opencv2/gapi/gtyped.hpp index 5b941c7bb6..1ce6201e11 100644 --- a/modules/gapi/include/opencv2/gapi/gtyped.hpp +++ b/modules/gapi/include/opencv2/gapi/gtyped.hpp @@ -25,13 +25,15 @@ namespace detail template struct ProtoToParam; template<> struct ProtoToParam { using type = cv::Mat; }; template<> struct ProtoToParam { using type = cv::Scalar; }; - template struct ProtoToParam > { using type = std::vector; }; + template struct ProtoToParam > { using type = std::vector; }; + template struct ProtoToParam > { using type = U; }; template using ProtoToParamT = typename ProtoToParam::type; template struct ProtoToMeta; template<> struct ProtoToMeta { using type = cv::GMatDesc; }; template<> struct ProtoToMeta { using type = cv::GScalarDesc; }; - template struct ProtoToMeta > { using type = cv::GArrayDesc; }; + template struct ProtoToMeta > { using type = cv::GArrayDesc; }; + template struct ProtoToMeta > { using type = cv::GOpaqueDesc; }; template using ProtoToMetaT = typename ProtoToMeta::type; //workaround for MSVC 19.0 bug diff --git a/modules/gapi/include/opencv2/gapi/ocl/goclkernel.hpp b/modules/gapi/include/opencv2/gapi/ocl/goclkernel.hpp index b729171ae1..e80854affc 100644 --- a/modules/gapi/include/opencv2/gapi/ocl/goclkernel.hpp +++ b/modules/gapi/include/opencv2/gapi/ocl/goclkernel.hpp @@ -68,9 +68,14 @@ public: { return outVecRef(output).wref(); } + template T& outOpaqueR(int output) // FIXME: the same issue + { + return outOpaqueRef(output).wref(); + } protected: detail::VectorRef& outVecRef(int output); + detail::VectorRef& outOpaqueRef(int output); std::vector m_args; std::unordered_map m_results; @@ -111,6 +116,10 @@ template struct ocl_get_in > { static const std::vector& get(GOCLContext &ctx, int idx) { return ctx.inArg(idx).rref(); } }; +template struct ocl_get_in > +{ + static const U& get(GOCLContext &ctx, int idx) { return ctx.inArg(idx).rref(); } +}; template struct ocl_get_in { static T get(GOCLContext &ctx, int idx) { return ctx.inArg(idx); } @@ -184,6 +193,10 @@ template struct ocl_get_out > { static std::vector& get(GOCLContext &ctx, int idx) { return ctx.outVecR(idx); } }; +template struct ocl_get_out > +{ + static U& get(GOCLContext &ctx, int idx) { return ctx.outOpaqueR(idx); } +}; template struct OCLCallHelper; diff --git a/modules/gapi/src/api/gbackend.cpp b/modules/gapi/src/api/gbackend.cpp index a2bf0d09f0..304c58195d 100644 --- a/modules/gapi/src/api/gbackend.cpp +++ b/modules/gapi/src/api/gbackend.cpp @@ -168,6 +168,10 @@ void bindInArg(Mag& mag, const RcDesc &rc, const GRunArg &arg, bool is_umat) 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")); } @@ -233,6 +237,10 @@ void bindOutArg(Mag& mag, const RcDesc &rc, const GRunArgP &arg, bool is_umat) 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; @@ -251,6 +259,11 @@ void resetInternalData(Mag& mag, const Data &d) (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::gapi::own::Scalar(); break; @@ -272,9 +285,10 @@ cv::GRunArg getArg(const Mag& mag, const RcDesc &ref) { 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 as object MUST be already there + // 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; @@ -297,7 +311,7 @@ cv::GRunArgP getObjPtr(Mag& mag, const RcDesc &rc, bool is_umat) else return GRunArgP(&mag.template slot()[rc.id]); case GShape::GSCALAR: return GRunArgP(&mag.template slot()[rc.id]); - // Note: .at() is intentional for GArray as object MUST be already there + // 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 @@ -307,6 +321,14 @@ cv::GRunArgP getObjPtr(Mag& mag, const RcDesc &rc, bool is_umat) // 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; @@ -320,6 +342,9 @@ void writeBack(const Mag& mag, const RcDesc &rc, GRunArgP &g_arg, bool is_umat) case GShape::GARRAY: // Do nothing - should we really do anything here? break; + case GShape::GOPAQUE: + // Do nothing - should we really do anything here? + break; case GShape::GMAT: { diff --git a/modules/gapi/src/api/gcall.cpp b/modules/gapi/src/api/gcall.cpp index 4c052ff3f0..6f5f65bbfd 100644 --- a/modules/gapi/src/api/gcall.cpp +++ b/modules/gapi/src/api/gcall.cpp @@ -64,6 +64,11 @@ cv::detail::GArrayU cv::GCall::yieldArray(int output) return cv::detail::GArrayU(m_priv->m_node, output); } +cv::detail::GOpaqueU cv::GCall::yieldOpaque(int output) +{ + return cv::detail::GOpaqueU(m_priv->m_node, output); +} + cv::GCall::Priv& cv::GCall::priv() { return *m_priv; diff --git a/modules/gapi/src/api/gopaque.cpp b/modules/gapi/src/api/gopaque.cpp new file mode 100644 index 0000000000..9dff6e7e37 --- /dev/null +++ b/modules/gapi/src/api/gopaque.cpp @@ -0,0 +1,45 @@ +// 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) 2019 Intel Corporation + + +#include "precomp.hpp" +#include +#include "api/gorigin.hpp" + +// cv::detail::GOpaqueU public implementation /////////////////////////////////// +cv::detail::GOpaqueU::GOpaqueU() + : m_priv(new GOrigin(GShape::GOPAQUE, cv::GNode::Param())) +{ +} + +cv::detail::GOpaqueU::GOpaqueU(const GNode &n, std::size_t out) + : m_priv(new GOrigin(GShape::GOPAQUE, n, out)) +{ +} + +cv::GOrigin& cv::detail::GOpaqueU::priv() +{ + return *m_priv; +} + +const cv::GOrigin& cv::detail::GOpaqueU::priv() const +{ + return *m_priv; +} + +void cv::detail::GOpaqueU::setConstructFcn(ConstructOpaque &&co) +{ + m_priv->ctor = std::move(co); +} + +namespace cv { +std::ostream& operator<<(std::ostream& os, const cv::GOpaqueDesc &) +{ + // FIXME: add type information here + os << "(Opaque)"; + return os; +} +} diff --git a/modules/gapi/src/api/gproto.cpp b/modules/gapi/src/api/gproto.cpp index 3e5e0e6940..c4cfca6a86 100644 --- a/modules/gapi/src/api/gproto.cpp +++ b/modules/gapi/src/api/gproto.cpp @@ -34,6 +34,9 @@ const cv::GOrigin& cv::gimpl::proto::origin_of(const cv::GProtoArg &arg) case cv::GProtoArg::index_of(): return util::get(arg).priv(); + case cv::GProtoArg::index_of(): + return util::get(arg).priv(); + default: util::throw_error(std::logic_error("Unsupported GProtoArg type")); } @@ -59,6 +62,7 @@ bool cv::gimpl::proto::is_dynamic(const cv::GArg& arg) case detail::ArgKind::GMATP: case detail::ArgKind::GSCALAR: case detail::ArgKind::GARRAY: + case detail::ArgKind::GOPAQUE: return true; default: @@ -85,6 +89,7 @@ cv::GProtoArg cv::gimpl::proto::rewrap(const cv::GArg &arg) case detail::ArgKind::GMATP: return GProtoArg(arg.get()); case detail::ArgKind::GSCALAR: return GProtoArg(arg.get()); case detail::ArgKind::GARRAY: return GProtoArg(arg.get()); + case detail::ArgKind::GOPAQUE: return GProtoArg(arg.get()); default: util::throw_error(std::logic_error("Unsupported GArg type")); } } @@ -110,6 +115,9 @@ cv::GMetaArg cv::descr_of(const cv::GRunArg &arg) case GRunArg::index_of(): return cv::GMetaArg(util::get(arg).descr_of()); + case GRunArg::index_of(): + return cv::GMetaArg(util::get(arg).descr_of()); + case GRunArg::index_of(): return cv::util::get(arg)->descr_of(); @@ -136,6 +144,7 @@ cv::GMetaArg cv::descr_of(const cv::GRunArgP &argp) case GRunArgP::index_of(): return GMetaArg(descr_of(*util::get(argp))); case GRunArgP::index_of(): return GMetaArg(descr_of(*util::get(argp))); case GRunArgP::index_of(): return GMetaArg(util::get(argp).descr_of()); + case GRunArgP::index_of(): return GMetaArg(util::get(argp).descr_of()); default: util::throw_error(std::logic_error("Unsupported GRunArgP type")); } } @@ -154,6 +163,7 @@ bool cv::can_describe(const GMetaArg& meta, const GRunArgP& argp) util::get(meta).canDescribe(*util::get(argp)); case GRunArgP::index_of(): return meta == GMetaArg(descr_of(*util::get(argp))); case GRunArgP::index_of(): return meta == GMetaArg(util::get(argp).descr_of()); + case GRunArgP::index_of(): return meta == GMetaArg(util::get(argp).descr_of()); default: util::throw_error(std::logic_error("Unsupported GRunArgP type")); } } @@ -172,6 +182,7 @@ bool cv::can_describe(const GMetaArg& meta, const GRunArg& arg) util::get(meta).canDescribe(util::get(arg)); case GRunArg::index_of(): return meta == cv::GMetaArg(descr_of(util::get(arg))); case GRunArg::index_of(): return meta == cv::GMetaArg(util::get(arg).descr_of()); + case GRunArg::index_of(): return meta == cv::GMetaArg(util::get(arg).descr_of()); case GRunArg::index_of(): return util::holds_alternative(meta); // FIXME(?) may be not the best option default: util::throw_error(std::logic_error("Unsupported GRunArg type")); } @@ -207,6 +218,10 @@ std::ostream& operator<<(std::ostream& os, const cv::GMetaArg &arg) case cv::GMetaArg::index_of(): os << util::get(arg); break; + + case cv::GMetaArg::index_of(): + os << util::get(arg); + break; default: GAPI_Assert(false); } diff --git a/modules/gapi/src/backends/common/gbackend.hpp b/modules/gapi/src/backends/common/gbackend.hpp index 0c9c20e444..dd5624ba2d 100644 --- a/modules/gapi/src/backends/common/gbackend.hpp +++ b/modules/gapi/src/backends/common/gbackend.hpp @@ -46,9 +46,9 @@ namespace magazine { } // namespace magazine #if !defined(GAPI_STANDALONE) -using Mag = magazine::Class; +using Mag = magazine::Class; #else -using Mag = magazine::Class; +using Mag = magazine::Class; #endif namespace magazine diff --git a/modules/gapi/src/backends/cpu/gcpubackend.cpp b/modules/gapi/src/backends/cpu/gcpubackend.cpp index 052b47f1d9..14eeaaacac 100644 --- a/modules/gapi/src/backends/cpu/gcpubackend.cpp +++ b/modules/gapi/src/backends/cpu/gcpubackend.cpp @@ -113,7 +113,8 @@ cv::GArg cv::gimpl::GCPUExecutable::packArg(const GArg &arg) // FIXME: this check has to be done somewhere in compilation stage. GAPI_Assert( arg.kind != cv::detail::ArgKind::GMAT && arg.kind != cv::detail::ArgKind::GSCALAR - && arg.kind != cv::detail::ArgKind::GARRAY); + && arg.kind != cv::detail::ArgKind::GARRAY + && arg.kind != cv::detail::ArgKind::GOPAQUE); if (arg.kind != cv::detail::ArgKind::GOBJREF) { @@ -129,9 +130,10 @@ cv::GArg cv::gimpl::GCPUExecutable::packArg(const GArg &arg) { case GShape::GMAT: return GArg(m_res.slot() [ref.id]); case GShape::GSCALAR: return GArg(m_res.slot()[ref.id]); - // Note: .at() is intentional for GArray as object MUST be already there + // 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 GArg(m_res.slot().at(ref.id)); + case GShape::GOPAQUE: return GArg(m_res.slot().at(ref.id)); default: util::throw_error(std::logic_error("Unsupported GShape type")); break; diff --git a/modules/gapi/src/backends/cpu/gcpukernel.cpp b/modules/gapi/src/backends/cpu/gcpukernel.cpp index 5bc77aa583..52137d8c0d 100644 --- a/modules/gapi/src/backends/cpu/gcpukernel.cpp +++ b/modules/gapi/src/backends/cpu/gcpukernel.cpp @@ -36,6 +36,11 @@ cv::detail::VectorRef& cv::GCPUContext::outVecRef(int output) return util::get(m_results.at(output)); } +cv::detail::OpaqueRef& cv::GCPUContext::outOpaqueRef(int output) +{ + return util::get(m_results.at(output)); +} + cv::GCPUKernel::GCPUKernel() { } diff --git a/modules/gapi/src/backends/fluid/gfluidbackend.cpp b/modules/gapi/src/backends/fluid/gfluidbackend.cpp index bdd4432c93..1c926b4d83 100644 --- a/modules/gapi/src/backends/fluid/gfluidbackend.cpp +++ b/modules/gapi/src/backends/fluid/gfluidbackend.cpp @@ -1250,6 +1250,7 @@ void cv::gimpl::GFluidExecutable::bindInArg(const cv::gimpl::RcDesc &rc, const G case GShape::GMAT: m_buffers[m_id_map.at(rc.id)].priv().bindTo(util::get(arg), true); break; case GShape::GSCALAR: m_res.slot()[rc.id] = util::get(arg); break; case GShape::GARRAY: m_res.slot()[rc.id] = util::get(arg); break; + case GShape::GOPAQUE: m_res.slot()[rc.id] = util::get(arg); break; } } @@ -1292,7 +1293,8 @@ void cv::gimpl::GFluidExecutable::packArg(cv::GArg &in_arg, const cv::GArg &op_a { GAPI_Assert(op_arg.kind != cv::detail::ArgKind::GMAT && op_arg.kind != cv::detail::ArgKind::GSCALAR - && op_arg.kind != cv::detail::ArgKind::GARRAY); + && op_arg.kind != cv::detail::ArgKind::GARRAY + && op_arg.kind != cv::detail::ArgKind::GOPAQUE); if (op_arg.kind == cv::detail::ArgKind::GOBJREF) { @@ -1305,6 +1307,10 @@ void cv::gimpl::GFluidExecutable::packArg(cv::GArg &in_arg, const cv::GArg &op_a { in_arg = GArg(m_res.slot()[ref.id]); } + else if (ref.shape == GShape::GOPAQUE) + { + in_arg = GArg(m_res.slot()[ref.id]); + } } } diff --git a/modules/gapi/src/backends/fluid/gfluidbackend.hpp b/modules/gapi/src/backends/fluid/gfluidbackend.hpp index c8598d7da8..63ca9deb83 100644 --- a/modules/gapi/src/backends/fluid/gfluidbackend.hpp +++ b/modules/gapi/src/backends/fluid/gfluidbackend.hpp @@ -129,7 +129,7 @@ class GFluidExecutable final: public GIslandExecutable std::vector m_script; - using Magazine = detail::magazine; + using Magazine = detail::magazine; Magazine m_res; std::size_t m_num_int_buffers; // internal buffers counter (m_buffers - num_scratch) diff --git a/modules/gapi/src/backends/ie/giebackend.cpp b/modules/gapi/src/backends/ie/giebackend.cpp index df6e347ff5..3941642156 100644 --- a/modules/gapi/src/backends/ie/giebackend.cpp +++ b/modules/gapi/src/backends/ie/giebackend.cpp @@ -31,6 +31,7 @@ #include #include +#include #include #include #include @@ -396,6 +397,10 @@ cv::GArg cv::gimpl::ie::GIEExecutable::packArg(const cv::GArg &arg) { // (and constructed by either bindIn/Out or resetInternal) case GShape::GARRAY: return GArg(m_res.slot().at(ref.id)); + // Note: .at() is intentional for GOpaque as object MUST be already there + // (and constructed by either bindIn/Out or resetInternal) + case GShape::GOPAQUE: return GArg(m_res.slot().at(ref.id)); + default: util::throw_error(std::logic_error("Unsupported GShape type")); break; diff --git a/modules/gapi/src/backends/ocl/goclbackend.cpp b/modules/gapi/src/backends/ocl/goclbackend.cpp index ea1e4d40e1..560d8446be 100644 --- a/modules/gapi/src/backends/ocl/goclbackend.cpp +++ b/modules/gapi/src/backends/ocl/goclbackend.cpp @@ -113,7 +113,8 @@ cv::GArg cv::gimpl::GOCLExecutable::packArg(const GArg &arg) // FIXME: this check has to be done somewhere in compilation stage. GAPI_Assert( arg.kind != cv::detail::ArgKind::GMAT && arg.kind != cv::detail::ArgKind::GSCALAR - && arg.kind != cv::detail::ArgKind::GARRAY); + && arg.kind != cv::detail::ArgKind::GARRAY + && arg.kind != cv::detail::ArgKind::GOPAQUE); if (arg.kind != cv::detail::ArgKind::GOBJREF) { @@ -129,9 +130,12 @@ cv::GArg cv::gimpl::GOCLExecutable::packArg(const GArg &arg) { case GShape::GMAT: return GArg(m_res.slot()[ref.id]); case GShape::GSCALAR: return GArg(m_res.slot()[ref.id]); - // Note: .at() is intentional for GArray as object MUST be already there + // Note: .at() is intentional for GArray as object MUST be already there // (and constructed by either bindIn/Out or resetInternal) case GShape::GARRAY: return GArg(m_res.slot().at(ref.id)); + // Note: .at() is intentional for GOpaque as object MUST be already there + // (and constructed by either bindIn/Out or resetInternal) + case GShape::GOPAQUE: return GArg(m_res.slot().at(ref.id)); default: util::throw_error(std::logic_error("Unsupported GShape type")); break; diff --git a/modules/gapi/src/backends/plaidml/gplaidmlbackend.cpp b/modules/gapi/src/backends/plaidml/gplaidmlbackend.cpp index 4de99a1af2..fcd52c92fc 100644 --- a/modules/gapi/src/backends/plaidml/gplaidmlbackend.cpp +++ b/modules/gapi/src/backends/plaidml/gplaidmlbackend.cpp @@ -276,7 +276,8 @@ cv::GArg cv::gimpl::GPlaidMLExecutable::packArg(const GArg &arg) { GAPI_Assert( arg.kind != cv::detail::ArgKind::GMAT && arg.kind != cv::detail::ArgKind::GSCALAR - && arg.kind != cv::detail::ArgKind::GARRAY); + && arg.kind != cv::detail::ArgKind::GARRAY + && arg.kind != cv::detail::ArgKind::GOPAQUE); if (arg.kind != cv::detail::ArgKind::GOBJREF) { diff --git a/modules/gapi/src/compiler/gcompiler.cpp b/modules/gapi/src/compiler/gcompiler.cpp index 9d48be6d07..1ee710c235 100644 --- a/modules/gapi/src/compiler/gcompiler.cpp +++ b/modules/gapi/src/compiler/gcompiler.cpp @@ -332,6 +332,9 @@ void cv::gimpl::GCompiler::validateInputMeta() case GProtoArg::index_of(): return util::holds_alternative(meta); + case GProtoArg::index_of(): + return util::holds_alternative(meta); + default: GAPI_Assert(false); } diff --git a/modules/gapi/src/compiler/gobjref.hpp b/modules/gapi/src/compiler/gobjref.hpp index bcc5047d8e..04686e2641 100644 --- a/modules/gapi/src/compiler/gobjref.hpp +++ b/modules/gapi/src/compiler/gobjref.hpp @@ -16,13 +16,14 @@ namespace cv namespace gimpl { - // Union type for various user-defined type constructors (GArray, etc) + // Union type for various user-defined type constructors (GArray, GOpaque, etc) // FIXME: Replace construct-only API with a more generic one // (probably with bits of introspection) // Not required for non-user-defined types (GMat, GScalar, etc) using HostCtor = util::variant < util::monostate , detail::ConstructVec + , detail::ConstructOpaque >; using ConstVal = util::variant diff --git a/modules/gapi/src/compiler/passes/dump_dot.cpp b/modules/gapi/src/compiler/passes/dump_dot.cpp index 86e008b962..15e6a9fa09 100644 --- a/modules/gapi/src/compiler/passes/dump_dot.cpp +++ b/modules/gapi/src/compiler/passes/dump_dot.cpp @@ -32,6 +32,7 @@ void dumpDot(const ade::Graph &g, std::ostream& os) {cv::GShape::GMAT, "GMat"}, {cv::GShape::GSCALAR, "GScalar"}, {cv::GShape::GARRAY, "GArray"}, + {cv::GShape::GOPAQUE, "GOpaque"}, }; auto format_op_label = [&gr](ade::NodeHandle nh) -> std::string { diff --git a/modules/gapi/test/gapi_opaque_tests.cpp b/modules/gapi/test/gapi_opaque_tests.cpp new file mode 100644 index 0000000000..d2ab22f24e --- /dev/null +++ b/modules/gapi/test/gapi_opaque_tests.cpp @@ -0,0 +1,197 @@ +// 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) 2019 Intel Corporation + +#include "test_precomp.hpp" +#include +#include + +namespace opencv_test +{ + +namespace ThisTest +{ +using GPointOpaque = cv::GOpaque; + +G_TYPED_KERNEL(GeneratePoint, , "test.opaque.gen_point") +{ + static GOpaqueDesc outMeta(const GMatDesc&) { return empty_gopaque_desc(); } +}; + +G_TYPED_KERNEL(FillMat, , int, int, cv::Size)>, "test.opaque.fill_mat") +{ + static GMatDesc outMeta(const GOpaqueDesc&, int depth, int chan, cv::Size size) + { + return cv::GMatDesc{depth, chan, size}; + } +}; + +G_TYPED_KERNEL(PaintPoint, , "test.opaque.paint_point") +{ + static GMatDesc outMeta(const GOpaqueDesc&, int depth, int chan, cv::Size size) + { + return cv::GMatDesc{depth, chan, size}; + } +}; + +struct MyCustomType{ + int num; + std::string s; +}; + +using GOpaq2 = std::tuple,GOpaque>; + +G_TYPED_KERNEL_M(GenerateOpaque, , "test.opaque.gen_point_multy") +{ + static std::tuple outMeta(const GMatDesc&, const GMatDesc&, std::string) + { + return std::make_tuple(empty_gopaque_desc(), empty_gopaque_desc()); + } +}; + +} // namespace ThisTest + +namespace +{ +GAPI_OCV_KERNEL(OCVGeneratePoint, ThisTest::GeneratePoint) +{ + static void run(const cv::Mat&, cv::Point& out) + { + out = cv::Point(42, 42); + } +}; + +GAPI_OCV_KERNEL(OCVFillMat, ThisTest::FillMat) +{ + static void run(int a, int, int, cv::Size, cv::Mat& out) + { + out = cv::Scalar(a); + } +}; + +GAPI_OCV_KERNEL(OCVPaintPoint, ThisTest::PaintPoint) +{ + static void run(cv::Point a, int, int, cv::Size, cv::Mat& out) + { + out.at(a) = 77; + } +}; + +GAPI_OCV_KERNEL(OCVGenerateOpaque, ThisTest::GenerateOpaque) +{ + static void run(const cv::Mat& a, const cv::Mat& b, const std::string& s, + ThisTest::MyCustomType &out1, ThisTest::MyCustomType &out2) + { + out1.num = a.size().width * a.size().height; + out1.s = s; + + out2.num = b.size().width * b.size().height; + auto s2 = s; + std::reverse(s2.begin(), s2.end()); + out2.s = s2; + } +}; +} // (anonymous namespace) + +TEST(GOpaque, TestOpaqueOut) +{ + cv::Mat input = cv::Mat(52, 52, CV_8U); + cv::Point point; + + cv::GMat in; + auto out = ThisTest::GeneratePoint::on(in); + + cv::GComputation c(cv::GIn(in), cv::GOut(out)); + c.apply(cv::gin(input), cv::gout(point), cv::compile_args(cv::gapi::kernels())); + + EXPECT_TRUE(point == cv::Point(42, 42)); +} + +TEST(GOpaque, TestOpaqueIn) +{ + cv::Size sz = {42, 42}; + int depth = CV_8U; + int chan = 1; + cv::Mat mat = cv::Mat(sz, CV_MAKETYPE(depth, chan)); + int fill = 0; + + cv::GOpaque in; + auto out = ThisTest::FillMat::on(in, depth, chan, sz); + + cv::GComputation c(cv::GIn(in), cv::GOut(out)); + c.apply(cv::gin(fill), cv::gout(mat), cv::compile_args(cv::gapi::kernels())); + + auto diff = cv::Mat(sz, CV_MAKETYPE(depth, chan), cv::Scalar(fill)) - mat; + EXPECT_EQ(cv::countNonZero(diff), 0); +} + +TEST(GOpaque, TestOpaqueBetween) +{ + cv::Size sz = {50, 50}; + int depth = CV_8U; + int chan = 1; + cv::Mat mat_in = cv::Mat::zeros(sz, CV_MAKETYPE(depth, chan)); + cv::Mat mat_out = cv::Mat::zeros(sz, CV_MAKETYPE(depth, chan)); + + cv::GMat in, out; + auto betw = ThisTest::GeneratePoint::on(in); + out = ThisTest::PaintPoint::on(betw, depth, chan, sz); + + cv::GComputation c(cv::GIn(in), cv::GOut(out)); + c.apply(cv::gin(mat_in), cv::gout(mat_out), cv::compile_args(cv::gapi::kernels())); + + int painted = mat_out.at(42, 42); + EXPECT_EQ(painted, 77); +} + +TEST(GOpaque, TestOpaqueCustomOut2) +{ + cv::Mat input1 = cv::Mat(52, 52, CV_8U); + cv::Mat input2 = cv::Mat(42, 42, CV_8U); + std::string str = "opaque"; + std::string str2 = str; + std::reverse(str2.begin(), str2.end()); + + ThisTest::MyCustomType out1, out2; + + cv::GMat in1, in2; + auto out = ThisTest::GenerateOpaque::on(in1, in2, str); + + cv::GComputation c(cv::GIn(in1, in2), cv::GOut(std::get<0>(out), std::get<1>(out))); + c.apply(cv::gin(input1, input2), cv::gout(out1, out2), cv::compile_args(cv::gapi::kernels())); + + EXPECT_EQ(out1.num, input1.size().width * input1.size().height); + EXPECT_EQ(out1.s, str); + + EXPECT_EQ(out2.num, input2.size().width * input2.size().height); + EXPECT_EQ(out2.s, str2); +} + +TEST(GOpaque_OpaqueRef, TestMov) +{ + // Warning: this test is testing some not-very-public APIs + // Test how OpaqueRef's mov() (aka poor man's move()) is working. + + using I = std::string; + + std::string str = "this string must be long due to short string optimization"; + const I gold(str); + + I test = gold; + const char* ptr = test.data(); + + cv::detail::OpaqueRef ref(test); + cv::detail::OpaqueRef mov; + mov.reset(); + + EXPECT_EQ(gold, ref.rref()); // ref = gold + + mov.mov(ref); + EXPECT_EQ(gold, mov.rref()); // mov obtained the data + EXPECT_EQ(ptr, mov.rref().data()); // pointer is unchanged (same data) + EXPECT_EQ(test, ref.rref()); // ref = test + EXPECT_NE(test, mov.rref()); // ref lost the data +} +} // namespace opencv_test diff --git a/modules/gapi/test/gapi_transform_tests.cpp b/modules/gapi/test/gapi_transform_tests.cpp index 01492e56df..ad1a6aae0b 100644 --- a/modules/gapi/test/gapi_transform_tests.cpp +++ b/modules/gapi/test/gapi_transform_tests.cpp @@ -22,10 +22,27 @@ using GMat2 = std::tuple; using GMat3 = std::tuple; using GScalar = cv::GScalar; template using GArray = cv::GArray; +template using GOpaque = cv::GOpaque; using ArrayT = int; using WrongArrayT = char; +struct CustomType{ + cv::Mat mat; + int i; + void *v; + CustomType* next; +}; + +struct AnotherCustomType{ + cv::Mat mat; + int i; + void *v; +}; + +using OpaqueT = CustomType; +using WrongOpaqueT = AnotherCustomType; + GAPI_TRANSFORM(gmat_in_gmat_out, , "gmat_in_gmat_out") { static GMat pattern(GMat) { return {}; } @@ -92,6 +109,36 @@ GAPI_TRANSFORM(gmat_gsc_garray_in_gmat2_out, ) { return {}; } }; +GAPI_TRANSFORM(gop_in_gmat_out, )>, "gop_in_gmat_out") +{ + static GMat pattern(GOpaque) { return {}; } + static GMat substitute(GOpaque) { return {}; } +}; + +GAPI_TRANSFORM(gmat_in_gop_out, (GMat)>, "gmat_in_gop_out") +{ + static GOpaque pattern(GMat) { return {}; } + static GOpaque substitute(GMat) { return {}; } +}; + +GAPI_TRANSFORM(gop_in_gscalar_out, )>, "gop_in_gscalar_out") +{ + static GScalar pattern(GOpaque) { return {}; } + static GScalar substitute(GOpaque) { return {}; } +}; + +GAPI_TRANSFORM(gscalar_in_gop_out, (GScalar)>, "gscalar_in_gop_out") +{ + static GOpaque pattern(GScalar) { return {}; } + static GOpaque substitute(GScalar) { return {}; } +}; + +GAPI_TRANSFORM(gmat_gsc_gopaque_in_gmat2_out, )>, "gmat_gsc_gopaque_in_gmat2_out") +{ + static GMat2 pattern(GMat, GScalar, GOpaque) { return {}; } + static GMat2 substitute(GMat, GScalar, GOpaque) { return {}; } +}; + } // anonymous namespace TEST(KernelPackageTransform, CreatePackage) @@ -108,10 +155,15 @@ TEST(KernelPackageTransform, CreatePackage) , garr_in_gscalar_out , gscalar_in_garr_out , gmat_gsc_garray_in_gmat2_out + , gop_in_gmat_out + , gmat_in_gop_out + , gop_in_gscalar_out + , gscalar_in_gop_out + , gmat_gsc_gopaque_in_gmat2_out >(); auto tr = pkg.get_transformations(); - EXPECT_EQ(11u, tr.size()); + EXPECT_EQ(16u, tr.size()); } TEST(KernelPackageTransform, Include) @@ -164,6 +216,29 @@ TEST(KernelPackageTransform, gmat_gsc_garray_in_gmat2_out) check(tr.substitute()); } +TEST(KernelPackageTransform, gmat_gsc_gopaque_in_gmat2_out) +{ + auto tr = gmat_gsc_gopaque_in_gmat2_out::transformation(); + + auto check = [](const cv::GComputation &comp){ + const auto &p = comp.priv(); + EXPECT_EQ(3u, p.m_ins.size()); + EXPECT_EQ(2u, p.m_outs.size()); + + EXPECT_TRUE(ProtoContainsT(p.m_ins[0])); + EXPECT_TRUE(ProtoContainsT(p.m_ins[1])); + EXPECT_TRUE(ProtoContainsT(p.m_ins[2])); + EXPECT_TRUE(cv::util::get(p.m_ins[2]).holds()); + EXPECT_FALSE(cv::util::get(p.m_ins[2]).holds()); + + EXPECT_TRUE(ProtoContainsT(p.m_outs[0])); + EXPECT_TRUE(ProtoContainsT(p.m_outs[1])); + }; + + check(tr.pattern()); + check(tr.substitute()); +} + namespace { template @@ -176,7 +251,17 @@ namespace } template - typename std::enable_if<(cv::detail::GTypeTraits::kind != cv::detail::ArgKind::GARRAY), void>::type + typename std::enable_if<(cv::detail::GTypeTraits::kind == cv::detail::ArgKind::GOPAQUE), void>::type + arg_check(const cv::GProtoArg &arg) + { + EXPECT_TRUE(ProtoContainsT(arg)); + EXPECT_TRUE(cv::util::get(arg).holds()); + EXPECT_FALSE(cv::util::get(arg).holds()); + } + + template + typename std::enable_if<(cv::detail::GTypeTraits::kind != cv::detail::ArgKind::GARRAY && + cv::detail::GTypeTraits::kind != cv::detail::ArgKind::GOPAQUE), void>::type arg_check(const cv::GProtoArg &arg) { EXPECT_TRUE(ProtoContainsT(arg)); @@ -242,4 +327,24 @@ TEST(KernelPackageTransform, gscalar_in_garr_out) transformTest>(); } +TEST(KernelPackageTransform, gop_in_gmat_out) +{ + transformTest, GMat>(); +} + +TEST(KernelPackageTransform, gmat_in_gop_out) +{ + transformTest>(); +} + +TEST(KernelPackageTransform, gop_in_gscalar_out) +{ + transformTest, GScalar>(); +} + +TEST(KernelPackageTransform, gscalar_in_gop_out) +{ + transformTest>(); +} + } // namespace opencv_test diff --git a/modules/gapi/test/internal/gapi_int_garg_test.cpp b/modules/gapi/test/internal/gapi_int_garg_test.cpp index c7da788ee3..aad112309c 100644 --- a/modules/gapi/test/internal/gapi_int_garg_test.cpp +++ b/modules/gapi/test/internal/gapi_int_garg_test.cpp @@ -37,6 +37,10 @@ using GArg_Test_Types = ::testing::Types , Expected, cv::detail::ArgKind::GARRAY> , Expected, cv::detail::ArgKind::GARRAY> , Expected, cv::detail::ArgKind::GARRAY> + , Expected, cv::detail::ArgKind::GOPAQUE> + , Expected, cv::detail::ArgKind::GOPAQUE> + , Expected, cv::detail::ArgKind::GOPAQUE> + , Expected, cv::detail::ArgKind::GOPAQUE> // Built-in types , Expected @@ -85,6 +89,11 @@ TEST(GArg, HasWrap) "GArray has custom marshalling logic"); static_assert(cv::detail::has_custom_wrap >::value, "GArray has custom marshalling logic"); + + static_assert(cv::detail::has_custom_wrap >::value, + "GOpaque has custom marshalling logic"); + static_assert(cv::detail::has_custom_wrap >::value, + "GOpaque has custom marshalling logic"); } TEST(GArg, GArrayU) @@ -97,5 +106,15 @@ TEST(GArg, GArrayU) EXPECT_NO_THROW(arg2.get()); } +TEST(GArg, GOpaqueU) +{ + // Placing a GOpaque into GArg automatically strips it to GOpaqueU + cv::GArg arg1 = cv::GArg(cv::GOpaque()); + EXPECT_NO_THROW(arg1.get()); + + cv::GArg arg2 = cv::GArg(cv::GOpaque()); + EXPECT_NO_THROW(arg2.get()); +} + } // namespace opencv_test