github.com/kaydxh/golang@v0.0.131/pkg/gocv/cgo/third_path/opencv4/include/opencv2/gapi/gkernel.hpp (about)

     1  // This file is part of OpenCV project.
     2  // It is subject to the license terms in the LICENSE file found in the top-level directory
     3  // of this distribution and at http://opencv.org/license.html.
     4  //
     5  // Copyright (C) 2018-2021 Intel Corporation
     6  
     7  
     8  #ifndef OPENCV_GAPI_GKERNEL_HPP
     9  #define OPENCV_GAPI_GKERNEL_HPP
    10  
    11  #include <functional>
    12  #include <iostream>
    13  #include <string>  // string
    14  #include <type_traits> // false_type, true_type
    15  #include <unordered_map> // map (for GKernelPackage)
    16  #include <utility> // tuple
    17  
    18  #include <opencv2/gapi/gcommon.hpp> // CompileArgTag
    19  #include <opencv2/gapi/util/util.hpp> // Seq
    20  #include <opencv2/gapi/gcall.hpp>
    21  #include <opencv2/gapi/garg.hpp>      // GArg
    22  #include <opencv2/gapi/gmetaarg.hpp>  // GMetaArg
    23  #include <opencv2/gapi/gtype_traits.hpp> // GTypeTraits
    24  #include <opencv2/gapi/util/compiler_hints.hpp> //suppress_unused_warning
    25  #include <opencv2/gapi/gtransform.hpp>
    26  
    27  namespace cv {
    28  
    29  struct GTypeInfo
    30  {
    31      GShape                 shape;
    32      cv::detail::OpaqueKind kind;
    33      detail::HostCtor       ctor;
    34  };
    35  
    36  using GShapes    = std::vector<GShape>;
    37  using GKinds     = std::vector<cv::detail::OpaqueKind>;
    38  using GCtors     = std::vector<detail::HostCtor>;
    39  using GTypesInfo = std::vector<GTypeInfo>;
    40  
    41  // GKernel describes kernel API to the system
    42  // FIXME: add attributes of a kernel, (e.g. number and types
    43  // of inputs, etc)
    44  struct GAPI_EXPORTS GKernel
    45  {
    46      using M = std::function<GMetaArgs(const GMetaArgs &, const GArgs &)>;
    47  
    48      std::string name;       // kernel ID, defined by its API (signature)
    49      std::string tag;        // some (implementation-specific) tag
    50      M           outMeta;    // generic adaptor to API::outMeta(...)
    51      GShapes     outShapes;  // types (shapes) kernel's outputs
    52      GKinds      inKinds;    // kinds of kernel's inputs (fixme: below)
    53      GCtors      outCtors;   // captured constructors for template output types
    54  };
    55  // TODO: It's questionable if inKinds should really be here. Instead,
    56  // this information could come from meta.
    57  
    58  // GKernelImpl describes particular kernel implementation to the system
    59  struct GAPI_EXPORTS GKernelImpl
    60  {
    61      util::any         opaque;    // backend-specific opaque info
    62      GKernel::M        outMeta;   // for deserialized graphs, the outMeta is taken here
    63  };
    64  
    65  template<typename, typename> class GKernelTypeM;
    66  
    67  namespace detail
    68  {
    69      ////////////////////////////////////////////////////////////////////////////
    70      // yield() is used in graph construction time as a generic method to obtain
    71      // lazy "return value" of G-API operations
    72      //
    73      template<typename T> struct Yield;
    74      template<> struct Yield<cv::GMat>
    75      {
    76          static inline cv::GMat yield(cv::GCall &call, int i) { return call.yield(i); }
    77      };
    78      template<> struct Yield<cv::GMatP>
    79      {
    80          static inline cv::GMatP yield(cv::GCall &call, int i) { return call.yieldP(i); }
    81      };
    82      template<> struct Yield<cv::GScalar>
    83      {
    84          static inline cv::GScalar yield(cv::GCall &call, int i) { return call.yieldScalar(i); }
    85      };
    86      template<typename U> struct Yield<cv::GArray<U> >
    87      {
    88          static inline cv::GArray<U> yield(cv::GCall &call, int i) { return call.yieldArray<U>(i); }
    89      };
    90      template<typename U> struct Yield<cv::GOpaque<U> >
    91      {
    92          static inline cv::GOpaque<U> yield(cv::GCall &call, int i) { return call.yieldOpaque<U>(i); }
    93      };
    94      template<> struct Yield<GFrame>
    95      {
    96          static inline cv::GFrame yield(cv::GCall &call, int i) { return call.yieldFrame(i); }
    97      };
    98  
    99      ////////////////////////////////////////////////////////////////////////////
   100      // Helper classes which brings outputMeta() marshalling to kernel
   101      // implementations
   102      //
   103      // 1. MetaType establishes G#Type -> G#Meta mapping between G-API dynamic
   104      //    types and its metadata descriptor types.
   105      //    This mapping is used to transform types to call outMeta() callback.
   106      template<typename T> struct MetaType;
   107      template<> struct MetaType<cv::GMat>    { using type = GMatDesc; };
   108      template<> struct MetaType<cv::GMatP>   { using type = GMatDesc; };
   109      template<> struct MetaType<cv::GFrame>  { using type = GFrameDesc; };
   110      template<> struct MetaType<cv::GScalar> { using type = GScalarDesc; };
   111      template<typename U> struct MetaType<cv::GArray<U> >  { using type = GArrayDesc; };
   112      template<typename U> struct MetaType<cv::GOpaque<U> > { using type = GOpaqueDesc; };
   113      template<typename T> struct MetaType    { using type = T; }; // opaque args passed as-is
   114      // FIXME: Move it to type traits?
   115  
   116      // 2. Hacky test based on MetaType to check if we operate on G-* type or not
   117      template<typename T> using is_nongapi_type = std::is_same<T, typename MetaType<T>::type>;
   118  
   119      // 3. Two ways to transform input arguments to its meta - for G-* and non-G* types:
   120      template<typename T>
   121      typename std::enable_if<!is_nongapi_type<T>::value, typename MetaType<T>::type>
   122      ::type get_in_meta(const GMetaArgs &in_meta, const GArgs &, int idx)
   123      {
   124          return util::get<typename MetaType<T>::type>(in_meta.at(idx));
   125      }
   126  
   127      template<typename T>
   128      typename std::enable_if<is_nongapi_type<T>::value, T>
   129      ::type get_in_meta(const GMetaArgs &, const GArgs &in_args, int idx)
   130      {
   131          return in_args.at(idx).template get<T>();
   132      }
   133  
   134      // 4. The MetaHelper itself: an entity which generates outMeta() call
   135      //    based on kernel signature, with arguments properly substituted.
   136      // 4.1 - case for multiple return values
   137      // FIXME: probably can be simplified with std::apply or analogue.
   138      template<typename, typename, typename>
   139      struct MetaHelper;
   140  
   141      template<typename K, typename... Ins, typename... Outs>
   142      struct MetaHelper<K, std::tuple<Ins...>, std::tuple<Outs...> >
   143      {
   144          template<int... IIs, int... OIs>
   145          static GMetaArgs getOutMeta_impl(const GMetaArgs &in_meta,
   146                                           const GArgs &in_args,
   147                                           detail::Seq<IIs...>,
   148                                           detail::Seq<OIs...>)
   149          {
   150              // FIXME: decay?
   151              using R   = std::tuple<typename MetaType<Outs>::type...>;
   152              const R r = K::outMeta( get_in_meta<Ins>(in_meta, in_args, IIs)... );
   153              return GMetaArgs{ GMetaArg(std::get<OIs>(r))... };
   154          }
   155          // FIXME: help users identify how outMeta must look like (via default impl w/static_assert?)
   156  
   157          static GMetaArgs getOutMeta(const GMetaArgs &in_meta,
   158                                      const GArgs &in_args)
   159          {
   160              return getOutMeta_impl(in_meta,
   161                                     in_args,
   162                                     typename detail::MkSeq<sizeof...(Ins)>::type(),
   163                                     typename detail::MkSeq<sizeof...(Outs)>::type());
   164          }
   165      };
   166  
   167      // 4.1 - case for a single return value
   168      // FIXME: How to avoid duplication here?
   169      template<typename K, typename... Ins, typename Out>
   170      struct MetaHelper<K, std::tuple<Ins...>, Out >
   171      {
   172          template<int... IIs>
   173          static GMetaArgs getOutMeta_impl(const GMetaArgs &in_meta,
   174                                           const GArgs &in_args,
   175                                           detail::Seq<IIs...>)
   176          {
   177              // FIXME: decay?
   178              using R = typename MetaType<Out>::type;
   179              const R r = K::outMeta( get_in_meta<Ins>(in_meta, in_args, IIs)... );
   180              return GMetaArgs{ GMetaArg(r) };
   181          }
   182          // FIXME: help users identify how outMeta must look like (via default impl w/static_assert?)
   183  
   184          static GMetaArgs getOutMeta(const GMetaArgs &in_meta,
   185                                      const GArgs &in_args)
   186          {
   187              return getOutMeta_impl(in_meta,
   188                                     in_args,
   189                                     typename detail::MkSeq<sizeof...(Ins)>::type());
   190          }
   191      };
   192  
   193      ////////////////////////////////////////////////////////////////////////////
   194      // Helper class to introduce tags to calls. By default there's no tag
   195      struct NoTag {
   196          static constexpr const char *tag() { return ""; }
   197      };
   198  
   199  } // namespace detail
   200  
   201  // GKernelType and GKernelTypeM are base classes which implement typed ::on()
   202  // method based on kernel signature. GKernelTypeM stands for multiple-return-value kernels
   203  //
   204  // G_TYPED_KERNEL and G_TYPED_KERNEL_M macros inherit user classes from GKernelType and
   205  // GKernelTypeM respectively.
   206  
   207  template<typename K, typename... R, typename... Args>
   208  class GKernelTypeM<K, std::function<std::tuple<R...>(Args...)> >
   209      : public detail::MetaHelper<K, std::tuple<Args...>, std::tuple<R...>>
   210      , public detail::NoTag
   211  {
   212      template<int... IIs>
   213      static std::tuple<R...> yield(cv::GCall &call, detail::Seq<IIs...>)
   214      {
   215          return std::make_tuple(detail::Yield<R>::yield(call, IIs)...);
   216      }
   217  
   218  public:
   219      using InArgs  = std::tuple<Args...>;
   220      using OutArgs = std::tuple<R...>;
   221  
   222      // TODO: Args&&... here?
   223      static std::tuple<R...> on(Args... args)
   224      {
   225          cv::GCall call(GKernel{ K::id()
   226                                , K::tag()
   227                                , &K::getOutMeta
   228                                , {detail::GTypeTraits<R>::shape...}
   229                                , {detail::GTypeTraits<Args>::op_kind...}
   230                                , {detail::GObtainCtor<R>::get()...}});
   231          call.pass(args...); // TODO: std::forward() here?
   232          return yield(call, typename detail::MkSeq<sizeof...(R)>::type());
   233      }
   234  };
   235  
   236  template<typename, typename> class GKernelType;
   237  
   238  template<typename K, typename R, typename... Args>
   239  class GKernelType<K, std::function<R(Args...)> >
   240      : public detail::MetaHelper<K, std::tuple<Args...>, R>
   241      , public detail::NoTag
   242  {
   243  public:
   244      using InArgs  = std::tuple<Args...>;
   245      using OutArgs = std::tuple<R>;
   246  
   247      static R on(Args... args)
   248      {
   249          cv::GCall call(GKernel{ K::id()
   250                                , K::tag()
   251                                , &K::getOutMeta
   252                                , {detail::GTypeTraits<R>::shape}
   253                                , {detail::GTypeTraits<Args>::op_kind...}
   254                                , {detail::GObtainCtor<R>::get()}});
   255          call.pass(args...);
   256          return detail::Yield<R>::yield(call, 0);
   257      }
   258  };
   259  
   260  namespace detail {
   261  // This tiny class eliminates the semantic difference between
   262  // GKernelType and GKernelTypeM.
   263  template<typename, typename> class KernelTypeMedium;
   264  
   265  template<typename K, typename... R, typename... Args>
   266  class KernelTypeMedium<K, std::function<std::tuple<R...>(Args...)>> :
   267      public cv::GKernelTypeM<K, std::function<std::tuple<R...>(Args...)>> {};
   268  
   269  template<typename K, typename R, typename... Args>
   270  class KernelTypeMedium<K, std::function<R(Args...)>> :
   271      public cv::GKernelType<K, std::function<R(Args...)>> {};
   272  } // namespace detail
   273  
   274  } // namespace cv
   275  
   276  
   277  // FIXME: I don't know a better way so far. Feel free to suggest one
   278  // The problem is that every typed kernel should have ::id() but body
   279  // of the class is defined by user (with outMeta, other stuff)
   280  
   281  //! @cond IGNORED
   282  #define G_ID_HELPER_CLASS(Class)  Class##IdHelper
   283  
   284  #define G_ID_HELPER_BODY(Class, Id)                                         \
   285      struct G_ID_HELPER_CLASS(Class)                                         \
   286      {                                                                       \
   287          static constexpr const char * id() {return Id;}                     \
   288      };                                                                      \
   289  //! @endcond
   290  
   291  #define GET_G_TYPED_KERNEL(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, NAME, ...) NAME
   292  #define COMBINE_SIGNATURE(...) __VA_ARGS__
   293  // Ensure correct __VA_ARGS__ expansion on Windows
   294  #define __WRAP_VAARGS(x) x
   295  
   296  /**
   297   * Helper for G_TYPED_KERNEL declares a new G-API Operation. See [Kernel API](@ref gapi_kernel_api)
   298   * for more details.
   299   *
   300   * @param Class type name for this operation.
   301   * @param API an `std::function<>`-like signature for the operation;
   302   *        return type is a single value or a tuple of multiple values.
   303   * @param Id string identifier for the operation. Must be unique.
   304   */
   305  #define G_TYPED_KERNEL_HELPER(Class, API, Id)                                               \
   306      G_ID_HELPER_BODY(Class, Id)                                                             \
   307      struct Class final: public cv::detail::KernelTypeMedium<Class, std::function API >,     \
   308                          public G_ID_HELPER_CLASS(Class)
   309  // {body} is to be defined by user
   310  
   311  #define G_TYPED_KERNEL_HELPER_2(Class, _1, _2, Id) \
   312  G_TYPED_KERNEL_HELPER(Class, COMBINE_SIGNATURE(_1, _2), Id)
   313  
   314  #define G_TYPED_KERNEL_HELPER_3(Class, _1, _2, _3, Id) \
   315  G_TYPED_KERNEL_HELPER(Class, COMBINE_SIGNATURE(_1, _2, _3), Id)
   316  
   317  #define G_TYPED_KERNEL_HELPER_4(Class, _1, _2, _3, _4, Id) \
   318  G_TYPED_KERNEL_HELPER(Class, COMBINE_SIGNATURE(_1, _2, _3, _4), Id)
   319  
   320  #define G_TYPED_KERNEL_HELPER_5(Class, _1, _2, _3, _4, _5, Id) \
   321  G_TYPED_KERNEL_HELPER(Class, COMBINE_SIGNATURE(_1, _2, _3, _4, _5), Id)
   322  
   323  #define G_TYPED_KERNEL_HELPER_6(Class, _1, _2, _3, _4, _5, _6, Id) \
   324  G_TYPED_KERNEL_HELPER(Class, COMBINE_SIGNATURE(_1, _2, _3, _4, _5, _6), Id)
   325  
   326  #define G_TYPED_KERNEL_HELPER_7(Class, _1, _2, _3, _4, _5, _6, _7, Id) \
   327  G_TYPED_KERNEL_HELPER(Class, COMBINE_SIGNATURE(_1, _2, _3, _4, _5, _6, _7), Id)
   328  
   329  #define G_TYPED_KERNEL_HELPER_8(Class, _1, _2, _3, _4, _5, _6, _7, _8, Id) \
   330  G_TYPED_KERNEL_HELPER(Class, COMBINE_SIGNATURE(_1, _2, _3, _4, _5, _6, _7, _8), Id)
   331  
   332  #define G_TYPED_KERNEL_HELPER_9(Class, _1, _2, _3, _4, _5, _6, _7, _8, _9, Id) \
   333  G_TYPED_KERNEL_HELPER(Class, COMBINE_SIGNATURE(_1, _2, _3, _4, _5, _6, _7, _8, _9), Id)
   334  
   335  #define G_TYPED_KERNEL_HELPER_10(Class, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, Id) \
   336  G_TYPED_KERNEL_HELPER(Class, COMBINE_SIGNATURE(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10), Id)
   337  
   338  /**
   339   * Declares a new G-API Operation. See [Kernel API](@ref gapi_kernel_api)
   340   * for more details.
   341   *
   342   * @param Class type name for this operation.
   343   */
   344  #define G_TYPED_KERNEL(Class, ...) __WRAP_VAARGS(GET_G_TYPED_KERNEL(__VA_ARGS__, \
   345                                                   G_TYPED_KERNEL_HELPER_10, \
   346                                                   G_TYPED_KERNEL_HELPER_9, \
   347                                                   G_TYPED_KERNEL_HELPER_8, \
   348                                                   G_TYPED_KERNEL_HELPER_7, \
   349                                                   G_TYPED_KERNEL_HELPER_6, \
   350                                                   G_TYPED_KERNEL_HELPER_5, \
   351                                                   G_TYPED_KERNEL_HELPER_4, \
   352                                                   G_TYPED_KERNEL_HELPER_3, \
   353                                                   G_TYPED_KERNEL_HELPER_2, \
   354                                                   G_TYPED_KERNEL_HELPER)(Class, __VA_ARGS__)) \
   355  
   356  /**
   357   * Declares a new G-API Operation. See [Kernel API](@ref gapi_kernel_api) for more details.
   358   *
   359   * @deprecated This macro is deprecated in favor of `G_TYPED_KERNEL` that is used for declaring any
   360   * G-API Operation.
   361   *
   362   * @param Class type name for this operation.
   363   */
   364  #define G_TYPED_KERNEL_M G_TYPED_KERNEL
   365  
   366  #define G_API_OP   G_TYPED_KERNEL
   367  #define G_API_OP_M G_API_OP
   368  
   369  namespace cv
   370  {
   371  namespace gapi
   372  {
   373      // Prework: model "Device" API before it gets to G-API headers.
   374      // FIXME: Don't mix with internal Backends class!
   375      /// @private
   376      class GAPI_EXPORTS GBackend
   377      {
   378      public:
   379          class Priv;
   380  
   381          // TODO: make it template (call `new` within??)
   382          GBackend();
   383          explicit GBackend(std::shared_ptr<Priv> &&p);
   384  
   385          Priv& priv();
   386          const Priv& priv() const;
   387          std::size_t hash() const;
   388  
   389          bool operator== (const GBackend &rhs) const;
   390  
   391      private:
   392          std::shared_ptr<Priv> m_priv;
   393      };
   394  
   395      inline bool operator != (const GBackend &lhs, const GBackend &rhs)
   396      {
   397          return !(lhs == rhs);
   398      }
   399  } // namespace gapi
   400  } // namespace cv
   401  
   402  namespace std
   403  {
   404      template<> struct hash<cv::gapi::GBackend>
   405      {
   406          std::size_t operator() (const cv::gapi::GBackend &b) const
   407          {
   408              return b.hash();
   409          }
   410      };
   411  } // namespace std
   412  
   413  
   414  namespace cv {
   415  namespace gapi {
   416      /// @private
   417      class GFunctor
   418      {
   419      public:
   420          virtual cv::GKernelImpl impl()       const = 0;
   421          virtual cv::gapi::GBackend backend() const = 0;
   422          const char* id()                     const { return m_id; }
   423  
   424          virtual ~GFunctor() = default;
   425      protected:
   426          GFunctor(const char* id) : m_id(id) { };
   427      private:
   428          const char* m_id;
   429      };
   430  
   431      /** \addtogroup gapi_compile_args
   432       * @{
   433       */
   434  
   435      // FIXME: Hide implementation
   436      /**
   437       * @brief A container class for heterogeneous kernel
   438       * implementation collections and graph transformations.
   439       *
   440       * GKernelPackage is a special container class which stores kernel
   441       * _implementations_ and graph _transformations_. Objects of this class
   442       * are created and passed to cv::GComputation::compile() to specify
   443       * which kernels to use and which transformations to apply in the
   444       * compiled graph. GKernelPackage may contain kernels of
   445       * different backends, e.g. be heterogeneous.
   446       *
   447       * The most easy way to create a kernel package is to use function
   448       * cv::gapi::kernels(). This template functions takes kernel
   449       * implementations in form of type list (variadic template) and
   450       * generates a kernel package atop of that.
   451       *
   452       * Kernel packages can be also generated programmatically, starting
   453       * with an empty package (created with the default constructor)
   454       * and then by populating it with kernels via call to
   455       * GKernelPackage::include(). Note this method is also a template
   456       * one since G-API kernel and transformation implementations are _types_,
   457       * not objects.
   458       *
   459       * Finally, two kernel packages can be combined into a new one
   460       * with function cv::gapi::combine().
   461       */
   462      class GAPI_EXPORTS_W_SIMPLE GKernelPackage
   463      {
   464  
   465          /// @private
   466          using M = std::unordered_map<std::string, std::pair<GBackend, GKernelImpl>>;
   467  
   468          /// @private
   469          M m_id_kernels;
   470  
   471          /// @private
   472          std::vector<GTransform> m_transformations;
   473  
   474      protected:
   475          /// @private
   476          // Remove ALL implementations of the given API (identified by ID)
   477          void removeAPI(const std::string &id);
   478  
   479          /// @private
   480          // Partial include() specialization for kernels
   481          template <typename KImpl>
   482          typename std::enable_if<(std::is_base_of<cv::detail::KernelTag, KImpl>::value), void>::type
   483          includeHelper()
   484          {
   485              auto backend     = KImpl::backend();
   486              auto kernel_id   = KImpl::API::id();
   487              auto kernel_impl = GKernelImpl{KImpl::kernel(), &KImpl::API::getOutMeta};
   488              removeAPI(kernel_id);
   489  
   490              m_id_kernels[kernel_id] = std::make_pair(backend, kernel_impl);
   491          }
   492  
   493          /// @private
   494          // Partial include() specialization for transformations
   495          template <typename TImpl>
   496          typename std::enable_if<(std::is_base_of<cv::detail::TransformTag, TImpl>::value), void>::type
   497          includeHelper()
   498          {
   499              m_transformations.emplace_back(TImpl::transformation());
   500          }
   501  
   502      public:
   503          void include(const GFunctor& functor)
   504          {
   505              m_id_kernels[functor.id()] = std::make_pair(functor.backend(), functor.impl());
   506          }
   507          /**
   508           * @brief Returns total number of kernels
   509           * in the package (across all backends included)
   510           *
   511           * @return a number of kernels in the package
   512           */
   513          std::size_t size() const;
   514  
   515          /**
   516           * @brief Returns vector of transformations included in the package
   517           *
   518           * @return vector of transformations included in the package
   519           */
   520          const std::vector<GTransform>& get_transformations() const;
   521  
   522          /**
   523           * @brief Returns vector of kernel ids included in the package
   524           *
   525           * @return vector of kernel ids included in the package
   526           */
   527          std::vector<std::string> get_kernel_ids() const;
   528  
   529          /**
   530           * @brief Test if a particular kernel _implementation_ KImpl is
   531           * included in this kernel package.
   532           *
   533           * @sa includesAPI()
   534           *
   535           * @note cannot be applied to transformations
   536           *
   537           * @return true if there is such kernel, false otherwise.
   538           */
   539          template<typename KImpl>
   540          bool includes() const
   541          {
   542              static_assert(std::is_base_of<cv::detail::KernelTag, KImpl>::value,
   543                            "includes() can be applied to kernels only");
   544  
   545              auto kernel_it = m_id_kernels.find(KImpl::API::id());
   546              return kernel_it != m_id_kernels.end() &&
   547                     kernel_it->second.first == KImpl::backend();
   548          }
   549  
   550          /**
   551           * @brief Remove all kernels associated with the given backend
   552           * from the package.
   553           *
   554           * Does nothing if there's no kernels of this backend in the package.
   555           *
   556           * @param backend backend which kernels to remove
   557           */
   558          void remove(const GBackend& backend);
   559  
   560          /**
   561           * @brief Remove all kernels implementing the given API from
   562           * the package.
   563           *
   564           * Does nothing if there's no kernels implementing the given interface.
   565           */
   566          template<typename KAPI>
   567          void remove()
   568          {
   569              removeAPI(KAPI::id());
   570          }
   571  
   572          // FIXME: Rename to includes() and distinguish API/impl case by
   573          //     statically?
   574          /**
   575           * Check if package contains ANY implementation of a kernel API
   576           * by API type.
   577           */
   578          template<typename KAPI>
   579          bool includesAPI() const
   580          {
   581              return includesAPI(KAPI::id());
   582          }
   583  
   584          /// @private
   585          bool includesAPI(const std::string &id) const;
   586  
   587          // FIXME: The below comment is wrong, and who needs this function?
   588          /**
   589           * @brief Find a kernel (by its API)
   590           *
   591           * Returns implementation corresponding id.
   592           * Throws if nothing found.
   593           *
   594           * @return Backend which hosts matching kernel implementation.
   595           *
   596           */
   597          template<typename KAPI>
   598          GBackend lookup() const
   599          {
   600              return lookup(KAPI::id()).first;
   601          }
   602  
   603          /// @private
   604          std::pair<cv::gapi::GBackend, cv::GKernelImpl>
   605          lookup(const std::string &id) const;
   606  
   607          // FIXME: No overwrites allowed?
   608          /**
   609           * @brief Put a new kernel implementation or a new transformation
   610           * KImpl into the package.
   611           */
   612          template<typename KImpl>
   613          void include()
   614          {
   615              includeHelper<KImpl>();
   616          }
   617  
   618          /**
   619           * @brief Adds a new kernel based on it's backend and id into the kernel package
   620           *
   621           * @param backend backend associated with the kernel
   622           * @param kernel_id a name/id of the kernel
   623           */
   624          void include(const cv::gapi::GBackend& backend, const std::string& kernel_id)
   625          {
   626              removeAPI(kernel_id);
   627              m_id_kernels[kernel_id] = std::make_pair(backend, GKernelImpl{{}, {}});
   628          }
   629  
   630          /**
   631           * @brief Lists all backends which are included into package
   632           *
   633           * @return vector of backends
   634           */
   635          std::vector<GBackend> backends() const;
   636  
   637          // TODO: Doxygen bug -- it wants me to place this comment
   638          // here, not below.
   639          /**
   640           * @brief Create a new package based on `lhs` and `rhs`.
   641           *
   642           * @param lhs "Left-hand-side" package in the process
   643           * @param rhs "Right-hand-side" package in the process
   644           * @return a new kernel package.
   645           */
   646          friend GAPI_EXPORTS GKernelPackage combine(const GKernelPackage  &lhs,
   647                                                     const GKernelPackage  &rhs);
   648      };
   649  
   650      /**
   651       * @brief Create a kernel package object containing kernels
   652       * and transformations specified in variadic template argument.
   653       *
   654       * In G-API, kernel implementations and transformations are _types_.
   655       * Every backend has its own kernel API (like GAPI_OCV_KERNEL() and
   656       * GAPI_FLUID_KERNEL()) but all of that APIs define a new type for
   657       * each kernel implementation.
   658       *
   659       * Use this function to pass kernel implementations (defined in
   660       * either way) and transformations to the system. Example:
   661       *
   662       * @snippet modules/gapi/samples/api_ref_snippets.cpp kernels_snippet
   663       *
   664       * Note that kernels() itself is a function returning object, not
   665       * a type, so having `()` at the end is important -- it must be a
   666       * function call.
   667       */
   668      template<typename... KK> GKernelPackage kernels()
   669      {
   670          // FIXME: currently there is no check that transformations' signatures are unique
   671          // and won't be any intersection in graph compilation stage
   672          static_assert(cv::detail::all_unique<typename KK::API...>::value, "Kernels API must be unique");
   673  
   674          GKernelPackage pkg;
   675  
   676          // For those who wonder - below is a trick to call a number of
   677          // methods based on parameter pack (zeroes just help hiding these
   678          // calls into a sequence which helps to expand this parameter pack).
   679          // Just note that `f(),a` always equals to `a` (with f() called!)
   680          // and parentheses are used to hide function call in the expanded sequence.
   681          // Leading 0 helps to handle case when KK is an empty list (kernels<>()).
   682          int unused[] = { 0, (pkg.include<KK>(), 0)... };
   683          cv::util::suppress_unused_warning(unused);
   684          return pkg;
   685      };
   686  
   687      template<typename... FF>
   688      GKernelPackage kernels(FF&... functors)
   689      {
   690          GKernelPackage pkg;
   691          int unused[] = { 0, (pkg.include(functors), 0)... };
   692          cv::util::suppress_unused_warning(unused);
   693          return pkg;
   694      };
   695  
   696      /** @} */
   697  
   698      // FYI - this function is already commented above
   699      GAPI_EXPORTS GKernelPackage combine(const GKernelPackage  &lhs,
   700                                          const GKernelPackage  &rhs);
   701  
   702      /**
   703       * @brief Combines multiple G-API kernel packages into one
   704       *
   705       * @overload
   706       *
   707       * This function successively combines the passed kernel packages using a right fold.
   708       * Calling `combine(a, b, c)` is equal to `combine(a, combine(b, c))`.
   709       *
   710       * @return The resulting kernel package
   711       */
   712      template<typename... Ps>
   713      GKernelPackage combine(const GKernelPackage &a, const GKernelPackage &b, Ps&&... rest)
   714      {
   715          return combine(a, combine(b, rest...));
   716      }
   717  
   718      /** \addtogroup gapi_compile_args
   719       * @{
   720       */
   721      /**
   722       * @brief cv::use_only() is a special combinator which hints G-API to use only
   723       * kernels specified in cv::GComputation::compile() (and not to extend kernels available by
   724       * default with that package).
   725       */
   726      struct GAPI_EXPORTS use_only
   727      {
   728          GKernelPackage pkg;
   729      };
   730      /** @} */
   731  
   732  } // namespace gapi
   733  
   734  namespace detail
   735  {
   736      template<> struct CompileArgTag<cv::gapi::GKernelPackage>
   737      {
   738          static const char* tag() { return "gapi.kernel_package"; }
   739      };
   740  
   741      template<> struct CompileArgTag<cv::gapi::use_only>
   742      {
   743          static const char* tag() { return "gapi.use_only"; }
   744      };
   745  } // namespace detail
   746  
   747  } // namespace cv
   748  
   749  #endif // OPENCV_GAPI_GKERNEL_HPP