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