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