From 08d42de68c70224649de8c0d401c97e314c18184 Mon Sep 17 00:00:00 2001 From: Michael Platings Date: Mon, 23 Sep 2024 10:39:44 +0000 Subject: [PATCH] Add early not-implemented checks If a function does not support the requested operation then it must return quickly to avoid delaying the fallback option. Changing the order of parameter checks caused some tests to fail, so the tests have been changed to avoid failing the not-implemented check. --- adapters/opencv/kleidicv_hal.cpp | 15 ++++ .../include/kleidicv/filters/gaussian_blur.h | 38 ++++++++- .../kleidicv/filters/separable_filter_2d.h | 25 +++++- kleidicv/include/kleidicv/filters/sobel.h | 8 ++ .../include/kleidicv/resize/resize_linear.h | 31 +++++++ .../include/kleidicv/workspace/border_types.h | 6 +- kleidicv/src/filters/gaussian_blur_api.cpp | 17 +++- kleidicv/src/filters/gaussian_blur_neon.cpp | 39 +++------ kleidicv/src/filters/gaussian_blur_sc.h | 38 +++------ kleidicv/src/filters/gaussian_blur_sme2.cpp | 2 +- kleidicv/src/filters/gaussian_blur_sve2.cpp | 2 +- .../src/filters/separable_filter_2d_api.cpp | 42 +++++++-- .../src/filters/separable_filter_2d_neon.cpp | 42 +++------ kleidicv/src/filters/separable_filter_2d_sc.h | 26 ++---- .../src/filters/separable_filter_2d_sme2.cpp | 18 ++-- .../src/filters/separable_filter_2d_sve2.cpp | 18 ++-- kleidicv/src/filters/sobel_api.cpp | 6 ++ kleidicv/src/filters/sobel_neon.cpp | 12 --- kleidicv/src/filters/sobel_sc.h | 12 --- kleidicv/src/resize/resize_linear_api.cpp | 8 ++ kleidicv/src/resize/resize_linear_neon.cpp | 10 +++ kleidicv/src/resize/resize_linear_sc.h | 10 +++ kleidicv_thread/src/kleidicv_thread.cpp | 72 ++++++++++++++-- test/api/test_gaussian_blur.cpp | 6 +- test/api/test_resize_linear.cpp | 13 +-- test/api/test_separable_filter_2d.cpp | 2 +- test/api/test_sobel.cpp | 16 ++-- test/api/test_thread.cpp | 85 +++++++++++++++++++ test/api/test_thread_resize.cpp | 17 ++++ 29 files changed, 448 insertions(+), 188 deletions(-) diff --git a/adapters/opencv/kleidicv_hal.cpp b/adapters/opencv/kleidicv_hal.cpp index 0d0bcb5cb..a4ec0112f 100644 --- a/adapters/opencv/kleidicv_hal.cpp +++ b/adapters/opencv/kleidicv_hal.cpp @@ -12,6 +12,7 @@ #include #include +#include "kleidicv/filters/gaussian_blur.h" #include "kleidicv/kleidicv.h" #include "kleidicv_thread/kleidicv_thread.h" #include "opencv2/core/base.hpp" @@ -524,6 +525,13 @@ int gaussian_blur_binomial(const uchar *src_data, size_t src_step, return CV_HAL_ERROR_NOT_IMPLEMENTED; } + // Check for not-implemented before allocating a context + if (!kleidicv::gaussian_blur_is_implemented(width, height, kernel_size, + kernel_size, 0, 0) || + !kleidicv::get_fixed_border_type(kleidicv_border_type)) { + return CV_HAL_ERROR_NOT_IMPLEMENTED; + } + kleidicv_filter_context_t *context; if (kleidicv_error_t create_err = kleidicv_filter_context_create( &context, cn, kernel_size, kernel_size, static_cast(width), @@ -570,6 +578,13 @@ int gaussian_blur(const uchar *src_data, size_t src_step, uchar *dst_data, return CV_HAL_ERROR_NOT_IMPLEMENTED; } + // Check for not-implemented before allocating a context + if (!kleidicv::gaussian_blur_is_implemented( + width, height, kernel_width, kernel_height, sigma_x, sigma_y) || + !kleidicv::get_fixed_border_type(kleidicv_border_type)) { + return CV_HAL_ERROR_NOT_IMPLEMENTED; + } + kleidicv_filter_context_t *context; if (kleidicv_error_t create_err = kleidicv_filter_context_create( &context, cn, kernel_width, kernel_height, static_cast(width), diff --git a/kleidicv/include/kleidicv/filters/gaussian_blur.h b/kleidicv/include/kleidicv/filters/gaussian_blur.h index debfd01bc..3c1823d0f 100644 --- a/kleidicv/include/kleidicv/filters/gaussian_blur.h +++ b/kleidicv/include/kleidicv/filters/gaussian_blur.h @@ -8,6 +8,7 @@ #include "kleidicv/config.h" #include "kleidicv/kleidicv.h" #include "kleidicv/types.h" +#include "kleidicv/workspace/border_types.h" extern "C" { // For internal use only. See instead kleidicv_gaussian_blur_u8. @@ -18,19 +19,48 @@ KLEIDICV_API_DECLARATION(kleidicv_gaussian_blur_stripe_u8, const uint8_t *src, size_t width, size_t height, size_t y_begin, size_t y_end, size_t channels, size_t kernel_width, size_t kernel_height, float sigma_x, float sigma_y, - kleidicv_border_type_t border_type, + kleidicv::FixedBorderType border_type, kleidicv_filter_context_t *context); } namespace kleidicv { +inline bool gaussian_blur_is_implemented(size_t width, size_t height, + size_t kernel_width, + size_t kernel_height, float sigma_x, + float sigma_y) { + if (kernel_width != kernel_height) { + return false; + } + + if (sigma_x != sigma_y) { + return false; + } + + if (width < kernel_width - 1 || height < kernel_width - 1) { + return false; + } + + switch (kernel_width) { + case 3: + case 5: + case 7: + case 15: + break; + default: + return false; + } + + return true; +} + namespace neon { kleidicv_error_t gaussian_blur_stripe_u8( const uint8_t *src, size_t src_stride, uint8_t *dst, size_t dst_stride, size_t width, size_t height, size_t y_begin, size_t y_end, size_t channels, size_t kernel_width, size_t kernel_height, float sigma_x, float sigma_y, - kleidicv_border_type_t border_type, kleidicv_filter_context_t *context); + FixedBorderType border_type, kleidicv_filter_context_t *context); } // namespace neon @@ -40,7 +70,7 @@ kleidicv_error_t gaussian_blur_stripe_u8( const uint8_t *src, size_t src_stride, uint8_t *dst, size_t dst_stride, size_t width, size_t height, size_t y_begin, size_t y_end, size_t channels, size_t kernel_width, size_t kernel_height, float sigma_x, float sigma_y, - kleidicv_border_type_t border_type, kleidicv_filter_context_t *context); + FixedBorderType border_type, kleidicv_filter_context_t *context); } // namespace sve2 @@ -50,7 +80,7 @@ kleidicv_error_t gaussian_blur_stripe_u8( const uint8_t *src, size_t src_stride, uint8_t *dst, size_t dst_stride, size_t width, size_t height, size_t y_begin, size_t y_end, size_t channels, size_t kernel_width, size_t kernel_height, float sigma_x, float sigma_y, - kleidicv_border_type_t border_type, kleidicv_filter_context_t *context); + FixedBorderType border_type, kleidicv_filter_context_t *context); } // namespace sme2 diff --git a/kleidicv/include/kleidicv/filters/separable_filter_2d.h b/kleidicv/include/kleidicv/filters/separable_filter_2d.h index d3607a6e6..d35b3369e 100644 --- a/kleidicv/include/kleidicv/filters/separable_filter_2d.h +++ b/kleidicv/include/kleidicv/filters/separable_filter_2d.h @@ -8,6 +8,7 @@ #include "kleidicv/config.h" #include "kleidicv/kleidicv.h" #include "kleidicv/types.h" +#include "kleidicv/workspace/border_types.h" extern "C" { // For internal use only. See instead kleidicv_separable_filter_2d_u8. @@ -19,7 +20,7 @@ KLEIDICV_API_DECLARATION(kleidicv_separable_filter_2d_stripe_u8, size_t y_begin, size_t y_end, size_t channels, const uint8_t *kernel_x, size_t kernel_width, const uint8_t *kernel_y, size_t kernel_height, - kleidicv_border_type_t border_type, + kleidicv::FixedBorderType border_type, kleidicv_filter_context_t *context); // For internal use only. See instead kleidicv_separable_filter_2d_u16. // Filter a horizontal stripe across an image. The stripe is defined by the @@ -30,7 +31,7 @@ KLEIDICV_API_DECLARATION(kleidicv_separable_filter_2d_stripe_u16, size_t y_begin, size_t y_end, size_t channels, const uint16_t *kernel_x, size_t kernel_width, const uint16_t *kernel_y, size_t kernel_height, - kleidicv_border_type_t border_type, + kleidicv::FixedBorderType border_type, kleidicv_filter_context_t *context); // For internal use only. See instead kleidicv_separable_filter_2d_s16. // Filter a horizontal stripe across an image. The stripe is defined by the @@ -41,8 +42,26 @@ KLEIDICV_API_DECLARATION(kleidicv_separable_filter_2d_stripe_s16, size_t y_begin, size_t y_end, size_t channels, const int16_t *kernel_x, size_t kernel_width, const int16_t *kernel_y, size_t kernel_height, - kleidicv_border_type_t border_type, + kleidicv::FixedBorderType border_type, kleidicv_filter_context_t *context); } +namespace kleidicv { + +inline bool separable_filter_2d_is_implemented(size_t width, size_t height, + size_t kernel_width, + size_t kernel_height) { + if (kernel_width != 5 || kernel_height != 5) { + return false; + } + + if (width < kernel_width - 1 || height < kernel_width - 1) { + return false; + } + + return true; +} + +} // namespace kleidicv + #endif // KLEIDICV_FILTERS_SEPARABLE_FILTER_2D_H diff --git a/kleidicv/include/kleidicv/filters/sobel.h b/kleidicv/include/kleidicv/filters/sobel.h index 243b620a7..ba131606e 100644 --- a/kleidicv/include/kleidicv/filters/sobel.h +++ b/kleidicv/include/kleidicv/filters/sobel.h @@ -26,6 +26,14 @@ KLEIDICV_API_DECLARATION(kleidicv_sobel_3x3_vertical_stripe_s16_u8, namespace kleidicv { +inline bool sobel_is_implemented(size_t width, size_t height, + size_t kernel_size) { + if (width < kernel_size - 1 || height < kernel_size - 1) { + return false; + } + return true; +} + namespace neon { kleidicv_error_t sobel_3x3_horizontal_stripe_s16_u8( const uint8_t *src, size_t src_stride, int16_t *dst, size_t dst_stride, diff --git a/kleidicv/include/kleidicv/resize/resize_linear.h b/kleidicv/include/kleidicv/resize/resize_linear.h index d31db4d25..ecea5bb29 100644 --- a/kleidicv/include/kleidicv/resize/resize_linear.h +++ b/kleidicv/include/kleidicv/resize/resize_linear.h @@ -9,6 +9,37 @@ namespace kleidicv { +inline bool resize_linear_u8_is_implemented(size_t src_width, size_t src_height, + size_t dst_width, + size_t dst_height) { + if (src_width == 0 || src_height == 0) { + return true; + } + const size_t implemented_ratios[] = {2, 4}; + for (size_t ratio : implemented_ratios) { + if (src_width * ratio == dst_width && src_height * ratio == dst_height) { + return true; + } + } + return false; +} + +inline bool resize_linear_f32_is_implemented(size_t src_width, + size_t src_height, + size_t dst_width, + size_t dst_height) { + if (src_width == 0 || src_height == 0) { + return true; + } + const size_t implemented_ratios[] = {2, 4, 8}; + for (size_t ratio : implemented_ratios) { + if (src_width * ratio == dst_width && src_height * ratio == dst_height) { + return true; + } + } + return false; +} + namespace neon { kleidicv_error_t resize_linear_stripe_u8(const uint8_t *src, size_t src_stride, size_t src_width, size_t src_height, diff --git a/kleidicv/include/kleidicv/workspace/border_types.h b/kleidicv/include/kleidicv/workspace/border_types.h index 0825bc372..14c729735 100644 --- a/kleidicv/include/kleidicv/workspace/border_types.h +++ b/kleidicv/include/kleidicv/workspace/border_types.h @@ -9,7 +9,7 @@ #include "kleidicv/kleidicv.h" -namespace KLEIDICV_TARGET_NAMESPACE { +namespace kleidicv { enum class FixedBorderType { REPLICATE, @@ -19,7 +19,7 @@ enum class FixedBorderType { }; inline std::optional get_fixed_border_type( - kleidicv_border_type_t border_type) KLEIDICV_STREAMING_COMPATIBLE { + kleidicv_border_type_t border_type) { switch (border_type) { case KLEIDICV_BORDER_TYPE_REPLICATE: return FixedBorderType::REPLICATE; @@ -34,6 +34,6 @@ inline std::optional get_fixed_border_type( } } -} // namespace KLEIDICV_TARGET_NAMESPACE +} // namespace kleidicv #endif // KLEIDICV_WORKSPACE_BORDER_TYPES_H diff --git a/kleidicv/src/filters/gaussian_blur_api.cpp b/kleidicv/src/filters/gaussian_blur_api.cpp index bb21315ed..d571480b6 100644 --- a/kleidicv/src/filters/gaussian_blur_api.cpp +++ b/kleidicv/src/filters/gaussian_blur_api.cpp @@ -18,9 +18,20 @@ kleidicv_error_t kleidicv_gaussian_blur_u8( size_t width, size_t height, size_t channels, size_t kernel_width, size_t kernel_height, float sigma_x, float sigma_y, kleidicv_border_type_t border_type, kleidicv_filter_context_t *context) { - return kleidicv_gaussian_blur_stripe_u8( - src, src_stride, dst, dst_stride, width, height, 0, height, channels, - kernel_width, kernel_height, sigma_x, sigma_y, border_type, context); + if (!kleidicv::gaussian_blur_is_implemented( + width, height, kernel_width, kernel_height, sigma_x, sigma_y)) { + return KLEIDICV_ERROR_NOT_IMPLEMENTED; + } + + auto fixed_border_type = kleidicv::get_fixed_border_type(border_type); + if (!fixed_border_type) { + return KLEIDICV_ERROR_NOT_IMPLEMENTED; + } + + return kleidicv_gaussian_blur_stripe_u8(src, src_stride, dst, dst_stride, + width, height, 0, height, channels, + kernel_width, kernel_height, sigma_x, + sigma_y, *fixed_border_type, context); } } // extern "C" diff --git a/kleidicv/src/filters/gaussian_blur_neon.cpp b/kleidicv/src/filters/gaussian_blur_neon.cpp index 8f047d0fc..e34000932 100644 --- a/kleidicv/src/filters/gaussian_blur_neon.cpp +++ b/kleidicv/src/filters/gaussian_blur_neon.cpp @@ -3,6 +3,7 @@ // SPDX-License-Identifier: Apache-2.0 #include +#include #include "kleidicv/ctypes.h" #include "kleidicv/filters/gaussian_blur.h" @@ -676,34 +677,27 @@ static kleidicv_error_t gaussian_blur(size_t kernel_size, const ScalarType *src, return gaussian_blur_fixed_kernel_size<15, IsBinomial>( src, src_stride, dst, dst_stride, rect, y_begin, y_end, channels, sigma, border_type, workspace); + // gaussian_blur_is_implemented checked the kernel size already. + // GCOVR_EXCL_START default: + assert(!"kernel size not implemented"); return KLEIDICV_ERROR_NOT_IMPLEMENTED; + // GCOVR_EXCL_STOP } } +// Does not include checks for whether the operation is implemented. +// This must be done earlier, by gaussian_blur_is_implemented. template static kleidicv_error_t gaussian_blur_checks( const T *src, size_t src_stride, T *dst, size_t dst_stride, size_t width, - size_t height, size_t channels, size_t kernel_width, size_t kernel_height, - float sigma_x, float sigma_y, SeparableFilterWorkspace *workspace) { + size_t height, size_t channels, SeparableFilterWorkspace *workspace) { CHECK_POINTERS(workspace); - if (kernel_width != kernel_height) { - return KLEIDICV_ERROR_NOT_IMPLEMENTED; - } - - if (sigma_x != sigma_y) { - return KLEIDICV_ERROR_NOT_IMPLEMENTED; - } - CHECK_POINTER_AND_STRIDE(src, src_stride, height); CHECK_POINTER_AND_STRIDE(dst, dst_stride, height); CHECK_IMAGE_SIZE(width, height); - if (width < kernel_width - 1 || height < kernel_width - 1) { - return KLEIDICV_ERROR_NOT_IMPLEMENTED; - } - if (channels > KLEIDICV_MAXIMUM_CHANNEL_COUNT) { return KLEIDICV_ERROR_RANGE; } @@ -725,33 +719,28 @@ KLEIDICV_TARGET_FN_ATTRS kleidicv_error_t gaussian_blur_stripe_u8( const uint8_t *src, size_t src_stride, uint8_t *dst, size_t dst_stride, size_t width, size_t height, size_t y_begin, size_t y_end, size_t channels, - size_t kernel_width, size_t kernel_height, float sigma_x, float sigma_y, - kleidicv_border_type_t border_type, kleidicv_filter_context_t *context) { + size_t kernel_width, size_t /*kernel_height*/, float sigma_x, + float /*sigma_y*/, FixedBorderType fixed_border_type, + kleidicv_filter_context_t *context) { auto *workspace = reinterpret_cast(context); kleidicv_error_t checks_result = gaussian_blur_checks( - src, src_stride, dst, dst_stride, width, height, channels, kernel_width, - kernel_height, sigma_x, sigma_y, workspace); + src, src_stride, dst, dst_stride, width, height, channels, workspace); if (checks_result != KLEIDICV_OK) { return checks_result; } - auto fixed_border_type = get_fixed_border_type(border_type); - if (!fixed_border_type) { - return KLEIDICV_ERROR_NOT_IMPLEMENTED; - } - Rectangle rect{width, height}; if (sigma_x == 0.0) { return gaussian_blur(kernel_width, src, src_stride, dst, dst_stride, rect, y_begin, y_end, channels, sigma_x, - *fixed_border_type, workspace); + fixed_border_type, workspace); } return gaussian_blur(kernel_width, src, src_stride, dst, dst_stride, rect, y_begin, y_end, channels, sigma_x, - *fixed_border_type, workspace); + fixed_border_type, workspace); } } // namespace kleidicv::neon diff --git a/kleidicv/src/filters/gaussian_blur_sc.h b/kleidicv/src/filters/gaussian_blur_sc.h index 65c7e5299..14141efd1 100644 --- a/kleidicv/src/filters/gaussian_blur_sc.h +++ b/kleidicv/src/filters/gaussian_blur_sc.h @@ -6,6 +6,7 @@ #define KLEIDICV_GAUSSIAN_BLUR_SC_H #include +#include #include "kleidicv/kleidicv.h" #include "kleidicv/separable_filter_15x15_sc.h" @@ -852,35 +853,28 @@ static kleidicv_error_t gaussian_blur( return gaussian_blur_fixed_kernel_size<15, IsBinomial>( src, src_stride, dst, dst_stride, rect, y_begin, y_end, channels, sigma, border_type, workspace); + // gaussian_blur_is_implemented checked the kernel size already. + // GCOVR_EXCL_START default: + assert(!"kernel size not implemented"); return KLEIDICV_ERROR_NOT_IMPLEMENTED; + // GCOVR_EXCL_STOP } } +// Does not include checks for whether the operation is implemented. +// This must be done earlier, by gaussian_blur_is_implemented. template static kleidicv_error_t gaussian_blur_checks( const T *src, size_t src_stride, T *dst, size_t dst_stride, size_t width, - size_t height, size_t channels, size_t kernel_width, size_t kernel_height, - float sigma_x, float sigma_y, + size_t height, size_t channels, SeparableFilterWorkspace *workspace) KLEIDICV_STREAMING_COMPATIBLE { CHECK_POINTERS(workspace); - if (kernel_width != kernel_height) { - return KLEIDICV_ERROR_NOT_IMPLEMENTED; - } - - if (sigma_x != sigma_y) { - return KLEIDICV_ERROR_NOT_IMPLEMENTED; - } - CHECK_POINTER_AND_STRIDE(src, src_stride, height); CHECK_POINTER_AND_STRIDE(dst, dst_stride, height); CHECK_IMAGE_SIZE(width, height); - if (width < kernel_width - 1 || height < kernel_width - 1) { - return KLEIDICV_ERROR_NOT_IMPLEMENTED; - } - if (channels > KLEIDICV_MAXIMUM_CHANNEL_COUNT) { return KLEIDICV_ERROR_RANGE; } @@ -900,34 +894,28 @@ static kleidicv_error_t gaussian_blur_checks( static kleidicv_error_t gaussian_blur_stripe_u8_sc( const uint8_t *src, size_t src_stride, uint8_t *dst, size_t dst_stride, size_t width, size_t height, size_t y_begin, size_t y_end, size_t channels, - size_t kernel_width, size_t kernel_height, float sigma_x, float sigma_y, - kleidicv_border_type_t border_type, + size_t kernel_width, size_t /*kernel_height*/, float sigma_x, + float /*sigma_y*/, FixedBorderType fixed_border_type, kleidicv_filter_context_t *context) KLEIDICV_STREAMING_COMPATIBLE { auto *workspace = reinterpret_cast(context); kleidicv_error_t checks_result = gaussian_blur_checks( - src, src_stride, dst, dst_stride, width, height, channels, kernel_width, - kernel_height, sigma_x, sigma_y, workspace); + src, src_stride, dst, dst_stride, width, height, channels, workspace); if (checks_result != KLEIDICV_OK) { return checks_result; } - auto fixed_border_type = get_fixed_border_type(border_type); - if (!fixed_border_type) { - return KLEIDICV_ERROR_NOT_IMPLEMENTED; - } - Rectangle rect{width, height}; if (sigma_x == 0.0) { return gaussian_blur(kernel_width, src, src_stride, dst, dst_stride, rect, y_begin, y_end, channels, sigma_x, - *fixed_border_type, workspace); + fixed_border_type, workspace); } return gaussian_blur(kernel_width, src, src_stride, dst, dst_stride, rect, y_begin, y_end, channels, sigma_x, - *fixed_border_type, workspace); + fixed_border_type, workspace); } } // namespace KLEIDICV_TARGET_NAMESPACE diff --git a/kleidicv/src/filters/gaussian_blur_sme2.cpp b/kleidicv/src/filters/gaussian_blur_sme2.cpp index f82698737..0ea5b4a5d 100644 --- a/kleidicv/src/filters/gaussian_blur_sme2.cpp +++ b/kleidicv/src/filters/gaussian_blur_sme2.cpp @@ -13,7 +13,7 @@ gaussian_blur_stripe_u8(const uint8_t *src, size_t src_stride, uint8_t *dst, size_t y_begin, size_t y_end, size_t channels, size_t kernel_width, size_t kernel_height, float sigma_x, float sigma_y, - kleidicv_border_type_t border_type, + FixedBorderType border_type, kleidicv_filter_context_t *context) { return gaussian_blur_stripe_u8_sc( src, src_stride, dst, dst_stride, width, height, y_begin, y_end, channels, diff --git a/kleidicv/src/filters/gaussian_blur_sve2.cpp b/kleidicv/src/filters/gaussian_blur_sve2.cpp index 04e50f8a6..a98aed200 100644 --- a/kleidicv/src/filters/gaussian_blur_sve2.cpp +++ b/kleidicv/src/filters/gaussian_blur_sve2.cpp @@ -12,7 +12,7 @@ kleidicv_error_t gaussian_blur_stripe_u8( const uint8_t *src, size_t src_stride, uint8_t *dst, size_t dst_stride, size_t width, size_t height, size_t y_begin, size_t y_end, size_t channels, size_t kernel_width, size_t kernel_height, float sigma_x, float sigma_y, - kleidicv_border_type_t border_type, kleidicv_filter_context_t *context) { + FixedBorderType border_type, kleidicv_filter_context_t *context) { return gaussian_blur_stripe_u8_sc( src, src_stride, dst, dst_stride, width, height, y_begin, y_end, channels, kernel_width, kernel_height, sigma_x, sigma_y, border_type, context); diff --git a/kleidicv/src/filters/separable_filter_2d_api.cpp b/kleidicv/src/filters/separable_filter_2d_api.cpp index 2372313b1..276b49628 100644 --- a/kleidicv/src/filters/separable_filter_2d_api.cpp +++ b/kleidicv/src/filters/separable_filter_2d_api.cpp @@ -16,7 +16,7 @@ kleidicv_error_t separable_filter_2d_stripe( const T *src, size_t src_stride, T *dst, size_t dst_stride, size_t width, size_t height, size_t y_begin, size_t y_end, size_t channels, const T *kernel_x, size_t kernel_width, const T *kernel_y, - size_t kernel_height, kleidicv_border_type_t border_type, + size_t kernel_height, FixedBorderType border_type, kleidicv_filter_context_t *context); } // namespace neon @@ -28,7 +28,7 @@ kleidicv_error_t separable_filter_2d_stripe( const T *src, size_t src_stride, T *dst, size_t dst_stride, size_t width, size_t height, size_t y_begin, size_t y_end, size_t channels, const T *kernel_x, size_t kernel_width, const T *kernel_y, - size_t kernel_height, kleidicv_border_type_t border_type, + size_t kernel_height, FixedBorderType border_type, kleidicv_filter_context_t *context); } // namespace sve2 @@ -40,7 +40,7 @@ kleidicv_error_t separable_filter_2d_stripe( const T *src, size_t src_stride, T *dst, size_t dst_stride, size_t width, size_t height, size_t y_begin, size_t y_end, size_t channels, const T *kernel_x, size_t kernel_width, const T *kernel_y, - size_t kernel_height, kleidicv_border_type_t border_type, + size_t kernel_height, FixedBorderType border_type, kleidicv_filter_context_t *context); } // namespace sme2 @@ -111,9 +111,19 @@ kleidicv_error_t kleidicv_separable_filter_2d_u8( size_t width, size_t height, size_t channels, const uint8_t *kernel_x, size_t kernel_width, const uint8_t *kernel_y, size_t kernel_height, kleidicv_border_type_t border_type, kleidicv_filter_context_t *context) { + if (!kleidicv::separable_filter_2d_is_implemented(width, height, kernel_width, + kernel_height)) { + return KLEIDICV_ERROR_NOT_IMPLEMENTED; + } + auto fixed_border_type = kleidicv::get_fixed_border_type(border_type); + if (!fixed_border_type) { + return KLEIDICV_ERROR_NOT_IMPLEMENTED; + } + return kleidicv_separable_filter_2d_stripe_u8( src, src_stride, dst, dst_stride, width, height, 0, height, channels, - kernel_x, kernel_width, kernel_y, kernel_height, border_type, context); + kernel_x, kernel_width, kernel_y, kernel_height, *fixed_border_type, + context); } kleidicv_error_t kleidicv_separable_filter_2d_u16( @@ -121,9 +131,19 @@ kleidicv_error_t kleidicv_separable_filter_2d_u16( size_t width, size_t height, size_t channels, const uint16_t *kernel_x, size_t kernel_width, const uint16_t *kernel_y, size_t kernel_height, kleidicv_border_type_t border_type, kleidicv_filter_context_t *context) { + if (!kleidicv::separable_filter_2d_is_implemented(width, height, kernel_width, + kernel_height)) { + return KLEIDICV_ERROR_NOT_IMPLEMENTED; + } + auto fixed_border_type = kleidicv::get_fixed_border_type(border_type); + if (!fixed_border_type) { + return KLEIDICV_ERROR_NOT_IMPLEMENTED; + } + return kleidicv_separable_filter_2d_stripe_u16( src, src_stride, dst, dst_stride, width, height, 0, height, channels, - kernel_x, kernel_width, kernel_y, kernel_height, border_type, context); + kernel_x, kernel_width, kernel_y, kernel_height, *fixed_border_type, + context); } kleidicv_error_t kleidicv_separable_filter_2d_s16( @@ -131,9 +151,19 @@ kleidicv_error_t kleidicv_separable_filter_2d_s16( size_t width, size_t height, size_t channels, const int16_t *kernel_x, size_t kernel_width, const int16_t *kernel_y, size_t kernel_height, kleidicv_border_type_t border_type, kleidicv_filter_context_t *context) { + if (!kleidicv::separable_filter_2d_is_implemented(width, height, kernel_width, + kernel_height)) { + return KLEIDICV_ERROR_NOT_IMPLEMENTED; + } + auto fixed_border_type = kleidicv::get_fixed_border_type(border_type); + if (!fixed_border_type) { + return KLEIDICV_ERROR_NOT_IMPLEMENTED; + } + return kleidicv_separable_filter_2d_stripe_s16( src, src_stride, dst, dst_stride, width, height, 0, height, channels, - kernel_x, kernel_width, kernel_y, kernel_height, border_type, context); + kernel_x, kernel_width, kernel_y, kernel_height, *fixed_border_type, + context); } } // extern "C" diff --git a/kleidicv/src/filters/separable_filter_2d_neon.cpp b/kleidicv/src/filters/separable_filter_2d_neon.cpp index f28e88f94..be9c6f147 100644 --- a/kleidicv/src/filters/separable_filter_2d_neon.cpp +++ b/kleidicv/src/filters/separable_filter_2d_neon.cpp @@ -317,23 +317,14 @@ class SeparableFilter2D { template static kleidicv_error_t separable_filter_2d_checks( const T *src, size_t src_stride, T *dst, size_t dst_stride, size_t width, - size_t height, size_t channels, const T *kernel_x, size_t kernel_width, - const T *kernel_y, size_t kernel_height, + size_t height, size_t channels, const T *kernel_x, const T *kernel_y, SeparableFilterWorkspace *workspace) { CHECK_POINTERS(workspace, kernel_x, kernel_y); - if (kernel_width != 5 || kernel_height != 5) { - return KLEIDICV_ERROR_NOT_IMPLEMENTED; - } - CHECK_POINTER_AND_STRIDE(src, src_stride, height); CHECK_POINTER_AND_STRIDE(dst, dst_stride, height); CHECK_IMAGE_SIZE(width, height); - if (width < kernel_width - 1 || height < kernel_width - 1) { - return KLEIDICV_ERROR_NOT_IMPLEMENTED; - } - if (channels > KLEIDICV_MAXIMUM_CHANNEL_COUNT) { return KLEIDICV_ERROR_RANGE; } @@ -354,25 +345,18 @@ template kleidicv_error_t separable_filter_2d_stripe( const T *src, size_t src_stride, T *dst, size_t dst_stride, size_t width, size_t height, size_t y_begin, size_t y_end, size_t channels, - const T *kernel_x, size_t kernel_width, const T *kernel_y, - size_t kernel_height, kleidicv_border_type_t border_type, + const T *kernel_x, size_t /*kernel_width*/, const T *kernel_y, + size_t /*kernel_height*/, FixedBorderType fixed_border_type, kleidicv_filter_context_t *context) { auto *workspace = reinterpret_cast(context); kleidicv_error_t checks_result = separable_filter_2d_checks( src, src_stride, dst, dst_stride, width, height, channels, kernel_x, - kernel_width, kernel_y, kernel_height, workspace); + kernel_y, workspace); if (checks_result != KLEIDICV_OK) { return checks_result; } - auto fixed_border_type = get_fixed_border_type(border_type); - // if the std::optional is empty, that means that the border type is not - // supported, so there's no need to check for specific types - if (!fixed_border_type) { - return KLEIDICV_ERROR_NOT_IMPLEMENTED; - } - Rectangle rect{width, height}; using SeparableFilterClass = SeparableFilter2D; @@ -383,19 +367,19 @@ kleidicv_error_t separable_filter_2d_stripe( Rows src_rows{src, src_stride, channels}; Rows dst_rows{dst, dst_stride, channels}; workspace->process(rect, y_begin, y_end, src_rows, dst_rows, channels, - *fixed_border_type, filter); + fixed_border_type, filter); return KLEIDICV_OK; } -#define KLEIDICV_INSTANTIATE_TEMPLATE(type) \ - template KLEIDICV_TARGET_FN_ATTRS kleidicv_error_t \ - separable_filter_2d_stripe( \ - const type *src, size_t src_stride, type *dst, size_t dst_stride, \ - size_t width, size_t height, size_t y_begin, size_t y_end, \ - size_t channels, const type *kernel_x, size_t kernel_width, \ - const type *kernel_y, size_t kernel_height, \ - kleidicv_border_type_t border_type, kleidicv_filter_context_t *context) +#define KLEIDICV_INSTANTIATE_TEMPLATE(type) \ + template KLEIDICV_TARGET_FN_ATTRS kleidicv_error_t \ + separable_filter_2d_stripe( \ + const type *src, size_t src_stride, type *dst, size_t dst_stride, \ + size_t width, size_t height, size_t y_begin, size_t y_end, \ + size_t channels, const type *kernel_x, size_t kernel_width, \ + const type *kernel_y, size_t kernel_height, FixedBorderType border_type, \ + kleidicv_filter_context_t *context) KLEIDICV_INSTANTIATE_TEMPLATE(uint8_t); KLEIDICV_INSTANTIATE_TEMPLATE(uint16_t); diff --git a/kleidicv/src/filters/separable_filter_2d_sc.h b/kleidicv/src/filters/separable_filter_2d_sc.h index 69f5eb276..868f67dd6 100644 --- a/kleidicv/src/filters/separable_filter_2d_sc.h +++ b/kleidicv/src/filters/separable_filter_2d_sc.h @@ -437,23 +437,14 @@ class SeparableFilter2D { template static kleidicv_error_t separable_filter_2d_checks( const T *src, size_t src_stride, T *dst, size_t dst_stride, size_t width, - size_t height, size_t channels, const T *kernel_x, size_t kernel_width, - const T *kernel_y, size_t kernel_height, + size_t height, size_t channels, const T *kernel_x, const T *kernel_y, SeparableFilterWorkspace *workspace) KLEIDICV_STREAMING_COMPATIBLE { CHECK_POINTERS(workspace, kernel_x, kernel_y); - if (kernel_width != 5 || kernel_height != 5) { - return KLEIDICV_ERROR_NOT_IMPLEMENTED; - } - CHECK_POINTER_AND_STRIDE(src, src_stride, height); CHECK_POINTER_AND_STRIDE(dst, dst_stride, height); CHECK_IMAGE_SIZE(width, height); - if (width < kernel_width - 1 || height < kernel_width - 1) { - return KLEIDICV_ERROR_NOT_IMPLEMENTED; - } - if (channels > KLEIDICV_MAXIMUM_CHANNEL_COUNT) { return KLEIDICV_ERROR_RANGE; } @@ -474,25 +465,18 @@ template kleidicv_error_t separable_filter_2d_stripe_sc( const T *src, size_t src_stride, T *dst, size_t dst_stride, size_t width, size_t height, size_t y_begin, size_t y_end, size_t channels, - const T *kernel_x, size_t kernel_width, const T *kernel_y, - size_t kernel_height, kleidicv_border_type_t border_type, + const T *kernel_x, size_t /*kernel_width*/, const T *kernel_y, + size_t /*kernel_height*/, FixedBorderType fixed_border_type, kleidicv_filter_context_t *context) KLEIDICV_STREAMING_COMPATIBLE { auto *workspace = reinterpret_cast(context); kleidicv_error_t checks_result = separable_filter_2d_checks( src, src_stride, dst, dst_stride, width, height, channels, kernel_x, - kernel_width, kernel_y, kernel_height, workspace); + kernel_y, workspace); if (checks_result != KLEIDICV_OK) { return checks_result; } - auto fixed_border_type = get_fixed_border_type(border_type); - // if the std::optional is empty, that means that the border type is not - // supported, so there's no need to check for specific types - if (!fixed_border_type) { - return KLEIDICV_ERROR_NOT_IMPLEMENTED; - } - Rectangle rect{width, height}; using SeparableFilterClass = SeparableFilter2D; @@ -523,7 +507,7 @@ kleidicv_error_t separable_filter_2d_stripe_sc( Rows src_rows{src, src_stride, channels}; Rows dst_rows{dst, dst_stride, channels}; workspace->process(rect, y_begin, y_end, src_rows, dst_rows, channels, - *fixed_border_type, filter); + fixed_border_type, filter); return KLEIDICV_OK; } diff --git a/kleidicv/src/filters/separable_filter_2d_sme2.cpp b/kleidicv/src/filters/separable_filter_2d_sme2.cpp index 45cfbb83f..8ba832ff5 100644 --- a/kleidicv/src/filters/separable_filter_2d_sme2.cpp +++ b/kleidicv/src/filters/separable_filter_2d_sme2.cpp @@ -14,21 +14,21 @@ separable_filter_2d_stripe(const T *src, size_t src_stride, T *dst, size_t y_begin, size_t y_end, size_t channels, const T *kernel_x, size_t kernel_width, const T *kernel_y, size_t kernel_height, - kleidicv_border_type_t border_type, + FixedBorderType border_type, kleidicv_filter_context_t *context) { return separable_filter_2d_stripe_sc( src, src_stride, dst, dst_stride, width, height, y_begin, y_end, channels, kernel_x, kernel_width, kernel_y, kernel_height, border_type, context); } -#define KLEIDICV_INSTANTIATE_TEMPLATE(type) \ - template KLEIDICV_TARGET_FN_ATTRS kleidicv_error_t \ - separable_filter_2d_stripe( \ - const type *src, size_t src_stride, type *dst, size_t dst_stride, \ - size_t width, size_t height, size_t y_begin, size_t y_end, \ - size_t channels, const type *kernel_x, size_t kernel_width, \ - const type *kernel_y, size_t kernel_height, \ - kleidicv_border_type_t border_type, kleidicv_filter_context_t *context) +#define KLEIDICV_INSTANTIATE_TEMPLATE(type) \ + template KLEIDICV_TARGET_FN_ATTRS kleidicv_error_t \ + separable_filter_2d_stripe( \ + const type *src, size_t src_stride, type *dst, size_t dst_stride, \ + size_t width, size_t height, size_t y_begin, size_t y_end, \ + size_t channels, const type *kernel_x, size_t kernel_width, \ + const type *kernel_y, size_t kernel_height, FixedBorderType border_type, \ + kleidicv_filter_context_t *context) KLEIDICV_INSTANTIATE_TEMPLATE(uint8_t); KLEIDICV_INSTANTIATE_TEMPLATE(uint16_t); diff --git a/kleidicv/src/filters/separable_filter_2d_sve2.cpp b/kleidicv/src/filters/separable_filter_2d_sve2.cpp index b203d8613..eae0f8c98 100644 --- a/kleidicv/src/filters/separable_filter_2d_sve2.cpp +++ b/kleidicv/src/filters/separable_filter_2d_sve2.cpp @@ -12,21 +12,21 @@ KLEIDICV_TARGET_FN_ATTRS kleidicv_error_t separable_filter_2d_stripe( const T *src, size_t src_stride, T *dst, size_t dst_stride, size_t width, size_t height, size_t y_begin, size_t y_end, size_t channels, const T *kernel_x, size_t kernel_width, const T *kernel_y, - size_t kernel_height, kleidicv_border_type_t border_type, + size_t kernel_height, FixedBorderType border_type, kleidicv_filter_context_t *context) { return separable_filter_2d_stripe_sc( src, src_stride, dst, dst_stride, width, height, y_begin, y_end, channels, kernel_x, kernel_width, kernel_y, kernel_height, border_type, context); } -#define KLEIDICV_INSTANTIATE_TEMPLATE(type) \ - template KLEIDICV_TARGET_FN_ATTRS kleidicv_error_t \ - separable_filter_2d_stripe( \ - const type *src, size_t src_stride, type *dst, size_t dst_stride, \ - size_t width, size_t height, size_t y_begin, size_t y_end, \ - size_t channels, const type *kernel_x, size_t kernel_width, \ - const type *kernel_y, size_t kernel_height, \ - kleidicv_border_type_t border_type, kleidicv_filter_context_t *context) +#define KLEIDICV_INSTANTIATE_TEMPLATE(type) \ + template KLEIDICV_TARGET_FN_ATTRS kleidicv_error_t \ + separable_filter_2d_stripe( \ + const type *src, size_t src_stride, type *dst, size_t dst_stride, \ + size_t width, size_t height, size_t y_begin, size_t y_end, \ + size_t channels, const type *kernel_x, size_t kernel_width, \ + const type *kernel_y, size_t kernel_height, FixedBorderType border_type, \ + kleidicv_filter_context_t *context) KLEIDICV_INSTANTIATE_TEMPLATE(uint8_t); KLEIDICV_INSTANTIATE_TEMPLATE(uint16_t); diff --git a/kleidicv/src/filters/sobel_api.cpp b/kleidicv/src/filters/sobel_api.cpp index ca0218e47..4953a54bc 100644 --- a/kleidicv/src/filters/sobel_api.cpp +++ b/kleidicv/src/filters/sobel_api.cpp @@ -22,12 +22,18 @@ extern "C" { kleidicv_error_t kleidicv_sobel_3x3_horizontal_s16_u8( const uint8_t *src, size_t src_stride, int16_t *dst, size_t dst_stride, size_t width, size_t height, size_t channels) { + if (!kleidicv::sobel_is_implemented(width, height, 3)) { + return KLEIDICV_ERROR_NOT_IMPLEMENTED; + } return kleidicv_sobel_3x3_horizontal_stripe_s16_u8( src, src_stride, dst, dst_stride, width, height, 0, height, channels); } kleidicv_error_t kleidicv_sobel_3x3_vertical_s16_u8( const uint8_t *src, size_t src_stride, int16_t *dst, size_t dst_stride, size_t width, size_t height, size_t channels) { + if (!kleidicv::sobel_is_implemented(width, height, 3)) { + return KLEIDICV_ERROR_NOT_IMPLEMENTED; + } return kleidicv_sobel_3x3_vertical_stripe_s16_u8( src, src_stride, dst, dst_stride, width, height, 0, height, channels); } diff --git a/kleidicv/src/filters/sobel_neon.cpp b/kleidicv/src/filters/sobel_neon.cpp index 330d091fe..b76b4e24b 100644 --- a/kleidicv/src/filters/sobel_neon.cpp +++ b/kleidicv/src/filters/sobel_neon.cpp @@ -136,12 +136,6 @@ kleidicv_error_t sobel_3x3_horizontal_stripe_s16_u8( CHECK_POINTER_AND_STRIDE(dst, dst_stride, height); CHECK_IMAGE_SIZE(width, height); - const size_t KernelSize = 3; - - if (width < KernelSize - 1 || height < KernelSize - 1) { - return KLEIDICV_ERROR_NOT_IMPLEMENTED; - } - if (channels > KLEIDICV_MAXIMUM_CHANNEL_COUNT) { return KLEIDICV_ERROR_RANGE; } @@ -172,12 +166,6 @@ kleidicv_error_t sobel_3x3_vertical_stripe_s16_u8( CHECK_POINTER_AND_STRIDE(dst, dst_stride, height); CHECK_IMAGE_SIZE(width, height); - const size_t KernelSize = 3; - - if (width < KernelSize - 1 || height < KernelSize - 1) { - return KLEIDICV_ERROR_NOT_IMPLEMENTED; - } - if (channels > KLEIDICV_MAXIMUM_CHANNEL_COUNT) { return KLEIDICV_ERROR_RANGE; } diff --git a/kleidicv/src/filters/sobel_sc.h b/kleidicv/src/filters/sobel_sc.h index c2e71c270..769f8a7fe 100644 --- a/kleidicv/src/filters/sobel_sc.h +++ b/kleidicv/src/filters/sobel_sc.h @@ -127,12 +127,6 @@ static kleidicv_error_t sobel_3x3_horizontal_stripe_s16_u8_sc( CHECK_POINTER_AND_STRIDE(dst, dst_stride, height); CHECK_IMAGE_SIZE(width, height); - const size_t KernelSize = 3; - - if (width < KernelSize - 1 || height < KernelSize - 1) { - return KLEIDICV_ERROR_NOT_IMPLEMENTED; - } - if (channels > KLEIDICV_MAXIMUM_CHANNEL_COUNT) { return KLEIDICV_ERROR_RANGE; } @@ -163,12 +157,6 @@ static kleidicv_error_t sobel_3x3_vertical_stripe_s16_u8_sc( CHECK_POINTER_AND_STRIDE(dst, dst_stride, height); CHECK_IMAGE_SIZE(width, height); - const size_t KernelSize = 3; - - if (width < KernelSize - 1 || height < KernelSize - 1) { - return KLEIDICV_ERROR_NOT_IMPLEMENTED; - } - if (channels > KLEIDICV_MAXIMUM_CHANNEL_COUNT) { return KLEIDICV_ERROR_RANGE; } diff --git a/kleidicv/src/resize/resize_linear_api.cpp b/kleidicv/src/resize/resize_linear_api.cpp index 97c71ff18..ecf72ddf0 100644 --- a/kleidicv/src/resize/resize_linear_api.cpp +++ b/kleidicv/src/resize/resize_linear_api.cpp @@ -23,6 +23,10 @@ static kleidicv_error_t resize_linear_u8(const uint8_t *src, size_t src_stride, size_t src_width, size_t src_height, uint8_t *dst, size_t dst_stride, size_t dst_width, size_t dst_height) { + if (!resize_linear_u8_is_implemented(src_width, src_height, dst_width, + dst_height)) { + return KLEIDICV_ERROR_NOT_IMPLEMENTED; + } return kleidicv_resize_linear_stripe_u8(src, src_stride, src_width, src_height, 0, src_height, dst, dst_stride, dst_width, dst_height); @@ -32,6 +36,10 @@ static kleidicv_error_t resize_linear_f32(const float *src, size_t src_stride, size_t src_width, size_t src_height, float *dst, size_t dst_stride, size_t dst_width, size_t dst_height) { + if (!resize_linear_f32_is_implemented(src_width, src_height, dst_width, + dst_height)) { + return KLEIDICV_ERROR_NOT_IMPLEMENTED; + } return kleidicv_resize_linear_stripe_f32(src, src_stride, src_width, src_height, 0, src_height, dst, dst_stride, dst_width, dst_height); diff --git a/kleidicv/src/resize/resize_linear_neon.cpp b/kleidicv/src/resize/resize_linear_neon.cpp index c9df0eb77..7b6d1d54d 100644 --- a/kleidicv/src/resize/resize_linear_neon.cpp +++ b/kleidicv/src/resize/resize_linear_neon.cpp @@ -2,6 +2,8 @@ // // SPDX-License-Identifier: Apache-2.0 +#include + #include "kleidicv/kleidicv.h" #include "kleidicv/neon.h" #include "kleidicv/resize/resize_linear.h" @@ -437,7 +439,11 @@ kleidicv_error_t resize_linear_stripe_u8(const uint8_t *src, size_t src_stride, return resize_4x4_u8(src, src_stride, src_width, src_height, y_begin, y_end, dst, dst_stride); } + // resize_linear_u8_is_implemented checked the kernel size already. + // GCOVR_EXCL_START + assert(!"resize ratio not implemented"); return KLEIDICV_ERROR_NOT_IMPLEMENTED; + // GCOVR_EXCL_STOP } KLEIDICV_TARGET_FN_ATTRS static kleidicv_error_t resize_2x2_f32( @@ -981,7 +987,11 @@ kleidicv_error_t resize_linear_stripe_f32(const float *src, size_t src_stride, return resize_8x8_f32(src, src_stride, src_width, src_height, y_begin, y_end, dst, dst_stride); } + // resize_linear_f32_is_implemented checked the kernel size already. + // GCOVR_EXCL_START + assert(!"resize ratio not implemented"); return KLEIDICV_ERROR_NOT_IMPLEMENTED; + // GCOVR_EXCL_STOP } } // namespace kleidicv::neon diff --git a/kleidicv/src/resize/resize_linear_sc.h b/kleidicv/src/resize/resize_linear_sc.h index 57067176c..eb60c195a 100644 --- a/kleidicv/src/resize/resize_linear_sc.h +++ b/kleidicv/src/resize/resize_linear_sc.h @@ -7,6 +7,8 @@ #include +#include + #include "kleidicv/kleidicv.h" #include "kleidicv/sve2.h" @@ -1126,7 +1128,11 @@ KLEIDICV_TARGET_FN_ATTRS static kleidicv_error_t resize_linear_stripe_u8_sc( return resize_4x4_u8_sc(src, src_stride, src_width, src_height, y_begin, y_end, dst, dst_stride); } + // resize_linear_f32_is_implemented checked the kernel size already. + // GCOVR_EXCL_START + assert(!"resize ratio not implemented"); return KLEIDICV_ERROR_NOT_IMPLEMENTED; + // GCOVR_EXCL_STOP } KLEIDICV_TARGET_FN_ATTRS static kleidicv_error_t resize_linear_stripe_f32_sc( @@ -1157,7 +1163,11 @@ KLEIDICV_TARGET_FN_ATTRS static kleidicv_error_t resize_linear_stripe_f32_sc( return resize_8x8_f32_sve128_sc(src, src_stride, src_width, src_height, y_begin, y_end, dst, dst_stride); } + // resize_linear_f32_is_implemented checked the kernel size already. + // GCOVR_EXCL_START + assert(!"resize ratio not implemented"); return KLEIDICV_ERROR_NOT_IMPLEMENTED; + // GCOVR_EXCL_STOP } } // namespace KLEIDICV_TARGET_NAMESPACE diff --git a/kleidicv_thread/src/kleidicv_thread.cpp b/kleidicv_thread/src/kleidicv_thread.cpp index 93461f579..97f938c32 100644 --- a/kleidicv_thread/src/kleidicv_thread.cpp +++ b/kleidicv_thread/src/kleidicv_thread.cpp @@ -397,12 +397,22 @@ kleidicv_error_t kleidicv_thread_gaussian_blur_u8( size_t kernel_height, float sigma_x, float sigma_y, kleidicv_border_type_t border_type, kleidicv_filter_context_t *context, kleidicv_thread_multithreading mt) { + if (!kleidicv::gaussian_blur_is_implemented( + width, height, kernel_width, kernel_height, sigma_x, sigma_y)) { + return KLEIDICV_ERROR_NOT_IMPLEMENTED; + } + + auto fixed_border_type = kleidicv::get_fixed_border_type(border_type); + if (!fixed_border_type) { + return KLEIDICV_ERROR_NOT_IMPLEMENTED; + } + auto callback = [=](size_t y_begin, size_t y_end, kleidicv_filter_context_t *thread_context) { return kleidicv_gaussian_blur_stripe_u8( src, src_stride, dst, dst_stride, width, height, y_begin, y_end, - channels, kernel_width, kernel_height, sigma_x, sigma_y, border_type, - thread_context); + channels, kernel_width, kernel_height, sigma_x, sigma_y, + *fixed_border_type, thread_context); }; return kleidicv_thread_filter(callback, width, height, channels, kernel_width, kernel_height, context, mt); @@ -414,12 +424,22 @@ kleidicv_error_t kleidicv_thread_separable_filter_2d_u8( size_t kernel_width, const uint8_t *kernel_y, size_t kernel_height, kleidicv_border_type_t border_type, kleidicv_filter_context_t *context, kleidicv_thread_multithreading mt) { + if (!kleidicv::separable_filter_2d_is_implemented(width, height, kernel_width, + kernel_height)) { + return KLEIDICV_ERROR_NOT_IMPLEMENTED; + } + + auto fixed_border_type = kleidicv::get_fixed_border_type(border_type); + if (!fixed_border_type) { + return KLEIDICV_ERROR_NOT_IMPLEMENTED; + } + auto callback = [=](size_t y_begin, size_t y_end, kleidicv_filter_context_t *thread_context) { return kleidicv_separable_filter_2d_stripe_u8( src, src_stride, dst, dst_stride, width, height, y_begin, y_end, - channels, kernel_x, kernel_width, kernel_y, kernel_height, border_type, - thread_context); + channels, kernel_x, kernel_width, kernel_y, kernel_height, + *fixed_border_type, thread_context); }; return kleidicv_thread_filter(callback, width, height, channels, kernel_width, kernel_height, context, mt); @@ -431,12 +451,22 @@ kleidicv_error_t kleidicv_thread_separable_filter_2d_u16( size_t kernel_width, const uint16_t *kernel_y, size_t kernel_height, kleidicv_border_type_t border_type, kleidicv_filter_context_t *context, kleidicv_thread_multithreading mt) { + if (!kleidicv::separable_filter_2d_is_implemented(width, height, kernel_width, + kernel_height)) { + return KLEIDICV_ERROR_NOT_IMPLEMENTED; + } + + auto fixed_border_type = kleidicv::get_fixed_border_type(border_type); + if (!fixed_border_type) { + return KLEIDICV_ERROR_NOT_IMPLEMENTED; + } + auto callback = [=](size_t y_begin, size_t y_end, kleidicv_filter_context_t *thread_context) { return kleidicv_separable_filter_2d_stripe_u16( src, src_stride, dst, dst_stride, width, height, y_begin, y_end, - channels, kernel_x, kernel_width, kernel_y, kernel_height, border_type, - thread_context); + channels, kernel_x, kernel_width, kernel_y, kernel_height, + *fixed_border_type, thread_context); }; return kleidicv_thread_filter(callback, width, height, channels, kernel_width, kernel_height, context, mt); @@ -448,12 +478,22 @@ kleidicv_error_t kleidicv_thread_separable_filter_2d_s16( size_t kernel_width, const int16_t *kernel_y, size_t kernel_height, kleidicv_border_type_t border_type, kleidicv_filter_context_t *context, kleidicv_thread_multithreading mt) { + if (!kleidicv::separable_filter_2d_is_implemented(width, height, kernel_width, + kernel_height)) { + return KLEIDICV_ERROR_NOT_IMPLEMENTED; + } + + auto fixed_border_type = kleidicv::get_fixed_border_type(border_type); + if (!fixed_border_type) { + return KLEIDICV_ERROR_NOT_IMPLEMENTED; + } + auto callback = [=](size_t y_begin, size_t y_end, kleidicv_filter_context_t *thread_context) { return kleidicv_separable_filter_2d_stripe_s16( src, src_stride, dst, dst_stride, width, height, y_begin, y_end, - channels, kernel_x, kernel_width, kernel_y, kernel_height, border_type, - thread_context); + channels, kernel_x, kernel_width, kernel_y, kernel_height, + *fixed_border_type, thread_context); }; return kleidicv_thread_filter(callback, width, height, channels, kernel_width, kernel_height, context, mt); @@ -463,6 +503,10 @@ kleidicv_error_t kleidicv_thread_sobel_3x3_horizontal_s16_u8( const uint8_t *src, size_t src_stride, int16_t *dst, size_t dst_stride, size_t width, size_t height, size_t channels, kleidicv_thread_multithreading mt) { + if (!kleidicv::sobel_is_implemented(width, height, 3)) { + return KLEIDICV_ERROR_NOT_IMPLEMENTED; + } + auto callback = [=](unsigned y_begin, unsigned y_end) { return kleidicv_sobel_3x3_horizontal_stripe_s16_u8( src, src_stride, dst, dst_stride, width, height, y_begin, y_end, @@ -475,6 +519,10 @@ kleidicv_error_t kleidicv_thread_sobel_3x3_vertical_s16_u8( const uint8_t *src, size_t src_stride, int16_t *dst, size_t dst_stride, size_t width, size_t height, size_t channels, kleidicv_thread_multithreading mt) { + if (!kleidicv::sobel_is_implemented(width, height, 3)) { + return KLEIDICV_ERROR_NOT_IMPLEMENTED; + } + auto callback = [=](unsigned y_begin, unsigned y_end) { return kleidicv_sobel_3x3_vertical_stripe_s16_u8(src, src_stride, dst, dst_stride, width, height, @@ -510,6 +558,10 @@ kleidicv_error_t kleidicv_thread_resize_linear_u8( const uint8_t *src, size_t src_stride, size_t src_width, size_t src_height, uint8_t *dst, size_t dst_stride, size_t dst_width, size_t dst_height, kleidicv_thread_multithreading mt) { + if (!kleidicv::resize_linear_u8_is_implemented(src_width, src_height, + dst_width, dst_height)) { + return KLEIDICV_ERROR_NOT_IMPLEMENTED; + } auto callback = [=](unsigned y_begin, unsigned y_end) { return kleidicv_resize_linear_stripe_u8( src, src_stride, src_width, src_height, y_begin, @@ -523,6 +575,10 @@ kleidicv_error_t kleidicv_thread_resize_linear_f32( const float *src, size_t src_stride, size_t src_width, size_t src_height, float *dst, size_t dst_stride, size_t dst_width, size_t dst_height, kleidicv_thread_multithreading mt) { + if (!kleidicv::resize_linear_f32_is_implemented(src_width, src_height, + dst_width, dst_height)) { + return KLEIDICV_ERROR_NOT_IMPLEMENTED; + } auto callback = [=](unsigned y_begin, unsigned y_end) { return kleidicv_resize_linear_stripe_f32( src, src_stride, src_width, src_height, y_begin, diff --git a/test/api/test_gaussian_blur.cpp b/test/api/test_gaussian_blur.cpp index 0d487b852..e559925cc 100644 --- a/test/api/test_gaussian_blur.cpp +++ b/test/api/test_gaussian_blur.cpp @@ -1054,13 +1054,13 @@ TYPED_TEST(GaussianBlur, OversizeImage) { EXPECT_EQ(KLEIDICV_ERROR_RANGE, gaussian_blur()( src, sizeof(TypeParam), dst, sizeof(TypeParam), - KLEIDICV_MAX_IMAGE_PIXELS + 1, 1, 1, 15, 15, 0.0, 0.0, + KLEIDICV_MAX_IMAGE_PIXELS + 1, 15, 1, 15, 15, 0.0, 0.0, KLEIDICV_BORDER_TYPE_REFLECT, context)); EXPECT_EQ(KLEIDICV_ERROR_RANGE, gaussian_blur()( src, sizeof(TypeParam), dst, sizeof(TypeParam), - KLEIDICV_MAX_IMAGE_PIXELS, KLEIDICV_MAX_IMAGE_PIXELS, 1, 15, 15, - 0.0, 0.0, KLEIDICV_BORDER_TYPE_REFLECT, context)); + KLEIDICV_MAX_IMAGE_PIXELS, KLEIDICV_MAX_IMAGE_PIXELS, 15, 15, + 15, 0.0, 0.0, KLEIDICV_BORDER_TYPE_REFLECT, context)); EXPECT_EQ(KLEIDICV_OK, kleidicv_filter_context_release(context)); } diff --git a/test/api/test_resize_linear.cpp b/test/api/test_resize_linear.cpp index e4cd0aa2d..576ec8684 100644 --- a/test/api/test_resize_linear.cpp +++ b/test/api/test_resize_linear.cpp @@ -241,15 +241,18 @@ TYPED_TEST(ResizeLinear, InvalidImageSize) { EXPECT_EQ(KLEIDICV_ERROR_RANGE, kleidicv_resize_linear( - src, sizeof(TypeParam), 1, 1, dst, + src, sizeof(TypeParam) * ((KLEIDICV_MAX_IMAGE_PIXELS + 1) / 2), + (KLEIDICV_MAX_IMAGE_PIXELS + 1) / 2, 1, dst, sizeof(TypeParam) * (KLEIDICV_MAX_IMAGE_PIXELS + 1), - KLEIDICV_MAX_IMAGE_PIXELS + 1, 1)); + KLEIDICV_MAX_IMAGE_PIXELS + 1, 2)); EXPECT_EQ(KLEIDICV_ERROR_RANGE, kleidicv_resize_linear( - src, sizeof(TypeParam), 1, 1, dst, - sizeof(TypeParam) * KLEIDICV_MAX_IMAGE_PIXELS, - KLEIDICV_MAX_IMAGE_PIXELS, KLEIDICV_MAX_IMAGE_PIXELS)); + src, sizeof(TypeParam) * ((KLEIDICV_MAX_IMAGE_PIXELS - 1) / 2), + (KLEIDICV_MAX_IMAGE_PIXELS - 1) / 2, + (KLEIDICV_MAX_IMAGE_PIXELS - 1) / 2, dst, + sizeof(TypeParam) * (KLEIDICV_MAX_IMAGE_PIXELS - 1), + KLEIDICV_MAX_IMAGE_PIXELS - 1, KLEIDICV_MAX_IMAGE_PIXELS - 1)); } TYPED_TEST(ResizeLinear, ZeroImageSize) { diff --git a/test/api/test_separable_filter_2d.cpp b/test/api/test_separable_filter_2d.cpp index 90518dc8f..b89f3553e 100644 --- a/test/api/test_separable_filter_2d.cpp +++ b/test/api/test_separable_filter_2d.cpp @@ -729,7 +729,7 @@ TYPED_TEST(SeparableFilter2D, OversizeImage) { EXPECT_EQ(KLEIDICV_ERROR_RANGE, separable_filter_2d()( src, sizeof(TypeParam), dst, sizeof(TypeParam), - KLEIDICV_MAX_IMAGE_PIXELS + 1, 1, 1, kernel, 5, kernel, 5, + KLEIDICV_MAX_IMAGE_PIXELS + 1, 5, 1, kernel, 5, kernel, 5, KLEIDICV_BORDER_TYPE_REPLICATE, context)); EXPECT_EQ(KLEIDICV_ERROR_RANGE, separable_filter_2d()( diff --git a/test/api/test_sobel.cpp b/test/api/test_sobel.cpp index 8f6cc71d7..af60dc010 100644 --- a/test/api/test_sobel.cpp +++ b/test/api/test_sobel.cpp @@ -97,7 +97,7 @@ TYPED_TEST(Sobel, Horizontal3x3) { typename KernelTestParams::InputType src[1] = {}; typename KernelTestParams::OutputType dst[1]; test::test_null_args(sobel_3x3_horizontal(), src, sizeof(src), dst, - sizeof(dst), 1, 1, 1); + sizeof(dst), 3, 3, 1); } // Tests sobel_3x3_vertical__ API. @@ -115,7 +115,7 @@ TYPED_TEST(Sobel, Vertical3x3) { typename KernelTestParams::InputType src[1] = {}; typename KernelTestParams::OutputType dst[1]; test::test_null_args(sobel_3x3_vertical(), src, sizeof(src), dst, - sizeof(dst), 1, 1, 1); + sizeof(dst), 3, 3, 1); } TYPED_TEST(Sobel, MisalignmentHorizontal) { @@ -125,12 +125,12 @@ TYPED_TEST(Sobel, MisalignmentHorizontal) { if (sizeof(typename KernelTestParams::InputType) != 1) { EXPECT_EQ(KLEIDICV_ERROR_ALIGNMENT, sobel_3x3_horizontal()(src, sizeof(src) + 1, dst, - sizeof(dst), 1, 2, 1)); + sizeof(dst), 3, 3, 1)); } if (sizeof(typename KernelTestParams::OutputType) != 1) { EXPECT_EQ(KLEIDICV_ERROR_ALIGNMENT, sobel_3x3_horizontal()(src, sizeof(src), dst, - sizeof(dst) + 1, 1, 2, 1)); + sizeof(dst) + 1, 3, 3, 1)); } } @@ -141,12 +141,12 @@ TYPED_TEST(Sobel, MisalignmentVertical) { if (sizeof(typename KernelTestParams::InputType) != 1) { EXPECT_EQ(KLEIDICV_ERROR_ALIGNMENT, sobel_3x3_vertical()(src, sizeof(src) + 1, dst, - sizeof(dst), 1, 2, 1)); + sizeof(dst), 3, 3, 1)); } if (sizeof(typename KernelTestParams::OutputType) != 1) { EXPECT_EQ(KLEIDICV_ERROR_ALIGNMENT, sobel_3x3_vertical()(src, sizeof(src), dst, - sizeof(dst) + 1, 1, 2, 1)); + sizeof(dst) + 1, 3, 3, 1)); } } @@ -253,7 +253,7 @@ TYPED_TEST(Sobel, OversizeImageHorizontal) { EXPECT_EQ(KLEIDICV_ERROR_RANGE, sobel_3x3_horizontal()( src, sizeof(src), dst, sizeof(dst), - KLEIDICV_MAX_IMAGE_PIXELS + 1, 1, 1)); + KLEIDICV_MAX_IMAGE_PIXELS + 1, 3, 1)); EXPECT_EQ(KLEIDICV_ERROR_RANGE, sobel_3x3_horizontal()( src, sizeof(src), dst, sizeof(dst), KLEIDICV_MAX_IMAGE_PIXELS, @@ -267,7 +267,7 @@ TYPED_TEST(Sobel, OversizeImageVertical) { EXPECT_EQ(KLEIDICV_ERROR_RANGE, sobel_3x3_vertical()( src, sizeof(src), dst, sizeof(dst), - KLEIDICV_MAX_IMAGE_PIXELS + 1, 1, 1)); + KLEIDICV_MAX_IMAGE_PIXELS + 1, 3, 1)); EXPECT_EQ(KLEIDICV_ERROR_RANGE, sobel_3x3_vertical()(src, sizeof(src), dst, sizeof(dst), KLEIDICV_MAX_IMAGE_PIXELS, diff --git a/test/api/test_thread.cpp b/test/api/test_thread.cpp index 20fa6f638..c16ae53ca 100644 --- a/test/api/test_thread.cpp +++ b/test/api/test_thread.cpp @@ -195,6 +195,35 @@ TEST_P(Thread, gaussian_blur_u8) { ASSERT_EQ(KLEIDICV_OK, kleidicv_filter_context_release(context)); } +TEST(ThreadGaussianBlur, NotImplemented) { + unsigned max_width = 10, max_height = 10; + size_t channels = 1; + size_t kernel_width = 5; + size_t kernel_height = kernel_width; + float sigma_x = 0.0F, sigma_y = 0.0F; + kleidicv_filter_context_t *context = nullptr; + ASSERT_EQ(KLEIDICV_OK, kleidicv_filter_context_create( + &context, channels, kernel_width, kernel_height, + max_width, max_height)); + + uint8_t src[1] = {}, dst[1] = {}; + // Image too small + EXPECT_EQ(KLEIDICV_ERROR_NOT_IMPLEMENTED, + kleidicv_thread_gaussian_blur_u8( + src, 1, dst, 1, 1, 1, channels, kernel_width, kernel_height, + sigma_x, sigma_y, KLEIDICV_BORDER_TYPE_REPLICATE, context, + get_multithreading_fake(2))); + // Border not supported + EXPECT_EQ( + KLEIDICV_ERROR_NOT_IMPLEMENTED, + kleidicv_thread_gaussian_blur_u8( + src, 1, dst, 1, max_width, max_height, channels, kernel_width, + kernel_height, sigma_x, sigma_y, KLEIDICV_BORDER_TYPE_TRANSPARENT, + context, get_multithreading_fake(2))); + + ASSERT_EQ(KLEIDICV_OK, kleidicv_filter_context_release(context)); +} + TEST_P(Thread, separable_filter_2d_u8) { check_separable_filter_2d(kleidicv_separable_filter_2d_u8, kleidicv_thread_separable_filter_2d_u8); @@ -210,6 +239,49 @@ TEST_P(Thread, separable_filter_2d_s16) { kleidicv_thread_separable_filter_2d_s16); } +template +void check_separable_filter_2d_not_implemented( + MultithreadedFunc multithreaded_func) { + unsigned max_width = 10, max_height = 10; + size_t channels = 1; + const size_t kernel_width = 5; + const size_t kernel_height = kernel_width; + + test::Array2D kernel_x{kernel_width, 1}; + kernel_x.set(0, 0, {1, 2, 3, 4, 5}); + test::Array2D kernel_y{kernel_height, 1}; + kernel_y.set(0, 0, {5, 6, 7, 8, 9}); + + kleidicv_filter_context_t *context = nullptr; + ASSERT_EQ(KLEIDICV_OK, kleidicv_filter_context_create( + &context, channels, kernel_width, kernel_height, + max_width, max_height)); + T src[1] = {}, dst[1] = {}; + // Image too small + EXPECT_EQ(KLEIDICV_ERROR_NOT_IMPLEMENTED, + multithreaded_func(src, 1, dst, 1, 1, 1, channels, kernel_x.data(), + kernel_width, kernel_y.data(), kernel_height, + KLEIDICV_BORDER_TYPE_REPLICATE, context, + get_multithreading_fake(2))); + // Border not supported + EXPECT_EQ(KLEIDICV_ERROR_NOT_IMPLEMENTED, + multithreaded_func(src, 1, dst, 1, max_width, max_height, channels, + kernel_x.data(), kernel_width, kernel_y.data(), + kernel_height, KLEIDICV_BORDER_TYPE_TRANSPARENT, + context, get_multithreading_fake(2))); + + ASSERT_EQ(KLEIDICV_OK, kleidicv_filter_context_release(context)); +} + +TEST(ThreadSeparableFilter2D, NotImplemented) { + check_separable_filter_2d_not_implemented( + kleidicv_thread_separable_filter_2d_u8); + check_separable_filter_2d_not_implemented( + kleidicv_thread_separable_filter_2d_s16); + check_separable_filter_2d_not_implemented( + kleidicv_thread_separable_filter_2d_u16); +} + TEST_P(Thread, SobelHorizontal1Channel) { check_unary_op(kleidicv_sobel_3x3_horizontal_s16_u8, kleidicv_thread_sobel_3x3_horizontal_s16_u8, @@ -234,6 +306,19 @@ TEST_P(Thread, SobelVertical3Channels) { 3, 3); } +TEST(ThreadSobel, NotImplemented) { + uint8_t src[1] = {}; + int16_t dst[1] = {}; + EXPECT_EQ(KLEIDICV_ERROR_NOT_IMPLEMENTED, + kleidicv_thread_sobel_3x3_vertical_s16_u8( + src, sizeof(src), dst, sizeof(dst), 1, 1, 1, + get_multithreading_fake(2))); + EXPECT_EQ(KLEIDICV_ERROR_NOT_IMPLEMENTED, + kleidicv_thread_sobel_3x3_horizontal_s16_u8( + src, sizeof(src), dst, sizeof(dst), 1, 1, 1, + get_multithreading_fake(2))); +} + INSTANTIATE_TEST_SUITE_P( , Thread, testing::Values(P{1, 1, 1}, P{1, 2, 1}, P{1, 2, 2}, P{2, 1, 2}, P{2, 2, 1}, diff --git a/test/api/test_thread_resize.cpp b/test/api/test_thread_resize.cpp index 1171df332..de1d66bf4 100644 --- a/test/api/test_thread_resize.cpp +++ b/test/api/test_thread_resize.cpp @@ -109,3 +109,20 @@ INSTANTIATE_TEST_SUITE_P(, ResizeThread, P{2, 1, 2}, P{2, 2, 1}, P{1, 3, 2}, P{2, 3, 1}, P{6, 4, 1}, P{4, 5, 2}, P{2, 6, 3}, P{1, 7, 4}, P{12, 34, 5})); + +TEST(ResizeThreadTest, NotImplemented) { + { + uint8_t src[1] = {}, dst[1] = {}; + EXPECT_EQ(KLEIDICV_ERROR_NOT_IMPLEMENTED, + kleidicv_thread_resize_linear_u8(src, sizeof(src), 2, 2, dst, + sizeof(dst), 3, 7, + get_multithreading_fake(2))); + } + { + float src[1] = {}, dst[1] = {}; + EXPECT_EQ(KLEIDICV_ERROR_NOT_IMPLEMENTED, + kleidicv_thread_resize_linear_f32(src, sizeof(src), 2, 2, dst, + sizeof(dst), 3, 7, + get_multithreading_fake(2))); + } +} -- GitLab