1717#include < opencv2/gapi/gcommon.hpp>
1818#include < opencv2/gapi/gkernel.hpp>
1919#include < opencv2/gapi/garg.hpp>
20+ #include < opencv2/gapi/gmetaarg.hpp>
2021#include < opencv2/gapi/util/compiler_hints.hpp> // suppress_unused_warning
2122#include < opencv2/gapi/util/util.hpp>
2223
@@ -109,11 +110,17 @@ class GAPI_EXPORTS GCPUContext
109110 return outOpaqueRef (output).wref <T>();
110111 }
111112
113+ GArg state ()
114+ {
115+ return m_state;
116+ }
117+
112118protected:
113119 detail::VectorRef& outVecRef (int output);
114120 detail::OpaqueRef& outOpaqueRef (int output);
115121
116122 std::vector<GArg> m_args;
123+ GArg m_state;
117124
118125 // FIXME: avoid conversion of arguments from internal representation to OpenCV one on each call
119126 // to OCV kernel. (This can be achieved by a two single time conversions in GCPUExecutable::run,
@@ -127,16 +134,18 @@ class GAPI_EXPORTS GCPUContext
127134class GAPI_EXPORTS GCPUKernel
128135{
129136public:
130- // This function is kernel's execution entry point (does the processing work)
131- using F = std::function<void (GCPUContext &)>;
137+ // This function is a kernel's execution entry point (does the processing work)
138+ using RunF = std::function<void (GCPUContext &)>;
139+ // This function is a stateful kernel's setup routine (configures state)
140+ using SetupF = std::function<void (const GMetaArgs &, const GArgs &, GArg &)>;
132141
133142 GCPUKernel ();
134- explicit GCPUKernel (const F& f );
143+ GCPUKernel (const RunF& runF, const SetupF& setupF = nullptr );
135144
136- void apply (GCPUContext &ctx);
145+ RunF m_runF = nullptr ;
146+ SetupF m_setupF = nullptr ;
137147
138- protected:
139- F m_f;
148+ bool m_isStateful = false ;
140149};
141150
142151// FIXME: This is an ugly ad-hoc implementation. TODO: refactor
@@ -269,12 +278,38 @@ template<typename U> struct get_out<cv::GOpaque<U>>
269278 }
270279};
271280
281+ template <typename , typename >
282+ struct OCVSetupHelper ;
283+
284+ template <typename Impl, typename ... Ins>
285+ struct OCVSetupHelper <Impl, std::tuple<Ins...>>
286+ {
287+ template <int ... IIs>
288+ static void setup_impl (const GMetaArgs &metaArgs, const GArgs &args, GArg &state,
289+ detail::Seq<IIs...>)
290+ {
291+ // TODO: unique_ptr <-> shared_ptr conversion ?
292+ // To check: Conversion is possible only if the state which should be passed to
293+ // 'setup' user callback isn't required to have previous value
294+ std::shared_ptr<typename Impl::State> stPtr;
295+ Impl::setup (detail::get_in_meta<Ins>(metaArgs, args, IIs)..., stPtr);
296+ state = GArg (stPtr);
297+ }
298+
299+ static void setup (const GMetaArgs &metaArgs, const GArgs &args, GArg& state)
300+ {
301+ setup_impl (metaArgs, args, state,
302+ typename detail::MkSeq<sizeof ...(Ins)>::type ());
303+ }
304+ };
305+
306+ // OCVCallHelper is a helper class to call stateless OCV kernels and OCV kernel functors.
272307template <typename , typename , typename >
273308struct OCVCallHelper ;
274309
275310// FIXME: probably can be simplified with std::apply or analogue.
276311template <typename Impl, typename ... Ins, typename ... Outs>
277- struct OCVCallHelper <Impl, std::tuple<Ins...>, std::tuple<Outs...> >
312+ struct OCVCallHelper <Impl, std::tuple<Ins...>, std::tuple<Outs...>>
278313{
279314 template <typename ... Inputs>
280315 struct call_and_postprocess
@@ -302,19 +337,16 @@ struct OCVCallHelper<Impl, std::tuple<Ins...>, std::tuple<Outs...> >
302337 // by comparing it's state (data ptr) before and after the call.
303338 // This is done by converting each output Mat into tracked_cv_mat object, and binding
304339 // them to parameters of ad-hoc function
305- // Convert own::Scalar to cv::Scalar before call kernel and run kernel
306- // convert cv::Scalar to own::Scalar after call kernel and write back results
307340 call_and_postprocess<decltype (get_in<Ins>::get (ctx, IIs))...>
308- ::call (get_in<Ins>::get(ctx, IIs)...,
309- get_out<Outs>::get(ctx, OIs)...);
341+ ::call (get_in<Ins>::get(ctx, IIs)..., get_out<Outs>::get(ctx, OIs)...);
310342 }
311343
312344 template <int ... IIs, int ... OIs>
313- static void call_impl (cv::GCPUContext &ctx, Impl& impl, detail::Seq<IIs...>, detail::Seq<OIs...>)
345+ static void call_impl (cv::GCPUContext &ctx, Impl& impl,
346+ detail::Seq<IIs...>, detail::Seq<OIs...>)
314347 {
315- call_and_postprocess<decltype (cv::detail::get_in<Ins>::get (ctx, IIs))...>
316- ::call (impl, cv::detail::get_in<Ins>::get(ctx, IIs)...,
317- cv::detail::get_out<Outs>::get(ctx, OIs)...);
348+ call_and_postprocess<decltype (get_in<Ins>::get (ctx, IIs))...>
349+ ::call (impl, get_in<Ins>::get(ctx, IIs)..., get_out<Outs>::get(ctx, OIs)...);
318350 }
319351
320352 static void call (GCPUContext &ctx)
@@ -335,23 +367,78 @@ struct OCVCallHelper<Impl, std::tuple<Ins...>, std::tuple<Outs...> >
335367 }
336368};
337369
370+ // OCVStCallHelper is a helper class to call stateful OCV kernels.
371+ template <typename , typename , typename >
372+ struct OCVStCallHelper ;
373+
374+ template <typename Impl, typename ... Ins, typename ... Outs>
375+ struct OCVStCallHelper <Impl, std::tuple<Ins...>, std::tuple<Outs...>> :
376+ OCVCallHelper<Impl, std::tuple<Ins...>, std::tuple<Outs...>>
377+ {
378+ template <typename ... Inputs>
379+ struct call_and_postprocess
380+ {
381+ template <typename ... Outputs>
382+ static void call (typename Impl::State& st, Inputs&&... ins, Outputs&&... outs)
383+ {
384+ Impl::run (std::forward<Inputs>(ins)..., outs..., st);
385+ postprocess (outs...);
386+ }
387+ };
388+
389+ template <int ... IIs, int ... OIs>
390+ static void call_impl (GCPUContext &ctx, detail::Seq<IIs...>, detail::Seq<OIs...>)
391+ {
392+ auto & st = *ctx.state ().get <std::shared_ptr<typename Impl::State>>();
393+ call_and_postprocess<decltype (get_in<Ins>::get (ctx, IIs))...>
394+ ::call (st, get_in<Ins>::get(ctx, IIs)..., get_out<Outs>::get(ctx, OIs)...);
395+ }
396+
397+ static void call (GCPUContext &ctx)
398+ {
399+ call_impl (ctx,
400+ typename detail::MkSeq<sizeof ...(Ins)>::type (),
401+ typename detail::MkSeq<sizeof ...(Outs)>::type ());
402+ }
403+ };
404+
338405} // namespace detail
339406
340407template <class Impl , class K >
341- class GCPUKernelImpl : public cv ::detail::OCVCallHelper<Impl, typename K::InArgs, typename K::OutArgs>,
342- public cv::detail::KernelTag
408+ class GCPUKernelImpl : public cv ::detail::KernelTag
409+ {
410+ using CallHelper = detail::OCVCallHelper<Impl, typename K::InArgs, typename K::OutArgs>;
411+
412+ public:
413+ using API = K;
414+
415+ static cv::gapi::GBackend backend () { return cv::gapi::cpu::backend (); }
416+ static cv::GCPUKernel kernel () { return GCPUKernel (&CallHelper::call); }
417+ };
418+
419+ template <class Impl , class K , class S >
420+ class GCPUStKernelImpl : public cv ::detail::KernelTag
343421{
344- using P = detail::OCVCallHelper<Impl, typename K::InArgs, typename K::OutArgs>;
422+ using StSetupHelper = detail::OCVSetupHelper<Impl, typename K::InArgs>;
423+ using StCallHelper = detail::OCVStCallHelper<Impl, typename K::InArgs, typename K::OutArgs>;
345424
346425public:
347426 using API = K;
427+ using State = S;
348428
349- static cv::gapi::GBackend backend () { return cv::gapi::cpu::backend (); }
350- static cv::GCPUKernel kernel () { return GCPUKernel (&P::call); }
429+ static cv::gapi::GBackend backend () { return cv::gapi::cpu::backend (); }
430+ static cv::GCPUKernel kernel () { return GCPUKernel (&StCallHelper::call,
431+ &StSetupHelper::setup); }
351432};
352433
353434#define GAPI_OCV_KERNEL (Name, API ) struct Name : public cv ::GCPUKernelImpl<Name, API>
354435
436+ // TODO: Reuse Anatoliy's logic for support of types with commas in macro.
437+ // Retrieve the common part from Anatoliy's logic to the separate place.
438+ #define GAPI_OCV_KERNEL_ST (Name, API, State ) \
439+ struct Name :public cv ::GCPUStKernelImpl<Name, API, State> \
440+
441+
355442class gapi ::cpu::GOCVFunctor : public gapi::GFunctor
356443{
357444public:
0 commit comments