github.com/kaydxh/golang@v0.0.131/pkg/gocv/cgo/third_path/opencv4/include/opencv2/gapi/ocl/goclkernel.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-2020 Intel Corporation
     6  
     7  
     8  #ifndef OPENCV_GAPI_GOCLKERNEL_HPP
     9  #define OPENCV_GAPI_GOCLKERNEL_HPP
    10  
    11  #include <vector>
    12  #include <functional>
    13  #include <map>
    14  #include <unordered_map>
    15  
    16  #include <opencv2/core/mat.hpp>
    17  #include <opencv2/gapi/gcommon.hpp>
    18  #include <opencv2/gapi/gkernel.hpp>
    19  #include <opencv2/gapi/garg.hpp>
    20  
    21  // FIXME: namespace scheme for backends?
    22  namespace cv {
    23  
    24  namespace gimpl
    25  {
    26      // Forward-declare an internal class
    27      class GOCLExecutable;
    28  } // namespace gimpl
    29  
    30  namespace gapi
    31  {
    32  /**
    33   * @brief This namespace contains G-API OpenCL backend functions, structures, and symbols.
    34   */
    35  namespace ocl
    36  {
    37      /**
    38       * \addtogroup gapi_std_backends G-API Standard Backends
    39       * @{
    40       */
    41      /**
    42       * @brief Get a reference to OCL backend.
    43       *
    44       * At the moment, the OCL backend is built atop of OpenCV
    45       * "Transparent API" (T-API), see cv::UMat for details.
    46       *
    47       * @sa gapi_std_backends
    48       */
    49      GAPI_EXPORTS cv::gapi::GBackend backend();
    50      /** @} */
    51  } // namespace ocl
    52  } // namespace gapi
    53  
    54  
    55  // Represents arguments which are passed to a wrapped OCL function
    56  // FIXME: put into detail?
    57  class GAPI_EXPORTS GOCLContext
    58  {
    59  public:
    60      // Generic accessor API
    61      template<typename T>
    62      const T& inArg(int input) { return m_args.at(input).get<T>(); }
    63  
    64      // Syntax sugar
    65      const cv::UMat&  inMat(int input);
    66      cv::UMat&  outMatR(int output); // FIXME: Avoid cv::Mat m = ctx.outMatR()
    67  
    68      const cv::Scalar& inVal(int input);
    69      cv::Scalar& outValR(int output); // FIXME: Avoid cv::Scalar s = ctx.outValR()
    70      template<typename T> std::vector<T>& outVecR(int output) // FIXME: the same issue
    71      {
    72          return outVecRef(output).wref<T>();
    73      }
    74      template<typename T> T& outOpaqueR(int output) // FIXME: the same issue
    75      {
    76          return outOpaqueRef(output).wref<T>();
    77      }
    78  
    79  protected:
    80      detail::VectorRef& outVecRef(int output);
    81      detail::OpaqueRef& outOpaqueRef(int output);
    82  
    83      std::vector<GArg> m_args;
    84      std::unordered_map<std::size_t, GRunArgP> m_results;
    85  
    86  
    87      friend class gimpl::GOCLExecutable;
    88  };
    89  
    90  class GAPI_EXPORTS GOCLKernel
    91  {
    92  public:
    93      // This function is kernel's execution entry point (does the processing work)
    94      using F = std::function<void(GOCLContext &)>;
    95  
    96      GOCLKernel();
    97      explicit GOCLKernel(const F& f);
    98  
    99      void apply(GOCLContext &ctx);
   100  
   101  protected:
   102      F m_f;
   103  };
   104  
   105  // FIXME: This is an ugly ad-hoc implementation. TODO: refactor
   106  
   107  namespace detail
   108  {
   109  template<class T> struct ocl_get_in;
   110  template<> struct ocl_get_in<cv::GMat>
   111  {
   112      static cv::UMat    get(GOCLContext &ctx, int idx) { return ctx.inMat(idx); }
   113  };
   114  template<> struct ocl_get_in<cv::GScalar>
   115  {
   116      static cv::Scalar get(GOCLContext &ctx, int idx) { return ctx.inVal(idx); }
   117  };
   118  template<typename U> struct ocl_get_in<cv::GArray<U> >
   119  {
   120      static const std::vector<U>& get(GOCLContext &ctx, int idx) { return ctx.inArg<VectorRef>(idx).rref<U>(); }
   121  };
   122  template<typename U> struct ocl_get_in<cv::GOpaque<U> >
   123  {
   124      static const U& get(GOCLContext &ctx, int idx) { return ctx.inArg<OpaqueRef>(idx).rref<U>(); }
   125  };
   126  template<class T> struct ocl_get_in
   127  {
   128      static T get(GOCLContext &ctx, int idx) { return ctx.inArg<T>(idx); }
   129  };
   130  
   131  struct tracked_cv_umat{
   132      //TODO Think if T - API could reallocate UMat to a proper size - how do we handle this ?
   133      //tracked_cv_umat(cv::UMat& m) : r{(m)}, original_data{m.getMat(ACCESS_RW).data} {}
   134      tracked_cv_umat(cv::UMat& m) : r(m), original_data{ nullptr } {}
   135      cv::UMat &r; // FIXME: It was a value (not a reference) before.
   136                   // Actually OCL backend should allocate its internal data!
   137      uchar* original_data;
   138  
   139      operator cv::UMat& (){ return r;}
   140      void validate() const{
   141          //if (r.getMat(ACCESS_RW).data != original_data)
   142          //{
   143          //    util::throw_error
   144          //        (std::logic_error
   145          //         ("OpenCV kernel output parameter was reallocated. \n"
   146          //          "Incorrect meta data was provided ?"));
   147          //}
   148  
   149      }
   150  };
   151  
   152  template<typename... Outputs>
   153  void postprocess_ocl(Outputs&... outs)
   154  {
   155      struct
   156      {
   157          void operator()(tracked_cv_umat* bm) { bm->validate(); }
   158          void operator()(...) {                  }
   159  
   160      } validate;
   161      //dummy array to unfold parameter pack
   162      int dummy[] = { 0, (validate(&outs), 0)... };
   163      cv::util::suppress_unused_warning(dummy);
   164  }
   165  
   166  template<class T> struct ocl_get_out;
   167  template<> struct ocl_get_out<cv::GMat>
   168  {
   169      static tracked_cv_umat get(GOCLContext &ctx, int idx)
   170      {
   171          auto& r = ctx.outMatR(idx);
   172          return{ r };
   173      }
   174  };
   175  template<> struct ocl_get_out<cv::GScalar>
   176  {
   177      static cv::Scalar& get(GOCLContext &ctx, int idx)
   178      {
   179          return ctx.outValR(idx);
   180      }
   181  };
   182  template<typename U> struct ocl_get_out<cv::GArray<U> >
   183  {
   184      static std::vector<U>& get(GOCLContext &ctx, int idx) { return ctx.outVecR<U>(idx);  }
   185  };
   186  template<typename U> struct ocl_get_out<cv::GOpaque<U> >
   187  {
   188      static U& get(GOCLContext &ctx, int idx) { return ctx.outOpaqueR<U>(idx);  }
   189  };
   190  
   191  template<typename, typename, typename>
   192  struct OCLCallHelper;
   193  
   194  // FIXME: probably can be simplified with std::apply or analogue.
   195  template<typename Impl, typename... Ins, typename... Outs>
   196  struct OCLCallHelper<Impl, std::tuple<Ins...>, std::tuple<Outs...> >
   197  {
   198      template<typename... Inputs>
   199      struct call_and_postprocess
   200      {
   201          template<typename... Outputs>
   202          static void call(Inputs&&... ins, Outputs&&... outs)
   203          {
   204              //not using a std::forward on outs is deliberate in order to
   205              //cause compilation error, by trying to bind rvalue references to lvalue references
   206              Impl::run(std::forward<Inputs>(ins)..., outs...);
   207  
   208              postprocess_ocl(outs...);
   209          }
   210      };
   211  
   212      template<int... IIs, int... OIs>
   213      static void call_impl(GOCLContext &ctx, detail::Seq<IIs...>, detail::Seq<OIs...>)
   214      {
   215          //TODO: Make sure that OpenCV kernels do not reallocate memory for output parameters
   216          //by comparing it's state (data ptr) before and after the call.
   217          //Convert own::Scalar to cv::Scalar before call kernel and run kernel
   218          //convert cv::Scalar to own::Scalar after call kernel and write back results
   219          call_and_postprocess<decltype(ocl_get_in<Ins>::get(ctx, IIs))...>::call(ocl_get_in<Ins>::get(ctx, IIs)..., ocl_get_out<Outs>::get(ctx, OIs)...);
   220      }
   221  
   222      static void call(GOCLContext &ctx)
   223      {
   224          call_impl(ctx,
   225              typename detail::MkSeq<sizeof...(Ins)>::type(),
   226              typename detail::MkSeq<sizeof...(Outs)>::type());
   227      }
   228  };
   229  
   230  } // namespace detail
   231  
   232  template<class Impl, class K>
   233  class GOCLKernelImpl: public cv::detail::OCLCallHelper<Impl, typename K::InArgs, typename K::OutArgs>,
   234                        public cv::detail::KernelTag
   235  {
   236      using P = detail::OCLCallHelper<Impl, typename K::InArgs, typename K::OutArgs>;
   237  
   238  public:
   239      using API = K;
   240  
   241      static cv::gapi::GBackend backend()  { return cv::gapi::ocl::backend(); }
   242      static cv::GOCLKernel     kernel()   { return GOCLKernel(&P::call);     }
   243  };
   244  
   245  #define GAPI_OCL_KERNEL(Name, API) struct Name: public cv::GOCLKernelImpl<Name, API>
   246  
   247  } // namespace cv
   248  
   249  #endif // OPENCV_GAPI_GOCLKERNEL_HPP