Merge pull request #18496 from AsyaPronina:comp_args_serialization
authorAnastasiya(Asya) Pronina <anastasiya.pronina@intel.com>
Wed, 7 Oct 2020 21:48:49 +0000 (00:48 +0300)
committerGitHub <noreply@github.com>
Wed, 7 Oct 2020 21:48:49 +0000 (21:48 +0000)
Serialization && deserialization for compile arguments

* Initial stub

* Add test on serialization of a custom type

* Namespaces rework

* Fix isSupported in test struct

* Fix clang lookup issue

* Initial implementation

* Drop the isSupported flag

* Initial implementation

* Removed internal header inclusion

* Switched to public API

* Implemented serialization

* Adding desirialize: WIP

* Fixed merge errors

* Implemented

* Final polishing

* Addressed review comments and added debug throw

* Added FluidROI test

* Polishing

* Polishing

* Polishing

* Polishing

* Polishing

* Updated CMakeLists.txt

* Fixed comments

* Addressed review comments

* Removed decay from deserialize_arg

* Addressed review comments

* Removed extra inclusion

* Fixed Win64 warning

* Update gcommon.hpp

* Update serialization.cpp

* Update gcommon.hpp

* gapi: drop GAPI_EXPORTS_W_SIMPLE from GCompileArg

Co-authored-by: Smirnov Alexey <alexey.smirnov@intel.com>
Co-authored-by: AsyaPronina <155jj@mail.ru>
modules/gapi/CMakeLists.txt
modules/gapi/include/opencv2/gapi/gcommon.hpp
modules/gapi/include/opencv2/gapi/s11n.hpp
modules/gapi/include/opencv2/gapi/s11n/base.hpp [new file with mode: 0644]
modules/gapi/misc/python/shadow_gapi.hpp
modules/gapi/src/api/s11n.cpp
modules/gapi/src/backends/common/serialization.cpp
modules/gapi/src/backends/common/serialization.hpp
modules/gapi/test/cpu/gapi_ocv_stateful_kernel_tests.cpp
modules/gapi/test/s11n/gapi_s11n_tests.cpp

index 0278d93..88ddeea 100644 (file)
@@ -49,6 +49,7 @@ file(GLOB gapi_ext_hdrs
     "${CMAKE_CURRENT_LIST_DIR}/include/opencv2/${name}/ocl/*.hpp"
     "${CMAKE_CURRENT_LIST_DIR}/include/opencv2/${name}/own/*.hpp"
     "${CMAKE_CURRENT_LIST_DIR}/include/opencv2/${name}/render/*.hpp"
+    "${CMAKE_CURRENT_LIST_DIR}/include/opencv2/${name}/s11n/*.hpp"
     "${CMAKE_CURRENT_LIST_DIR}/include/opencv2/${name}/streaming/*.hpp"
     "${CMAKE_CURRENT_LIST_DIR}/include/opencv2/${name}/plaidml/*.hpp"
     "${CMAKE_CURRENT_LIST_DIR}/include/opencv2/${name}/util/*.hpp"
index e008fe4..2b260ed 100644 (file)
@@ -19,6 +19,7 @@
 #include <opencv2/gapi/own/exports.hpp>
 #include <opencv2/gapi/own/assert.hpp>
 #include <opencv2/gapi/render/render_types.hpp>
+#include <opencv2/gapi/s11n/base.hpp>
 
 namespace cv {
 
@@ -94,6 +95,15 @@ enum class GShape: int
     GFRAME,
 };
 
+namespace gapi {
+namespace s11n {
+namespace detail {
+template<typename T> struct wrap_serialize;
+} // namespace detail
+} // namespace s11n
+} // namespace gapi
+
+
 struct GCompileArg;
 
 namespace detail {
@@ -139,7 +149,7 @@ namespace detail {
  * passed in (a variadic template parameter pack) into a vector of
  * cv::GCompileArg objects.
  */
-struct GAPI_EXPORTS_W_SIMPLE GCompileArg
+struct GCompileArg
 {
 public:
     // NB: Required for pythnon bindings
@@ -151,6 +161,7 @@ public:
     template<typename T, typename std::enable_if<!detail::is_compile_arg<T>::value, int>::type = 0>
     explicit GCompileArg(T &&t)
         : tag(detail::CompileArgTag<typename std::decay<T>::type>::tag())
+        , serializeF(&cv::gapi::s11n::detail::wrap_serialize<T>::serialize)
         , arg(t)
     {
     }
@@ -165,7 +176,13 @@ public:
         return util::any_cast<T>(arg);
     }
 
+    void serialize(cv::gapi::s11n::IOStream& os) const
+    {
+        serializeF(os, *this);
+    }
+
 private:
+    std::function<void(cv::gapi::s11n::IOStream&, const GCompileArg&)> serializeF;
     util::any arg;
 };
 
@@ -198,6 +215,19 @@ inline cv::util::optional<T> getCompileArg(const cv::GCompileArgs &args)
     }
     return cv::util::optional<T>();
 }
+
+namespace s11n {
+namespace detail {
+template<typename T> struct wrap_serialize
+{
+    static void serialize(IOStream& os, const GCompileArg& arg)
+    {
+        using decayed_type = typename std::decay<T>::type;
+        S11N<decayed_type>::serialize(os, arg.get<decayed_type>());
+    }
+};
+} // namespace detail
+} // namespace s11n
 } // namespace gapi
 
 /**
index 0b61304..e8a8dbc 100644 (file)
@@ -10,6 +10,7 @@
 #include <vector>
 #include <map>
 #include <unordered_map>
+#include <opencv2/gapi/s11n/base.hpp>
 #include <opencv2/gapi/gcomputation.hpp>
 
 namespace cv {
@@ -17,14 +18,13 @@ namespace gapi {
 
 namespace detail {
     GAPI_EXPORTS cv::GComputation getGraph(const std::vector<char> &p);
-} // namespace detail
 
-namespace detail {
     GAPI_EXPORTS cv::GMetaArgs getMetaArgs(const std::vector<char> &p);
-} // namespace detail
 
-namespace detail {
     GAPI_EXPORTS cv::GRunArgs getRunArgs(const std::vector<char> &p);
+
+    template<typename... Types>
+    cv::GCompileArgs getCompileArgs(const std::vector<char> &p);
 } // namespace detail
 
 GAPI_EXPORTS std::vector<char> serialize(const cv::GComputation &c);
@@ -35,6 +35,7 @@ T deserialize(const std::vector<char> &p);
 
 //} //ananymous namespace
 
+GAPI_EXPORTS std::vector<char> serialize(const cv::GCompileArgs&);
 GAPI_EXPORTS std::vector<char> serialize(const cv::GMetaArgs&);
 GAPI_EXPORTS std::vector<char> serialize(const cv::GRunArgs&);
 
@@ -53,6 +54,11 @@ cv::GRunArgs deserialize(const std::vector<char> &p) {
     return detail::getRunArgs(p);
 }
 
+template<typename T, typename... Types> inline
+typename std::enable_if<std::is_same<T, GCompileArgs>::value, GCompileArgs>::
+type deserialize(const std::vector<char> &p) {
+    return detail::getCompileArgs<Types...>(p);
+}
 } // namespace gapi
 } // namespace cv
 
@@ -91,6 +97,10 @@ struct GAPI_EXPORTS IIStream {
     virtual IIStream& operator>> (std::string &) = 0;
 };
 
+namespace detail {
+GAPI_EXPORTS std::unique_ptr<IIStream> getInStream(const std::vector<char> &p);
+} // namespace detail
+
 ////////////////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////////////////
 // S11N operators
@@ -174,17 +184,48 @@ IIStream& operator>> (IIStream& is, std::vector<T> &ts) {
     }
     return is;
 }
+} // namespace s11n
 
-namespace detail {
-    // Will be used along with default types if possible in specific cases (compile args, etc)
-    // Note: actual implementation is defined by user
-    template<typename T>
-    struct GAPI_EXPORTS S11N {
-        static void serialize(IOStream &, const T &) {}
-        static T deserialize(IIStream &) { T t; return t; }
-    };
+namespace detail
+{
+template<typename T> struct deserialize_arg;
+
+template<> struct deserialize_arg<std::tuple<>> {
+static GCompileArg exec(cv::gapi::s11n::IIStream&, const std::string&) {
+        throw std::logic_error("Passed arg can't be deserialized!");
+    }
+};
+
+template<typename T, typename... Types>
+struct deserialize_arg<std::tuple<T, Types...>> {
+static GCompileArg exec(cv::gapi::s11n::IIStream& is, const std::string& tag) {
+    if (tag == cv::detail::CompileArgTag<T>::tag()) {
+        return GCompileArg {
+            cv::gapi::s11n::detail::S11N<T>::deserialize(is)
+        };
+    }
+
+    return deserialize_arg<std::tuple<Types...>>::exec(is, tag);
+}
+};
+
+template<typename... Types>
+cv::GCompileArgs getCompileArgs(const std::vector<char> &p) {
+    std::unique_ptr<cv::gapi::s11n::IIStream> pIs = cv::gapi::s11n::detail::getInStream(p);
+    cv::gapi::s11n::IIStream& is = *pIs;
+    cv::GCompileArgs args;
+
+    uint32_t sz = 0;
+    is >> sz;
+    for (uint32_t i = 0; i < sz; ++i) {
+        std::string tag;
+        is >> tag;
+        args.push_back(cv::gapi::detail::deserialize_arg<std::tuple<Types...>>::exec(is, tag));
+    }
+
+    return args;
+}
 } // namespace detail
-} // namespace s11n
 } // namespace gapi
 } // namespace cv
 
diff --git a/modules/gapi/include/opencv2/gapi/s11n/base.hpp b/modules/gapi/include/opencv2/gapi/s11n/base.hpp
new file mode 100644 (file)
index 0000000..6bf5d5f
--- /dev/null
@@ -0,0 +1,36 @@
+// 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) 2020 Intel Corporation
+
+#ifndef OPENCV_GAPI_S11N_BASE_HPP
+#define OPENCV_GAPI_S11N_BASE_HPP
+
+#include <opencv2/gapi/own/assert.hpp>
+
+namespace cv {
+namespace gapi {
+namespace s11n {
+struct IOStream;
+struct IIStream;
+
+namespace detail {
+// Will be used along with default types if possible in specific cases (compile args, etc)
+// Note: actual implementation is defined by user
+template<typename T>
+struct S11N {
+    static void serialize(IOStream &, const T &) {
+        GAPI_Assert(false && "No serialization routine is provided!");
+    }
+    static T deserialize(IIStream &) {
+        GAPI_Assert(false && "No deserialization routine is provided!");
+    }
+};
+
+} // namespace detail
+} // namespace s11n
+} // namespace gapi
+} // namespace cv
+
+#endif // OPENCV_GAPI_S11N_BASE_HPP
index dab083d..4f98844 100644 (file)
@@ -3,6 +3,8 @@
 
 namespace cv
 {
+   struct GAPI_EXPORTS_W_SIMPLE GCompileArg { };
+
    GAPI_EXPORTS_W GCompileArgs compile_args(gapi::GKernelPackage pkg);
 
    class GAPI_EXPORTS_W_SIMPLE GProtoArg { };
index 54a0850..52c276f 100644 (file)
@@ -44,6 +44,13 @@ std::vector<char> cv::gapi::serialize(const cv::GRunArgs& ra)
     return os.data();
 }
 
+std::vector<char> cv::gapi::serialize(const cv::GCompileArgs& ca)
+{
+    cv::gapi::s11n::ByteMemoryOutStream os;
+    serialize(os, ca);
+    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)
index c0b3281..ca73d29 100644 (file)
@@ -329,6 +329,13 @@ IIStream& operator>> (IIStream& is,       cv::gapi::wip::draw::Line &l) {
 
 // G-API types /////////////////////////////////////////////////////////////////
 
+IOStream& operator<< (IOStream& os, const cv::GCompileArg& arg)
+{
+    os << arg.tag;
+    arg.serialize(os);
+    return os;
+}
+
 // Stubs (empty types)
 
 IOStream& operator<< (IOStream& os, cv::util::monostate  ) {return os;}
@@ -865,6 +872,14 @@ IIStream& ByteMemoryInStream::operator>> (std::string& str) {
     return *this;
 }
 
+GAPI_EXPORTS std::unique_ptr<IIStream> detail::getInStream(const std::vector<char> &p) {
+    return std::unique_ptr<ByteMemoryInStream>(new ByteMemoryInStream(p));
+}
+
+GAPI_EXPORTS void serialize(IOStream& os, const cv::GCompileArgs &ca) {
+    os << ca;
+}
+
 GAPI_EXPORTS void serialize(IOStream& os, const cv::GMetaArgs &ma) {
     os << ma;
 }
@@ -882,7 +897,6 @@ GAPI_EXPORTS GRunArgs run_args_deserialize(IIStream& is) {
     return s;
 }
 
-
 } // namespace s11n
 } // namespace gapi
 } // namespace cv
index 4c60e71..e2aa56c 100644 (file)
@@ -40,6 +40,8 @@ struct GSerialized {
 
 // G-API types /////////////////////////////////////////////////////////////////
 
+GAPI_EXPORTS IOStream& operator<< (IOStream& os, const cv::GCompileArg& arg);
+
 GAPI_EXPORTS IOStream& operator<< (IOStream& os, cv::util::monostate  );
 GAPI_EXPORTS IIStream& operator>> (IIStream& is, cv::util::monostate &);
 
@@ -268,6 +270,11 @@ public:
     virtual IIStream& operator>> (std::string &) override;
 };
 
+namespace detail {
+GAPI_EXPORTS std::unique_ptr<IIStream> getInStream(const std::vector<char> &p);
+} // namespace detail
+
+GAPI_EXPORTS void serialize(IOStream& os, const cv::GCompileArgs &ca);
 GAPI_EXPORTS void serialize(IOStream& os, const cv::GMetaArgs &ma);
 GAPI_EXPORTS void serialize(IOStream& os, const cv::GRunArgs &ra);
 GAPI_EXPORTS GMetaArgs meta_args_deserialize(IIStream& is);
index 75ca798..fe6a1f9 100644 (file)
@@ -21,7 +21,7 @@ namespace opencv_test
     {
         std::string method;
     };
-}
+} // namespace opencv_test
 
 namespace cv
 {
@@ -31,11 +31,11 @@ namespace cv
         {
             static const char* tag()
             {
-                return "org.opencv.test..background_substractor_state_params";
+                return "org.opencv.test.background_substractor_state_params";
             }
         };
-    }
-}
+    } // namespace detail
+} // namespace cv
 
 namespace opencv_test
 {
index 10fe586..1a4faec 100644 (file)
@@ -34,6 +34,17 @@ namespace detail {
 } // namespace gapi
 } // namespace cv
 
+
+namespace cv {
+namespace detail {
+template<> struct CompileArgTag<MyCustomType> {
+    static const char* tag() {
+        return "org.opencv.test.mycustomtype";
+    }
+};
+} // namespace detail
+} // namespace cv
+
 namespace opencv_test {
 
 struct S11N_Basic: public ::testing::Test {
@@ -511,4 +522,15 @@ TEST_F(S11N_Basic, Test_Custom_Type) {
     MyCustomType new_var = cv::gapi::s11n::detail::S11N<MyCustomType>::deserialize(is);
     EXPECT_EQ(var, new_var);
 }
+
+TEST_F(S11N_Basic, Test_Custom_CompileArg) {
+    MyCustomType customVar{1248, "World", {1280, 720, 640, 480}, {{5, 32434142342}, {7, 34242432}}};
+
+    std::vector<char> sArgs = cv::gapi::serialize(cv::compile_args(customVar));
+
+    GCompileArgs dArgs = cv::gapi::deserialize<GCompileArgs, MyCustomType>(sArgs);
+
+    MyCustomType dCustomVar = cv::gapi::getCompileArg<MyCustomType>(dArgs).value();
+    EXPECT_EQ(customVar, dCustomVar);
+}
 } // namespace opencv_test