Merge pull request #18127 from smirnov-alexey:as/gapi_serialization
authorAlexey Smirnov <alexey.smirnov@intel.com>
Mon, 7 Sep 2020 17:10:03 +0000 (20:10 +0300)
committerGitHub <noreply@github.com>
Mon, 7 Sep 2020 17:10:03 +0000 (17:10 +0000)
[G-API]: Add GOpaque and GArray serialization support

* Add GOpaque and GArray serialization support

* Address review comments

* Remove holds() method

* Address review comments

* Remove comments

* Align streaming with kind changes

* Fix kind in kernel

* Address review comments

26 files changed:
modules/gapi/include/opencv2/gapi/garg.hpp
modules/gapi/include/opencv2/gapi/garray.hpp
modules/gapi/include/opencv2/gapi/gcommon.hpp
modules/gapi/include/opencv2/gapi/gkernel.hpp
modules/gapi/include/opencv2/gapi/gopaque.hpp
modules/gapi/include/opencv2/gapi/gtype_traits.hpp
modules/gapi/src/api/garray.cpp
modules/gapi/src/api/gopaque.cpp
modules/gapi/src/api/gorigin.cpp
modules/gapi/src/api/gorigin.hpp
modules/gapi/src/api/s11n.cpp
modules/gapi/src/backends/common/serialization.cpp
modules/gapi/src/backends/common/serialization.hpp
modules/gapi/src/backends/cpu/gcpubackend.cpp
modules/gapi/src/backends/ie/giebackend.cpp
modules/gapi/src/compiler/gmodel.cpp
modules/gapi/src/compiler/gmodel.hpp
modules/gapi/src/compiler/gmodelbuilder.cpp
modules/gapi/src/compiler/gobjref.hpp
modules/gapi/src/compiler/passes/meta.cpp
modules/gapi/test/gapi_array_tests.cpp
modules/gapi/test/gapi_opaque_tests.cpp
modules/gapi/test/internal/gapi_int_garg_test.cpp
modules/gapi/test/internal/gapi_int_gmodel_builder_test.cpp
modules/gapi/test/s11n/gapi_s11n_tests.cpp
modules/gapi/test/s11n/gapi_sample_pipelines_s11n.cpp

index 3f243a8..cca080d 100644 (file)
@@ -2,7 +2,7 @@
 // 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 Intel Corporation
+// Copyright (C) 2018-2020 Intel Corporation
 
 
 #ifndef OPENCV_GAPI_GARG_HPP
@@ -170,7 +170,8 @@ inline GRunArgsP& operator += (GRunArgsP &lhs, const GRunArgsP &rhs)
 namespace gapi
 {
     GAPI_EXPORTS cv::GRunArgsP bind(cv::GRunArgs &results);
-} // namespace gapi
+    GAPI_EXPORTS cv::GRunArg   bind(cv::GRunArgP &out);     // FIXME: think more about it
+}
 
 template<typename... Ts> inline GRunArgs gin(const Ts&... args)
 {
index 3f18af9..99f6661 100644 (file)
@@ -2,7 +2,7 @@
 // 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 Intel Corporation
+// Copyright (C) 2018-2020 Intel Corporation
 
 
 #ifndef OPENCV_GAPI_GARRAY_HPP
@@ -49,31 +49,6 @@ std::ostream& operator<<(std::ostream& os, const cv::GArrayDesc &desc);
 
 namespace detail
 {
-    // FIXME: This type spec needs to be:
-    // 1) shared with GOpaque (not needed right now)
-    // 2) unified with the serialization (S11N, not merged right now).
-    // Adding it to type traits is problematic due to our header deps
-    // (which also need to be fixed).
-    enum class TypeSpec: int {
-        OPAQUE_SPEC,
-        MAT,
-        RECT
-    };
-    // FIXME: Reuse the below from "opaque traits" of S11N!
-    template<typename T> struct GTypeSpec;
-    template<typename T> struct GTypeSpec
-    {
-        static constexpr const TypeSpec spec = TypeSpec::OPAQUE_SPEC;
-    };
-    template<>           struct GTypeSpec<cv::Mat>
-    {
-        static constexpr const TypeSpec spec = TypeSpec::MAT;
-    };
-    template<>           struct GTypeSpec<cv::Rect>
-    {
-        static constexpr const TypeSpec spec = TypeSpec::RECT;
-    };
-
     // ConstructVec is a callback which stores information about T and is used by
     // G-API runtime to construct arrays in host memory (T remains opaque for G-API).
     // ConstructVec is carried into G-API internals by GArrayU.
@@ -112,6 +87,11 @@ namespace detail
         template <typename T>
         void specifyType();                       // Store type of initial GArray<T>
 
+        template <typename T>
+        void storeKind();
+
+        void setKind(cv::detail::OpaqueKind);
+
         std::shared_ptr<GOrigin> m_priv;
         std::shared_ptr<TypeHintBase> m_hint;
     };
@@ -128,6 +108,11 @@ namespace detail
         m_hint.reset(new TypeHint<typename std::decay<T>::type>);
     };
 
+    template <typename T>
+    void GArrayU::storeKind(){
+        setKind(cv::detail::GOpaqueTraits<T>::kind);
+    };
+
     // This class represents a typed STL vector reference.
     // Depending on origins, this reference may be either "just a" reference to
     // an object created externally, OR actually own the underlying object
@@ -138,7 +123,6 @@ namespace detail
         // These fields are set by the derived class(es)
         std::size_t    m_elemSize = 0ul;
         cv::GArrayDesc m_desc;
-        TypeSpec       m_spec;
         virtual ~BasicVectorRef() {}
 
         virtual void mov(BasicVectorRef &ref) = 0;
@@ -163,7 +147,6 @@ namespace detail
         {
             m_elemSize = sizeof(T);
             if (vec) m_desc = cv::descr_of(*vec);
-            m_spec = GTypeSpec<T>::spec;
         }
 
     public:
@@ -238,7 +221,6 @@ namespace detail
             wref() = std::move(tv->wref());
         }
 
-
         virtual const void* ptr() const override { return &rref(); }
         virtual std::size_t size() const override { return rref().size(); }
     };
@@ -253,6 +235,7 @@ namespace detail
     class VectorRef
     {
         std::shared_ptr<BasicVectorRef> m_ref;
+        cv::detail::OpaqueKind m_kind;
 
         template<typename T> inline void check() const
         {
@@ -262,9 +245,17 @@ namespace detail
 
     public:
         VectorRef() = default;
-        template<typename T> explicit VectorRef(const std::vector<T>& vec) : m_ref(new VectorRefT<T>(vec)) {}
-        template<typename T> explicit VectorRef(std::vector<T>& vec)       : m_ref(new VectorRefT<T>(vec)) {}
-        template<typename T> explicit VectorRef(std::vector<T>&& vec)      : m_ref(new VectorRefT<T>(vec)) {}
+        template<typename T> explicit VectorRef(const std::vector<T>& vec) :
+                                            m_ref(new VectorRefT<T>(vec)), m_kind(GOpaqueTraits<T>::kind) {}
+        template<typename T> explicit VectorRef(std::vector<T>& vec)       :
+                                            m_ref(new VectorRefT<T>(vec)), m_kind(GOpaqueTraits<T>::kind) {}
+        template<typename T> explicit VectorRef(std::vector<T>&& vec)      :
+                                            m_ref(new VectorRefT<T>(std::move(vec))), m_kind(GOpaqueTraits<T>::kind) {}
+
+        cv::detail::OpaqueKind getKind() const
+        {
+            return m_kind;
+        }
 
         template<typename T> void reset()
         {
@@ -274,6 +265,12 @@ namespace detail
             static_cast<VectorRefT<T>&>(*m_ref).reset();
         }
 
+        template <typename T>
+        void storeKind()
+        {
+            m_kind = cv::detail::GOpaqueTraits<T>::kind;
+        }
+
         template<typename T> std::vector<T>& wref()
         {
             check<T>();
@@ -303,11 +300,6 @@ namespace detail
 
         // May be used to uniquely identify this object internally
         const void *ptr() const { return m_ref->ptr(); }
-
-        TypeSpec spec() const
-        {
-            return m_ref->m_spec;
-        }
     };
 
     // Helper (FIXME: work-around?)
@@ -349,10 +341,12 @@ private:
 
     static void VCTor(detail::VectorRef& vref) {
         vref.reset<HT>();
+        vref.storeKind<HT>();
     }
     void putDetails() {
         m_ref.setConstructFcn(&VCTor);
-        m_ref.specifyType<HT>();
+        m_ref.specifyType<HT>();  // FIXME: to unify those 2 to avoid excessive dynamic_cast
+        m_ref.storeKind<HT>();    //
     }
 
     detail::GArrayU m_ref;
index adece19..06499c1 100644 (file)
@@ -21,6 +21,8 @@
 
 namespace cv {
 
+class GMat; // FIXME: forward declaration for GOpaqueTraits
+
 namespace detail
 {
     // This is a trait-like structure to mark backend-specific compile arguments
@@ -32,6 +34,38 @@ namespace detail
     {};
     struct TransformTag
     {};
+
+    // This enum is utilized mostly by GArray and GOpaque to store and recognize their internal data
+    // types (aka Host type). Also it is widely used during serialization routine.
+    enum class OpaqueKind: int
+    {
+        CV_UNKNOWN,    // Unknown, generic, opaque-to-GAPI data type unsupported in graph seriallization
+        CV_BOOL,       // bool user G-API data
+        CV_INT,        // int user G-API data
+        CV_DOUBLE,     // double user G-API data
+        CV_POINT,      // cv::Point user G-API data
+        CV_SIZE,       // cv::Size user G-API data
+        CV_RECT,       // cv::Rect user G-API data
+        CV_SCALAR,     // cv::Scalar user G-API data
+        CV_MAT,        // cv::Mat user G-API data
+    };
+
+    // Type traits helper which simplifies the extraction of kind from type
+    template<typename T> struct GOpaqueTraits;
+    template<typename T> struct GOpaqueTraits    { static constexpr const OpaqueKind kind = OpaqueKind::CV_UNKNOWN; };
+    template<> struct GOpaqueTraits<int>         { static constexpr const OpaqueKind kind = OpaqueKind::CV_INT; };
+    template<> struct GOpaqueTraits<double>      { static constexpr const OpaqueKind kind = OpaqueKind::CV_DOUBLE; };
+    template<> struct GOpaqueTraits<cv::Size>    { static constexpr const OpaqueKind kind = OpaqueKind::CV_SIZE; };
+    template<> struct GOpaqueTraits<bool>        { static constexpr const OpaqueKind kind = OpaqueKind::CV_BOOL; };
+    template<> struct GOpaqueTraits<cv::Scalar>  { static constexpr const OpaqueKind kind = OpaqueKind::CV_SCALAR; };
+    template<> struct GOpaqueTraits<cv::Point>   { static constexpr const OpaqueKind kind = OpaqueKind::CV_POINT; };
+    template<> struct GOpaqueTraits<cv::Mat>     { static constexpr const OpaqueKind kind = OpaqueKind::CV_MAT; };
+    template<> struct GOpaqueTraits<cv::Rect>    { static constexpr const OpaqueKind kind = OpaqueKind::CV_RECT; };
+    template<> struct GOpaqueTraits<cv::GMat>    { static constexpr const OpaqueKind kind = OpaqueKind::CV_MAT; };
+    // GArray is not supporting bool type for now due to difference in std::vector<bool> implementation
+    using GOpaqueTraitsArrayTypes = std::tuple<int, double, cv::Size, cv::Scalar, cv::Point, cv::Mat, cv::Rect>;
+    // GOpaque is not supporting cv::Mat and cv::Scalar since there are GScalar and GMat types
+    using GOpaqueTraitsOpaqueTypes = std::tuple<bool, int, double, cv::Size, cv::Point, cv::Rect>;
 } // namespace detail
 
 // This definition is here because it is reused by both public(?) and internal
index bd8cf63..bd96933 100644 (file)
@@ -26,8 +26,8 @@
 
 namespace cv {
 
-using GSpecs = std::vector<cv::detail::ArgSpec>;
 using GShapes = std::vector<GShape>;
+using GKinds = std::vector<cv::detail::OpaqueKind>;
 
 // GKernel describes kernel API to the system
 // FIXME: add attributes of a kernel, (e.g. number and types
@@ -39,10 +39,10 @@ struct GAPI_EXPORTS GKernel
     const std::string name;       // kernel ID, defined by its API (signature)
     const std::string tag;        // some (implementation-specific) tag
     const M           outMeta;    // generic adaptor to API::outMeta(...)
-    const GSpecs      inSpecs;    // specs of kernel's inputs (FIXME: below)
     const GShapes     outShapes;  // types (shapes) kernel's outputs
+    const GKinds      inKinds;    // kinds of kernel's inputs (fixme: below)
 };
-// TODO: It's questionable if inSpecs should really be here. Instead,
+// TODO: It's questionable if inKinds should really be here. Instead,
 // this information could come from meta.
 
 // GKernelImpl describes particular kernel implementation to the system
@@ -213,8 +213,8 @@ public:
         cv::GCall call(GKernel{ K::id()
                               , K::tag()
                               , &K::getOutMeta
-                              , {detail::GTypeTraits<Args>::spec...}
-                              , {detail::GTypeTraits<R>::shape...}});
+                              , {detail::GTypeTraits<R>::shape...}
+                              , {detail::GTypeTraits<Args>::op_kind...}});
         call.pass(args...); // TODO: std::forward() here?
         return yield(call, typename detail::MkSeq<sizeof...(R)>::type());
     }
@@ -238,8 +238,8 @@ public:
         cv::GCall call(GKernel{ K::id()
                               , K::tag()
                               , &K::getOutMeta
-                              , {detail::GTypeTraits<Args>::spec...}
-                              , {detail::GTypeTraits<R>::shape}});
+                              , {detail::GTypeTraits<R>::shape}
+                              , {detail::GTypeTraits<Args>::op_kind...}});
         call.pass(args...);
         return detail::Yield<R>::yield(call, 0);
     }
index 7d3d663..9cfd588 100644 (file)
@@ -2,7 +2,7 @@
 // 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
+// Copyright (C) 2019-2020 Intel Corporation
 
 
 #ifndef OPENCV_GAPI_GOPAQUE_HPP
@@ -46,7 +46,6 @@ 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.
@@ -81,6 +80,11 @@ namespace detail
         template <typename T>
         void specifyType();                       // Store type of initial GOpaque<T>
 
+        template <typename T>
+        void storeKind();
+
+        void setKind(cv::detail::OpaqueKind);
+
         std::shared_ptr<GOrigin> m_priv;
         std::shared_ptr<TypeHintBase> m_hint;
     };
@@ -97,6 +101,12 @@ namespace detail
         m_hint.reset(new TypeHint<util::decay_t<T>>);
     };
 
+    template <typename T>
+    void GOpaqueU::storeKind(){
+        // FIXME: Add assert here on cv::Mat and cv::Scalar?
+        setKind(cv::detail::GOpaqueTraits<T>::kind);
+    };
+
     // 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
@@ -213,6 +223,7 @@ namespace detail
     class OpaqueRef
     {
         std::shared_ptr<BasicOpaqueRef> m_ref;
+        cv::detail::OpaqueKind m_kind;
 
         template<typename T> inline void check() const
         {
@@ -222,13 +233,19 @@ namespace detail
     public:
         OpaqueRef() = default;
 
-
         template<
             typename T,
             typename = util::are_different_t<OpaqueRef, T>
         >
+        // FIXME: probably won't work with const object
         explicit OpaqueRef(T&& obj) :
-            m_ref(new OpaqueRefT<util::decay_t<T>>(std::forward<T>(obj))) {}
+            m_ref(new OpaqueRefT<util::decay_t<T>>(std::forward<T>(obj))),
+            m_kind(GOpaqueTraits<T>::kind) {}
+
+        cv::detail::OpaqueKind getKind() const
+        {
+            return m_kind;
+        }
 
         template<typename T> void reset()
         {
@@ -238,6 +255,12 @@ namespace detail
             static_cast<OpaqueRefT<T>&>(*m_ref).reset();
         }
 
+        template <typename T>
+        void storeKind()
+        {
+            m_kind = cv::detail::GOpaqueTraits<T>::kind;
+        }
+
         template<typename T> T& wref()
         {
             check<T>();
@@ -285,10 +308,12 @@ private:
 
     static void CTor(detail::OpaqueRef& ref) {
         ref.reset<HT>();
+        ref.storeKind<HT>();
     }
     void putDetails() {
         m_ref.setConstructFcn(&CTor);
-        m_ref.specifyType<HT>();
+        m_ref.specifyType<HT>(); // FIXME: to unify those 2 to avoid excessive dynamic_cast
+        m_ref.storeKind<HT>();   //
     }
 
     detail::GOpaqueU m_ref;
index 0f22e3b..9b1c693 100644 (file)
@@ -41,98 +41,45 @@ namespace detail
         GOPAQUE,      // a cv::GOpaqueU (note - exactly GOpaqueU, not GOpaque<T>!)
     };
 
-    // This enum captures some information about T in GArray<T> and GOpaque<T>
-    enum class ArgSpec: int
-    {
-        OPAQUE_SPEC,  // Unknown, generic, opaque-to-GAPI data type
-        GMAT,         // a GMat
-        RECT,         // a cv::Rect
-        // NB: Add more types when required
-    };
-
-    // Describe specialization types of interest first
-    // FIXME: It comes to GArg but ideally it should go to *Desc{}
-    // type family. Bringing it there is a more massive change though.
-    template<typename T> struct GSpecTraits;
-    template<typename T> struct GSpecTraits
-    {
-        static constexpr const ArgSpec spec = ArgSpec::OPAQUE_SPEC;
-    };
-    template<>           struct GSpecTraits<cv::GMat>
-    {
-        static constexpr const ArgSpec spec = ArgSpec::GMAT;
-    };
-    template<>           struct GSpecTraits<cv::Rect>
-    {
-        static constexpr const ArgSpec spec = ArgSpec::RECT;
-    };
-
-    enum class OpaqueKind: int
-    {
-        CV_UNKNOWN,    // Unknown, generic, opaque-to-GAPI data type unsupported in graph seriallization
-        CV_BOOL,       // bool user G-API data
-        CV_INT,        // int user G-API data
-        CV_DOUBLE,     // double user G-API data
-        CV_POINT,      // cv::Point user G-API data
-        CV_SIZE,       // cv::Size user G-API data
-        CV_RECT,       // cv::Rect user G-API data
-        CV_SCALAR,     // cv::Scalar user G-API data
-        CV_MAT,        // cv::Mat user G-API data
-    };
-
-    template<typename T> struct GOpaqueTraits;
-    template<typename T> struct GOpaqueTraits    { static constexpr const OpaqueKind kind = OpaqueKind::CV_UNKNOWN; };
-    template<> struct GOpaqueTraits<int>         { static constexpr const OpaqueKind kind = OpaqueKind::CV_INT; };
-    template<> struct GOpaqueTraits<double>      { static constexpr const OpaqueKind kind = OpaqueKind::CV_DOUBLE; };
-    template<> struct GOpaqueTraits<cv::Size>    { static constexpr const OpaqueKind kind = OpaqueKind::CV_SIZE; };
-    template<> struct GOpaqueTraits<bool>        { static constexpr const OpaqueKind kind = OpaqueKind::CV_BOOL; };
-    template<> struct GOpaqueTraits<cv::Scalar>  { static constexpr const OpaqueKind kind = OpaqueKind::CV_SCALAR; };
-    template<> struct GOpaqueTraits<cv::Point>   { static constexpr const OpaqueKind kind = OpaqueKind::CV_POINT; };
-    template<> struct GOpaqueTraits<cv::Mat>     { static constexpr const OpaqueKind kind = OpaqueKind::CV_MAT; };
-    template<> struct GOpaqueTraits<cv::Rect>    { static constexpr const OpaqueKind kind = OpaqueKind::CV_RECT; };
-
     // Describe G-API types (G-types) with traits.  Mostly used by
     // cv::GArg to store meta information about types passed into
     // operation arguments. Please note that cv::GComputation is
     // defined on GProtoArgs, not GArgs!
-    //
-    // spec is a type specialization (makes sense for GArray<> and GOpaque<>)
-    // for the rest, it is just OPAQUE_VAL by default.
     template<typename T> struct GTypeTraits;
     template<typename T> struct GTypeTraits
     {
         static constexpr const ArgKind kind = ArgKind::OPAQUE_VAL;
-        static constexpr const ArgSpec spec = ArgSpec::OPAQUE_SPEC;
+        static constexpr const OpaqueKind op_kind = OpaqueKind::CV_UNKNOWN;
     };
     template<>           struct GTypeTraits<cv::GMat>
     {
         static constexpr const ArgKind kind = ArgKind::GMAT;
         static constexpr const GShape shape = GShape::GMAT;
-        static constexpr const ArgSpec spec = ArgSpec::OPAQUE_SPEC;
+        static constexpr const OpaqueKind op_kind = OpaqueKind::CV_UNKNOWN;
     };
     template<>           struct GTypeTraits<cv::GMatP>
     {
         static constexpr const ArgKind kind = ArgKind::GMATP;
         static constexpr const GShape shape = GShape::GMAT;
-        static constexpr const ArgSpec spec = ArgSpec::OPAQUE_SPEC;
+        static constexpr const OpaqueKind op_kind = OpaqueKind::CV_UNKNOWN;
     };
     template<>           struct GTypeTraits<cv::GFrame>
     {
         static constexpr const ArgKind kind = ArgKind::GFRAME;
         static constexpr const GShape shape = GShape::GMAT;
-        static constexpr const ArgSpec spec = ArgSpec::OPAQUE_SPEC;
+        static constexpr const OpaqueKind op_kind = OpaqueKind::CV_UNKNOWN;
     };
     template<>           struct GTypeTraits<cv::GScalar>
     {
         static constexpr const ArgKind kind = ArgKind::GSCALAR;
         static constexpr const GShape shape = GShape::GSCALAR;
-        static constexpr const ArgSpec spec = ArgSpec::OPAQUE_SPEC;
+        static constexpr const OpaqueKind op_kind = OpaqueKind::CV_UNKNOWN;
     };
     template<class T> struct GTypeTraits<cv::GArray<T> >
     {
         static constexpr const ArgKind kind = ArgKind::GARRAY;
         static constexpr const GShape shape = GShape::GARRAY;
-        static constexpr const ArgSpec spec = GSpecTraits<T>::spec;
+        static constexpr const OpaqueKind op_kind = GOpaqueTraits<T>::kind;
         using host_type  = std::vector<T>;
         using strip_type = cv::detail::VectorRef;
         static cv::detail::GArrayU   wrap_value(const cv::GArray<T>  &t) { return t.strip();}
@@ -143,7 +90,7 @@ namespace detail
     {
         static constexpr const ArgKind kind = ArgKind::GOPAQUE;
         static constexpr const GShape shape = GShape::GOPAQUE;
-        static constexpr const ArgSpec spec = GSpecTraits<T>::spec;
+        static constexpr const OpaqueKind op_kind = GOpaqueTraits<T>::kind;
         using host_type  = T;
         using strip_type = cv::detail::OpaqueRef;
         static cv::detail::GOpaqueU  wrap_value(const cv::GOpaque<T>  &t) { return t.strip();}
@@ -176,7 +123,6 @@ namespace detail
     template<>           struct GTypeOf<cv::Scalar>            { using type = cv::GScalar;   };
     template<typename U> struct GTypeOf<std::vector<U> >       { using type = cv::GArray<U>; };
     template<typename U> struct GTypeOf                        { using type = cv::GOpaque<U>;};
-
     // 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<cv::gapi::wip::IStreamSource::Ptr> { using type = cv::GMat;};
index bdd46b9..e99ce6a 100644 (file)
@@ -2,7 +2,7 @@
 // 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 Intel Corporation
+// Copyright (C) 2018-2020 Intel Corporation
 
 
 #include "precomp.hpp"
@@ -35,6 +35,11 @@ void cv::detail::GArrayU::setConstructFcn(ConstructVec &&cv)
     m_priv->ctor = std::move(cv);
 }
 
+void cv::detail::GArrayU::setKind(cv::detail::OpaqueKind kind)
+{
+    m_priv->kind = kind;
+}
+
 namespace cv {
 std::ostream& operator<<(std::ostream& os, const cv::GArrayDesc &)
 {
index 9dff6e7..71bf1bc 100644 (file)
@@ -2,7 +2,7 @@
 // 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
+// Copyright (C) 2019-2020 Intel Corporation
 
 
 #include "precomp.hpp"
@@ -35,6 +35,11 @@ void cv::detail::GOpaqueU::setConstructFcn(ConstructOpaque &&co)
     m_priv->ctor = std::move(co);
 }
 
+void cv::detail::GOpaqueU::setKind(cv::detail::OpaqueKind kind)
+{
+    m_priv->kind = kind;
+}
+
 namespace cv {
 std::ostream& operator<<(std::ostream& os, const cv::GOpaqueDesc &)
 {
index 312d614..d78e906 100644 (file)
@@ -2,7 +2,7 @@
 // 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 Intel Corporation
+// Copyright (C) 2018-2020 Intel Corporation
 
 
 #include "precomp.hpp"
 cv::GOrigin::GOrigin(GShape s,
                     const cv::GNode& n,
                     std::size_t p,
-                    const cv::gimpl::HostCtor c)
-    : shape(s), node(n), port(p), ctor(c)
+                    const cv::gimpl::HostCtor c,
+                    cv::detail::OpaqueKind k)
+    : shape(s), node(n), port(p), ctor(c), kind(k)
 {
 }
 
 cv::GOrigin::GOrigin(GShape s, cv::gimpl::ConstVal v)
-    : shape(s), node(cv::GNode::Const()), value(v), port(INVALID_PORT)
+    : shape(s), node(cv::GNode::Const()), value(v), port(INVALID_PORT), kind(cv::detail::OpaqueKind::CV_UNKNOWN)
 {
 }
 
index 7129b2f..2f01544 100644 (file)
@@ -2,8 +2,7 @@
 // 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 Intel Corporation
-
+// Copyright (C) 2018-2020 Intel Corporation
 
 #ifndef OPENCV_GAPI_GORIGIN_HPP
 #define OPENCV_GAPI_GORIGIN_HPP
@@ -30,7 +29,8 @@ struct GOrigin
     GOrigin(GShape s,
             const GNode& n,
             std::size_t p = INVALID_PORT,
-            const gimpl::HostCtor h = {});
+            const gimpl::HostCtor h = {},
+            cv::detail::OpaqueKind kind = cv::detail::OpaqueKind::CV_UNKNOWN);
     GOrigin(GShape s, gimpl::ConstVal value);
 
     const GShape          shape;           // Shape of a produced object
@@ -38,6 +38,7 @@ struct GOrigin
     const gimpl::ConstVal value;           // Node can have initial constant value, now only scalar is supported
     const std::size_t     port;            // GNode's output number; FIXME: "= max_size" in C++14
     gimpl::HostCtor       ctor;            // FIXME: replace with an interface?
+    detail::OpaqueKind    kind;            // primary is needed for GOpaque and GArray
 };
 
 namespace detail
index f3893dd..b56c34f 100644 (file)
@@ -44,6 +44,8 @@ std::vector<char> cv::gapi::serialize(const cv::GRunArgs& ra)
     return os.data();
 }
 
+// FIXME: This function should move from S11N to GRunArg-related entities.
+// it has nothing to do with the S11N as it is
 cv::GRunArgsP cv::gapi::bind(cv::GRunArgs &results)
 {
     cv::GRunArgsP outputs;
@@ -77,3 +79,36 @@ cv::GRunArgsP cv::gapi::bind(cv::GRunArgs &results)
     }
     return outputs;
 }
+
+// FIXME: move it out of s11n to api/
+// FIXME: don't we have such function already?
+cv::GRunArg cv::gapi::bind(cv::GRunArgP &out)
+{
+    using T = cv::GRunArgP;
+    switch (out.index())
+    {
+#if !defined(GAPI_STANDALONE)
+    case T::index_of<cv::UMat*>() :
+        GAPI_Assert(false && "Please implement this!");
+        break;
+#endif
+
+    case T::index_of<cv::detail::VectorRef>() :
+        return cv::GRunArg(cv::util::get<cv::detail::VectorRef>(out));
+
+    case T::index_of<cv::detail::OpaqueRef>() :
+        return cv::GRunArg(cv::util::get<cv::detail::OpaqueRef>(out));
+
+    case T::index_of<cv::Mat*>() :
+        return cv::GRunArg(*cv::util::get<cv::Mat*>(out));
+
+    case T::index_of<cv::Scalar*>() :
+        return cv::GRunArg(*cv::util::get<cv::Scalar*>(out));
+
+    default:
+        // ...maybe our types were extended
+        GAPI_Assert(false && "This value type is UNKNOWN!");
+        break;
+    }
+    return cv::GRunArg();
+}
index 7b275a7..ea97f17 100644 (file)
@@ -292,25 +292,85 @@ I::IStream& operator >> (I::IStream& is, cv::gapi::wip::IStreamSource::Ptr &)
     return is;
 }
 
-I::OStream& operator<< (I::OStream& os, const cv::detail::VectorRef &)
+namespace
+{
+template<typename Ref, typename T, typename... Ts>
+struct putToStream;
+
+template<typename Ref>
+struct putToStream<Ref, std::tuple<>>
+{
+    static void put(I::OStream&, const Ref &)
+    {
+        GAPI_Assert(false && "Unsupported type for GArray/GOpaque serialization");
+    }
+};
+
+template<typename Ref, typename T, typename... Ts>
+struct putToStream<Ref, std::tuple<T, Ts...>>
+{
+    static void put(I::OStream& os, const Ref &r)
+    {
+        if (r.getKind() == cv::detail::GOpaqueTraits<T>::kind) {
+            os << r.template rref<T>();
+        } else {
+            putToStream<Ref, std::tuple<Ts...> >::put(os, r);
+        }
+    }
+};
+
+template<typename Ref, typename T, typename... Ts>
+struct getFromStream;
+
+template<typename Ref>
+struct getFromStream<Ref, std::tuple<>>
 {
-    GAPI_Assert(false && "Serialization: Unsupported << for cv::detail::VectorRef &");
+    static void get(I::IStream&, Ref &, cv::detail::OpaqueKind)
+    {
+        GAPI_Assert(false && "Unsupported type for GArray/GOpaque deserialization");
+    }
+};
+
+template<typename Ref, typename T, typename... Ts>
+struct getFromStream<Ref, std::tuple<T, Ts...>>
+{
+    static void get(I::IStream& is, Ref &r, cv::detail::OpaqueKind kind) {
+        if (kind == cv::detail::GOpaqueTraits<T>::kind) {
+            r.template reset<T>();
+            auto& val = r.template wref<T>();
+            is >> val;
+        } else {
+            getFromStream<Ref, std::tuple<Ts...> >::get(is, r, kind);
+        }
+    }
+};
+}
+
+I::OStream& operator<< (I::OStream& os, const cv::detail::VectorRef& ref)
+{
+    os << ref.getKind();
+    putToStream<cv::detail::VectorRef, cv::detail::GOpaqueTraitsArrayTypes>::put(os, ref);
     return os;
 }
-I::IStream& operator >> (I::IStream& is, cv::detail::VectorRef &)
+I::IStream& operator >> (I::IStream& is, cv::detail::VectorRef& ref)
 {
-    GAPI_Assert(false && "Serialization: Unsupported >> for cv::detail::VectorRef &");
+    cv::detail::OpaqueKind kind;
+    is >> kind;
+    getFromStream<cv::detail::VectorRef, cv::detail::GOpaqueTraitsArrayTypes>::get(is, ref, kind);
     return is;
 }
 
-I::OStream& operator<< (I::OStream& os, const cv::detail::OpaqueRef &)
+I::OStream& operator<< (I::OStream& os, const cv::detail::OpaqueRef& ref)
 {
-    GAPI_Assert(false && "Serialization: Unsupported << for cv::detail::OpaqueRef &");
+    os << ref.getKind();
+    putToStream<cv::detail::OpaqueRef, cv::detail::GOpaqueTraitsOpaqueTypes>::put(os, ref);
     return os;
 }
-I::IStream& operator >> (I::IStream& is, cv::detail::OpaqueRef &)
+I::IStream& operator >> (I::IStream& is, cv::detail::OpaqueRef& ref)
 {
-    GAPI_Assert(false && "Serialization: Unsupported >> for cv::detail::OpaqueRef &");
+    cv::detail::OpaqueKind kind;
+    is >> kind;
+    getFromStream<cv::detail::OpaqueRef, cv::detail::GOpaqueTraitsOpaqueTypes>::get(is, ref, kind);
     return is;
 }
 // Enums and structures
@@ -350,7 +410,6 @@ I::IStream& operator>> (I::IStream& is, cv::gimpl::Data::Storage &s) {
     return get_enum<cv::gimpl::Data::Storage>(is, s);
 }
 
-
 I::OStream& operator<< (I::OStream& os, const cv::GArg &arg) {
     // Only GOBJREF and OPAQUE_VAL kinds can be serialized/deserialized
     GAPI_Assert(   arg.kind == cv::detail::ArgKind::OPAQUE_VAL
@@ -376,6 +435,7 @@ I::OStream& operator<< (I::OStream& os, const cv::GArg &arg) {
     }
     return os;
 }
+
 I::IStream& operator>> (I::IStream& is, cv::GArg &arg) {
     is >> arg.kind >> arg.opaque_kind;
 
@@ -447,12 +507,50 @@ I::IStream& operator>> (I::IStream& is, cv::gimpl::Op &op) {
 I::OStream& operator<< (I::OStream& os, const cv::gimpl::Data &d) {
     // FIXME: HostCtor is not stored here!!
     // FIXME: Storage may be incorrect for subgraph-to-graph process
-    return os << d.shape << d.rc << d.meta << d.storage;
+    return os << d.shape << d.rc << d.meta << d.storage << d.kind;
 }
+
+namespace
+{
+template<typename Ref, typename T, typename... Ts>
+struct initCtor;
+
+template<typename Ref>
+struct initCtor<Ref, std::tuple<>>
+{
+    static void init(cv::gimpl::Data&)
+    {
+        GAPI_Assert(false && "Unsupported type for GArray/GOpaque deserialization");
+    }
+};
+
+template<typename Ref, typename T, typename... Ts>
+struct initCtor<Ref, std::tuple<T, Ts...>>
+{
+    static void init(cv::gimpl::Data& d) {
+        if (d.kind == cv::detail::GOpaqueTraits<T>::kind) {
+            static std::function<void(Ref&)> ctor = [](Ref& ref){ref.template reset<T>();};
+            d.ctor = ctor;
+        } else {
+            initCtor<Ref, std::tuple<Ts...> >::init(d);
+        }
+    }
+};
+} // anonymous namespace
+
 I::IStream& operator>> (I::IStream& is, cv::gimpl::Data &d) {
     // FIXME: HostCtor is not stored here!!
     // FIXME: Storage may be incorrect for subgraph-to-graph process
-    return is >> d.shape >> d.rc >> d.meta >> d.storage;
+    is >> d.shape >> d.rc >> d.meta >> d.storage >> d.kind;
+    if (d.shape == cv::GShape::GARRAY)
+    {
+        initCtor<cv::detail::VectorRef, cv::detail::GOpaqueTraitsArrayTypes>::init(d);
+    }
+    else if (d.shape == cv::GShape::GOPAQUE)
+    {
+        initCtor<cv::detail::OpaqueRef, cv::detail::GOpaqueTraitsOpaqueTypes>::init(d);
+    }
+    return is;
 }
 
 
@@ -478,6 +576,14 @@ void serialize( I::OStream& os
               , const ade::Graph &g
               , const std::vector<ade::NodeHandle> &nodes) {
     cv::gimpl::GModel::ConstGraph cg(g);
+    serialize(os, g, cg.metadata().get<cv::gimpl::Protocol>(), nodes);
+}
+
+void serialize( I::OStream& os
+              , const ade::Graph &g
+              , const cv::gimpl::Protocol &p
+              , const std::vector<ade::NodeHandle> &nodes) {
+    cv::gimpl::GModel::ConstGraph cg(g);
     GSerialized s;
     for (auto &nh : nodes) {
         switch (cg.metadata(nh).get<NodeType>().t)
@@ -488,7 +594,7 @@ void serialize( I::OStream& os
         }
     }
     s.m_counter = cg.metadata().get<cv::gimpl::DataObjectCounter>();
-    s.m_proto   = cg.metadata().get<cv::gimpl::Protocol>();
+    s.m_proto   = p;
     os << s.m_ops << s.m_datas << s.m_counter << s.m_proto;
 }
 
index a7b8537..90169f6 100644 (file)
@@ -121,7 +121,6 @@ GAPI_EXPORTS I::IStream& operator>> (I::IStream& is,       cv::GArg &arg);
 //I::OStream& operator<< (I::OStream& os, const cv::GRunArg &arg);
 //I::IStream& operator>> (I::IStream& is, cv::GRunArg &arg);
 
-
 GAPI_EXPORTS I::OStream& operator<< (I::OStream& os, const cv::GKernel &k);
 GAPI_EXPORTS I::IStream& operator>> (I::IStream& is,       cv::GKernel &k);
 
@@ -167,6 +166,14 @@ GAPI_EXPORTS void serialize( I::OStream& os
                            , const ade::Graph &g
                            , const std::vector<ade::NodeHandle> &nodes);
 
+// The top-level serialization routine.
+// Note it is just a single function which takes a GModel and a list of nodes
+// and writes the data to the stream (recursively)
+GAPI_EXPORTS void serialize( I::OStream& os
+                           , const ade::Graph &g
+                           , const cv::gimpl::Protocol &p
+                           , const std::vector<ade::NodeHandle> &nodes);
+
 // The top-level deserialization routineS.
 // Unfortunately the deserialization is a two-step process:
 // 1. First we decode a stream into some intermediate representation
index 06c2510..780c0e9 100644 (file)
@@ -194,7 +194,7 @@ void cv::gimpl::GCPUExecutable::run(std::vector<InObj>  &&input_objs,
     {
         const auto &desc = gm.metadata(nh).get<Data>();
 
-        if (   desc.storage == Data::Storage::INTERNAL
+        if (   desc.storage == Data::Storage::INTERNAL               // FIXME: to reconsider
             && !util::holds_alternative<util::monostate>(desc.ctor))
         {
             // FIXME: Note that compile-time constant data objects (like
index 227d393..df4ffb1 100644 (file)
@@ -614,7 +614,7 @@ struct InferList2: public cv::detail::KernelTag {
             GAPI_Assert(util::holds_alternative<cv::GArrayDesc>(mm)
                         && "Non-array inputs are not supported");
 
-            if (op.k.inSpecs[idx] == cv::detail::ArgSpec::RECT) {
+            if (op.k.inKinds[idx] == cv::detail::OpaqueKind::CV_RECT) {
                 // This is a cv::Rect -- configure the IE preprocessing
                 ii->setPrecision(toIE(meta_0.depth));
                 ii->getPreProcess().setResizeAlgorithm(IE::RESIZE_BILINEAR);
@@ -622,7 +622,7 @@ struct InferList2: public cv::detail::KernelTag {
                 // This is a cv::GMat (equals to: cv::Mat)
                 // Just validate that it is really the type
                 // (other types are prohibited here)
-                GAPI_Assert(op.k.inSpecs[idx] == cv::detail::ArgSpec::GMAT);
+                GAPI_Assert(op.k.inKinds[idx] == cv::detail::OpaqueKind::CV_MAT);
             }
             idx++; // NB: Never forget to increment the counter
         }
@@ -666,11 +666,11 @@ struct InferList2: public cv::detail::KernelTag {
                 GAPI_Assert(this_vec.size() == list_size);
                 // Prepare input {{{
                 IE::Blob::Ptr this_blob;
-                if (this_vec.spec() == cv::detail::TypeSpec::RECT) {
+                if (this_vec.getKind() == cv::detail::OpaqueKind::CV_RECT) {
                     // ROI case - create an ROI blob
                     const auto &vec = this_vec.rref<cv::Rect>();
                     this_blob = IE::make_shared_blob(blob_0, toIE(vec[list_idx]));
-                } else if (this_vec.spec() == cv::detail::TypeSpec::MAT) {
+                } else if (this_vec.getKind() == cv::detail::OpaqueKind::CV_MAT) {
                     // Mat case - create a regular blob
                     // FIXME: NOW Assume Mats are always BLOBS (not
                     // images)
index cbeaf81..39dc1da 100644 (file)
@@ -2,7 +2,7 @@
 // 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 Intel Corporation
+// Copyright (C) 2018-2020 Intel Corporation
 
 
 #include "precomp.hpp"
@@ -54,7 +54,7 @@ ade::NodeHandle GModel::mkDataNode(GModel::Graph &g, const GOrigin& origin)
     // associated host-type constructor (e.g. when the array is
     // somewhere in the middle of the graph).
     auto ctor_copy = origin.ctor;
-    g.metadata(data_h).set(Data{origin.shape, id, meta, ctor_copy, storage});
+    g.metadata(data_h).set(Data{origin.shape, id, meta, ctor_copy, origin.kind, storage});
     return data_h;
 }
 
@@ -67,8 +67,9 @@ ade::NodeHandle GModel::mkDataNode(GModel::Graph &g, const GShape shape)
     GMetaArg meta;
     HostCtor ctor;
     Data::Storage storage = Data::Storage::INTERNAL; // By default, all objects are marked INTERNAL
+    cv::detail::OpaqueKind kind = cv::detail::OpaqueKind::CV_UNKNOWN;
 
-    g.metadata(data_h).set(Data{shape, id, meta, ctor, storage});
+    g.metadata(data_h).set(Data{shape, id, meta, ctor, kind, storage});
     return data_h;
 }
 
index 1b16079..8f78ba4 100644 (file)
@@ -2,7 +2,7 @@
 // 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 Intel Corporation
+// Copyright (C) 2018-2020 Intel Corporation
 
 
 #ifndef OPENCV_GAPI_GMODEL_HPP
@@ -26,6 +26,7 @@
 
 #include <opencv2/gapi/garg.hpp>
 #include <opencv2/gapi/gkernel.hpp>
+#include <opencv2/gapi/gcommon.hpp>
 
 #include "compiler/gobjref.hpp"
 #include "compiler/gislandmodel.hpp"
@@ -71,6 +72,7 @@ struct Data
     int      rc;
     GMetaArg meta;
     HostCtor ctor;  // T-specific helper to deal with unknown types in our code
+    cv::detail::OpaqueKind kind; // FIXME: is needed to store GArray/GOpaque type
     // FIXME: Why rc+shape+meta is not represented as RcDesc here?
 
     enum class Storage: int
index c53c7b2..87e9ab5 100644 (file)
@@ -2,7 +2,7 @@
 // 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 Intel Corporation
+// Copyright (C) 2018-2020 Intel Corporation
 
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -139,7 +139,7 @@ cv::gimpl::Unrolled cv::gimpl::unrollExpr(const GProtoArgs &ins,
                     std::size_t port  = ade::util::index(it);
                     GShape shape      = ade::util::value(it);
 
-                    GOrigin org { shape, node, port};
+                    GOrigin org { shape, node, port, {}, origin.kind };
                     origins.insert(org);
                 }
 
index 3387070..acbb64b 100644 (file)
@@ -55,7 +55,6 @@ namespace detail
     template<> struct GTypeTraits<cv::gimpl::RcDesc>
     {
         static constexpr const ArgKind kind = ArgKind::GOBJREF;
-        static constexpr const ArgSpec spec = ArgSpec::OPAQUE_SPEC;
     };
 }
 
index 40c6f9a..51d4c88 100644 (file)
@@ -2,7 +2,7 @@
 // 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 Intel Corporation
+// Copyright (C) 2018-2020 Intel Corporation
 
 
 #include "precomp.hpp"
@@ -94,18 +94,21 @@ void cv::gimpl::passes::inferMeta(ade::passes::PassContext &ctx, bool meta_is_in
                 GAPI_Assert(gr.metadata(output_nh).get<NodeType>().t == NodeType::DATA);
 
                 auto       &output_meta = gr.metadata(output_nh).get<Data>().meta;
-                if (!meta_is_initialized && !util::holds_alternative<util::monostate>(output_meta))
-                {
-                    GAPI_LOG_INFO(NULL,
-                                  "!!! Output object has an initialized meta - "
-                                  "how it is possible today?" << std::endl; );
-                    if (output_meta != out_metas.at(output_port))
-                    {
-                      util::throw_error(std::logic_error("Fatal: meta mismatch"));
-                        // FIXME: New exception type?
-                        // FIXME: More details!
-                    }
-                }
+
+                cv::util::suppress_unused_warning(meta_is_initialized);
+                // FIXME: calling compile() with meta the second time when cannot reshape will lead to error below
+                //if (!meta_is_initialized && !util::holds_alternative<util::monostate>(output_meta))
+                //{
+                //    GAPI_LOG_INFO(NULL,
+                //                  "!!! Output object has an initialized meta - "
+                //                  "how it is possible today?" << std::endl; );
+                //    if (output_meta != out_metas.at(output_port))
+                //    {
+                //      util::throw_error(std::logic_error("Fatal: meta mismatch"));
+                //        // FIXME: New exception type?
+                //        // FIXME: More details!
+                //    }
+                //}
                 // Store meta in graph
                 output_meta = out_metas.at(output_port);
             }
index a109bb5..b6f4a6e 100644 (file)
@@ -188,18 +188,38 @@ TEST(GArray_VectorRef, TestMov)
     EXPECT_EQ(V{}, vtest);
 }
 
-TEST(GArray_VectorRef, Spec)
+TEST(GArray_VectorRef, Kind)
 {
     cv::detail::VectorRef v1(std::vector<cv::Rect>{});
-    EXPECT_EQ(cv::detail::TypeSpec::RECT, v1.spec());
+    EXPECT_EQ(cv::detail::OpaqueKind::CV_RECT, v1.getKind());
 
     cv::detail::VectorRef v2(std::vector<cv::Mat>{});
-    EXPECT_EQ(cv::detail::TypeSpec::MAT,  v2.spec());
+    EXPECT_EQ(cv::detail::OpaqueKind::CV_MAT,  v2.getKind());
 
     cv::detail::VectorRef v3(std::vector<int>{});
-    EXPECT_EQ(cv::detail::TypeSpec::OPAQUE_SPEC, v3.spec());
+    EXPECT_EQ(cv::detail::OpaqueKind::CV_INT, v3.getKind());
 
-    cv::detail::VectorRef v4(std::vector<std::string>{});
-    EXPECT_EQ(cv::detail::TypeSpec::OPAQUE_SPEC, v4.spec());
+    cv::detail::VectorRef v4(std::vector<double>{});
+    EXPECT_EQ(cv::detail::OpaqueKind::CV_DOUBLE, v4.getKind());
+
+    cv::detail::VectorRef v5(std::vector<cv::Scalar>{});
+    EXPECT_EQ(cv::detail::OpaqueKind::CV_SCALAR, v5.getKind());
+
+    cv::detail::VectorRef v6(std::vector<cv::Point>{});
+    EXPECT_EQ(cv::detail::OpaqueKind::CV_POINT, v6.getKind());
+
+    cv::detail::VectorRef v7(std::vector<cv::Size>{});
+    EXPECT_EQ(cv::detail::OpaqueKind::CV_SIZE, v7.getKind());
+
+    cv::detail::VectorRef v8(std::vector<std::string>{});
+    EXPECT_EQ(cv::detail::OpaqueKind::CV_UNKNOWN, v8.getKind());
+}
+
+TEST(GArray_VectorRef, TestRvalue)
+{
+    // Warning: this test is testing some not-very-public APIs
+    cv::detail::VectorRef vref(std::vector<int>{3, 5, -4});
+    auto v = std::vector<int>{3, 5, -4};
+    EXPECT_EQ(vref.rref<int>(), v);
 }
 } // namespace opencv_test
index 0623d2e..6a5cb1a 100644 (file)
@@ -214,4 +214,25 @@ TEST(GOpaque_OpaqueRef, TestMov)
     EXPECT_EQ(test, ref.rref<I>());         // ref = test
     EXPECT_NE(test, mov.rref<I>());         // ref lost the data
 }
+
+TEST(GOpaque_OpaqueRef, Kind)
+{
+    cv::detail::OpaqueRef v1(cv::Rect{});
+    EXPECT_EQ(cv::detail::OpaqueKind::CV_RECT, v1.getKind());
+
+    cv::detail::OpaqueRef v3(int{});
+    EXPECT_EQ(cv::detail::OpaqueKind::CV_INT, v3.getKind());
+
+    cv::detail::OpaqueRef v4(double{});
+    EXPECT_EQ(cv::detail::OpaqueKind::CV_DOUBLE, v4.getKind());
+
+    cv::detail::OpaqueRef v6(cv::Point{});
+    EXPECT_EQ(cv::detail::OpaqueKind::CV_POINT, v6.getKind());
+
+    cv::detail::OpaqueRef v7(cv::Size{});
+    EXPECT_EQ(cv::detail::OpaqueKind::CV_SIZE, v7.getKind());
+
+    cv::detail::OpaqueRef v8(std::string{});
+    EXPECT_EQ(cv::detail::OpaqueKind::CV_UNKNOWN, v8.getKind());
+}
 } // namespace opencv_test
index 5bb9024..7c596df 100644 (file)
@@ -76,61 +76,6 @@ TYPED_TEST(GArgKind, RValue)
     EXPECT_EQ(TestFixture::Kind, arg.kind);
 }
 
-// Repeat the same for Spec
-
-template<class T, cv::detail::ArgSpec Exp>
-struct ExpectedS
-{
-    using type = T;
-    static const constexpr cv::detail::ArgSpec spec = Exp;
-};
-
-template<typename T>
-struct ArgSpec: public ::testing::Test
-{
-    using Type = typename T::type;
-    const cv::detail::ArgSpec Spec = T::spec;
-};
-
-using Arg_Spec_Types = ::testing::Types
-   <
-  // G-API types
-     ExpectedS<cv::GMat,                 cv::detail::ArgSpec::OPAQUE_SPEC>
-   , ExpectedS<cv::GMatP,                cv::detail::ArgSpec::OPAQUE_SPEC>
-   , ExpectedS<cv::GFrame,               cv::detail::ArgSpec::OPAQUE_SPEC>
-   , ExpectedS<cv::GScalar,              cv::detail::ArgSpec::OPAQUE_SPEC>
-   , ExpectedS<cv::GArray<int>,          cv::detail::ArgSpec::OPAQUE_SPEC>
-   , ExpectedS<cv::GArray<float>,        cv::detail::ArgSpec::OPAQUE_SPEC>
-   , ExpectedS<cv::GArray<cv::Point>,    cv::detail::ArgSpec::OPAQUE_SPEC>
-   , ExpectedS<cv::GArray<cv::Rect>,     cv::detail::ArgSpec::RECT>
-   , ExpectedS<cv::GArray<cv::GMat>,     cv::detail::ArgSpec::GMAT>
-   , ExpectedS<cv::GOpaque<int>,         cv::detail::ArgSpec::OPAQUE_SPEC>
-   , ExpectedS<cv::GOpaque<float>,       cv::detail::ArgSpec::OPAQUE_SPEC>
-   , ExpectedS<cv::GOpaque<cv::Point>,   cv::detail::ArgSpec::OPAQUE_SPEC>
-   , ExpectedS<cv::GOpaque<cv::Rect>,    cv::detail::ArgSpec::RECT>
-// FIXME: causes internal conflicts in GOpaque/descr_of
-// , ExpectedS<cv::GOpaque<cv::Mat>,     cv::detail::ArgSpec::GMAT>
-
- // Built-in types
-   , ExpectedS<int,                      cv::detail::ArgSpec::OPAQUE_SPEC>
-   , ExpectedS<float,                    cv::detail::ArgSpec::OPAQUE_SPEC>
-   , ExpectedS<int*,                     cv::detail::ArgSpec::OPAQUE_SPEC>
-   , ExpectedS<cv::Point,                cv::detail::ArgSpec::OPAQUE_SPEC>
-   , ExpectedS<std::string,              cv::detail::ArgSpec::OPAQUE_SPEC>
-   , ExpectedS<cv::Mat,                  cv::detail::ArgSpec::OPAQUE_SPEC>
-   , ExpectedS<std::vector<int>,         cv::detail::ArgSpec::OPAQUE_SPEC>
-   , ExpectedS<std::vector<cv::Point>,   cv::detail::ArgSpec::OPAQUE_SPEC>
-   >;
-
-TYPED_TEST_CASE(ArgSpec, Arg_Spec_Types);
-
-TYPED_TEST(ArgSpec, Basic)
-{
-    const auto this_spec = cv::detail::GTypeTraits<typename TestFixture::Type>::spec;
-    EXPECT_EQ(TestFixture::Spec, this_spec);
-}
-
-// }}
 ////////////////////////////////////////////////////////////////////////////////
 
 TEST(GArg, HasWrap)
@@ -170,6 +115,4 @@ TEST(GArg, GOpaqueU)
     cv::GArg arg2 = cv::GArg(cv::GOpaque<cv::Point>());
     EXPECT_NO_THROW(arg2.get<cv::detail::GOpaqueU>());
 }
-
-
 } // namespace opencv_test
index a97fc35..f6543e5 100644 (file)
@@ -10,6 +10,7 @@
 #include <ade/util/zip_range.hpp>   // util::indexed
 
 #include <opencv2/gapi/gkernel.hpp>
+#include <opencv2/gapi/gcommon.hpp>
 #include "compiler/gmodelbuilder.hpp"
 #include "compiler/gmodel.hpp" // RcDesc, GModel::init
 
@@ -27,8 +28,8 @@ namespace
         return cv::GCall(cv::GKernel{ "gapi.test.unaryop"
                                     , ""
                                     , nullptr
-                                    , { D::ArgSpec::OPAQUE_SPEC }
-                                    , { GShape::GMAT } }).pass(m).yield(0);
+                                    , { GShape::GMAT }
+                                    , { D::OpaqueKind::CV_UNKNOWN } }).pass(m).yield(0);
     }
 
     cv::GMat binaryOp(cv::GMat m1, cv::GMat m2)
@@ -36,8 +37,8 @@ namespace
         return cv::GCall(cv::GKernel{ "gapi.test.binaryOp"
                                     , ""
                                     , nullptr
-                                    , { D::ArgSpec::OPAQUE_SPEC, D::ArgSpec::OPAQUE_SPEC }
-                                    , { GShape::GMAT } }).pass(m1, m2).yield(0);
+                                    , { GShape::GMAT }
+                                    , { D::OpaqueKind::CV_UNKNOWN, D::OpaqueKind::CV_UNKNOWN } }).pass(m1, m2).yield(0);
     }
 
     std::vector<ade::NodeHandle> collectOperations(const cv::gimpl::GModel::Graph& gr)
index 00ee10f..561fcb2 100644 (file)
@@ -23,6 +23,21 @@ private:
     std::vector<char> m_buffer;
 };
 
+namespace
+{
+    template<typename T>
+    bool operator==(const cv::detail::VectorRef& a, const cv::detail::VectorRef& b)
+    {
+        return a.rref<T>() == b.rref<T>();
+    }
+
+    template<typename T>
+    bool operator==(const cv::detail::OpaqueRef& a, const cv::detail::OpaqueRef& b)
+    {
+        return a.rref<T>() == b.rref<T>();
+    }
+}
+
 TEST_F(S11N_Basic, Test_int_pos) {
     int x = 42;
     put(x);
@@ -213,6 +228,60 @@ TEST_F(S11N_Basic, Test_RunArgs_Scalar) {
     EXPECT_EQ(scalar2, out_scalar2);
 }
 
+TEST_F(S11N_Basic, Test_RunArg_Opaque) {
+    auto op = cv::detail::OpaqueRef(42);
+    auto v = cv::GRunArg{ op };
+    put(v);
+    cv::GRunArg out_v = get<cv::GRunArg>();
+    cv::detail::OpaqueRef out_op = cv::util::get<cv::detail::OpaqueRef>(out_v);
+    EXPECT_TRUE(operator==<int>(op, out_op));
+}
+
+TEST_F(S11N_Basic, Test_RunArgs_Opaque) {
+    cv::detail::OpaqueRef op1 = cv::detail::OpaqueRef(cv::Point(1, 2));
+    cv::detail::OpaqueRef op2 = cv::detail::OpaqueRef(cv::Size(12, 21));
+    GRunArgs v;
+    v.resize(2);
+    v[0] = cv::GRunArg{ op1 };
+    v[1] = cv::GRunArg{ op2 };
+    put(v);
+    cv::GRunArgs out_v = get<cv::GRunArgs>();
+    cv::detail::OpaqueRef out_op1 = cv::util::get<cv::detail::OpaqueRef>(out_v[0]);
+    cv::detail::OpaqueRef out_op2 = cv::util::get<cv::detail::OpaqueRef>(out_v[1]);
+    EXPECT_TRUE(operator==<cv::Point>(op1, out_op1));
+    EXPECT_TRUE(operator==<cv::Size>(op2, out_op2));
+}
+
+TEST_F(S11N_Basic, Test_RunArg_Array) {
+    auto op = cv::detail::VectorRef(std::vector<cv::Mat>{cv::Mat::eye(3, 3, CV_8UC1), cv::Mat::zeros(5, 5, CV_8UC3)});
+
+    auto v = cv::GRunArg{ op };
+    put(v);
+    cv::GRunArg out_v = get<cv::GRunArg>();
+    cv::detail::VectorRef out_op = cv::util::get<cv::detail::VectorRef>(out_v);
+    auto vec1 = op.rref<cv::Mat>();
+    auto vec2 = out_op.rref<cv::Mat>();
+    EXPECT_EQ(0, cv::norm(vec1[0], vec2[0], cv::NORM_INF));
+    EXPECT_EQ(0, cv::norm(vec1[1], vec2[1], cv::NORM_INF));
+}
+
+TEST_F(S11N_Basic, Test_RunArgs_Array) {
+    auto vec_sc = std::vector<cv::Scalar>{cv::Scalar(11), cv::Scalar(31)};
+    auto vec_d = std::vector<double>{0.4, 1.0, 123.55, 22.08};
+    cv::detail::VectorRef op1 = cv::detail::VectorRef(vec_sc);
+    cv::detail::VectorRef op2 = cv::detail::VectorRef(vec_d);
+    GRunArgs v;
+    v.resize(2);
+    v[0] = cv::GRunArg{ op1 };
+    v[1] = cv::GRunArg{ op2 };
+    put(v);
+    cv::GRunArgs out_v = get<cv::GRunArgs>();
+    cv::detail::VectorRef out_op1 = cv::util::get<cv::detail::VectorRef>(out_v[0]);
+    cv::detail::VectorRef out_op2 = cv::util::get<cv::detail::VectorRef>(out_v[1]);
+    EXPECT_TRUE(operator==<cv::Scalar>(op1, out_op1));
+    EXPECT_TRUE(operator==<double>(op2, out_op2));
+}
+
 TEST_F(S11N_Basic, Test_RunArgs_MatScalar) {
     cv::Mat mat = cv::Mat::eye(cv::Size(64, 64), CV_8UC3);
     cv::Scalar scalar = cv::Scalar(128, 33, 53);
@@ -254,7 +323,6 @@ TEST_F(S11N_Basic, Test_Bind_RunArgs_MatScalar) {
     v[0] = cv::GRunArg{ mat };
     v[1] = cv::GRunArg{ scalar };
     GRunArgsP output = cv::gapi::bind(v);
-    std::cout << "output size  " <<  output.size() << std::endl;
     unsigned int i = 0;
     for (auto it : output)
     {
index 89956bf..930d996 100644 (file)
@@ -282,4 +282,206 @@ TEST(S11N, Pipeline_CustomRGB2YUV)
     }
 }
 
+namespace ThisTest
+{
+    using GOpBool = GOpaque<bool>;
+    using GOpInt = GOpaque<int>;
+    using GOpDouble = GOpaque<double>;
+    using GOpPoint = GOpaque<cv::Point>;
+    using GOpSize = GOpaque<cv::Size>;
+    using GOpRect = GOpaque<cv::Rect>;
+
+    using GOpOut = std::tuple<GOpPoint, GOpSize, GOpRect>;
+
+    G_TYPED_KERNEL_M(OpGenerate, <GOpOut(GOpBool, GOpInt, GOpDouble)>, "test.s11n.gopaque")
+    {
+        static std::tuple<GOpaqueDesc, GOpaqueDesc, GOpaqueDesc> outMeta(const GOpaqueDesc&, const GOpaqueDesc&, const GOpaqueDesc&) {
+            return std::make_tuple(empty_gopaque_desc(), empty_gopaque_desc(), empty_gopaque_desc());
+        }
+    };
+
+    GAPI_OCV_KERNEL(OCVOpGenerate, OpGenerate)
+    {
+        static void run(const bool& b, const int& i, const double& d,
+                        cv::Point& p, cv::Size& s, cv::Rect& r)
+        {
+            p = cv::Point(i, i*2);
+            s = b ? cv::Size(42, 42) : cv::Size(7, 7);
+            int ii = static_cast<int>(d);
+            r = cv::Rect(ii, ii, ii, ii);
+        }
+    };
+
+    using GArrInt = GArray<int>;
+    using GArrDouble = GArray<double>;
+    using GArrPoint = GArray<cv::Point>;
+    using GArrSize = GArray<cv::Size>;
+    using GArrRect = GArray<cv::Rect>;
+    using GArrMat = GArray<cv::Mat>;
+    using GArrScalar = GArray<cv::Scalar>;
+
+    using GArrOut = std::tuple<GArrPoint, GArrSize, GArrRect, GArrMat>;
+
+    G_TYPED_KERNEL_M(ArrGenerate, <GArrOut(GArrInt, GArrInt, GArrDouble, GArrScalar)>, "test.s11n.garray")
+    {
+        static std::tuple<GArrayDesc, GArrayDesc, GArrayDesc, GArrayDesc> outMeta(const GArrayDesc&, const GArrayDesc&,
+                                                                                  const GArrayDesc&, const GArrayDesc&) {
+            return std::make_tuple(empty_array_desc(), empty_array_desc(), empty_array_desc(), empty_array_desc());
+        }
+    };
+
+    GAPI_OCV_KERNEL(OCVArrGenerate, ArrGenerate)
+    {
+        static void run(const std::vector<int>& b, const std::vector<int>& i,
+                        const std::vector<double>& d, const std::vector<cv::Scalar>& sc,
+                        std::vector<cv::Point>& p, std::vector<cv::Size>& s,
+                        std::vector<cv::Rect>& r, std::vector<cv::Mat>& m)
+        {
+            p.clear(); p.resize(b.size());
+            s.clear(); s.resize(b.size());
+            r.clear(); r.resize(b.size());
+            m.clear(); m.resize(b.size());
+
+            for (std::size_t idx = 0; idx < b.size(); ++idx)
+            {
+                p[idx] = cv::Point(i[idx], i[idx]*2);
+                s[idx] = b[idx] == 1 ? cv::Size(42, 42) : cv::Size(7, 7);
+                int ii = static_cast<int>(d[idx]);
+                r[idx] = cv::Rect(ii, ii, ii, ii);
+                m[idx] = cv::Mat(3, 3, CV_8UC1, sc[idx]);
+            }
+        }
+    };
+
+    G_TYPED_KERNEL_M(OpArrK1, <std::tuple<GArrInt,GOpSize>(GOpInt, GArrSize)>, "test.s11n.oparrk1")
+    {
+        static std::tuple<GArrayDesc, GOpaqueDesc> outMeta(const GOpaqueDesc&, const GArrayDesc&) {
+            return std::make_tuple(empty_array_desc(), empty_gopaque_desc());
+        }
+    };
+
+    GAPI_OCV_KERNEL(OCVOpArrK1, OpArrK1)
+    {
+        static void run(const int& i, const std::vector<cv::Size>& vs,
+                        std::vector<int>& vi, cv::Size& s)
+        {
+            vi.clear(); vi.resize(vs.size());
+            s = cv::Size(i, i);
+            for (std::size_t idx = 0; idx < vs.size(); ++ idx)
+                vi[idx] = vs[idx].area();
+        }
+    };
+
+    G_TYPED_KERNEL_M(OpArrK2, <std::tuple<GOpDouble,GArrPoint>(GArrInt, GOpSize)>, "test.s11n.oparrk2")
+    {
+        static std::tuple<GOpaqueDesc, GArrayDesc> outMeta(const GArrayDesc&, const GOpaqueDesc&) {
+            return std::make_tuple(empty_gopaque_desc(), empty_array_desc());
+        }
+    };
+
+    GAPI_OCV_KERNEL(OCVOpArrK2, OpArrK2)
+    {
+        static void run(const std::vector<int>& vi, const cv::Size& s,
+                        double& d, std::vector<cv::Point>& vp)
+        {
+            vp.clear(); vp.resize(vi.size());
+            d = s.area() * 1.5;
+            for (std::size_t idx = 0; idx < vi.size(); ++ idx)
+                vp[idx] = cv::Point(vi[idx], vi[idx]);
+        }
+    };
+} // namespace ThisTest
+
+TEST(S11N, Pipeline_GOpaque)
+{
+    using namespace ThisTest;
+    GOpBool in1;
+    GOpInt in2;
+    GOpDouble in3;
+
+    auto out = OpGenerate::on(in1, in2, in3);
+    cv::GComputation c(cv::GIn(in1, in2, in3), cv::GOut(std::get<0>(out), std::get<1>(out), std::get<2>(out)));
+
+    auto p = cv::gapi::serialize(c);
+    auto dc = cv::gapi::deserialize<cv::GComputation>(p);
+
+    bool b = true;
+    int i = 33;
+    double d = 128.7;
+    cv::Point pp;
+    cv::Size s;
+    cv::Rect r;
+    dc.apply(cv::gin(b, i, d), cv::gout(pp, s, r), cv::compile_args(cv::gapi::kernels<OCVOpGenerate>()));
+
+    EXPECT_EQ(pp, cv::Point(i, i*2));
+    EXPECT_EQ(s, cv::Size(42, 42));
+    int ii = static_cast<int>(d);
+    EXPECT_EQ(r, cv::Rect(ii, ii, ii, ii));
+}
+
+TEST(S11N, Pipeline_GArray)
+{
+    using namespace ThisTest;
+    GArrInt in1, in2;
+    GArrDouble in3;
+    GArrScalar in4;
+
+    auto out = ArrGenerate::on(in1, in2, in3, in4);
+    cv::GComputation c(cv::GIn(in1, in2, in3, in4),
+                       cv::GOut(std::get<0>(out), std::get<1>(out),
+                                std::get<2>(out), std::get<3>(out)));
+
+    auto p = cv::gapi::serialize(c);
+    auto dc = cv::gapi::deserialize<cv::GComputation>(p);
+
+    std::vector<int> b {1, 0, -1};
+    std::vector<int> i {3, 0 , 59};
+    std::vector<double> d {0.7, 120.5, 44.14};
+    std::vector<cv::Scalar> sc {cv::Scalar::all(10), cv::Scalar::all(15), cv::Scalar::all(99)};
+    std::vector<cv::Point> pp;
+    std::vector<cv::Size> s;
+    std::vector<cv::Rect> r;
+    std::vector<cv::Mat> m;
+    dc.apply(cv::gin(b, i, d, sc), cv::gout(pp, s, r, m), cv::compile_args(cv::gapi::kernels<OCVArrGenerate>()));
+
+    for (std::size_t idx = 0; idx < b.size(); ++idx)
+    {
+        EXPECT_EQ(pp[idx], cv::Point(i[idx], i[idx]*2));
+        EXPECT_EQ(s[idx], b[idx] == 1 ? cv::Size(42, 42) : cv::Size(7, 7));
+        int ii = static_cast<int>(d[idx]);
+        EXPECT_EQ(r[idx], cv::Rect(ii, ii, ii, ii));
+    }
+}
+
+TEST(S11N, Pipeline_GArray_GOpaque_Multinode)
+{
+    using namespace ThisTest;
+    GOpInt in1;
+    GArrSize in2;
+
+    auto tmp = OpArrK1::on(in1, in2);
+    auto out = OpArrK2::on(std::get<0>(tmp), std::get<1>(tmp));
+
+    cv::GComputation c(cv::GIn(in1, in2),
+                       cv::GOut(std::get<0>(out), std::get<1>(out)));
+
+    auto p = cv::gapi::serialize(c);
+    auto dc = cv::gapi::deserialize<cv::GComputation>(p);
+
+    int i = 42;
+    std::vector<cv::Size> s{cv::Size(11, 22), cv::Size(13, 18)};
+    double d;
+    std::vector<cv::Point> pp;
+
+    dc.apply(cv::gin(i, s), cv::gout(d, pp), cv::compile_args(cv::gapi::kernels<OCVOpArrK1, OCVOpArrK2>()));
+
+    auto st = cv::Size(i ,i);
+    EXPECT_EQ(d, st.area() * 1.5);
+
+    for (std::size_t idx = 0; idx < s.size(); ++idx)
+    {
+        EXPECT_EQ(pp[idx], cv::Point(s[idx].area(), s[idx].area()));
+    }
+}
+
 } // namespace opencv_test