From ef4b4ae784f7533ed6d9e7b51827a894c32ed48e Mon Sep 17 00:00:00 2001 From: Michele Di Giorgio Date: Tue, 4 Jul 2017 17:19:43 +0100 Subject: COMPMID-438: Add support for floating point Min-Max Location layer. Change-Id: I84ae564a40fc7320a6f94a84d53906ba51404f51 Reviewed-on: http://mpd-gerrit.cambridge.arm.com/79797 Reviewed-by: Anthony Barbier Tested-by: Kaizen --- src/core/NEON/kernels/NEMinMaxLocationKernel.cpp | 141 ++++++++++++++++++----- 1 file changed, 114 insertions(+), 27 deletions(-) (limited to 'src/core/NEON/kernels/NEMinMaxLocationKernel.cpp') diff --git a/src/core/NEON/kernels/NEMinMaxLocationKernel.cpp b/src/core/NEON/kernels/NEMinMaxLocationKernel.cpp index 1e41ddcf80..a6da7f415d 100644 --- a/src/core/NEON/kernels/NEMinMaxLocationKernel.cpp +++ b/src/core/NEON/kernels/NEMinMaxLocationKernel.cpp @@ -41,14 +41,14 @@ namespace arm_compute { NEMinMaxKernel::NEMinMaxKernel() - : _func(), _input(nullptr), _min(), _max(), _min_init(), _max_init(), _mtx() + : _func(), _input(nullptr), _min(), _max(), _mtx() { } -void NEMinMaxKernel::configure(const IImage *input, int32_t *min, int32_t *max) +void NEMinMaxKernel::configure(const IImage *input, void *min, void *max) { ARM_COMPUTE_ERROR_ON_TENSOR_NOT_2D(input); - ARM_COMPUTE_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(input, 1, DataType::U8, DataType::S16); + ARM_COMPUTE_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(input, 1, DataType::U8, DataType::S16, DataType::F32); ARM_COMPUTE_ERROR_ON(nullptr == min); ARM_COMPUTE_ERROR_ON(nullptr == max); @@ -56,20 +56,19 @@ void NEMinMaxKernel::configure(const IImage *input, int32_t *min, int32_t *max) _min = min; _max = max; - switch(input->info()->format()) + switch(_input->info()->data_type()) { - case Format::U8: - _min_init = UCHAR_MAX; - _max_init = 0; - _func = &NEMinMaxKernel::minmax_U8; + case DataType::U8: + _func = &NEMinMaxKernel::minmax_U8; break; - case Format::S16: - _min_init = SHRT_MAX; - _max_init = SHRT_MIN; - _func = &NEMinMaxKernel::minmax_S16; + case DataType::S16: + _func = &NEMinMaxKernel::minmax_S16; + break; + case DataType::F32: + _func = &NEMinMaxKernel::minmax_F32; break; default: - ARM_COMPUTE_ERROR("You called with the wrong img formats"); + ARM_COMPUTE_ERROR("Unsupported data type"); break; } @@ -93,8 +92,24 @@ void NEMinMaxKernel::run(const Window &window) void NEMinMaxKernel::reset() { ARM_COMPUTE_ERROR_ON_UNCONFIGURED_KERNEL(this); - *_min = _min_init; - *_max = _max_init; + switch(_input->info()->data_type()) + { + case DataType::U8: + *static_cast(_min) = UCHAR_MAX; + *static_cast(_max) = 0; + break; + case DataType::S16: + *static_cast(_min) = SHRT_MAX; + *static_cast(_max) = SHRT_MIN; + break; + case DataType::F32: + *static_cast(_min) = std::numeric_limits::max(); + *static_cast(_max) = std::numeric_limits::lowest(); + break; + default: + ARM_COMPUTE_ERROR("Unsupported data type"); + break; + } } template @@ -102,14 +117,19 @@ void NEMinMaxKernel::update_min_max(const T min, const T max) { std::lock_guard lock(_mtx); - if(min < *_min) + using type = typename std::conditional::value, float, int32_t>::type; + + auto min_ptr = static_cast(_min); + auto max_ptr = static_cast(_max); + + if(min < *min_ptr) { - *_min = min; + *min_ptr = min; } - if(max > *_max) + if(max > *max_ptr) { - *_max = max; + *max_ptr = max; } } @@ -229,6 +249,65 @@ void NEMinMaxKernel::minmax_S16(Window win) update_min_max(min_i, max_i); } +void NEMinMaxKernel::minmax_F32(Window win) +{ + float32x2_t carry_min = vdup_n_f32(std::numeric_limits::max()); + float32x2_t carry_max = vdup_n_f32(std::numeric_limits::lowest()); + + float carry_min_scalar = std::numeric_limits::max(); + float carry_max_scalar = std::numeric_limits::lowest(); + + const int x_start = win.x().start(); + const int x_end = win.x().end(); + + // Handle X dimension manually to split into two loops + // First one will use vector operations, second one processes the left over pixels + win.set(Window::DimX, Window::Dimension(0, 1, 1)); + + Iterator input(_input, win); + + execute_window_loop(win, [&](const Coordinates & id) + { + int x = x_start; + const auto in_ptr = reinterpret_cast(input.ptr()); + + // Vector loop + for(; x <= x_end - 8; x += 8) + { + const float32x4x2_t pixels = vld2q_f32(in_ptr + x); + const float32x4_t tmp_min1 = vminq_f32(pixels.val[0], pixels.val[1]); + const float32x4_t tmp_max1 = vmaxq_f32(pixels.val[0], pixels.val[1]); + const float32x2_t tmp_min2 = vmin_f32(vget_high_f32(tmp_min1), vget_low_f32(tmp_min1)); + const float32x2_t tmp_max2 = vmax_f32(vget_high_f32(tmp_max1), vget_low_f32(tmp_max1)); + carry_min = vmin_f32(tmp_min2, carry_min); + carry_max = vmax_f32(tmp_max2, carry_max); + } + + // Process leftover pixels + for(; x < x_end; ++x) + { + const float pixel = in_ptr[x]; + carry_min_scalar = std::min(pixel, carry_min_scalar); + carry_max_scalar = std::max(pixel, carry_max_scalar); + } + + }, + input); + + // Reduce result + carry_min = vpmin_f32(carry_min, carry_min); + carry_max = vpmax_f32(carry_max, carry_max); + carry_min = vpmin_f32(carry_min, carry_min); + carry_max = vpmax_f32(carry_max, carry_max); + + // Extract max/min values + const float min_i = std::min(vget_lane_f32(carry_min, 0), carry_min_scalar); + const float max_i = std::max(vget_lane_f32(carry_max, 0), carry_max_scalar); + + // Perform reduction of local min/max values + update_min_max(min_i, max_i); +} + NEMinMaxLocationKernel::NEMinMaxLocationKernel() : _func(nullptr), _input(nullptr), _min(nullptr), _max(nullptr), _min_count(nullptr), _max_count(nullptr), _min_loc(nullptr), _max_loc(nullptr) { @@ -271,12 +350,12 @@ const NEMinMaxLocationKernel::MinMaxLocFunction NEMinMaxLocationKernel::create_f &NEMinMaxLocationKernel::minmax_loc... }; -void NEMinMaxLocationKernel::configure(const IImage *input, int32_t *min, int32_t *max, +void NEMinMaxLocationKernel::configure(const IImage *input, void *min, void *max, ICoordinates2DArray *min_loc, ICoordinates2DArray *max_loc, uint32_t *min_count, uint32_t *max_count) { ARM_COMPUTE_ERROR_ON_TENSOR_NOT_2D(input); - ARM_COMPUTE_ERROR_ON_FORMAT_NOT_IN(input, Format::U8, Format::S16); + ARM_COMPUTE_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(input, 1, DataType::U8, DataType::S16, DataType::F32); ARM_COMPUTE_ERROR_ON(nullptr == min); ARM_COMPUTE_ERROR_ON(nullptr == max); @@ -295,16 +374,19 @@ void NEMinMaxLocationKernel::configure(const IImage *input, int32_t *min, int32_ unsigned int table_idx = (count_min << 3) | (count_max << 2) | (loc_min << 1) | loc_max; - switch(input->info()->format()) + switch(input->info()->data_type()) { - case Format::U8: + case DataType::U8: _func = create_func_table::type>::func_table[table_idx]; break; - case Format::S16: + case DataType::S16: _func = create_func_table::type>::func_table[table_idx]; break; + case DataType::F32: + _func = create_func_table::type>::func_table[table_idx]; + break; default: - ARM_COMPUTE_ERROR("You called with the wrong img formats"); + ARM_COMPUTE_ERROR("Unsupported data type"); break; } @@ -349,6 +431,11 @@ void NEMinMaxLocationKernel::minmax_loc(const Window &win) _max_loc->clear(); } + using type = typename std::conditional::value, float, int32_t>::type; + + auto min_ptr = static_cast(_min); + auto max_ptr = static_cast(_max); + execute_window_loop(win, [&](const Coordinates & id) { auto in_ptr = reinterpret_cast(input.ptr()); @@ -360,7 +447,7 @@ void NEMinMaxLocationKernel::minmax_loc(const Window &win) if(count_min || loc_min) { - if(*_min == pixel) + if(*min_ptr == pixel) { if(count_min) { @@ -376,7 +463,7 @@ void NEMinMaxLocationKernel::minmax_loc(const Window &win) if(count_max || loc_max) { - if(*_max == pixel) + if(*max_ptr == pixel) { if(count_max) { -- cgit v1.2.1