gfluidkernel.hpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442
  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-2019 Intel Corporation
  6. #ifndef OPENCV_GAPI_FLUID_KERNEL_HPP
  7. #define OPENCV_GAPI_FLUID_KERNEL_HPP
  8. #include <vector>
  9. #include <functional>
  10. #include <map>
  11. #include <unordered_map>
  12. #include <opencv2/gapi/opencv_includes.hpp>
  13. #include <opencv2/gapi/gcommon.hpp>
  14. #include <opencv2/gapi/gkernel.hpp>
  15. #include <opencv2/gapi/garg.hpp>
  16. #include <opencv2/gapi/fluid/gfluidbuffer.hpp>
  17. // FIXME: namespace scheme for backends?
  18. namespace cv {
  19. namespace gapi
  20. {
  21. /**
  22. * @brief This namespace contains G-API Fluid backend functions, structures, and symbols.
  23. */
  24. namespace fluid
  25. {
  26. /**
  27. * \addtogroup gapi_std_backends G-API Standard Backends
  28. * @{
  29. */
  30. /**
  31. * @brief Get a reference to Fluid backend.
  32. *
  33. * @sa gapi_std_backends
  34. */
  35. GAPI_EXPORTS cv::gapi::GBackend backend();
  36. /** @} */
  37. } // namespace fluid
  38. } // namespace gapi
  39. class GAPI_EXPORTS GFluidKernel
  40. {
  41. public:
  42. enum class Kind
  43. {
  44. Filter,
  45. Resize,
  46. YUV420toRGB //Color conversion of 4:2:0 chroma sub-sampling formats (NV12, I420 ..etc) to RGB
  47. };
  48. // This function is a generic "doWork" callback
  49. using F = std::function<void(const cv::GArgs&, const std::vector<gapi::fluid::Buffer*> &)>;
  50. // This function is a generic "initScratch" callback
  51. using IS = std::function<void(const cv::GMetaArgs &, const cv::GArgs&, gapi::fluid::Buffer &)>;
  52. // This function is a generic "resetScratch" callback
  53. using RS = std::function<void(gapi::fluid::Buffer &)>;
  54. // This function describes kernel metadata inference rule.
  55. using M = std::function<GMetaArgs(const GMetaArgs &, const GArgs &)>;
  56. // This function is a generic "getBorder" callback (extracts border-related data from kernel's input parameters)
  57. using B = std::function<gapi::fluid::BorderOpt(const GMetaArgs&, const GArgs&)>;
  58. // This function is a generic "getWindow" callback (extracts window-related data from kernel's input parameters)
  59. using GW = std::function<int(const GMetaArgs&, const GArgs&)>;
  60. // FIXME: move implementations out of header file
  61. GFluidKernel() {}
  62. GFluidKernel(Kind k, int l, bool scratch, const F& f, const IS &is, const RS &rs, const B& b, const GW& win)
  63. : m_kind(k)
  64. , m_lpi(l)
  65. , m_scratch(scratch)
  66. , m_f(f)
  67. , m_is(is)
  68. , m_rs(rs)
  69. , m_b(b)
  70. , m_gw(win) {}
  71. Kind m_kind;
  72. const int m_lpi = -1;
  73. const bool m_scratch = false;
  74. const F m_f;
  75. const IS m_is;
  76. const RS m_rs;
  77. const B m_b;
  78. const GW m_gw;
  79. };
  80. // FIXME!!!
  81. // This is the temporary and experimental API
  82. // which should be replaced by runtime roi-based scheduling
  83. /** \addtogroup gapi_compile_args
  84. * @{
  85. */
  86. /**
  87. * @brief This structure allows to control the output image region
  88. * which Fluid backend will produce in the graph.
  89. *
  90. * This feature is useful for external tiling and parallelism, but
  91. * will be deprecated in the future releases.
  92. */
  93. struct GFluidOutputRois
  94. {
  95. std::vector<cv::Rect> rois;
  96. };
  97. /**
  98. * @brief This structure forces Fluid backend to generate multiple
  99. * parallel output regions in the graph. These regions execute in parallel.
  100. *
  101. * This feature may be deprecated in the future releases.
  102. */
  103. struct GFluidParallelOutputRois
  104. {
  105. std::vector<GFluidOutputRois> parallel_rois;
  106. };
  107. /**
  108. * @brief This structure allows to customize the way how Fluid executes
  109. * parallel regions.
  110. *
  111. * For example, user can utilize his own threading runtime via this parameter.
  112. * The `parallel_for` member functor is called by the Fluid runtime with the
  113. * following arguments:
  114. *
  115. * @param size Size of the parallel range to process
  116. * @param f A function which should be called for every integer index
  117. * in this range by the specified parallel_for implementation.
  118. *
  119. * This feature may be deprecated in the future releases.
  120. */
  121. struct GFluidParallelFor
  122. {
  123. //this function accepts:
  124. // - size of the "parallel" range as the first argument
  125. // - and a function to be called on the range items, designated by item index
  126. std::function<void(std::size_t size, std::function<void(std::size_t index)>)> parallel_for;
  127. };
  128. /** @} gapi_compile_args */
  129. namespace detail
  130. {
  131. template<> struct CompileArgTag<GFluidOutputRois>
  132. {
  133. static const char* tag() { return "gapi.fluid.outputRois"; }
  134. };
  135. template<> struct CompileArgTag<GFluidParallelFor>
  136. {
  137. static const char* tag() { return "gapi.fluid.parallelFor"; }
  138. };
  139. template<> struct CompileArgTag<GFluidParallelOutputRois>
  140. {
  141. static const char* tag() { return "gapi.fluid.parallelOutputRois"; }
  142. };
  143. } // namespace detail
  144. namespace detail
  145. {
  146. template<class T> struct fluid_get_in;
  147. template<> struct fluid_get_in<cv::GMat>
  148. {
  149. static const cv::gapi::fluid::View& get(const cv::GArgs &in_args, int idx)
  150. {
  151. return *in_args[idx].unsafe_get<cv::gapi::fluid::View*>();
  152. }
  153. };
  154. template<> struct fluid_get_in<cv::GScalar>
  155. {
  156. // FIXME: change to return by reference when moved to own::Scalar
  157. static cv::Scalar get(const cv::GArgs &in_args, int idx)
  158. {
  159. return in_args[idx].unsafe_get<cv::Scalar>();
  160. }
  161. };
  162. template<typename U> struct fluid_get_in<cv::GArray<U>>
  163. {
  164. static const std::vector<U>& get(const cv::GArgs &in_args, int idx)
  165. {
  166. return in_args.at(idx).unsafe_get<cv::detail::VectorRef>().rref<U>();
  167. }
  168. };
  169. template<typename U> struct fluid_get_in<cv::GOpaque<U>>
  170. {
  171. static const U& get(const cv::GArgs &in_args, int idx)
  172. {
  173. return in_args.at(idx).unsafe_get<cv::detail::OpaqueRef>().rref<U>();
  174. }
  175. };
  176. template<class T> struct fluid_get_in
  177. {
  178. static const T& get(const cv::GArgs &in_args, int idx)
  179. {
  180. return in_args[idx].unsafe_get<T>();
  181. }
  182. };
  183. template<bool, typename Impl, typename... Ins>
  184. struct scratch_helper;
  185. template<typename Impl, typename... Ins>
  186. struct scratch_helper<true, Impl, Ins...>
  187. {
  188. // Init
  189. template<int... IIs>
  190. static void help_init_impl(const cv::GMetaArgs &metas,
  191. const cv::GArgs &in_args,
  192. gapi::fluid::Buffer &scratch_buf,
  193. detail::Seq<IIs...>)
  194. {
  195. Impl::initScratch(get_in_meta<Ins>(metas, in_args, IIs)..., scratch_buf);
  196. }
  197. static void help_init(const cv::GMetaArgs &metas,
  198. const cv::GArgs &in_args,
  199. gapi::fluid::Buffer &b)
  200. {
  201. help_init_impl(metas, in_args, b, typename detail::MkSeq<sizeof...(Ins)>::type());
  202. }
  203. // Reset
  204. static void help_reset(gapi::fluid::Buffer &b)
  205. {
  206. Impl::resetScratch(b);
  207. }
  208. };
  209. template<typename Impl, typename... Ins>
  210. struct scratch_helper<false, Impl, Ins...>
  211. {
  212. static void help_init(const cv::GMetaArgs &,
  213. const cv::GArgs &,
  214. gapi::fluid::Buffer &)
  215. {
  216. GAPI_Assert(false);
  217. }
  218. static void help_reset(gapi::fluid::Buffer &)
  219. {
  220. GAPI_Assert(false);
  221. }
  222. };
  223. template<typename T> struct is_gmat_type
  224. {
  225. static const constexpr bool value = std::is_same<cv::GMat, T>::value;
  226. };
  227. template<bool CallCustomGetBorder, typename Impl, typename... Ins>
  228. struct get_border_helper;
  229. template<typename Impl, typename... Ins>
  230. struct get_border_helper<true, Impl, Ins...>
  231. {
  232. template<int... IIs>
  233. static gapi::fluid::BorderOpt get_border_impl(const GMetaArgs &metas,
  234. const cv::GArgs &in_args,
  235. cv::detail::Seq<IIs...>)
  236. {
  237. return util::make_optional(Impl::getBorder(cv::detail::get_in_meta<Ins>(metas, in_args, IIs)...));
  238. }
  239. static gapi::fluid::BorderOpt help(const GMetaArgs &metas,
  240. const cv::GArgs &in_args)
  241. {
  242. return get_border_impl(metas, in_args, typename detail::MkSeq<sizeof...(Ins)>::type());
  243. }
  244. };
  245. template<typename Impl, typename... Ins>
  246. struct get_border_helper<false, Impl, Ins...>
  247. {
  248. static gapi::fluid::BorderOpt help(const cv::GMetaArgs &,
  249. const cv::GArgs &)
  250. {
  251. return {};
  252. }
  253. };
  254. template<bool CallCustomGetWindow, typename, typename... Ins>
  255. struct get_window_helper;
  256. template<typename Impl, typename... Ins>
  257. struct get_window_helper<true, Impl, Ins...>
  258. {
  259. template<int... IIs>
  260. static int get_window_impl(const GMetaArgs &metas,
  261. const cv::GArgs &in_args,
  262. cv::detail::Seq<IIs...>)
  263. {
  264. return Impl::getWindow(cv::detail::get_in_meta<Ins>(metas, in_args, IIs)...);
  265. }
  266. static int help(const GMetaArgs &metas, const cv::GArgs &in_args)
  267. {
  268. return get_window_impl(metas, in_args, typename detail::MkSeq<sizeof...(Ins)>::type());
  269. }
  270. };
  271. template<typename Impl, typename... Ins>
  272. struct get_window_helper<false, Impl, Ins...>
  273. {
  274. static int help(const cv::GMetaArgs &,
  275. const cv::GArgs &)
  276. {
  277. return Impl::Window;
  278. }
  279. };
  280. template<typename C, typename T>
  281. struct has_Window
  282. {
  283. private:
  284. template<class U>
  285. static constexpr auto Check(U*) -> typename std::is_same<decltype(U::Window), T>::type;
  286. template<typename>
  287. static constexpr std::false_type Check(...);
  288. typedef decltype(Check<C>(0)) Result;
  289. public:
  290. static constexpr bool value = Result::value;
  291. };
  292. template<bool hasWindow, typename Impl>
  293. struct callCustomGetBorder;
  294. template<typename Impl>
  295. struct callCustomGetBorder<true, Impl>
  296. {
  297. static constexpr bool value = (Impl::Window != 1);
  298. };
  299. template<typename Impl>
  300. struct callCustomGetBorder<false, Impl>
  301. {
  302. static constexpr bool value = true;
  303. };
  304. template<typename, typename, typename, bool UseScratch>
  305. struct FluidCallHelper;
  306. template<typename Impl, typename... Ins, typename... Outs, bool UseScratch>
  307. struct FluidCallHelper<Impl, std::tuple<Ins...>, std::tuple<Outs...>, UseScratch>
  308. {
  309. static_assert(all_satisfy<is_gmat_type, Outs...>::value, "return type must be GMat");
  310. static_assert(contains<GMat, Ins...>::value, "input must contain at least one GMat");
  311. // Execution dispatcher ////////////////////////////////////////////////////
  312. template<int... IIs, int... OIs>
  313. static void call_impl(const cv::GArgs &in_args,
  314. const std::vector<gapi::fluid::Buffer*> &out_bufs,
  315. detail::Seq<IIs...>,
  316. detail::Seq<OIs...>)
  317. {
  318. Impl::run(fluid_get_in<Ins>::get(in_args, IIs)..., *out_bufs[OIs]...);
  319. }
  320. static void call(const cv::GArgs &in_args,
  321. const std::vector<gapi::fluid::Buffer*> &out_bufs)
  322. {
  323. constexpr int numOuts = (sizeof...(Outs)) + (UseScratch ? 1 : 0);
  324. call_impl(in_args, out_bufs,
  325. typename detail::MkSeq<sizeof...(Ins)>::type(),
  326. typename detail::MkSeq<numOuts>::type());
  327. }
  328. // Scratch buffer initialization dispatcher ////////////////////////////////
  329. static void init_scratch(const GMetaArgs &metas,
  330. const cv::GArgs &in_args,
  331. gapi::fluid::Buffer &b)
  332. {
  333. scratch_helper<UseScratch, Impl, Ins...>::help_init(metas, in_args, b);
  334. }
  335. // Scratch buffer reset dispatcher /////////////////////////////////////////
  336. static void reset_scratch(gapi::fluid::Buffer &scratch_buf)
  337. {
  338. scratch_helper<UseScratch, Impl, Ins...>::help_reset(scratch_buf);
  339. }
  340. static gapi::fluid::BorderOpt getBorder(const GMetaArgs &metas, const cv::GArgs &in_args)
  341. {
  342. constexpr bool hasWindow = has_Window<Impl, const int>::value;
  343. // User must provide "init" callback if Window != 1
  344. // TODO: move to constexpr if when we enable C++17
  345. return get_border_helper<callCustomGetBorder<hasWindow, Impl>::value, Impl, Ins...>::help(metas, in_args);
  346. }
  347. static int getWindow(const GMetaArgs &metas, const cv::GArgs &in_args)
  348. {
  349. constexpr bool callCustomGetWindow = !(has_Window<Impl, const int>::value);
  350. return get_window_helper<callCustomGetWindow, Impl, Ins...>::help(metas, in_args);
  351. }
  352. };
  353. } // namespace detail
  354. template<class Impl, class K, bool UseScratch>
  355. class GFluidKernelImpl : public cv::detail::KernelTag
  356. {
  357. static const int LPI = 1;
  358. static const auto Kind = GFluidKernel::Kind::Filter;
  359. using P = detail::FluidCallHelper<Impl, typename K::InArgs, typename K::OutArgs, UseScratch>;
  360. public:
  361. using API = K;
  362. static GFluidKernel kernel()
  363. {
  364. // FIXME: call() and getOutMeta() needs to be renamed so it is clear these
  365. // functions are internal wrappers, not user API
  366. return GFluidKernel(Impl::Kind, Impl::LPI,
  367. UseScratch,
  368. &P::call, &P::init_scratch, &P::reset_scratch, &P::getBorder, &P::getWindow);
  369. }
  370. static cv::gapi::GBackend backend() { return cv::gapi::fluid::backend(); }
  371. };
  372. #define GAPI_FLUID_KERNEL(Name, API, Scratch) struct Name: public cv::GFluidKernelImpl<Name, API, Scratch>
  373. } // namespace cv
  374. #endif // OPENCV_GAPI_GCPUKERNEL_HPP