// 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) 2018-2019 Intel Corporation #ifndef OPENCV_GAPI_FLUID_KERNEL_HPP #define OPENCV_GAPI_FLUID_KERNEL_HPP #include #include #include #include #include #include #include #include #include // FIXME: namespace scheme for backends? namespace cv { namespace gapi { /** * @brief This namespace contains G-API Fluid backend functions, structures, and symbols. */ namespace fluid { /** * \addtogroup gapi_std_backends G-API Standard Backends * @{ */ /** * @brief Get a reference to Fluid backend. * * @sa gapi_std_backends */ GAPI_EXPORTS cv::gapi::GBackend backend(); /** @} */ } // namespace fluid } // namespace gapi class GAPI_EXPORTS GFluidKernel { public: enum class Kind { Filter, Resize, YUV420toRGB //Color conversion of 4:2:0 chroma sub-sampling formats (NV12, I420 ..etc) to RGB }; // This function is a generic "doWork" callback using F = std::function &)>; // This function is a generic "initScratch" callback using IS = std::function; // This function is a generic "resetScratch" callback using RS = std::function; // This function describes kernel metadata inference rule. using M = std::function; // This function is a generic "getBorder" callback (extracts border-related data from kernel's input parameters) using B = std::function; // This function is a generic "getWindow" callback (extracts window-related data from kernel's input parameters) using GW = std::function; // FIXME: move implementations out of header file GFluidKernel() {} GFluidKernel(Kind k, int l, bool scratch, const F& f, const IS &is, const RS &rs, const B& b, const GW& win) : m_kind(k) , m_lpi(l) , m_scratch(scratch) , m_f(f) , m_is(is) , m_rs(rs) , m_b(b) , m_gw(win) {} Kind m_kind; const int m_lpi = -1; const bool m_scratch = false; const F m_f; const IS m_is; const RS m_rs; const B m_b; const GW m_gw; }; // FIXME!!! // This is the temporary and experimental API // which should be replaced by runtime roi-based scheduling /** \addtogroup gapi_compile_args * @{ */ /** * @brief This structure allows to control the output image region * which Fluid backend will produce in the graph. * * This feature is useful for external tiling and parallelism, but * will be deprecated in the future releases. */ struct GFluidOutputRois { std::vector rois; }; /** * @brief This structure forces Fluid backend to generate multiple * parallel output regions in the graph. These regions execute in parallel. * * This feature may be deprecated in the future releases. */ struct GFluidParallelOutputRois { std::vector parallel_rois; }; /** * @brief This structure allows to customize the way how Fluid executes * parallel regions. * * For example, user can utilize his own threading runtime via this parameter. * The `parallel_for` member functor is called by the Fluid runtime with the * following arguments: * * @param size Size of the parallel range to process * @param f A function which should be called for every integer index * in this range by the specified parallel_for implementation. * * This feature may be deprecated in the future releases. */ struct GFluidParallelFor { //this function accepts: // - size of the "parallel" range as the first argument // - and a function to be called on the range items, designated by item index std::function)> parallel_for; }; /** @} gapi_compile_args */ namespace detail { template<> struct CompileArgTag { static const char* tag() { return "gapi.fluid.outputRois"; } }; template<> struct CompileArgTag { static const char* tag() { return "gapi.fluid.parallelFor"; } }; template<> struct CompileArgTag { static const char* tag() { return "gapi.fluid.parallelOutputRois"; } }; } // namespace detail namespace detail { template struct fluid_get_in; template<> struct fluid_get_in { static const cv::gapi::fluid::View& get(const cv::GArgs &in_args, int idx) { return *in_args[idx].unsafe_get(); } }; template<> struct fluid_get_in { // FIXME: change to return by reference when moved to own::Scalar static const cv::Scalar get(const cv::GArgs &in_args, int idx) { return in_args[idx].unsafe_get(); } }; template struct fluid_get_in> { static const std::vector& get(const cv::GArgs &in_args, int idx) { return in_args.at(idx).unsafe_get().rref(); } }; template struct fluid_get_in> { static const U& get(const cv::GArgs &in_args, int idx) { return in_args.at(idx).unsafe_get().rref(); } }; template struct fluid_get_in { static const T& get(const cv::GArgs &in_args, int idx) { return in_args[idx].unsafe_get(); } }; template struct scratch_helper; template struct scratch_helper { // Init template static void help_init_impl(const cv::GMetaArgs &metas, const cv::GArgs &in_args, gapi::fluid::Buffer &scratch_buf, detail::Seq) { Impl::initScratch(get_in_meta(metas, in_args, IIs)..., scratch_buf); } static void help_init(const cv::GMetaArgs &metas, const cv::GArgs &in_args, gapi::fluid::Buffer &b) { help_init_impl(metas, in_args, b, typename detail::MkSeq::type()); } // Reset static void help_reset(gapi::fluid::Buffer &b) { Impl::resetScratch(b); } }; template struct scratch_helper { static void help_init(const cv::GMetaArgs &, const cv::GArgs &, gapi::fluid::Buffer &) { GAPI_Assert(false); } static void help_reset(gapi::fluid::Buffer &) { GAPI_Assert(false); } }; template struct is_gmat_type { static const constexpr bool value = std::is_same::value; }; template struct get_border_helper; template struct get_border_helper { template static gapi::fluid::BorderOpt get_border_impl(const GMetaArgs &metas, const cv::GArgs &in_args, cv::detail::Seq) { return util::make_optional(Impl::getBorder(cv::detail::get_in_meta(metas, in_args, IIs)...)); } static gapi::fluid::BorderOpt help(const GMetaArgs &metas, const cv::GArgs &in_args) { return get_border_impl(metas, in_args, typename detail::MkSeq::type()); } }; template struct get_border_helper { static gapi::fluid::BorderOpt help(const cv::GMetaArgs &, const cv::GArgs &) { return {}; } }; template struct get_window_helper; template struct get_window_helper { template static int get_window_impl(const GMetaArgs &metas, const cv::GArgs &in_args, cv::detail::Seq) { return Impl::getWindow(cv::detail::get_in_meta(metas, in_args, IIs)...); } static int help(const GMetaArgs &metas, const cv::GArgs &in_args) { return get_window_impl(metas, in_args, typename detail::MkSeq::type()); } }; template struct get_window_helper { static int help(const cv::GMetaArgs &, const cv::GArgs &) { return Impl::Window; } }; template struct has_Window { private: template static constexpr auto Check(U*) -> typename std::is_same::type; template static constexpr std::false_type Check(...); typedef decltype(Check(0)) Result; public: static constexpr bool value = Result::value; }; template struct callCustomGetBorder; template struct callCustomGetBorder { static constexpr bool value = (Impl::Window != 1); }; template struct callCustomGetBorder { static constexpr bool value = true; }; template struct FluidCallHelper; template struct FluidCallHelper, std::tuple, UseScratch> { static_assert(all_satisfy::value, "return type must be GMat"); static_assert(contains::value, "input must contain at least one GMat"); // Execution dispatcher //////////////////////////////////////////////////// template static void call_impl(const cv::GArgs &in_args, const std::vector &out_bufs, detail::Seq, detail::Seq) { Impl::run(fluid_get_in::get(in_args, IIs)..., *out_bufs[OIs]...); } static void call(const cv::GArgs &in_args, const std::vector &out_bufs) { constexpr int numOuts = (sizeof...(Outs)) + (UseScratch ? 1 : 0); call_impl(in_args, out_bufs, typename detail::MkSeq::type(), typename detail::MkSeq::type()); } // Scratch buffer initialization dispatcher //////////////////////////////// static void init_scratch(const GMetaArgs &metas, const cv::GArgs &in_args, gapi::fluid::Buffer &b) { scratch_helper::help_init(metas, in_args, b); } // Scratch buffer reset dispatcher ///////////////////////////////////////// static void reset_scratch(gapi::fluid::Buffer &scratch_buf) { scratch_helper::help_reset(scratch_buf); } static gapi::fluid::BorderOpt getBorder(const GMetaArgs &metas, const cv::GArgs &in_args) { constexpr bool hasWindow = has_Window::value; // User must provide "init" callback if Window != 1 // TODO: move to constexpr if when we enable C++17 return get_border_helper::value, Impl, Ins...>::help(metas, in_args); } static int getWindow(const GMetaArgs &metas, const cv::GArgs &in_args) { constexpr bool callCustomGetWindow = !(has_Window::value); return get_window_helper::help(metas, in_args); } }; } // namespace detail template class GFluidKernelImpl : public cv::detail::KernelTag { static const int LPI = 1; static const auto Kind = GFluidKernel::Kind::Filter; using P = detail::FluidCallHelper; public: using API = K; static GFluidKernel kernel() { // FIXME: call() and getOutMeta() needs to be renamed so it is clear these // functions are internal wrappers, not user API return GFluidKernel(Impl::Kind, Impl::LPI, UseScratch, &P::call, &P::init_scratch, &P::reset_scratch, &P::getBorder, &P::getWindow); } static cv::gapi::GBackend backend() { return cv::gapi::fluid::backend(); } }; #define GAPI_FLUID_KERNEL(Name, API, Scratch) struct Name: public cv::GFluidKernelImpl } // namespace cv #endif // OPENCV_GAPI_GCPUKERNEL_HPP