Publishing 2019 R1 content
[platform/upstream/dldt.git] / inference-engine / thirdparty / fluid / modules / gapi / src / backends / fluid / gfluidcore.cpp
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-2019 Intel Corporation
6
7 #if !defined(GAPI_STANDALONE)
8
9 #include "precomp.hpp"
10
11 #include "opencv2/gapi/own/assert.hpp"
12 #include "opencv2/core/traits.hpp"
13 #include "opencv2/core/hal/hal.hpp"
14 #include "opencv2/core/hal/intrin.hpp"
15
16 #include "opencv2/gapi/core.hpp"
17
18 #include "opencv2/gapi/fluid/gfluidbuffer.hpp"
19 #include "opencv2/gapi/fluid/gfluidkernel.hpp"
20 #include "opencv2/gapi/fluid/core.hpp"
21
22 #include "gfluidbuffer_priv.hpp"
23 #include "gfluidbackend.hpp"
24 #include "gfluidutils.hpp"
25
26 #include <cassert>
27 #include <cmath>
28 #include <cstdlib>
29
30 namespace cv {
31 namespace gapi {
32 namespace fluid {
33
34 //---------------------
35 //
36 // Arithmetic functions
37 //
38 //---------------------
39
40 template<typename DST, typename SRC1, typename SRC2>
41 static inline DST absdiff(SRC1 x, SRC2 y)
42 {
43     auto result = x > y? x - y: y - x;
44     return saturate<DST>(result, roundf);
45 }
46
47 template<typename DST, typename SRC1, typename SRC2>
48 static inline DST addWeighted(SRC1 src1, SRC2 src2, float alpha, float beta, float gamma)
49 {
50     float dst = src1*alpha + src2*beta + gamma;
51     return saturate<DST>(dst, roundf);
52 }
53
54 template<typename DST, typename SRC1, typename SRC2>
55 static inline DST add(SRC1 x, SRC2 y)
56 {
57     return saturate<DST>(x + y, roundf);
58 }
59
60 template<typename DST, typename SRC1, typename SRC2>
61 static inline DST sub(SRC1 x, SRC2 y)
62 {
63     return saturate<DST>(x - y, roundf);
64 }
65
66 template<typename DST, typename SRC1, typename SRC2>
67 static inline DST subr(SRC1 x, SRC2 y)
68 {
69     return saturate<DST>(y - x, roundf); // reverse: y - x
70 }
71
72 template<typename DST, typename SRC1, typename SRC2>
73 static inline DST mul(SRC1 x, SRC2 y, float scale=1)
74 {
75     auto result = scale * x * y;
76     return saturate<DST>(result, rintf);
77 }
78
79 template<typename DST, typename SRC1, typename SRC2>
80 static inline DST div(SRC1 x, SRC2 y, float scale=1)
81 {
82     // like OpenCV: returns 0, if y=0
83     auto result = y? scale * x / y: 0;
84     return saturate<DST>(result, rintf);
85 }
86
87 template<typename DST, typename SRC1, typename SRC2>
88 static inline DST divr(SRC1 x, SRC2 y, float scale=1)
89 {
90     auto result = x? scale * y / x: 0; // reverse: y / x
91     return saturate<DST>(result, rintf);
92 }
93
94 //---------------------------
95 //
96 // Fluid kernels: addWeighted
97 //
98 //---------------------------
99
100 template<typename DST, typename SRC1, typename SRC2>
101 static void run_addweighted(Buffer &dst, const View &src1, const View &src2,
102                             double alpha, double beta, double gamma)
103 {
104     static_assert(std::is_same<SRC1, SRC2>::value, "wrong types");
105
106     const auto *in1 = src1.InLine<SRC1>(0);
107     const auto *in2 = src2.InLine<SRC2>(0);
108           auto *out = dst.OutLine<DST>();
109
110     int width  = dst.length();
111     int chan   = dst.meta().chan;
112     int length = width * chan;
113
114     // NB: assume in/out types are not 64-bits
115     auto _alpha = static_cast<float>( alpha );
116     auto _beta  = static_cast<float>( beta  );
117     auto _gamma = static_cast<float>( gamma );
118
119     for (int l=0; l < length; l++)
120         out[l] = addWeighted<DST>(in1[l], in2[l], _alpha, _beta, _gamma);
121 }
122
123 GAPI_FLUID_KERNEL(GFluidAddW, cv::gapi::core::GAddW, false)
124 {
125     static const int Window = 1;
126
127     static void run(const View &src1, double alpha, const View &src2,
128                                       double beta, double gamma, int /*dtype*/,
129                         Buffer &dst)
130     {
131         //      DST     SRC1    SRC2    OP               __VA_ARGS__
132         BINARY_(uchar , uchar , uchar , run_addweighted, dst, src1, src2, alpha, beta, gamma);
133         BINARY_(uchar , ushort, ushort, run_addweighted, dst, src1, src2, alpha, beta, gamma);
134         BINARY_(uchar ,  short,  short, run_addweighted, dst, src1, src2, alpha, beta, gamma);
135         BINARY_( short,  short,  short, run_addweighted, dst, src1, src2, alpha, beta, gamma);
136         BINARY_(ushort, ushort, ushort, run_addweighted, dst, src1, src2, alpha, beta, gamma);
137         BINARY_( float, uchar , uchar , run_addweighted, dst, src1, src2, alpha, beta, gamma);
138         BINARY_( float, ushort, ushort, run_addweighted, dst, src1, src2, alpha, beta, gamma);
139         BINARY_( float,  short,  short, run_addweighted, dst, src1, src2, alpha, beta, gamma);
140
141         CV_Error(cv::Error::StsBadArg, "unsupported combination of types");
142     }
143 };
144
145 //--------------------------
146 //
147 // Fluid kernels: +, -, *, /
148 //
149 //--------------------------
150
151 enum Arithm { ARITHM_ABSDIFF, ARITHM_ADD, ARITHM_SUBTRACT, ARITHM_MULTIPLY, ARITHM_DIVIDE };
152
153 template<typename DST, typename SRC1, typename SRC2>
154 static void run_arithm(Buffer &dst, const View &src1, const View &src2, Arithm arithm,
155                        double scale=1)
156 {
157     static_assert(std::is_same<SRC1, SRC2>::value, "wrong types");
158
159     const auto *in1 = src1.InLine<SRC1>(0);
160     const auto *in2 = src2.InLine<SRC2>(0);
161           auto *out = dst.OutLine<DST>();
162
163     int width  = dst.length();
164     int chan   = dst.meta().chan;
165     int length = width * chan;
166
167     // NB: assume in/out types are not 64-bits
168     float _scale = static_cast<float>( scale );
169
170     switch (arithm)
171     {
172     case ARITHM_ABSDIFF:
173         for (int l=0; l < length; l++)
174             out[l] = absdiff<DST>(in1[l], in2[l]);
175         break;
176     case ARITHM_ADD:
177         for (int l=0; l < length; l++)
178             out[l] = add<DST>(in1[l], in2[l]);
179         break;
180     case ARITHM_SUBTRACT:
181         for (int l=0; l < length; l++)
182             out[l] = sub<DST>(in1[l], in2[l]);
183         break;
184     case ARITHM_MULTIPLY:
185         for (int l=0; l < length; l++)
186             out[l] = mul<DST>(in1[l], in2[l], _scale);
187         break;
188     case ARITHM_DIVIDE:
189         for (int l=0; l < length; l++)
190             out[l] = div<DST>(in1[l], in2[l], _scale);
191         break;
192     default: CV_Error(cv::Error::StsBadArg, "unsupported arithmetic operation");
193     }
194 }
195
196 GAPI_FLUID_KERNEL(GFluidAdd, cv::gapi::core::GAdd, false)
197 {
198     static const int Window = 1;
199
200     static void run(const View &src1, const View &src2, int /*dtype*/, Buffer &dst)
201     {
202         //      DST     SRC1    SRC2    OP          __VA_ARGS__
203         BINARY_(uchar , uchar , uchar , run_arithm, dst, src1, src2, ARITHM_ADD);
204         BINARY_(uchar ,  short,  short, run_arithm, dst, src1, src2, ARITHM_ADD);
205         BINARY_(uchar ,  float,  float, run_arithm, dst, src1, src2, ARITHM_ADD);
206         BINARY_( short,  short,  short, run_arithm, dst, src1, src2, ARITHM_ADD);
207         BINARY_( float, uchar , uchar , run_arithm, dst, src1, src2, ARITHM_ADD);
208         BINARY_( float,  short,  short, run_arithm, dst, src1, src2, ARITHM_ADD);
209         BINARY_( float,  float,  float, run_arithm, dst, src1, src2, ARITHM_ADD);
210
211         CV_Error(cv::Error::StsBadArg, "unsupported combination of types");
212     }
213 };
214
215 GAPI_FLUID_KERNEL(GFluidSub, cv::gapi::core::GSub, false)
216 {
217     static const int Window = 1;
218
219     static void run(const View &src1, const View &src2, int /*dtype*/, Buffer &dst)
220     {
221         //      DST     SRC1    SRC2    OP          __VA_ARGS__
222         BINARY_(uchar , uchar , uchar , run_arithm, dst, src1, src2, ARITHM_SUBTRACT);
223         BINARY_(uchar ,  short,  short, run_arithm, dst, src1, src2, ARITHM_SUBTRACT);
224         BINARY_(uchar ,  float,  float, run_arithm, dst, src1, src2, ARITHM_SUBTRACT);
225         BINARY_( short,  short,  short, run_arithm, dst, src1, src2, ARITHM_SUBTRACT);
226         BINARY_( float, uchar , uchar , run_arithm, dst, src1, src2, ARITHM_SUBTRACT);
227         BINARY_( float,  short,  short, run_arithm, dst, src1, src2, ARITHM_SUBTRACT);
228         BINARY_( float,  float,  float, run_arithm, dst, src1, src2, ARITHM_SUBTRACT);
229
230         CV_Error(cv::Error::StsBadArg, "unsupported combination of types");
231     }
232 };
233
234 GAPI_FLUID_KERNEL(GFluidMul, cv::gapi::core::GMul, false)
235 {
236     static const int Window = 1;
237
238     static void run(const View &src1, const View &src2, double scale, int /*dtype*/, Buffer &dst)
239     {
240         //      DST     SRC1    SRC2    OP          __VA_ARGS__
241         BINARY_(uchar , uchar , uchar , run_arithm, dst, src1, src2, ARITHM_MULTIPLY, scale);
242         BINARY_(uchar ,  short,  short, run_arithm, dst, src1, src2, ARITHM_MULTIPLY, scale);
243         BINARY_(uchar ,  float,  float, run_arithm, dst, src1, src2, ARITHM_MULTIPLY, scale);
244         BINARY_( short,  short,  short, run_arithm, dst, src1, src2, ARITHM_MULTIPLY, scale);
245         BINARY_( float, uchar , uchar , run_arithm, dst, src1, src2, ARITHM_MULTIPLY, scale);
246         BINARY_( float,  short,  short, run_arithm, dst, src1, src2, ARITHM_MULTIPLY, scale);
247         BINARY_( float,  float,  float, run_arithm, dst, src1, src2, ARITHM_MULTIPLY, scale);
248
249         CV_Error(cv::Error::StsBadArg, "unsupported combination of types");
250     }
251 };
252
253 GAPI_FLUID_KERNEL(GFluidDiv, cv::gapi::core::GDiv, false)
254 {
255     static const int Window = 1;
256
257     static void run(const View &src1, const View &src2, double scale, int /*dtype*/, Buffer &dst)
258     {
259         //      DST     SRC1    SRC2    OP          __VA_ARGS__
260         BINARY_(uchar , uchar , uchar , run_arithm, dst, src1, src2, ARITHM_DIVIDE, scale);
261         BINARY_(uchar ,  short,  short, run_arithm, dst, src1, src2, ARITHM_DIVIDE, scale);
262         BINARY_(uchar ,  float,  float, run_arithm, dst, src1, src2, ARITHM_DIVIDE, scale);
263         BINARY_( short,  short,  short, run_arithm, dst, src1, src2, ARITHM_DIVIDE, scale);
264         BINARY_( float, uchar , uchar , run_arithm, dst, src1, src2, ARITHM_DIVIDE, scale);
265         BINARY_( float,  short,  short, run_arithm, dst, src1, src2, ARITHM_DIVIDE, scale);
266         BINARY_( float,  float,  float, run_arithm, dst, src1, src2, ARITHM_DIVIDE, scale);
267
268         CV_Error(cv::Error::StsBadArg, "unsupported combination of types");
269     }
270 };
271
272 GAPI_FLUID_KERNEL(GFluidAbsDiff, cv::gapi::core::GAbsDiff, false)
273 {
274     static const int Window = 1;
275
276     static void run(const View &src1, const View &src2, Buffer &dst)
277     {
278         //      DST     SRC1    SRC2    OP          __VA_ARGS__
279         BINARY_(uchar , uchar , uchar , run_arithm, dst, src1, src2, ARITHM_ABSDIFF);
280         BINARY_(ushort, ushort, ushort, run_arithm, dst, src1, src2, ARITHM_ABSDIFF);
281         BINARY_( short,  short,  short, run_arithm, dst, src1, src2, ARITHM_ABSDIFF);
282         BINARY_( float,  float,  float, run_arithm, dst, src1, src2, ARITHM_ABSDIFF);
283
284         CV_Error(cv::Error::StsBadArg, "unsupported combination of types");
285     }
286 };
287
288 //--------------------------------------
289 //
290 // Fluid kernels: +, -, *, / with Scalar
291 //
292 //--------------------------------------
293
294 static inline v_uint16x8  v_add_16u(const v_uint16x8 &x, const v_uint16x8 &y) { return x + y; }
295 static inline v_uint16x8  v_sub_16u(const v_uint16x8 &x, const v_uint16x8 &y) { return x - y; }
296 static inline v_uint16x8 v_subr_16u(const v_uint16x8 &x, const v_uint16x8 &y) { return y - x; }
297
298 static inline v_float32x4  v_add_32f(const v_float32x4 &x, const v_float32x4 &y) { return x + y; }
299 static inline v_float32x4  v_sub_32f(const v_float32x4 &x, const v_float32x4 &y) { return x - y; }
300 static inline v_float32x4 v_subr_32f(const v_float32x4 &x, const v_float32x4 &y) { return y - x; }
301
302 static inline int  s_add_8u(uchar x, uchar y) { return x + y; }
303 static inline int  s_sub_8u(uchar x, uchar y) { return x - y; }
304 static inline int s_subr_8u(uchar x, uchar y) { return y - x; }
305
306 static inline float  s_add_32f(float x, float y) { return x + y; }
307 static inline float  s_sub_32f(float x, float y) { return x - y; }
308 static inline float s_subr_32f(float x, float y) { return y - x; }
309
310 // manual SIMD if important case 8UC3
311 static void run_arithm_s3(uchar out[], const uchar in[], int width, const uchar scalar[],
312                           v_uint16x8 (*v_op)(const v_uint16x8&, const v_uint16x8&),
313                           int (*s_op)(uchar, uchar))
314 {
315     int w = 0;
316
317 #if CV_SIMD128
318     for (; w <= width-16; w+=16)
319     {
320         v_uint8x16 x, y, z;
321         v_load_deinterleave(&in[3*w], x, y, z);
322
323         v_uint16x8 r0, r1;
324
325         v_expand(x, r0, r1);
326         r0 = v_op(r0, v_setall_u16(scalar[0])); // x + scalar[0]
327         r1 = v_op(r1, v_setall_u16(scalar[0]));
328         x = v_pack(r0, r1);
329
330         v_expand(y, r0, r1);
331         r0 = v_op(r0, v_setall_u16(scalar[1])); // y + scalar[1]
332         r1 = v_op(r1, v_setall_u16(scalar[1]));
333         y = v_pack(r0, r1);
334
335         v_expand(z, r0, r1);
336         r0 = v_op(r0, v_setall_u16(scalar[2])); // z + scalar[2]
337         r1 = v_op(r1, v_setall_u16(scalar[2]));
338         z = v_pack(r0, r1);
339
340         v_store_interleave(&out[3*w], x, y, z);
341     }
342 #endif
343     cv::util::suppress_unused_warning(v_op);
344     for (; w < width; w++)
345     {
346         out[3*w    ] = saturate<uchar>( s_op(in[3*w    ], scalar[0]) );
347         out[3*w + 1] = saturate<uchar>( s_op(in[3*w + 1], scalar[1]) );
348         out[3*w + 2] = saturate<uchar>( s_op(in[3*w + 2], scalar[2]) );
349     }
350 }
351
352 // manually SIMD if rounding 32F into 8U, single channel
353 static void run_arithm_s1(uchar out[], const float in[], int width, const float scalar[],
354                           v_float32x4 (*v_op)(const v_float32x4&, const v_float32x4&),
355                           float (*s_op)(float, float))
356 {
357     int w = 0;
358
359 #if CV_SIMD128
360     for (; w <= width-16; w+=16)
361     {
362         v_float32x4 r0, r1, r2, r3;
363         r0 = v_load(&in[w     ]);
364         r1 = v_load(&in[w +  4]);
365         r2 = v_load(&in[w +  8]);
366         r3 = v_load(&in[w + 12]);
367
368         r0 = v_op(r0, v_setall_f32(scalar[0])); // r + scalar[0]
369         r1 = v_op(r1, v_setall_f32(scalar[0]));
370         r2 = v_op(r2, v_setall_f32(scalar[0]));
371         r3 = v_op(r3, v_setall_f32(scalar[0]));
372
373         v_int32x4 i0, i1, i2, i3;
374         i0 = v_round(r0);
375         i1 = v_round(r1);
376         i2 = v_round(r2);
377         i3 = v_round(r3);
378
379         v_uint16x8 us0, us1;
380         us0 = v_pack_u(i0, i1);
381         us1 = v_pack_u(i2, i3);
382
383         v_uint8x16 uc;
384         uc = v_pack(us0, us1);
385
386         v_store(&out[w], uc);
387     }
388 #endif
389     cv::util::suppress_unused_warning(v_op);
390     for (; w < width; w++)
391     {
392         out[w] = saturate<uchar>(s_op(in[w], scalar[0]), std::roundf);
393     }
394 }
395
396 static void run_arithm_s_add3(uchar out[], const uchar in[], int width, const uchar scalar[])
397 {
398     run_arithm_s3(out, in, width, scalar, v_add_16u, s_add_8u);
399 }
400
401 static void run_arithm_s_sub3(uchar out[], const uchar in[], int width, const uchar scalar[])
402 {
403     run_arithm_s3(out, in, width, scalar, v_sub_16u, s_sub_8u);
404 }
405
406 static void run_arithm_s_subr3(uchar out[], const uchar in[], int width, const uchar scalar[])
407 {
408     run_arithm_s3(out, in, width, scalar, v_subr_16u, s_subr_8u); // reverse: subr
409 }
410
411 static void run_arithm_s_add1(uchar out[], const float in[], int width, const float scalar[])
412 {
413     run_arithm_s1(out, in, width, scalar, v_add_32f, s_add_32f);
414 }
415
416 static void run_arithm_s_sub1(uchar out[], const float in[], int width, const float scalar[])
417 {
418     run_arithm_s1(out, in, width, scalar, v_sub_32f, s_sub_32f);
419 }
420
421 static void run_arithm_s_subr1(uchar out[], const float in[], int width, const float scalar[])
422 {
423     run_arithm_s1(out, in, width, scalar, v_subr_32f, s_subr_32f); // reverse: subr
424 }
425
426 // manually unroll the inner cycle by channels
427 template<typename DST, typename SRC, typename SCALAR, typename FUNC>
428 static void run_arithm_s(DST out[], const SRC in[], int width, int chan,
429                          const SCALAR scalar[4], FUNC func)
430 {
431     if (chan == 4)
432     {
433         for (int w=0; w < width; w++)
434         {
435             out[4*w + 0] = func(in[4*w + 0], scalar[0]);
436             out[4*w + 1] = func(in[4*w + 1], scalar[1]);
437             out[4*w + 2] = func(in[4*w + 2], scalar[2]);
438             out[4*w + 3] = func(in[4*w + 3], scalar[3]);
439         }
440     }
441     else
442     if (chan == 3)
443     {
444         for (int w=0; w < width; w++)
445         {
446             out[3*w + 0] = func(in[3*w + 0], scalar[0]);
447             out[3*w + 1] = func(in[3*w + 1], scalar[1]);
448             out[3*w + 2] = func(in[3*w + 2], scalar[2]);
449         }
450     }
451     else
452     if (chan == 2)
453     {
454         for (int w=0; w < width; w++)
455         {
456             out[2*w + 0] = func(in[2*w + 0], scalar[0]);
457             out[2*w + 1] = func(in[2*w + 1], scalar[1]);
458         }
459     }
460     else
461     if (chan == 1)
462     {
463         for (int w=0; w < width; w++)
464         {
465             out[w] = func(in[w], scalar[0]);
466         }
467     }
468     else
469         CV_Error(cv::Error::StsBadArg, "unsupported number of channels");
470 }
471
472 template<typename DST, typename SRC>
473 static void run_arithm_s(Buffer &dst, const View &src, const float scalar[4], Arithm arithm,
474                          float scale=1)
475 {
476     const auto *in  = src.InLine<SRC>(0);
477           auto *out = dst.OutLine<DST>();
478
479     int width  = dst.length();
480     int chan   = dst.meta().chan;
481
482     // What if we cast the scalar into the SRC type?
483     const SRC myscal[4] = { static_cast<SRC>(scalar[0]), static_cast<SRC>(scalar[1]),
484                             static_cast<SRC>(scalar[2]), static_cast<SRC>(scalar[3]) };
485     bool usemyscal = (myscal[0] == scalar[0]) && (myscal[1] == scalar[1]) &&
486                      (myscal[2] == scalar[2]) && (myscal[3] == scalar[3]);
487
488     switch (arithm)
489     {
490     case ARITHM_ABSDIFF:
491         for (int w=0; w < width; w++)
492             for (int c=0; c < chan; c++)
493                 out[chan*w + c] = absdiff<DST>(in[chan*w + c], scalar[c]);
494         break;
495     case ARITHM_ADD:
496         if (usemyscal)
497         {
498             if (std::is_same<DST,uchar>::value &&
499                 std::is_same<SRC,uchar>::value &&
500                 chan == 3)
501                 run_arithm_s_add3((uchar*)out, (const uchar*)in, width, (const uchar*)myscal);
502             else if (std::is_same<DST,uchar>::value &&
503                      std::is_same<SRC,float>::value &&
504                      chan == 1)
505                 run_arithm_s_add1((uchar*)out, (const float*)in, width, (const float*)myscal);
506             else
507                 run_arithm_s(out, in, width, chan, myscal, add<DST,SRC,SRC>);
508         }
509         else
510             run_arithm_s(out, in, width, chan, scalar, add<DST,SRC,float>);
511         break;
512     case ARITHM_SUBTRACT:
513         if (usemyscal)
514         {
515             if (std::is_same<DST,uchar>::value &&
516                 std::is_same<SRC,uchar>::value &&
517                 chan == 3)
518                 run_arithm_s_sub3((uchar*)out, (const uchar*)in, width, (const uchar*)myscal);
519             else if (std::is_same<DST,uchar>::value &&
520                      std::is_same<SRC,float>::value &&
521                      chan == 1)
522                 run_arithm_s_sub1((uchar*)out, (const float*)in, width, (const float*)myscal);
523             else
524                 run_arithm_s(out, in, width, chan, myscal, sub<DST,SRC,SRC>);
525         }
526         else
527             run_arithm_s(out, in, width, chan, scalar, sub<DST,SRC,float>);
528         break;
529     // TODO: optimize miltiplication and division
530     case ARITHM_MULTIPLY:
531         for (int w=0; w < width; w++)
532             for (int c=0; c < chan; c++)
533                 out[chan*w + c] = mul<DST>(in[chan*w + c], scalar[c], scale);
534         break;
535     case ARITHM_DIVIDE:
536         for (int w=0; w < width; w++)
537             for (int c=0; c < chan; c++)
538                 out[chan*w + c] = div<DST>(in[chan*w + c], scalar[c], scale);
539         break;
540     default: CV_Error(cv::Error::StsBadArg, "unsupported arithmetic operation");
541     }
542 }
543
544 template<typename DST, typename SRC>
545 static void run_arithm_rs(Buffer &dst, const View &src, const float scalar[4], Arithm arithm,
546                           float scale=1)
547 {
548     const auto *in  = src.InLine<SRC>(0);
549           auto *out = dst.OutLine<DST>();
550
551     int width  = dst.length();
552     int chan   = dst.meta().chan;
553
554     // What if we cast the scalar into the SRC type?
555     const SRC myscal[4] = { static_cast<SRC>(scalar[0]), static_cast<SRC>(scalar[1]),
556                             static_cast<SRC>(scalar[2]), static_cast<SRC>(scalar[3]) };
557     bool usemyscal = (myscal[0] == scalar[0]) && (myscal[1] == scalar[1]) &&
558                      (myscal[2] == scalar[2]) && (myscal[3] == scalar[3]);
559
560     switch (arithm)
561     {
562     case ARITHM_SUBTRACT:
563         if (usemyscal)
564         {
565             if (std::is_same<DST,uchar>::value &&
566                 std::is_same<SRC,uchar>::value &&
567                 chan == 3)
568                 run_arithm_s_subr3((uchar*)out, (const uchar*)in, width, (const uchar*)myscal);
569             else if (std::is_same<DST,uchar>::value &&
570                      std::is_same<SRC,float>::value &&
571                      chan == 1)
572                 run_arithm_s_subr1((uchar*)out, (const float*)in, width, (const float*)myscal);
573             else
574                 run_arithm_s(out, in, width, chan, myscal, subr<DST,SRC,SRC>);
575         }
576         else
577             run_arithm_s(out, in, width, chan, scalar, subr<DST,SRC,float>);
578         break;
579     // TODO: optimize division
580     case ARITHM_DIVIDE:
581         for (int w=0; w < width; w++)
582             for (int c=0; c < chan; c++)
583                 out[chan*w + c] = div<DST>(scalar[c], in[chan*w + c], scale);
584         break;
585     default: CV_Error(cv::Error::StsBadArg, "unsupported arithmetic operation");
586     }
587 }
588
589 GAPI_FLUID_KERNEL(GFluidAbsDiffC, cv::gapi::core::GAbsDiffC, false)
590 {
591     static const int Window = 1;
592
593     static void run(const View &src, const cv::Scalar &_scalar, Buffer &dst)
594     {
595         const float scalar[4] = {
596             static_cast<float>(_scalar[0]),
597             static_cast<float>(_scalar[1]),
598             static_cast<float>(_scalar[2]),
599             static_cast<float>(_scalar[3])
600         };
601
602         //     DST     SRC     OP            __VA_ARGS__
603         UNARY_(uchar , uchar , run_arithm_s, dst, src, scalar, ARITHM_ABSDIFF);
604         UNARY_(ushort, ushort, run_arithm_s, dst, src, scalar, ARITHM_ABSDIFF);
605         UNARY_( short,  short, run_arithm_s, dst, src, scalar, ARITHM_ABSDIFF);
606
607         CV_Error(cv::Error::StsBadArg, "unsupported combination of types");
608     }
609 };
610
611 GAPI_FLUID_KERNEL(GFluidAddC, cv::gapi::core::GAddC, false)
612 {
613     static const int Window = 1;
614
615     static void run(const View &src, const cv::Scalar &_scalar, int /*dtype*/, Buffer &dst)
616     {
617         const float scalar[4] = {
618             static_cast<float>(_scalar[0]),
619             static_cast<float>(_scalar[1]),
620             static_cast<float>(_scalar[2]),
621             static_cast<float>(_scalar[3])
622         };
623
624         //     DST     SRC     OP            __VA_ARGS__
625         UNARY_(uchar , uchar , run_arithm_s, dst, src, scalar, ARITHM_ADD);
626         UNARY_(uchar ,  short, run_arithm_s, dst, src, scalar, ARITHM_ADD);
627         UNARY_(uchar ,  float, run_arithm_s, dst, src, scalar, ARITHM_ADD);
628         UNARY_( short,  short, run_arithm_s, dst, src, scalar, ARITHM_ADD);
629         UNARY_( float, uchar , run_arithm_s, dst, src, scalar, ARITHM_ADD);
630         UNARY_( float,  short, run_arithm_s, dst, src, scalar, ARITHM_ADD);
631         UNARY_( float,  float, run_arithm_s, dst, src, scalar, ARITHM_ADD);
632
633         CV_Error(cv::Error::StsBadArg, "unsupported combination of types");
634     }
635 };
636
637 GAPI_FLUID_KERNEL(GFluidSubC, cv::gapi::core::GSubC, false)
638 {
639     static const int Window = 1;
640
641     static void run(const View &src, const cv::Scalar &_scalar, int /*dtype*/, Buffer &dst)
642     {
643         const float scalar[4] = {
644             static_cast<float>(_scalar[0]),
645             static_cast<float>(_scalar[1]),
646             static_cast<float>(_scalar[2]),
647             static_cast<float>(_scalar[3])
648         };
649
650         //     DST     SRC     OP            __VA_ARGS__
651         UNARY_(uchar , uchar , run_arithm_s, dst, src, scalar, ARITHM_SUBTRACT);
652         UNARY_(uchar ,  short, run_arithm_s, dst, src, scalar, ARITHM_SUBTRACT);
653         UNARY_(uchar ,  float, run_arithm_s, dst, src, scalar, ARITHM_SUBTRACT);
654         UNARY_( short,  short, run_arithm_s, dst, src, scalar, ARITHM_SUBTRACT);
655         UNARY_( float, uchar , run_arithm_s, dst, src, scalar, ARITHM_SUBTRACT);
656         UNARY_( float,  short, run_arithm_s, dst, src, scalar, ARITHM_SUBTRACT);
657         UNARY_( float,  float, run_arithm_s, dst, src, scalar, ARITHM_SUBTRACT);
658
659         CV_Error(cv::Error::StsBadArg, "unsupported combination of types");
660     }
661 };
662
663 GAPI_FLUID_KERNEL(GFluidSubRC, cv::gapi::core::GSubRC, false)
664 {
665     static const int Window = 1;
666
667     static void run(const cv::Scalar &_scalar, const View &src, int /*dtype*/, Buffer &dst)
668     {
669         const float scalar[4] = {
670             static_cast<float>(_scalar[0]),
671             static_cast<float>(_scalar[1]),
672             static_cast<float>(_scalar[2]),
673             static_cast<float>(_scalar[3])
674         };
675
676         //     DST     SRC     OP             __VA_ARGS__
677         UNARY_(uchar , uchar , run_arithm_rs, dst, src, scalar, ARITHM_SUBTRACT);
678         UNARY_(uchar ,  short, run_arithm_rs, dst, src, scalar, ARITHM_SUBTRACT);
679         UNARY_(uchar ,  float, run_arithm_rs, dst, src, scalar, ARITHM_SUBTRACT);
680         UNARY_( short,  short, run_arithm_rs, dst, src, scalar, ARITHM_SUBTRACT);
681         UNARY_( float, uchar , run_arithm_rs, dst, src, scalar, ARITHM_SUBTRACT);
682         UNARY_( float,  short, run_arithm_rs, dst, src, scalar, ARITHM_SUBTRACT);
683         UNARY_( float,  float, run_arithm_rs, dst, src, scalar, ARITHM_SUBTRACT);
684
685         CV_Error(cv::Error::StsBadArg, "unsupported combination of types");
686     }
687 };
688
689 GAPI_FLUID_KERNEL(GFluidMulC, cv::gapi::core::GMulC, false)
690 {
691     static const int Window = 1;
692
693     static void run(const View &src, const cv::Scalar &_scalar, int /*dtype*/, Buffer &dst)
694     {
695         const float scalar[4] = {
696             static_cast<float>(_scalar[0]),
697             static_cast<float>(_scalar[1]),
698             static_cast<float>(_scalar[2]),
699             static_cast<float>(_scalar[3])
700         };
701         const float scale = 1.f;
702
703         //     DST     SRC     OP            __VA_ARGS__
704         UNARY_(uchar , uchar , run_arithm_s, dst, src, scalar, ARITHM_MULTIPLY, scale);
705         UNARY_(uchar ,  short, run_arithm_s, dst, src, scalar, ARITHM_MULTIPLY, scale);
706         UNARY_(uchar ,  float, run_arithm_s, dst, src, scalar, ARITHM_MULTIPLY, scale);
707         UNARY_( short,  short, run_arithm_s, dst, src, scalar, ARITHM_MULTIPLY, scale);
708         UNARY_( float, uchar , run_arithm_s, dst, src, scalar, ARITHM_MULTIPLY, scale);
709         UNARY_( float,  short, run_arithm_s, dst, src, scalar, ARITHM_MULTIPLY, scale);
710         UNARY_( float,  float, run_arithm_s, dst, src, scalar, ARITHM_MULTIPLY, scale);
711
712         CV_Error(cv::Error::StsBadArg, "unsupported combination of types");
713     }
714 };
715
716 GAPI_FLUID_KERNEL(GFluidMulCOld, cv::gapi::core::GMulCOld, false)
717 {
718     static const int Window = 1;
719
720     static void run(const View &src, double _scalar, int /*dtype*/, Buffer &dst)
721     {
722         const float scalar[4] = {
723             static_cast<float>(_scalar),
724             static_cast<float>(_scalar),
725             static_cast<float>(_scalar),
726             static_cast<float>(_scalar)
727         };
728         const float scale = 1.f;
729
730         //     DST     SRC     OP            __VA_ARGS__
731         UNARY_(uchar , uchar , run_arithm_s, dst, src, scalar, ARITHM_MULTIPLY, scale);
732         UNARY_(uchar ,  short, run_arithm_s, dst, src, scalar, ARITHM_MULTIPLY, scale);
733         UNARY_(uchar ,  float, run_arithm_s, dst, src, scalar, ARITHM_MULTIPLY, scale);
734         UNARY_( short,  short, run_arithm_s, dst, src, scalar, ARITHM_MULTIPLY, scale);
735         UNARY_( float, uchar , run_arithm_s, dst, src, scalar, ARITHM_MULTIPLY, scale);
736         UNARY_( float,  short, run_arithm_s, dst, src, scalar, ARITHM_MULTIPLY, scale);
737         UNARY_( float,  float, run_arithm_s, dst, src, scalar, ARITHM_MULTIPLY, scale);
738
739         CV_Error(cv::Error::StsBadArg, "unsupported combination of types");
740     }
741 };
742
743 GAPI_FLUID_KERNEL(GFluidDivC, cv::gapi::core::GDivC, false)
744 {
745     static const int Window = 1;
746
747     static void run(const View &src, const cv::Scalar &_scalar, double _scale, int /*dtype*/,
748                     Buffer &dst)
749     {
750         const float scalar[4] = {
751             static_cast<float>(_scalar[0]),
752             static_cast<float>(_scalar[1]),
753             static_cast<float>(_scalar[2]),
754             static_cast<float>(_scalar[3])
755         };
756         const float scale = static_cast<float>(_scale);
757
758         //     DST     SRC     OP            __VA_ARGS__
759         UNARY_(uchar , uchar , run_arithm_s, dst, src, scalar, ARITHM_DIVIDE, scale);
760         UNARY_(uchar ,  short, run_arithm_s, dst, src, scalar, ARITHM_DIVIDE, scale);
761         UNARY_(uchar ,  float, run_arithm_s, dst, src, scalar, ARITHM_DIVIDE, scale);
762         UNARY_( short,  short, run_arithm_s, dst, src, scalar, ARITHM_DIVIDE, scale);
763         UNARY_( float, uchar , run_arithm_s, dst, src, scalar, ARITHM_DIVIDE, scale);
764         UNARY_( float,  short, run_arithm_s, dst, src, scalar, ARITHM_DIVIDE, scale);
765         UNARY_( float,  float, run_arithm_s, dst, src, scalar, ARITHM_DIVIDE, scale);
766
767         CV_Error(cv::Error::StsBadArg, "unsupported combination of types");
768     }
769 };
770
771 GAPI_FLUID_KERNEL(GFluidDivRC, cv::gapi::core::GDivRC, false)
772 {
773     static const int Window = 1;
774
775     static void run(const cv::Scalar &_scalar, const View &src, double _scale, int /*dtype*/,
776                     Buffer &dst)
777     {
778         const float scalar[4] = {
779             static_cast<float>(_scalar[0]),
780             static_cast<float>(_scalar[1]),
781             static_cast<float>(_scalar[2]),
782             static_cast<float>(_scalar[3])
783         };
784         const float scale = static_cast<float>(_scale);
785
786         //     DST     SRC     OP             __VA_ARGS__
787         UNARY_(uchar , uchar , run_arithm_rs, dst, src, scalar, ARITHM_DIVIDE, scale);
788         UNARY_(uchar ,  short, run_arithm_rs, dst, src, scalar, ARITHM_DIVIDE, scale);
789         UNARY_(uchar ,  float, run_arithm_rs, dst, src, scalar, ARITHM_DIVIDE, scale);
790         UNARY_( short,  short, run_arithm_rs, dst, src, scalar, ARITHM_DIVIDE, scale);
791         UNARY_( float, uchar , run_arithm_rs, dst, src, scalar, ARITHM_DIVIDE, scale);
792         UNARY_( float,  short, run_arithm_rs, dst, src, scalar, ARITHM_DIVIDE, scale);
793         UNARY_( float,  float, run_arithm_rs, dst, src, scalar, ARITHM_DIVIDE, scale);
794
795         CV_Error(cv::Error::StsBadArg, "unsupported combination of types");
796     }
797 };
798
799 //----------------------------
800 //
801 // Fluid math kernels: bitwise
802 //
803 //----------------------------
804
805 enum Bitwise { BW_AND, BW_OR, BW_XOR, BW_NOT };
806
807 template<typename DST, typename SRC1, typename SRC2>
808 static void run_bitwise2(Buffer &dst, const View &src1, const View &src2, Bitwise bitwise)
809 {
810     static_assert(std::is_same<DST, SRC1>::value, "wrong types");
811     static_assert(std::is_same<DST, SRC2>::value, "wrong types");
812
813     const auto *in1 = src1.InLine<SRC1>(0);
814     const auto *in2 = src2.InLine<SRC2>(0);
815           auto *out = dst.OutLine<DST>();
816
817     int width  = dst.length();
818     int chan   = dst.meta().chan;
819     int length = width * chan;
820
821     switch (bitwise)
822     {
823     case BW_AND:
824         for (int l=0; l < length; l++)
825             out[l] = in1[l] & in2[l];
826         break;
827     case BW_OR:
828         for (int l=0; l < length; l++)
829             out[l] = in1[l] | in2[l];
830         break;
831     case BW_XOR:
832         for (int l=0; l < length; l++)
833             out[l] = in1[l] ^ in2[l];
834         break;
835     default: CV_Error(cv::Error::StsBadArg, "unsupported bitwise operation");
836     }
837 }
838
839 template<typename DST, typename SRC>
840 static void run_bitwise1(Buffer &dst, const View &src, Bitwise bitwise)
841 {
842     static_assert(std::is_same<DST, SRC>::value, "wrong types");
843
844     const auto *in  = src.InLine<SRC>(0);
845           auto *out = dst.OutLine<DST>();
846
847     int width  = dst.length();
848     int chan   = dst.meta().chan;
849     int length = width * chan;
850
851     switch (bitwise)
852     {
853     case BW_NOT:
854         for (int l=0; l < length; l++)
855             out[l] = ~in[l];
856         break;
857     default: CV_Error(cv::Error::StsBadArg, "unsupported bitwise operation");
858     }
859 }
860
861 GAPI_FLUID_KERNEL(GFluidAnd, cv::gapi::core::GAnd, false)
862 {
863     static const int Window = 1;
864
865     static void run(const View &src1, const View &src2, Buffer &dst)
866     {
867
868         //      DST     SRC1    SRC2    OP            __VA_ARGS__
869         BINARY_(uchar , uchar , uchar , run_bitwise2, dst, src1, src2, BW_AND);
870         BINARY_(ushort, ushort, ushort, run_bitwise2, dst, src1, src2, BW_AND);
871         BINARY_( short,  short,  short, run_bitwise2, dst, src1, src2, BW_AND);
872
873         CV_Error(cv::Error::StsBadArg, "unsupported combination of types");
874     }
875 };
876
877 GAPI_FLUID_KERNEL(GFluidOr, cv::gapi::core::GOr, false)
878 {
879     static const int Window = 1;
880
881     static void run(const View &src1, const View &src2, Buffer &dst)
882     {
883
884         //      DST     SRC1    SRC2    OP            __VA_ARGS__
885         BINARY_(uchar , uchar , uchar , run_bitwise2, dst, src1, src2, BW_OR);
886         BINARY_(ushort, ushort, ushort, run_bitwise2, dst, src1, src2, BW_OR);
887         BINARY_( short,  short,  short, run_bitwise2, dst, src1, src2, BW_OR);
888
889         CV_Error(cv::Error::StsBadArg, "unsupported combination of types");
890     }
891 };
892
893 GAPI_FLUID_KERNEL(GFluidXor, cv::gapi::core::GXor, false)
894 {
895     static const int Window = 1;
896
897     static void run(const View &src1, const View &src2, Buffer &dst)
898     {
899
900         //      DST     SRC1    SRC2    OP            __VA_ARGS__
901         BINARY_(uchar , uchar , uchar , run_bitwise2, dst, src1, src2, BW_XOR);
902         BINARY_(ushort, ushort, ushort, run_bitwise2, dst, src1, src2, BW_XOR);
903         BINARY_( short,  short,  short, run_bitwise2, dst, src1, src2, BW_XOR);
904
905         CV_Error(cv::Error::StsBadArg, "unsupported combination of types");
906     }
907 };
908
909 GAPI_FLUID_KERNEL(GFluidNot, cv::gapi::core::GNot, false)
910 {
911     static const int Window = 1;
912
913     static void run(const View &src, Buffer &dst)
914     {
915         //     DST     SRC     OP            __VA_ARGS__
916         UNARY_(uchar , uchar , run_bitwise1, dst, src, BW_NOT);
917         UNARY_(ushort, ushort, run_bitwise1, dst, src, BW_NOT);
918         UNARY_( short,  short, run_bitwise1, dst, src, BW_NOT);
919
920         CV_Error(cv::Error::StsBadArg, "unsupported combination of types");
921     }
922 };
923
924 //-------------------
925 //
926 // Fluid kernels: LUT
927 //
928 //-------------------
929
930 GAPI_FLUID_KERNEL(GFluidLUT, cv::gapi::core::GLUT, false)
931 {
932     static const int Window = 1;
933
934     static void run(const View &src, const cv::Mat& lut, Buffer &dst)
935     {
936         GAPI_Assert(CV_8U == dst.meta().depth);
937         GAPI_Assert(CV_8U == src.meta().depth);
938
939         GAPI_DbgAssert(CV_8U == lut.type());
940         GAPI_DbgAssert(256 == lut.cols * lut.rows);
941         GAPI_DbgAssert(dst.length() == src.length());
942         GAPI_DbgAssert(dst.meta().chan == src.meta().chan);
943
944         const auto *in  = src.InLine<uchar>(0);
945               auto *out = dst.OutLine<uchar>();
946
947         int width  = dst.length();
948         int chan   = dst.meta().chan;
949         int length = width * chan;
950
951         for (int l=0; l < length; l++)
952             out[l] = lut.data[ in[l] ];
953     }
954 };
955
956 //-------------------------
957 //
958 // Fluid kernels: convertTo
959 //
960 //-------------------------
961
962 template<typename DST, typename SRC>
963 static void run_convertto(Buffer &dst, const View &src, double _alpha, double _beta)
964 {
965     const auto *in  = src.InLine<SRC>(0);
966           auto *out = dst.OutLine<DST>();
967
968     int width  = dst.length();
969     int chan   = dst.meta().chan;
970     int length = width * chan;
971
972     // NB: don't do this if SRC or DST is 64-bit
973     auto alpha = static_cast<float>( _alpha );
974     auto beta  = static_cast<float>( _beta  );
975
976     // compute faster if no alpha no beta
977     if (alpha == 1 && beta == 0)
978     {
979         // manual SIMD if need rounding
980         if (std::is_integral<DST>::value && std::is_floating_point<SRC>::value)
981         {
982             GAPI_Assert(( std::is_same<SRC,float>::value ));
983
984             int l = 0; // cycle index
985
986         #if CV_SIMD128
987             if (std::is_same<DST,uchar>::value)
988             {
989                 for (; l <= length-16; l+=16)
990                 {
991                     v_int32x4 i0, i1, i2, i3;
992                     i0 = v_round( v_load( (float*)& in[l     ] ) );
993                     i1 = v_round( v_load( (float*)& in[l +  4] ) );
994                     i2 = v_round( v_load( (float*)& in[l +  8] ) );
995                     i3 = v_round( v_load( (float*)& in[l + 12] ) );
996
997                     v_uint16x8 us0, us1;
998                     us0 = v_pack_u(i0, i1);
999                     us1 = v_pack_u(i2, i3);
1000
1001                     v_uint8x16 uc;
1002                     uc = v_pack(us0, us1);
1003                     v_store((uchar*)& out[l], uc);
1004                 }
1005             }
1006             if (std::is_same<DST,ushort>::value)
1007             {
1008                 for (; l <= length-8; l+=8)
1009                 {
1010                     v_int32x4 i0, i1;
1011                     i0 = v_round( v_load( (float*)& in[l     ] ) );
1012                     i1 = v_round( v_load( (float*)& in[l +  4] ) );
1013
1014                     v_uint16x8 us;
1015                     us = v_pack_u(i0, i1);
1016                     v_store((ushort*)& out[l], us);
1017                 }
1018             }
1019         #endif
1020
1021             // tail of SIMD cycle
1022             for (; l < length; l++)
1023             {
1024                 out[l] = saturate<DST>(in[l], rintf);
1025             }
1026         }
1027         else if (std::is_integral<DST>::value) // here SRC is integral
1028         {
1029             for (int l=0; l < length; l++)
1030             {
1031                 out[l] = saturate<DST>(in[l]);
1032             }
1033         }
1034         else // DST is floating-point, SRC is any
1035         {
1036             for (int l=0; l < length; l++)
1037             {
1038                 out[l] = static_cast<DST>(in[l]);
1039             }
1040         }
1041     }
1042     else // if alpha or beta is non-trivial
1043     {
1044         // TODO: optimize if alpha and beta and data are integral
1045         for (int l=0; l < length; l++)
1046         {
1047             out[l] = saturate<DST>(in[l]*alpha + beta, rintf);
1048         }
1049     }
1050 }
1051
1052 GAPI_FLUID_KERNEL(GFluidConvertTo, cv::gapi::core::GConvertTo, false)
1053 {
1054     static const int Window = 1;
1055
1056     static void run(const View &src, int /*rtype*/, double alpha, double beta, Buffer &dst)
1057     {
1058         //     DST     SRC     OP             __VA_ARGS__
1059         UNARY_(uchar , uchar , run_convertto, dst, src, alpha, beta);
1060         UNARY_(uchar , ushort, run_convertto, dst, src, alpha, beta);
1061         UNARY_(uchar ,  float, run_convertto, dst, src, alpha, beta);
1062         UNARY_(ushort, uchar , run_convertto, dst, src, alpha, beta);
1063         UNARY_(ushort, ushort, run_convertto, dst, src, alpha, beta);
1064         UNARY_(ushort,  float, run_convertto, dst, src, alpha, beta);
1065         UNARY_( float, uchar , run_convertto, dst, src, alpha, beta);
1066         UNARY_( float, ushort, run_convertto, dst, src, alpha, beta);
1067         UNARY_( float,  float, run_convertto, dst, src, alpha, beta);
1068
1069         CV_Error(cv::Error::StsBadArg, "unsupported combination of types");
1070     }
1071 };
1072
1073 //-----------------------------
1074 //
1075 // Fluid math kernels: min, max
1076 //
1077 //-----------------------------
1078
1079 enum Minmax { MM_MIN, MM_MAX };
1080
1081 template<typename DST, typename SRC1, typename SRC2>
1082 static void run_minmax(Buffer &dst, const View &src1, const View &src2, Minmax minmax)
1083 {
1084     static_assert(std::is_same<DST, SRC1>::value, "wrong types");
1085     static_assert(std::is_same<DST, SRC2>::value, "wrong types");
1086
1087     const auto *in1 = src1.InLine<SRC1>(0);
1088     const auto *in2 = src2.InLine<SRC2>(0);
1089           auto *out = dst.OutLine<DST>();
1090
1091     int width = dst.length();
1092     int chan  = dst.meta().chan;
1093
1094     int length = width * chan;
1095
1096     switch (minmax)
1097     {
1098     case MM_MIN:
1099         for (int l=0; l < length; l++)
1100             out[l] = in1[l] < in2[l]? in1[l]: in2[l];
1101         break;
1102     case MM_MAX:
1103         for (int l=0; l < length; l++)
1104             out[l] = in1[l] > in2[l]? in1[l]: in2[l];
1105         break;
1106     default: CV_Error(cv::Error::StsBadArg, "unsupported min/max operation");
1107     }
1108 }
1109
1110 GAPI_FLUID_KERNEL(GFluidMin, cv::gapi::core::GMin, false)
1111 {
1112     static const int Window = 1;
1113
1114     static void run(const View &src1, const View &src2, Buffer &dst)
1115     {
1116         //      DST     SRC1    SRC2    OP          __VA_ARGS__
1117         BINARY_(uchar , uchar , uchar , run_minmax, dst, src1, src2, MM_MIN);
1118         BINARY_(ushort, ushort, ushort, run_minmax, dst, src1, src2, MM_MIN);
1119         BINARY_( short,  short,  short, run_minmax, dst, src1, src2, MM_MIN);
1120         BINARY_( float,  float,  float, run_minmax, dst, src1, src2, MM_MIN);
1121
1122         CV_Error(cv::Error::StsBadArg, "unsupported combination of types");
1123     }
1124 };
1125
1126 GAPI_FLUID_KERNEL(GFluidMax, cv::gapi::core::GMax, false)
1127 {
1128     static const int Window = 1;
1129
1130     static void run(const View &src1, const View &src2, Buffer &dst)
1131     {
1132         //      DST     SRC1    SRC2    OP          __VA_ARGS__
1133         BINARY_(uchar , uchar , uchar , run_minmax, dst, src1, src2, MM_MAX);
1134         BINARY_(ushort, ushort, ushort, run_minmax, dst, src1, src2, MM_MAX);
1135         BINARY_( short,  short,  short, run_minmax, dst, src1, src2, MM_MAX);
1136         BINARY_( float,  float,  float, run_minmax, dst, src1, src2, MM_MAX);
1137
1138         CV_Error(cv::Error::StsBadArg, "unsupported combination of types");
1139     }
1140 };
1141
1142 //-----------------------
1143 //
1144 // Fluid kernels: compare
1145 //
1146 //-----------------------
1147
1148 enum Compare { CMP_EQ, CMP_NE, CMP_GE, CMP_GT, CMP_LE, CMP_LT };
1149
1150 template<typename DST, typename SRC1, typename SRC2>
1151 static void run_cmp(Buffer &dst, const View &src1, const View &src2, Compare compare)
1152 {
1153     static_assert(std::is_same<SRC1, SRC2>::value, "wrong types");
1154     static_assert(std::is_same<DST, uchar>::value, "wrong types");
1155
1156     const auto *in1 = src1.InLine<SRC1>(0);
1157     const auto *in2 = src2.InLine<SRC2>(0);
1158           auto *out = dst.OutLine<DST>();
1159
1160     int width = dst.length();
1161     int chan  = dst.meta().chan;
1162
1163     int length = width * chan;
1164
1165     switch (compare)
1166     {
1167     case CMP_EQ:
1168         for (int l=0; l < length; l++)
1169             out[l] = in1[l] == in2[l]? 255: 0;
1170         break;
1171     case CMP_NE:
1172         for (int l=0; l < length; l++)
1173             out[l] = in1[l] != in2[l]? 255: 0;
1174         break;
1175     case CMP_GE:
1176         for (int l=0; l < length; l++)
1177             out[l] = in1[l] >= in2[l]? 255: 0;
1178         break;
1179     case CMP_LE:
1180         for (int l=0; l < length; l++)
1181             out[l] = in1[l] <= in2[l]? 255: 0;
1182         break;
1183     case CMP_GT:
1184         for (int l=0; l < length; l++)
1185             out[l] = in1[l] > in2[l]? 255: 0;
1186         break;
1187     case CMP_LT:
1188         for (int l=0; l < length; l++)
1189             out[l] = in1[l] < in2[l]? 255: 0;
1190         break;
1191     default:
1192         CV_Error(cv::Error::StsBadArg, "unsupported compare operation");
1193     }
1194 }
1195
1196 GAPI_FLUID_KERNEL(GFluidCmpEQ, cv::gapi::core::GCmpEQ, false)
1197 {
1198     static const int Window = 1;
1199
1200     static void run(const View &src1, const View &src2, Buffer &dst)
1201     {
1202         //      DST    SRC1    SRC2    OP       __VA_ARGS__
1203         BINARY_(uchar, uchar , uchar , run_cmp, dst, src1, src2, CMP_EQ);
1204         BINARY_(uchar,  short,  short, run_cmp, dst, src1, src2, CMP_EQ);
1205         BINARY_(uchar,  float,  float, run_cmp, dst, src1, src2, CMP_EQ);
1206
1207         CV_Error(cv::Error::StsBadArg, "unsupported combination of types");
1208     }
1209 };
1210
1211 GAPI_FLUID_KERNEL(GFluidCmpNE, cv::gapi::core::GCmpNE, false)
1212 {
1213     static const int Window = 1;
1214
1215     static void run(const View &src1, const View &src2, Buffer &dst)
1216     {
1217         //      DST    SRC1    SRC2    OP       __VA_ARGS__
1218         BINARY_(uchar, uchar , uchar , run_cmp, dst, src1, src2, CMP_NE);
1219         BINARY_(uchar,  short,  short, run_cmp, dst, src1, src2, CMP_NE);
1220         BINARY_(uchar,  float,  float, run_cmp, dst, src1, src2, CMP_NE);
1221
1222         CV_Error(cv::Error::StsBadArg, "unsupported combination of types");
1223     }
1224 };
1225
1226 GAPI_FLUID_KERNEL(GFluidCmpGE, cv::gapi::core::GCmpGE, false)
1227 {
1228     static const int Window = 1;
1229
1230     static void run(const View &src1, const View &src2, Buffer &dst)
1231     {
1232         //      DST    SRC1    SRC2    OP       __VA_ARGS__
1233         BINARY_(uchar, uchar , uchar , run_cmp, dst, src1, src2, CMP_GE);
1234         BINARY_(uchar,  short,  short, run_cmp, dst, src1, src2, CMP_GE);
1235         BINARY_(uchar,  float,  float, run_cmp, dst, src1, src2, CMP_GE);
1236
1237         CV_Error(cv::Error::StsBadArg, "unsupported combination of types");
1238     }
1239 };
1240
1241 GAPI_FLUID_KERNEL(GFluidCmpGT, cv::gapi::core::GCmpGT, false)
1242 {
1243     static const int Window = 1;
1244
1245     static void run(const View &src1, const View &src2, Buffer &dst)
1246     {
1247         //      DST    SRC1    SRC2    OP       __VA_ARGS__
1248         BINARY_(uchar, uchar , uchar , run_cmp, dst, src1, src2, CMP_GT);
1249         BINARY_(uchar,  short,  short, run_cmp, dst, src1, src2, CMP_GT);
1250         BINARY_(uchar,  float,  float, run_cmp, dst, src1, src2, CMP_GT);
1251
1252         CV_Error(cv::Error::StsBadArg, "unsupported combination of types");
1253     }
1254 };
1255
1256 GAPI_FLUID_KERNEL(GFluidCmpLE, cv::gapi::core::GCmpLE, false)
1257 {
1258     static const int Window = 1;
1259
1260     static void run(const View &src1, const View &src2, Buffer &dst)
1261     {
1262         //      DST    SRC1    SRC2    OP       __VA_ARGS__
1263         BINARY_(uchar, uchar , uchar , run_cmp, dst, src1, src2, CMP_LE);
1264         BINARY_(uchar,  short,  short, run_cmp, dst, src1, src2, CMP_LE);
1265         BINARY_(uchar,  float,  float, run_cmp, dst, src1, src2, CMP_LE);
1266
1267         CV_Error(cv::Error::StsBadArg, "unsupported combination of types");
1268     }
1269 };
1270
1271 GAPI_FLUID_KERNEL(GFluidCmpLT, cv::gapi::core::GCmpLT, false)
1272 {
1273     static const int Window = 1;
1274
1275     static void run(const View &src1, const View &src2, Buffer &dst)
1276     {
1277         //      DST    SRC1    SRC2    OP       __VA_ARGS__
1278         BINARY_(uchar, uchar , uchar , run_cmp, dst, src1, src2, CMP_LT);
1279         BINARY_(uchar,  short,  short, run_cmp, dst, src1, src2, CMP_LT);
1280         BINARY_(uchar,  float,  float, run_cmp, dst, src1, src2, CMP_LT);
1281
1282         CV_Error(cv::Error::StsBadArg, "unsupported combination of types");
1283     }
1284 };
1285
1286 //---------------------
1287 //
1288 // Compare with GScalar
1289 //
1290 //---------------------
1291
1292 template<typename DST, typename SRC, typename SCALAR=double>
1293 static void run_cmp(DST out[], const SRC in[], int length, Compare compare, SCALAR s)
1294 {
1295     switch (compare)
1296     {
1297     case CMP_EQ:
1298         for (int l=0; l < length; l++)
1299             out[l] = in[l] == s? 255: 0;
1300         break;
1301     case CMP_NE:
1302         for (int l=0; l < length; l++)
1303             out[l] = in[l] != s? 255: 0;
1304         break;
1305     case CMP_GE:
1306         for (int l=0; l < length; l++)
1307             out[l] = in[l] >= s? 255: 0;
1308         break;
1309     case CMP_LE:
1310         for (int l=0; l < length; l++)
1311             out[l] = in[l] <= s? 255: 0;
1312         break;
1313     case CMP_GT:
1314         for (int l=0; l < length; l++)
1315             out[l] = in[l] > s? 255: 0;
1316         break;
1317     case CMP_LT:
1318         for (int l=0; l < length; l++)
1319             out[l] = in[l] < s? 255: 0;
1320         break;
1321     default:
1322         CV_Error(cv::Error::StsBadArg, "unsupported compare operation");
1323     }
1324 }
1325
1326 template<typename DST, typename SRC>
1327 static void run_cmp(Buffer &dst, const View &src, Compare compare, const cv::Scalar &scalar)
1328 {
1329     static_assert(std::is_same<DST, uchar>::value, "wrong types");
1330
1331     const auto *in  = src.InLine<SRC>(0);
1332           auto *out = dst.OutLine<DST>();
1333
1334     int width = dst.length();
1335     int chan  = dst.meta().chan;
1336
1337     int length = width * chan;
1338
1339     // compute faster if scalar rounds to SRC
1340     double d =                   scalar[0]  ;
1341     SRC    s = static_cast<SRC>( scalar[0] );
1342
1343     if (s == d)
1344         run_cmp(out, in, length, compare, s);
1345     else
1346         run_cmp(out, in, length, compare, d);
1347 }
1348
1349 GAPI_FLUID_KERNEL(GFluidCmpEQScalar, cv::gapi::core::GCmpEQScalar, false)
1350 {
1351     static const int Window = 1;
1352
1353     static void run(const View &src, const cv::Scalar &scalar, Buffer &dst)
1354     {
1355         //     DST    SRC     OP       __VA_ARGS__
1356         UNARY_(uchar, uchar , run_cmp, dst, src, CMP_EQ, scalar);
1357         UNARY_(uchar,  short, run_cmp, dst, src, CMP_EQ, scalar);
1358         UNARY_(uchar,  float, run_cmp, dst, src, CMP_EQ, scalar);
1359
1360         CV_Error(cv::Error::StsBadArg, "unsupported combination of types");
1361     }
1362 };
1363
1364 GAPI_FLUID_KERNEL(GFluidCmpNEScalar, cv::gapi::core::GCmpNEScalar, false)
1365 {
1366     static const int Window = 1;
1367
1368     static void run(const View &src, const cv::Scalar &scalar, Buffer &dst)
1369     {
1370         //     DST    SRC     OP       __VA_ARGS__
1371         UNARY_(uchar, uchar , run_cmp, dst, src, CMP_NE, scalar);
1372         UNARY_(uchar,  short, run_cmp, dst, src, CMP_NE, scalar);
1373         UNARY_(uchar,  float, run_cmp, dst, src, CMP_NE, scalar);
1374
1375         CV_Error(cv::Error::StsBadArg, "unsupported combination of types");
1376     }
1377 };
1378
1379 GAPI_FLUID_KERNEL(GFluidCmpGEScalar, cv::gapi::core::GCmpGEScalar, false)
1380 {
1381     static const int Window = 1;
1382
1383     static void run(const View &src, const cv::Scalar &scalar, Buffer &dst)
1384     {
1385         //     DST    SRC     OP       __VA_ARGS__
1386         UNARY_(uchar, uchar , run_cmp, dst, src, CMP_GE, scalar);
1387         UNARY_(uchar,  short, run_cmp, dst, src, CMP_GE, scalar);
1388         UNARY_(uchar,  float, run_cmp, dst, src, CMP_GE, scalar);
1389
1390         CV_Error(cv::Error::StsBadArg, "unsupported combination of types");
1391     }
1392 };
1393
1394 GAPI_FLUID_KERNEL(GFluidCmpGTScalar, cv::gapi::core::GCmpGTScalar, false)
1395 {
1396     static const int Window = 1;
1397
1398     static void run(const View &src, const cv::Scalar &scalar, Buffer &dst)
1399     {
1400         //     DST    SRC     OP       __VA_ARGS__
1401         UNARY_(uchar, uchar , run_cmp, dst, src, CMP_GT, scalar);
1402         UNARY_(uchar,  short, run_cmp, dst, src, CMP_GT, scalar);
1403         UNARY_(uchar,  float, run_cmp, dst, src, CMP_GT, scalar);
1404
1405         CV_Error(cv::Error::StsBadArg, "unsupported combination of types");
1406     }
1407 };
1408
1409 GAPI_FLUID_KERNEL(GFluidCmpLEScalar, cv::gapi::core::GCmpLEScalar, false)
1410 {
1411     static const int Window = 1;
1412
1413     static void run(const View &src, const cv::Scalar &scalar, Buffer &dst)
1414     {
1415         //     DST    SRC     OP       __VA_ARGS__
1416         UNARY_(uchar, uchar , run_cmp, dst, src, CMP_LE, scalar);
1417         UNARY_(uchar,  short, run_cmp, dst, src, CMP_LE, scalar);
1418         UNARY_(uchar,  float, run_cmp, dst, src, CMP_LE, scalar);
1419
1420         CV_Error(cv::Error::StsBadArg, "unsupported combination of types");
1421     }
1422 };
1423
1424 GAPI_FLUID_KERNEL(GFluidCmpLTScalar, cv::gapi::core::GCmpLTScalar, false)
1425 {
1426     static const int Window = 1;
1427
1428     static void run(const View &src, const cv::Scalar &scalar, Buffer &dst)
1429     {
1430         //     DST    SRC     OP       __VA_ARGS__
1431         UNARY_(uchar, uchar , run_cmp, dst, src, CMP_LT, scalar);
1432         UNARY_(uchar,  short, run_cmp, dst, src, CMP_LT, scalar);
1433         UNARY_(uchar,  float, run_cmp, dst, src, CMP_LT, scalar);
1434
1435         CV_Error(cv::Error::StsBadArg, "unsupported combination of types");
1436     }
1437 };
1438
1439 //-------------------------
1440 //
1441 // Fluid kernels: threshold
1442 //
1443 //-------------------------
1444
1445 template<typename DST, typename SRC>
1446 static void run_threshold(Buffer &dst, const View &src, const cv::Scalar &thresh,
1447                                                         const cv::Scalar &maxval,
1448                                                                      int  type)
1449 {
1450     static_assert(std::is_same<DST, SRC>::value, "wrong types");
1451
1452     const auto *in  = src.InLine<SRC>(0);
1453           auto *out = dst.OutLine<DST>();
1454
1455     int width = dst.length();
1456     int chan  = dst.meta().chan;
1457
1458     int length = width * chan;
1459
1460     DST thresh_ = saturate<DST>(thresh[0], floord);
1461     DST threshd = saturate<DST>(thresh[0], roundd);
1462     DST maxvald = saturate<DST>(maxval[0], roundd);
1463
1464     switch (type)
1465     {
1466     case cv::THRESH_BINARY:
1467         for (int l=0; l < length; l++)
1468             out[l] = in[l] > thresh_? maxvald: 0;
1469         break;
1470     case cv::THRESH_BINARY_INV:
1471         for (int l=0; l < length; l++)
1472             out[l] = in[l] > thresh_? 0: maxvald;
1473         break;
1474     case cv::THRESH_TRUNC:
1475         for (int l=0; l < length; l++)
1476             out[l] = in[l] > thresh_? threshd: in[l];
1477         break;
1478     case cv::THRESH_TOZERO:
1479         for (int l=0; l < length; l++)
1480             out[l] = in[l] > thresh_? in[l]: 0;
1481         break;
1482     case cv::THRESH_TOZERO_INV:
1483         for (int l=0; l < length; l++)
1484             out[l] = in[l] > thresh_? 0: in[l];
1485         break;
1486     default: CV_Error(cv::Error::StsBadArg, "unsupported threshold type");
1487     }
1488 }
1489
1490 GAPI_FLUID_KERNEL(GFluidThreshold, cv::gapi::core::GThreshold, false)
1491 {
1492     static const int Window = 1;
1493
1494     static void run(const View &src, const cv::Scalar &thresh,
1495                                      const cv::Scalar &maxval,
1496                                                   int  type,
1497                         Buffer &dst)
1498     {
1499         //     DST     SRC     OP             __VA_ARGS__
1500         UNARY_(uchar , uchar , run_threshold, dst, src, thresh, maxval, type);
1501         UNARY_(ushort, ushort, run_threshold, dst, src, thresh, maxval, type);
1502         UNARY_( short,  short, run_threshold, dst, src, thresh, maxval, type);
1503
1504         CV_Error(cv::Error::StsBadArg, "unsupported combination of types");
1505     }
1506 };
1507
1508 //------------------------
1509 //
1510 // Fluid kernels: in-range
1511 //
1512 //------------------------
1513
1514 static void run_inrange3(uchar out[], const uchar in[], int width,
1515                          const uchar lower[], const uchar upper[])
1516 {
1517     int w = 0; // cycle index
1518
1519 #if CV_SIMD128
1520     for (; w <= width-16; w+=16)
1521     {
1522         v_uint8x16 i0, i1, i2;
1523         v_load_deinterleave(&in[3*w], i0, i1, i2);
1524
1525         v_uint8x16 o;
1526         o = (i0 >= v_setall_u8(lower[0])) & (i0 <= v_setall_u8(upper[0])) &
1527             (i1 >= v_setall_u8(lower[1])) & (i1 <= v_setall_u8(upper[1])) &
1528             (i2 >= v_setall_u8(lower[2])) & (i2 <= v_setall_u8(upper[2]));
1529
1530         v_store(&out[w], o);
1531     }
1532 #endif
1533
1534     for (; w < width; w++)
1535     {
1536         out[w] = in[3*w  ] >= lower[0] && in[3*w  ] <= upper[0] &&
1537                  in[3*w+1] >= lower[1] && in[3*w+1] <= upper[1] &&
1538                  in[3*w+2] >= lower[2] && in[3*w+2] <= upper[2] ? 255: 0;
1539     }
1540 }
1541
1542 template<typename DST, typename SRC>
1543 static void run_inrange(Buffer &dst, const View &src, const cv::Scalar &upperb,
1544                                                       const cv::Scalar &lowerb)
1545 {
1546     static_assert(std::is_same<DST, uchar>::value, "wrong types");
1547
1548     const auto *in  = src.InLine<SRC>(0);
1549           auto *out = dst.OutLine<DST>();
1550
1551     int width = src.length();
1552     int chan  = src.meta().chan;
1553     GAPI_Assert(dst.meta().chan == 1);
1554
1555     SRC lower[4], upper[4];
1556     for (int c=0; c < chan; c++)
1557     {
1558         if (std::is_integral<SRC>::value)
1559         {
1560             // for integral input, in[i] >= lower equals in[i] >= ceil(lower)
1561             // so we can optimize compare operations by rounding lower/upper
1562             lower[c] = saturate<SRC>(lowerb[c],  ceild);
1563             upper[c] = saturate<SRC>(upperb[c], floord);
1564         }
1565         else
1566         {
1567             // FIXME: now values used in comparison are floats (while they
1568             // have double precision initially). Comparison float/float
1569             // may differ from float/double (how it should work in this case)
1570             //
1571             // Example: threshold=1/3 (or 1/10)
1572             lower[c] = static_cast<SRC>(lowerb[c]);
1573             upper[c] = static_cast<SRC>(upperb[c]);
1574         }
1575     }
1576
1577     // manually SIMD for important case if RGB/BGR
1578     if (std::is_same<SRC,uchar>::value && chan==3)
1579     {
1580         run_inrange3((uchar*)out, (const uchar*)in, width,
1581                      (const uchar*)lower, (const uchar*)upper);
1582         return;
1583     }
1584
1585     // TODO: please manually SIMD if multiple channels:
1586     // modern compilers would perfectly vectorize this code if one channel,
1587     // but may need help with de-interleaving channels if RGB/BGR image etc
1588     switch (chan)
1589     {
1590     case 1:
1591         for (int w=0; w < width; w++)
1592             out[w] = in[w] >= lower[0] && in[w] <= upper[0]? 255: 0;
1593         break;
1594     case 2:
1595         for (int w=0; w < width; w++)
1596             out[w] = in[2*w  ] >= lower[0] && in[2*w  ] <= upper[0] &&
1597                      in[2*w+1] >= lower[1] && in[2*w+1] <= upper[1] ? 255: 0;
1598         break;
1599     case 3:
1600         for (int w=0; w < width; w++)
1601             out[w] = in[3*w  ] >= lower[0] && in[3*w  ] <= upper[0] &&
1602                      in[3*w+1] >= lower[1] && in[3*w+1] <= upper[1] &&
1603                      in[3*w+2] >= lower[2] && in[3*w+2] <= upper[2] ? 255: 0;
1604         break;
1605     case 4:
1606         for (int w=0; w < width; w++)
1607             out[w] = in[4*w  ] >= lower[0] && in[4*w  ] <= upper[0] &&
1608                      in[4*w+1] >= lower[1] && in[4*w+1] <= upper[1] &&
1609                      in[4*w+2] >= lower[2] && in[4*w+2] <= upper[2] &&
1610                      in[4*w+3] >= lower[3] && in[4*w+3] <= upper[3] ? 255: 0;
1611         break;
1612     default: CV_Error(cv::Error::StsBadArg, "unsupported number of channels");
1613     }
1614 }
1615
1616 GAPI_FLUID_KERNEL(GFluidInRange, cv::gapi::core::GInRange, false)
1617 {
1618     static const int Window = 1;
1619
1620     static void run(const View &src, const cv::Scalar &lowerb, const cv::Scalar& upperb,
1621                         Buffer &dst)
1622     {
1623         //       DST     SRC    OP           __VA_ARGS__
1624         INRANGE_(uchar, uchar , run_inrange, dst, src, upperb, lowerb);
1625         INRANGE_(uchar, ushort, run_inrange, dst, src, upperb, lowerb);
1626         INRANGE_(uchar,  short, run_inrange, dst, src, upperb, lowerb);
1627         INRANGE_(uchar,  float, run_inrange, dst, src, upperb, lowerb);
1628
1629         CV_Error(cv::Error::StsBadArg, "unsupported combination of types");
1630     }
1631 };
1632
1633 //----------------------
1634 //
1635 // Fluid kernels: select
1636 //
1637 //----------------------
1638
1639 // manually vectored function for important case if RGB/BGR image
1640 static void run_select_row3(int width, uchar out[], uchar in1[], uchar in2[], uchar in3[])
1641 {
1642     int w = 0; // cycle index
1643
1644 #if CV_SIMD128
1645     for (; w <= width-16; w+=16)
1646     {
1647         v_uint8x16 a1, b1, c1;
1648         v_uint8x16 a2, b2, c2;
1649         v_uint8x16 mask;
1650         v_uint8x16 a, b, c;
1651
1652         v_load_deinterleave(&in1[3*w], a1, b1, c1);
1653         v_load_deinterleave(&in2[3*w], a2, b2, c2);
1654
1655         mask = v_load(&in3[w]);
1656         mask = mask != v_setzero_u8();
1657
1658         a = v_select(mask, a1, a2);
1659         b = v_select(mask, b1, b2);
1660         c = v_select(mask, c1, c2);
1661
1662         v_store_interleave(&out[3*w], a, b, c);
1663     }
1664 #endif
1665
1666     for (; w < width; w++)
1667     {
1668         out[3*w    ] = in3[w]? in1[3*w    ]: in2[3*w    ];
1669         out[3*w + 1] = in3[w]? in1[3*w + 1]: in2[3*w + 1];
1670         out[3*w + 2] = in3[w]? in1[3*w + 2]: in2[3*w + 2];
1671     }
1672 }
1673
1674 // parameter chan is compile-time known constant, normally chan=1..4
1675 template<int chan, typename DST, typename SRC1, typename SRC2, typename SRC3>
1676 static void run_select_row(int width, DST out[], SRC1 in1[], SRC2 in2[], SRC3 in3[])
1677 {
1678     if (std::is_same<DST,uchar>::value && chan==3)
1679     {
1680         // manually vectored function for important case if RGB/BGR image
1681         run_select_row3(width, (uchar*)out, (uchar*)in1, (uchar*)in2, (uchar*)in3);
1682         return;
1683     }
1684
1685     // because `chan` is template parameter, its value is known at compilation time,
1686     // so that modern compilers would efficiently vectorize this cycle if chan==1
1687     // (if chan>1, compilers may need help with de-interleaving of the channels)
1688     for (int w=0; w < width; w++)
1689     {
1690         for (int c=0; c < chan; c++)
1691         {
1692             out[w*chan + c] = in3[w]? in1[w*chan + c]: in2[w*chan + c];
1693         }
1694     }
1695 }
1696
1697 template<typename DST, typename SRC1, typename SRC2, typename SRC3>
1698 static void run_select(Buffer &dst, const View &src1, const View &src2, const View &src3)
1699 {
1700     static_assert(std::is_same<DST ,  SRC1>::value, "wrong types");
1701     static_assert(std::is_same<DST ,  SRC2>::value, "wrong types");
1702     static_assert(std::is_same<uchar, SRC3>::value, "wrong types");
1703
1704     auto *out = dst.OutLine<DST>();
1705
1706     const auto *in1 = src1.InLine<SRC1>(0);
1707     const auto *in2 = src2.InLine<SRC2>(0);
1708     const auto *in3 = src3.InLine<SRC3>(0);
1709
1710     int width = dst.length();
1711     int chan  = dst.meta().chan;
1712
1713     switch (chan)
1714     {
1715     case 1: run_select_row<1>(width, out, in1, in2, in3); break;
1716     case 2: run_select_row<2>(width, out, in1, in2, in3); break;
1717     case 3: run_select_row<3>(width, out, in1, in2, in3); break;
1718     case 4: run_select_row<4>(width, out, in1, in2, in3); break;
1719     default: CV_Error(cv::Error::StsBadArg, "unsupported number of channels");
1720     }
1721 }
1722
1723 GAPI_FLUID_KERNEL(GFluidSelect, cv::gapi::core::GSelect, false)
1724 {
1725     static const int Window = 1;
1726
1727     static void run(const View &src1, const View &src2, const View &src3, Buffer &dst)
1728     {
1729         //      DST     SRC1    SRC2    SRC3   OP          __VA_ARGS__
1730         SELECT_(uchar , uchar , uchar , uchar, run_select, dst, src1, src2, src3);
1731         SELECT_(ushort, ushort, ushort, uchar, run_select, dst, src1, src2, src3);
1732         SELECT_( short,  short,  short, uchar, run_select, dst, src1, src2, src3);
1733
1734         CV_Error(cv::Error::StsBadArg, "unsupported combination of types");
1735     }
1736 };
1737
1738 //----------------------------------------------------
1739 //
1740 // Fluid kernels: split, merge, polat2cart, cart2polar
1741 //
1742 //----------------------------------------------------
1743
1744 GAPI_FLUID_KERNEL(GFluidSplit3, cv::gapi::core::GSplit3, false)
1745 {
1746     static const int Window = 1;
1747
1748     static void run(const View &src, Buffer &dst1, Buffer &dst2, Buffer &dst3)
1749     {
1750         const auto *in   =  src.InLine<uchar>(0);
1751               auto *out1 = dst1.OutLine<uchar>();
1752               auto *out2 = dst2.OutLine<uchar>();
1753               auto *out3 = dst3.OutLine<uchar>();
1754
1755         GAPI_Assert(3 == src.meta().chan);
1756         int width = src.length();
1757
1758         int w = 0; // cycle counter
1759
1760     #if CV_SIMD128
1761         for (; w <= width-16; w+=16)
1762         {
1763             v_uint8x16 a, b, c;
1764             v_load_deinterleave(&in[3*w], a, b, c);
1765             v_store(&out1[w], a);
1766             v_store(&out2[w], b);
1767             v_store(&out3[w], c);
1768         }
1769     #endif
1770
1771         for (; w < width; w++)
1772         {
1773             out1[w] = in[3*w    ];
1774             out2[w] = in[3*w + 1];
1775             out3[w] = in[3*w + 2];
1776         }
1777     }
1778 };
1779
1780 GAPI_FLUID_KERNEL(GFluidSplit4, cv::gapi::core::GSplit4, false)
1781 {
1782     static const int Window = 1;
1783
1784     static void run(const View &src, Buffer &dst1, Buffer &dst2, Buffer &dst3, Buffer &dst4)
1785     {
1786         const auto *in   =  src.InLine<uchar>(0);
1787               auto *out1 = dst1.OutLine<uchar>();
1788               auto *out2 = dst2.OutLine<uchar>();
1789               auto *out3 = dst3.OutLine<uchar>();
1790               auto *out4 = dst4.OutLine<uchar>();
1791
1792         GAPI_Assert(4 == src.meta().chan);
1793         int width = src.length();
1794
1795         int w = 0; // cycle counter
1796
1797     #if CV_SIMD128
1798         for (; w <= width-16; w+=16)
1799         {
1800             v_uint8x16 a, b, c, d;
1801             v_load_deinterleave(&in[4*w], a, b, c, d);
1802             v_store(&out1[w], a);
1803             v_store(&out2[w], b);
1804             v_store(&out3[w], c);
1805             v_store(&out4[w], d);
1806         }
1807     #endif
1808
1809         for (; w < width; w++)
1810         {
1811             out1[w] = in[4*w    ];
1812             out2[w] = in[4*w + 1];
1813             out3[w] = in[4*w + 2];
1814             out4[w] = in[4*w + 3];
1815         }
1816     }
1817 };
1818
1819 GAPI_FLUID_KERNEL(GFluidMerge3, cv::gapi::core::GMerge3, false)
1820 {
1821     static const int Window = 1;
1822
1823     static void run(const View &src1, const View &src2, const View &src3, Buffer &dst)
1824     {
1825         const auto *in1 = src1.InLine<uchar>(0);
1826         const auto *in2 = src2.InLine<uchar>(0);
1827         const auto *in3 = src3.InLine<uchar>(0);
1828               auto *out = dst.OutLine<uchar>();
1829
1830         GAPI_Assert(3 == dst.meta().chan);
1831         int width = dst.length();
1832
1833         int w = 0; // cycle counter
1834
1835     #if CV_SIMD128
1836         for (; w <= width-16; w+=16)
1837         {
1838             v_uint8x16 a, b, c;
1839             a = v_load(&in1[w]);
1840             b = v_load(&in2[w]);
1841             c = v_load(&in3[w]);
1842             v_store_interleave(&out[3*w], a, b, c);
1843         }
1844     #endif
1845
1846         for (; w < width; w++)
1847         {
1848             out[3*w    ] = in1[w];
1849             out[3*w + 1] = in2[w];
1850             out[3*w + 2] = in3[w];
1851         }
1852     }
1853 };
1854
1855 GAPI_FLUID_KERNEL(GFluidMerge4, cv::gapi::core::GMerge4, false)
1856 {
1857     static const int Window = 1;
1858
1859     static void run(const View &src1, const View &src2, const View &src3, const View &src4,
1860                     Buffer &dst)
1861     {
1862         const auto *in1 = src1.InLine<uchar>(0);
1863         const auto *in2 = src2.InLine<uchar>(0);
1864         const auto *in3 = src3.InLine<uchar>(0);
1865         const auto *in4 = src4.InLine<uchar>(0);
1866               auto *out = dst.OutLine<uchar>();
1867
1868         GAPI_Assert(4 == dst.meta().chan);
1869         int width = dst.length();
1870
1871         int w = 0; // cycle counter
1872
1873     #if CV_SIMD128
1874         for (; w <= width-16; w+=16)
1875         {
1876             v_uint8x16 a, b, c, d;
1877             a = v_load(&in1[w]);
1878             b = v_load(&in2[w]);
1879             c = v_load(&in3[w]);
1880             d = v_load(&in4[w]);
1881             v_store_interleave(&out[4*w], a, b, c, d);
1882         }
1883     #endif
1884
1885         for (; w < width; w++)
1886         {
1887             out[4*w    ] = in1[w];
1888             out[4*w + 1] = in2[w];
1889             out[4*w + 2] = in3[w];
1890             out[4*w + 3] = in4[w];
1891         }
1892     }
1893 };
1894
1895 GAPI_FLUID_KERNEL(GFluidPolarToCart, cv::gapi::core::GPolarToCart, false)
1896 {
1897     static const int Window = 1;
1898
1899     static void run(const View &src1, const View &src2, bool angleInDegrees,
1900                     Buffer &dst1, Buffer &dst2)
1901     {
1902         GAPI_Assert(src1.meta().depth == CV_32F);
1903         GAPI_Assert(src2.meta().depth == CV_32F);
1904         GAPI_Assert(dst1.meta().depth == CV_32F);
1905         GAPI_Assert(dst2.meta().depth == CV_32F);
1906
1907         const auto * in1 = src1.InLine<float>(0);
1908         const auto * in2 = src2.InLine<float>(0);
1909               auto *out1 = dst1.OutLine<float>();
1910               auto *out2 = dst2.OutLine<float>();
1911
1912         int width = src1.length();
1913         int chan  = src2.meta().chan;
1914         int length = width * chan;
1915
1916         // SIMD: compiler vectoring!
1917         for (int l=0; l < length; l++)
1918         {
1919             float angle = angleInDegrees?
1920                           in2[l] * static_cast<float>(CV_PI / 180):
1921                           in2[l];
1922             float magnitude = in1[l];
1923             float x = magnitude * std::cos(angle);
1924             float y = magnitude * std::sin(angle);
1925             out1[l] = x;
1926             out2[l] = y;
1927         }
1928     }
1929 };
1930
1931 GAPI_FLUID_KERNEL(GFluidCartToPolar, cv::gapi::core::GCartToPolar, false)
1932 {
1933     static const int Window = 1;
1934
1935     static void run(const View &src1, const View &src2, bool angleInDegrees,
1936                     Buffer &dst1, Buffer &dst2)
1937     {
1938         GAPI_Assert(src1.meta().depth == CV_32F);
1939         GAPI_Assert(src2.meta().depth == CV_32F);
1940         GAPI_Assert(dst1.meta().depth == CV_32F);
1941         GAPI_Assert(dst2.meta().depth == CV_32F);
1942
1943         const auto * in1 = src1.InLine<float>(0);
1944         const auto * in2 = src2.InLine<float>(0);
1945               auto *out1 = dst1.OutLine<float>();
1946               auto *out2 = dst2.OutLine<float>();
1947
1948         int width = src1.length();
1949         int chan  = src2.meta().chan;
1950         int length = width * chan;
1951
1952         // SIMD: compiler vectoring!
1953         for (int l=0; l < length; l++)
1954         {
1955             float x = in1[l];
1956             float y = in2[l];
1957             float magnitude = std::hypot(y, x);
1958             float angle_rad = std::atan2(y, x);
1959             float angle = angleInDegrees?
1960                           angle_rad * static_cast<float>(180 / CV_PI):
1961                           angle_rad;
1962             out1[l] = magnitude;
1963             out2[l] = angle;
1964         }
1965     }
1966 };
1967
1968 GAPI_FLUID_KERNEL(GFluidPhase, cv::gapi::core::GPhase, false)
1969 {
1970     static const int Window = 1;
1971
1972     static void run(const View &src_x,
1973                     const View &src_y,
1974                     bool angleInDegrees,
1975                     Buffer &dst)
1976     {
1977         const auto w = dst.length() * dst.meta().chan;
1978         if (src_x.meta().depth == CV_32F && src_y.meta().depth == CV_32F)
1979         {
1980             hal::fastAtan32f(src_y.InLine<float>(0),
1981                              src_x.InLine<float>(0),
1982                              dst.OutLine<float>(),
1983                              w,
1984                              angleInDegrees);
1985         }
1986         else if (src_x.meta().depth == CV_64F && src_y.meta().depth == CV_64F)
1987         {
1988             hal::fastAtan64f(src_y.InLine<double>(0),
1989                              src_x.InLine<double>(0),
1990                              dst.OutLine<double>(),
1991                              w,
1992                              angleInDegrees);
1993         } else GAPI_Assert(false && !"Phase supports 32F/64F input only!");
1994     }
1995 };
1996
1997 GAPI_FLUID_KERNEL(GFluidResize, cv::gapi::core::GResize, true)
1998 {
1999     static const int Window = 1;
2000     static const auto Kind = GFluidKernel::Kind::Resize;
2001
2002     constexpr static const int INTER_RESIZE_COEF_BITS = 11;
2003     constexpr static const int INTER_RESIZE_COEF_SCALE = 1 << INTER_RESIZE_COEF_BITS;
2004     constexpr static const short ONE = INTER_RESIZE_COEF_SCALE;
2005
2006     struct ResizeUnit
2007     {
2008         short alpha0;
2009         short alpha1;
2010         int   s0;
2011         int   s1;
2012     };
2013
2014     static ResizeUnit map(double ratio, int start, int max, int outCoord)
2015     {
2016         float f = static_cast<float>((outCoord + 0.5f) * ratio - 0.5f);
2017         int s = cvFloor(f);
2018         f -= s;
2019
2020         ResizeUnit ru;
2021
2022         ru.s0 = std::max(s - start, 0);
2023         ru.s1 = ((f == 0.0) || s + 1 >= max) ? s - start : s - start + 1;
2024
2025         ru.alpha0 = saturate_cast<short>((1.0f - f) * INTER_RESIZE_COEF_SCALE);
2026         ru.alpha1 = saturate_cast<short>((f) * INTER_RESIZE_COEF_SCALE);
2027
2028         return ru;
2029     }
2030
2031     static void initScratch(const cv::GMatDesc& in,
2032                             cv::Size outSz, double /*fx*/, double /*fy*/, int /*interp*/,
2033                             cv::gapi::fluid::Buffer &scratch)
2034     {
2035         CV_Assert(in.depth == CV_8U && in.chan == 3);
2036
2037         cv::Size scratch_size{static_cast<int>(outSz.width * sizeof(ResizeUnit)), 1};
2038
2039         cv::GMatDesc desc;
2040         desc.chan  = 1;
2041         desc.depth = CV_8UC1;
2042         desc.size  = to_own(scratch_size);
2043
2044         cv::gapi::fluid::Buffer buffer(desc);
2045         scratch = std::move(buffer);
2046
2047         ResizeUnit* mapX = scratch.OutLine<ResizeUnit>();
2048         double hRatio = (double)in.size.width / outSz.width;
2049
2050         for (int x = 0, w = outSz.width; x < w; x++)
2051         {
2052             mapX[x] = map(hRatio, 0, in.size.width, x);
2053         }
2054     }
2055
2056     static void resetScratch(cv::gapi::fluid::Buffer& /*scratch*/)
2057     {}
2058
2059     static void run(const cv::gapi::fluid::View& in, cv::Size /*sz*/, double /*fx*/, double /*fy*/, int /*interp*/,
2060                     cv::gapi::fluid::Buffer& out, cv::gapi::fluid::Buffer &scratch)
2061     {
2062         double vRatio = (double)in.meta().size.height / out.meta().size.height;
2063         auto mapY = map(vRatio, in.y(), in.meta().size.height, out.y());
2064
2065         auto beta0 = mapY.alpha0;
2066         auto beta1 = mapY.alpha1;
2067
2068         const auto src0 = in.InLine <unsigned char>(mapY.s0);
2069         const auto src1 = in.InLine <unsigned char>(mapY.s1);
2070
2071         auto dst = out.OutLine<unsigned char>();
2072
2073         ResizeUnit* mapX = scratch.OutLine<ResizeUnit>();
2074
2075         for (int x = 0; x < out.length(); x++)
2076         {
2077             short alpha0 = mapX[x].alpha0;
2078             short alpha1 = mapX[x].alpha1;
2079             int sx0 = mapX[x].s0;
2080             int sx1 = mapX[x].s1;
2081
2082             int res00 = src0[3*sx0    ]*alpha0 + src0[3*(sx1)    ]*alpha1;
2083             int res10 = src1[3*sx0    ]*alpha0 + src1[3*(sx1)    ]*alpha1;
2084
2085             int res01 = src0[3*sx0 + 1]*alpha0 + src0[3*(sx1) + 1]*alpha1;
2086             int res11 = src1[3*sx0 + 1]*alpha0 + src1[3*(sx1) + 1]*alpha1;
2087
2088             int res02 = src0[3*sx0 + 2]*alpha0 + src0[3*(sx1) + 2]*alpha1;
2089             int res12 = src1[3*sx0 + 2]*alpha0 + src1[3*(sx1) + 2]*alpha1;
2090
2091             dst[3*x    ] = uchar(( ((beta0 * (res00 >> 4)) >> 16) + ((beta1 * (res10 >> 4)) >> 16) + 2)>>2);
2092             dst[3*x + 1] = uchar(( ((beta0 * (res01 >> 4)) >> 16) + ((beta1 * (res11 >> 4)) >> 16) + 2)>>2);
2093             dst[3*x + 2] = uchar(( ((beta0 * (res02 >> 4)) >> 16) + ((beta1 * (res12 >> 4)) >> 16) + 2)>>2);
2094         }
2095     }
2096 };
2097
2098 GAPI_FLUID_KERNEL(GFluidSqrt, cv::gapi::core::GSqrt, false)
2099 {
2100     static const int Window = 1;
2101
2102     static void run(const View &in, Buffer &out)
2103     {
2104         const auto w = out.length() * out.meta().chan;
2105         if (in.meta().depth == CV_32F)
2106         {
2107             hal::sqrt32f(in.InLine<float>(0),
2108                          out.OutLine<float>(0),
2109                          w);
2110         }
2111         else if (in.meta().depth == CV_64F)
2112         {
2113             hal::sqrt64f(in.InLine<double>(0),
2114                          out.OutLine<double>(0),
2115                          w);
2116         } else GAPI_Assert(false && !"Sqrt supports 32F/64F input only!");
2117     }
2118 };
2119
2120 } // namespace fliud
2121 } // namespace gapi
2122 } // namespace cv
2123
2124 cv::gapi::GKernelPackage cv::gapi::core::fluid::kernels()
2125 {
2126     using namespace cv::gapi::fluid;
2127
2128     return cv::gapi::kernels
2129      <       GFluidAdd
2130             ,GFluidSub
2131             ,GFluidMul
2132             ,GFluidDiv
2133             ,GFluidAbsDiff
2134             ,GFluidAnd
2135             ,GFluidOr
2136             ,GFluidXor
2137             ,GFluidMin
2138             ,GFluidMax
2139             ,GFluidCmpGT
2140             ,GFluidCmpGE
2141             ,GFluidCmpLE
2142             ,GFluidCmpLT
2143             ,GFluidCmpEQ
2144             ,GFluidCmpNE
2145             ,GFluidAddW
2146             ,GFluidNot
2147             ,GFluidLUT
2148             ,GFluidConvertTo
2149             ,GFluidSplit3
2150             ,GFluidSplit4
2151             ,GFluidMerge3
2152             ,GFluidMerge4
2153             ,GFluidSelect
2154             ,GFluidPolarToCart
2155             ,GFluidCartToPolar
2156             ,GFluidPhase
2157             ,GFluidAddC
2158             ,GFluidSubC
2159             ,GFluidSubRC
2160             ,GFluidMulC
2161             ,GFluidMulCOld
2162             ,GFluidDivC
2163             ,GFluidDivRC
2164             ,GFluidAbsDiffC
2165             ,GFluidCmpGTScalar
2166             ,GFluidCmpGEScalar
2167             ,GFluidCmpLEScalar
2168             ,GFluidCmpLTScalar
2169             ,GFluidCmpEQScalar
2170             ,GFluidCmpNEScalar
2171             ,GFluidThreshold
2172             ,GFluidInRange
2173             ,GFluidResize
2174             ,GFluidSqrt
2175         #if 0
2176             ,GFluidMean        -- not fluid
2177             ,GFluidSum         -- not fluid
2178             ,GFluidNormL1      -- not fluid
2179             ,GFluidNormL2      -- not fluid
2180             ,GFluidNormInf     -- not fluid
2181             ,GFluidIntegral    -- not fluid
2182             ,GFluidThresholdOT -- not fluid
2183             ,GFluidResize      -- not fluid (?)
2184             ,GFluidRemap       -- not fluid
2185             ,GFluidFlip        -- not fluid
2186             ,GFluidCrop        -- not fluid
2187             ,GFluidConcatHor
2188             ,GFluidConcatVert  -- not fluid
2189         #endif
2190         >();
2191 }
2192
2193 #endif // !defined(GAPI_STANDALONE)