1
0
mirror of https://github.com/opencv/opencv.git synced 2026-07-30 07:43:03 +04:00

Merge pull request #16213 from TolyaTalamanov:at/lambdas-for-kernels

G-API: Using functors as kernel implementation

* Implement ability to create kernel impls from functors

* Clean up

* Replace make_ocv_functor to ocv_kernel

* Clean up

* Replace GCPUFunctor -> GOCVFunctor
* Move GOCVFunctor to cv::gapi::cpu namespace

* Implement override for rvalue and lvalue cases

* Fix comments to review

* Remove GAPI_EXPORT for template functions

* Fix indentation
This commit is contained in:
Anatoliy Talamanov
2020-02-17 23:29:55 +03:00
committed by GitHub
parent f3237fdc6e
commit a6ef9b4584
3 changed files with 208 additions and 1 deletions
@@ -72,6 +72,17 @@ namespace cpu
*/
GAPI_EXPORTS cv::gapi::GBackend backend();
/** @} */
class GOCVFunctor;
//! @cond IGNORED
template<typename K, typename Callable>
GOCVFunctor ocv_kernel(const Callable& c);
template<typename K, typename Callable>
GOCVFunctor ocv_kernel(Callable& c);
//! @endcond
} // namespace cpu
} // namespace gapi
@@ -279,6 +290,12 @@ struct OCVCallHelper<Impl, std::tuple<Ins...>, std::tuple<Outs...> >
Impl::run(std::forward<Inputs>(ins)..., outs...);
postprocess(outs...);
}
template<typename... Outputs>
static void call(Impl& impl, Inputs&&... ins, Outputs&&... outs)
{
impl(std::forward<Inputs>(ins)..., outs...);
}
};
template<int... IIs, int... OIs>
@@ -290,7 +307,17 @@ struct OCVCallHelper<Impl, std::tuple<Ins...>, std::tuple<Outs...> >
//them to parameters of ad-hoc function
//Convert own::Scalar to cv::Scalar before call kernel and run kernel
//convert cv::Scalar to own::Scalar after call kernel and write back results
call_and_postprocess<decltype(get_in<Ins>::get(ctx, IIs))...>::call(get_in<Ins>::get(ctx, IIs)..., get_out<Outs>::get(ctx, OIs)...);
call_and_postprocess<decltype(get_in<Ins>::get(ctx, IIs))...>
::call(get_in<Ins>::get(ctx, IIs)...,
get_out<Outs>::get(ctx, OIs)...);
}
template<int... IIs, int... OIs>
static void call_impl(cv::GCPUContext &ctx, Impl& impl, detail::Seq<IIs...>, detail::Seq<OIs...>)
{
call_and_postprocess<decltype(cv::detail::get_in<Ins>::get(ctx, IIs))...>
::call(impl, cv::detail::get_in<Ins>::get(ctx, IIs)...,
cv::detail::get_out<Outs>::get(ctx, OIs)...);
}
static void call(GCPUContext &ctx)
@@ -299,6 +326,16 @@ struct OCVCallHelper<Impl, std::tuple<Ins...>, std::tuple<Outs...> >
typename detail::MkSeq<sizeof...(Ins)>::type(),
typename detail::MkSeq<sizeof...(Outs)>::type());
}
// NB: Same as call but calling the object
// This necessary for kernel implementations that have a state
// and are represented as an object
static void callFunctor(cv::GCPUContext &ctx, Impl& impl)
{
call_impl(ctx, impl,
typename detail::MkSeq<sizeof...(Ins)>::type(),
typename detail::MkSeq<sizeof...(Outs)>::type());
}
};
} // namespace detail
@@ -318,6 +355,39 @@ public:
#define GAPI_OCV_KERNEL(Name, API) struct Name: public cv::GCPUKernelImpl<Name, API>
class gapi::cpu::GOCVFunctor : public gapi::GFunctor
{
public:
using Impl = std::function<void(GCPUContext &)>;
GOCVFunctor(const char* id, const Impl& impl)
: gapi::GFunctor(id), impl_{GCPUKernel(impl)}
{
}
GKernelImpl impl() const override { return impl_; }
gapi::GBackend backend() const override { return gapi::cpu::backend(); }
private:
GKernelImpl impl_;
};
//! @cond IGNORED
template<typename K, typename Callable>
gapi::cpu::GOCVFunctor gapi::cpu::ocv_kernel(Callable& c)
{
using P = detail::OCVCallHelper<Callable, typename K::InArgs, typename K::OutArgs>;
return GOCVFunctor(K::id(), std::bind(&P::callFunctor, std::placeholders::_1, std::ref(c)));
}
template<typename K, typename Callable>
gapi::cpu::GOCVFunctor gapi::cpu::ocv_kernel(const Callable& c)
{
using P = detail::OCVCallHelper<Callable, typename K::InArgs, typename K::OutArgs>;
return GOCVFunctor(K::id(), std::bind(&P::callFunctor, std::placeholders::_1, c));
}
//! @endcond
} // namespace cv
#endif // OPENCV_GAPI_GCPUKERNEL_HPP
@@ -383,6 +383,20 @@ namespace std
namespace cv {
namespace gapi {
class GFunctor
{
public:
virtual cv::GKernelImpl impl() const = 0;
virtual cv::gapi::GBackend backend() const = 0;
const char* id() const { return m_id; }
virtual ~GFunctor() = default;
protected:
GFunctor(const char* id) : m_id(id) { };
private:
const char* m_id;
};
/** \addtogroup gapi_compile_args
* @{
*/
@@ -460,6 +474,10 @@ namespace gapi {
}
public:
void include(const GFunctor& functor)
{
m_id_kernels[functor.id()] = std::make_pair(functor.backend(), functor.impl());
}
/**
* @brief Returns total number of kernels
* in the package (across all backends included)
@@ -618,6 +636,15 @@ namespace gapi {
return pkg;
};
template<typename... FF>
GKernelPackage kernels(FF&... functors)
{
GKernelPackage pkg;
int unused[] = { 0, (pkg.include(functors), 0)... };
cv::util::suppress_unused_warning(unused);
return pkg;
};
/** @} */
// FYI - this function is already commented above