From 2ea02b201232a40e71bb6598ad0f84304a5b879b Mon Sep 17 00:00:00 2001 From: Anton Potapov Date: Tue, 22 Sep 2020 18:18:26 +0300 Subject: [PATCH] [PP GAPI] Split/Merge kernels; support for 8S, 16U, 16S, 32S (#2276) - introduced type_dispatch primitive - refactored SplitX and MergeX kernels to use type_dispatch - extended SplitX and MergeX to support 8S, 16U, 16S, 32S types --- .../preprocessing/ie_preprocess_gapi_kernels.cpp | 128 ++++++++++++++++++--- .../fluid_preproc/cpu/fluid_tests_cpu.cpp | 4 +- 2 files changed, 115 insertions(+), 17 deletions(-) diff --git a/inference-engine/src/preprocessing/ie_preprocess_gapi_kernels.cpp b/inference-engine/src/preprocessing/ie_preprocess_gapi_kernels.cpp index e104dcf..153eaed 100644 --- a/inference-engine/src/preprocessing/ie_preprocess_gapi_kernels.cpp +++ b/inference-engine/src/preprocessing/ie_preprocess_gapi_kernels.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #if defined(__GNUC__) && (__GNUC__ <= 5) #include @@ -431,13 +432,93 @@ void splitRow(const uint8_t* in, std::array& outs, int length) { } } +namespace { + template + struct cv_type_to_depth; + + template<> struct cv_type_to_depth { enum { depth = CV_8U }; }; + template<> struct cv_type_to_depth { enum { depth = CV_8S }; }; + template<> struct cv_type_to_depth { enum { depth = CV_16U }; }; + template<> struct cv_type_to_depth { enum { depth = CV_16S }; }; + template<> struct cv_type_to_depth { enum { depth = CV_32S }; }; + template<> struct cv_type_to_depth { enum { depth = CV_32F }; }; + + template + struct typelist {}; + + template + struct head; + + template class list, typename head_t, typename ... types> + struct head> { using type = head_t;}; + + template + using head_t = typename head::type; + + template + struct type_to_type {}; +} + +namespace { + template + struct type_dispatch_impl; + + template class typelist, typename... type> + struct type_dispatch_impl> { + + template + static result_t dispatch(type_id_t type_id, type_to_id_t&& type_to_id, type_to_value_t&& type_to_value, default_t default_value) { + result_t res = default_value; + + std::initializer_list ({(type_id == type_to_id(type_to_type{}) ? (res = type_to_value(type_to_type{})), 0 : 0)...}); + return res; + } + }; +} + +template()(type_to_type> {}))> +result_t type_dispatch(type_id_t type_id, type_to_id_t&& type_to_id, type_to_value_t&& type_to_value, default_t default_value = {}){ + return type_dispatch_impl::template dispatch(std::forward(type_id), + std::forward(type_to_id), + std::forward(type_to_value), + std::forward(default_value)); +} + +namespace { + struct cv_type_id { + template + const int operator()(type_to_type ){ return cv_type_to_depth::depth;} + }; + +} +template +bool is_cv_type_in_list(const int type_id){ + return type_dispatch(type_id, cv_type_id{}, [](...){ return true;}, false); +} + +namespace { + using merge_supported_types = typelist; + + template + struct typed_merge_row { + using p_f = void (*)(const std::array& ins, uint8_t* out, int length); + + template + p_f operator()(type_to_type ){ return mergeRow;} + }; +} + GAPI_FLUID_KERNEL(FMerge2, Merge2, false) { static const int LPI = 4; static const int Window = 1; static void run(const cv::gapi::fluid::View& a, const cv::gapi::fluid::View& b, cv::gapi::fluid::Buffer& out) { - const auto rowFunc = (a.meta().depth == CV_8U) ? &mergeRow : &mergeRow; + + GAPI_DbgAssert(is_cv_type_in_list(out.meta().depth)); + + const auto rowFunc = type_dispatch(out.meta().depth, cv_type_id{}, typed_merge_row<2>{}, nullptr); for (int l = 0; l < out.lpi(); l++) { rowFunc({a.InLineB(l), b.InLineB(l)}, out.OutLineB(l), a.length()); } @@ -451,7 +532,10 @@ GAPI_FLUID_KERNEL(FMerge3, Merge3, false) { const cv::gapi::fluid::View& b, const cv::gapi::fluid::View& c, cv::gapi::fluid::Buffer& out) { - const auto rowFunc = (a.meta().depth == CV_8U) ? &mergeRow : &mergeRow; + + GAPI_DbgAssert(is_cv_type_in_list(out.meta().depth)); + + const auto rowFunc = type_dispatch(out.meta().depth, cv_type_id{}, typed_merge_row<3>{}, nullptr); for (int l = 0; l < out.lpi(); l++) { rowFunc({a.InLineB(l), b.InLineB(l), c.InLineB(l)}, out.OutLineB(l), a.length()); } @@ -466,13 +550,29 @@ GAPI_FLUID_KERNEL(FMerge4, Merge4, false) { const cv::gapi::fluid::View& c, const cv::gapi::fluid::View& d, cv::gapi::fluid::Buffer& out) { - const auto rowFunc = (a.meta().depth == CV_8U) ? &mergeRow : &mergeRow; + + GAPI_DbgAssert(is_cv_type_in_list(out.meta().depth)); + + const auto rowFunc = type_dispatch(out.meta().depth, cv_type_id{}, typed_merge_row<4>{}, nullptr); for (int l = 0; l < out.lpi(); l++) { rowFunc({a.InLineB(l), b.InLineB(l), c.InLineB(l), d.InLineB(l)}, out.OutLineB(l), a.length()); } } }; + +namespace { +using split_supported_types = typelist; + +template +struct typed_split_row { + using p_f = void (*)(const uint8_t* in, std::array& outs, int length); + + template + p_f operator()(type_to_type ){ return splitRow;} +}; + +} GAPI_FLUID_KERNEL(FSplit2, Split2, false) { static const int LPI = 4; static const int Window = 1; @@ -484,10 +584,9 @@ GAPI_FLUID_KERNEL(FSplit2, Split2, false) { GAPI_DbgAssert(1 == out2.meta().chan); GAPI_DbgAssert(in.meta().depth == out1.meta().depth); GAPI_DbgAssert(in.meta().depth == out2.meta().depth); - GAPI_DbgAssert(CV_8U == in.meta().depth || CV_32F == in.meta().depth); - const auto rowFunc = (in.meta().depth == CV_8U) ? - &splitRow : - &splitRow; + GAPI_DbgAssert(is_cv_type_in_list(in.meta().depth)); + + const auto rowFunc = type_dispatch(in.meta().depth, cv_type_id{}, typed_split_row<2>{}, nullptr); for (int i = 0, lpi = out1.lpi(); i < lpi; i++) { std::array outs = {out1.OutLineB(i), out2.OutLineB(i)}; rowFunc(in.InLineB(i), outs, in.length()); @@ -509,10 +608,10 @@ GAPI_FLUID_KERNEL(FSplit3, Split3, false) { GAPI_DbgAssert(in.meta().depth == out1.meta().depth); GAPI_DbgAssert(in.meta().depth == out2.meta().depth); GAPI_DbgAssert(in.meta().depth == out3.meta().depth); - GAPI_DbgAssert(CV_8U == in.meta().depth || CV_32F == in.meta().depth); - const auto rowFunc = (in.meta().depth == CV_8U) ? - &splitRow : - &splitRow; + + GAPI_DbgAssert(is_cv_type_in_list(in.meta().depth)); + + const auto rowFunc = type_dispatch(in.meta().depth, cv_type_id{}, typed_split_row<3>{}, nullptr); for (int i = 0, lpi = out1.lpi(); i < lpi; i++) { std::array outs = {out1.OutLineB(i), out2.OutLineB(i), out3.OutLineB(i)}; @@ -538,10 +637,9 @@ GAPI_FLUID_KERNEL(FSplit4, Split4, false) { GAPI_DbgAssert(in.meta().depth == out2.meta().depth); GAPI_DbgAssert(in.meta().depth == out3.meta().depth); GAPI_DbgAssert(in.meta().depth == out4.meta().depth); - GAPI_DbgAssert(CV_8U == in.meta().depth || CV_32F == in.meta().depth); - const auto rowFunc = (in.meta().depth == CV_8U) ? - &splitRow : - &splitRow; + GAPI_DbgAssert(is_cv_type_in_list(in.meta().depth)); + + const auto rowFunc = type_dispatch(in.meta().depth, cv_type_id{}, typed_split_row<4>{}, nullptr); for (int i = 0, lpi = out1.lpi(); i < lpi; i++) { std::array outs = {out1.OutLineB(i), out2.OutLineB(i), out3.OutLineB(i), out4.OutLineB(i)}; diff --git a/inference-engine/tests_deprecated/fluid_preproc/cpu/fluid_tests_cpu.cpp b/inference-engine/tests_deprecated/fluid_preproc/cpu/fluid_tests_cpu.cpp index acdac01..6164bb3 100644 --- a/inference-engine/tests_deprecated/fluid_preproc/cpu/fluid_tests_cpu.cpp +++ b/inference-engine/tests_deprecated/fluid_preproc/cpu/fluid_tests_cpu.cpp @@ -132,7 +132,7 @@ INSTANTIATE_TEST_CASE_P(ResizeTestFluid_F32, ResizeTestGAPI, INSTANTIATE_TEST_CASE_P(SplitTestFluid, SplitTestGAPI, Combine(Values(2, 3, 4), - Values(CV_8U, CV_32F), + Values(CV_8U, CV_8S, CV_16U, CV_16S, CV_32F, CV_32S), Values(TEST_SIZES), Values(0))); @@ -144,7 +144,7 @@ INSTANTIATE_TEST_CASE_P(ChanToPlaneTestFluid, ChanToPlaneTestGAPI, INSTANTIATE_TEST_CASE_P(MergeTestFluid, MergeTestGAPI, Combine(Values(2, 3, 4), - Values(CV_8U, CV_32F), + Values(CV_8U, CV_8S, CV_16U, CV_16S, CV_32F, CV_32S), Values(TEST_SIZES), Values(0))); -- 2.7.4