gkernel.hpp 27 KB

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