| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | // SPDX-FileCopyrightText: 2023 - 2025 Arm Limited and/or its affiliates <open-source-office@arm.com> | ||
| 2 | // | ||
| 3 | // SPDX-License-Identifier: Apache-2.0 | ||
| 4 | |||
| 5 | #include "kleidicv/dispatch.h" | ||
| 6 | #include "kleidicv/filters/separable_filter_2d.h" | ||
| 7 | #include "kleidicv/kleidicv.h" | ||
| 8 | #include "kleidicv/workspace/separable.h" | ||
| 9 | |||
| 10 | namespace kleidicv { | ||
| 11 | |||
| 12 | namespace neon { | ||
| 13 | |||
| 14 | template <typename T> | ||
| 15 | kleidicv_error_t separable_filter_2d_stripe( | ||
| 16 | const T *src, size_t src_stride, T *dst, size_t dst_stride, size_t width, | ||
| 17 | size_t height, size_t y_begin, size_t y_end, size_t channels, | ||
| 18 | const T *kernel_x, size_t kernel_width, const T *kernel_y, | ||
| 19 | size_t kernel_height, FixedBorderType border_type, | ||
| 20 | kleidicv_filter_context_t *context); | ||
| 21 | |||
| 22 | } // namespace neon | ||
| 23 | |||
| 24 | namespace sve2 { | ||
| 25 | |||
| 26 | template <typename T> | ||
| 27 | kleidicv_error_t separable_filter_2d_stripe( | ||
| 28 | const T *src, size_t src_stride, T *dst, size_t dst_stride, size_t width, | ||
| 29 | size_t height, size_t y_begin, size_t y_end, size_t channels, | ||
| 30 | const T *kernel_x, size_t kernel_width, const T *kernel_y, | ||
| 31 | size_t kernel_height, FixedBorderType border_type, | ||
| 32 | kleidicv_filter_context_t *context); | ||
| 33 | |||
| 34 | } // namespace sve2 | ||
| 35 | |||
| 36 | namespace sme { | ||
| 37 | |||
| 38 | template <typename T> | ||
| 39 | kleidicv_error_t separable_filter_2d_stripe( | ||
| 40 | const T *src, size_t src_stride, T *dst, size_t dst_stride, size_t width, | ||
| 41 | size_t height, size_t y_begin, size_t y_end, size_t channels, | ||
| 42 | const T *kernel_x, size_t kernel_width, const T *kernel_y, | ||
| 43 | size_t kernel_height, FixedBorderType border_type, | ||
| 44 | kleidicv_filter_context_t *context); | ||
| 45 | |||
| 46 | } // namespace sme | ||
| 47 | |||
| 48 | } // namespace kleidicv | ||
| 49 | |||
| 50 | #define KLEIDICV_DEFINE_C_API(name, type) \ | ||
| 51 | KLEIDICV_MULTIVERSION_C_API( \ | ||
| 52 | name, &kleidicv::neon::separable_filter_2d_stripe<type>, \ | ||
| 53 | KLEIDICV_SVE2_IMPL_IF(kleidicv::sve2::separable_filter_2d_stripe<type>), \ | ||
| 54 | &kleidicv::sme::separable_filter_2d_stripe<type>, nullptr) | ||
| 55 | |||
| 56 |
4/4✓ Branch 0 taken 2 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 1 times.
|
10 | KLEIDICV_DEFINE_C_API(kleidicv_separable_filter_2d_stripe_u8, uint8_t); |
| 57 |
4/4✓ Branch 0 taken 2 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 1 times.
|
10 | KLEIDICV_DEFINE_C_API(kleidicv_separable_filter_2d_stripe_u16, uint16_t); |
| 58 |
4/4✓ Branch 0 taken 2 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 1 times.
|
10 | KLEIDICV_DEFINE_C_API(kleidicv_separable_filter_2d_stripe_s16, int16_t); |
| 59 | |||
| 60 | extern "C" { | ||
| 61 | |||
| 62 | using KLEIDICV_TARGET_NAMESPACE::Rectangle; | ||
| 63 | using KLEIDICV_TARGET_NAMESPACE::SeparableFilterWorkspace; | ||
| 64 | |||
| 65 | 2784 | kleidicv_error_t kleidicv_filter_context_create( | |
| 66 | kleidicv_filter_context_t **context, size_t max_channels, | ||
| 67 | size_t max_kernel_width, size_t max_kernel_height, size_t max_image_width, | ||
| 68 | size_t max_image_height) { | ||
| 69 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2780 times.
|
2784 | CHECK_POINTERS(context); |
| 70 | |||
| 71 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2776 times.
|
2780 | if (max_kernel_width != max_kernel_height) { |
| 72 | 4 | return KLEIDICV_ERROR_NOT_IMPLEMENTED; | |
| 73 | } | ||
| 74 | |||
| 75 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2772 times.
|
2776 | if (max_channels > KLEIDICV_MAXIMUM_CHANNEL_COUNT) { |
| 76 | 4 | return KLEIDICV_ERROR_NOT_IMPLEMENTED; | |
| 77 | } | ||
| 78 | |||
| 79 |
6/7✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2768 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 2764 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 8 times.
✓ Branch 6 taken 2764 times.
|
2772 | CHECK_IMAGE_SIZE(max_image_width, max_image_height); |
| 80 | |||
| 81 | // As we cannot predict the intermediate size based on the parameters given, | ||
| 82 | // just use the largest possible size out of all available operations. | ||
| 83 | 2764 | constexpr size_t intermediate_size = sizeof(uint32_t); | |
| 84 | 5528 | auto workspace = SeparableFilterWorkspace::create( | |
| 85 | 2764 | Rectangle{max_image_width, max_image_height}, max_channels, | |
| 86 | intermediate_size); | ||
| 87 |
2/2✓ Branch 0 taken 2760 times.
✓ Branch 1 taken 4 times.
|
2764 | if (!workspace) { |
| 88 | 4 | *context = nullptr; | |
| 89 | 4 | return KLEIDICV_ERROR_ALLOCATION; | |
| 90 | } | ||
| 91 | |||
| 92 | 2760 | *context = reinterpret_cast<kleidicv_filter_context_t *>(workspace.release()); | |
| 93 | 2760 | return KLEIDICV_OK; | |
| 94 | 2784 | } | |
| 95 | |||
| 96 | 2764 | kleidicv_error_t kleidicv_filter_context_release( | |
| 97 | kleidicv_filter_context_t *context) { | ||
| 98 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2760 times.
|
2764 | CHECK_POINTERS(context); |
| 99 | |||
| 100 | // Deliberately create and immediately destroy a unique_ptr to delete the | ||
| 101 | // workspace. | ||
| 102 | // NOLINTBEGIN(bugprone-unused-raii) | ||
| 103 | 2760 | SeparableFilterWorkspace::Pointer{ | |
| 104 | 2760 | reinterpret_cast<SeparableFilterWorkspace *>(context)}; | |
| 105 | // NOLINTEND(bugprone-unused-raii) | ||
| 106 | 2760 | return KLEIDICV_OK; | |
| 107 | 2764 | } | |
| 108 | |||
| 109 | 336 | kleidicv_error_t kleidicv_separable_filter_2d_u8( | |
| 110 | const uint8_t *src, size_t src_stride, uint8_t *dst, size_t dst_stride, | ||
| 111 | size_t width, size_t height, size_t channels, const uint8_t *kernel_x, | ||
| 112 | size_t kernel_width, const uint8_t *kernel_y, size_t kernel_height, | ||
| 113 | kleidicv_border_type_t border_type, kleidicv_filter_context_t *context) { | ||
| 114 |
4/4✓ Branch 0 taken 100 times.
✓ Branch 1 taken 236 times.
✓ Branch 2 taken 100 times.
✓ Branch 3 taken 236 times.
|
672 | if (!kleidicv::separable_filter_2d_is_implemented(width, height, kernel_width, |
| 115 | 336 | kernel_height)) { | |
| 116 | 100 | return KLEIDICV_ERROR_NOT_IMPLEMENTED; | |
| 117 | } | ||
| 118 | 236 | auto fixed_border_type = kleidicv::get_fixed_border_type(border_type); | |
| 119 |
2/2✓ Branch 0 taken 224 times.
✓ Branch 1 taken 12 times.
|
236 | if (!fixed_border_type) { |
| 120 | 12 | return KLEIDICV_ERROR_NOT_IMPLEMENTED; | |
| 121 | } | ||
| 122 | |||
| 123 | 448 | return kleidicv_separable_filter_2d_stripe_u8( | |
| 124 | 224 | src, src_stride, dst, dst_stride, width, height, 0, height, channels, | |
| 125 | 224 | kernel_x, kernel_width, kernel_y, kernel_height, *fixed_border_type, | |
| 126 | 224 | context); | |
| 127 | 336 | } | |
| 128 | |||
| 129 | 336 | kleidicv_error_t kleidicv_separable_filter_2d_u16( | |
| 130 | const uint16_t *src, size_t src_stride, uint16_t *dst, size_t dst_stride, | ||
| 131 | size_t width, size_t height, size_t channels, const uint16_t *kernel_x, | ||
| 132 | size_t kernel_width, const uint16_t *kernel_y, size_t kernel_height, | ||
| 133 | kleidicv_border_type_t border_type, kleidicv_filter_context_t *context) { | ||
| 134 |
4/4✓ Branch 0 taken 100 times.
✓ Branch 1 taken 236 times.
✓ Branch 2 taken 100 times.
✓ Branch 3 taken 236 times.
|
672 | if (!kleidicv::separable_filter_2d_is_implemented(width, height, kernel_width, |
| 135 | 336 | kernel_height)) { | |
| 136 | 100 | return KLEIDICV_ERROR_NOT_IMPLEMENTED; | |
| 137 | } | ||
| 138 | 236 | auto fixed_border_type = kleidicv::get_fixed_border_type(border_type); | |
| 139 |
2/2✓ Branch 0 taken 224 times.
✓ Branch 1 taken 12 times.
|
236 | if (!fixed_border_type) { |
| 140 | 12 | return KLEIDICV_ERROR_NOT_IMPLEMENTED; | |
| 141 | } | ||
| 142 | |||
| 143 | 448 | return kleidicv_separable_filter_2d_stripe_u16( | |
| 144 | 224 | src, src_stride, dst, dst_stride, width, height, 0, height, channels, | |
| 145 | 224 | kernel_x, kernel_width, kernel_y, kernel_height, *fixed_border_type, | |
| 146 | 224 | context); | |
| 147 | 336 | } | |
| 148 | |||
| 149 | 332 | kleidicv_error_t kleidicv_separable_filter_2d_s16( | |
| 150 | const int16_t *src, size_t src_stride, int16_t *dst, size_t dst_stride, | ||
| 151 | size_t width, size_t height, size_t channels, const int16_t *kernel_x, | ||
| 152 | size_t kernel_width, const int16_t *kernel_y, size_t kernel_height, | ||
| 153 | kleidicv_border_type_t border_type, kleidicv_filter_context_t *context) { | ||
| 154 |
4/4✓ Branch 0 taken 100 times.
✓ Branch 1 taken 232 times.
✓ Branch 2 taken 100 times.
✓ Branch 3 taken 232 times.
|
664 | if (!kleidicv::separable_filter_2d_is_implemented(width, height, kernel_width, |
| 155 | 332 | kernel_height)) { | |
| 156 | 100 | return KLEIDICV_ERROR_NOT_IMPLEMENTED; | |
| 157 | } | ||
| 158 | 232 | auto fixed_border_type = kleidicv::get_fixed_border_type(border_type); | |
| 159 |
2/2✓ Branch 0 taken 220 times.
✓ Branch 1 taken 12 times.
|
232 | if (!fixed_border_type) { |
| 160 | 12 | return KLEIDICV_ERROR_NOT_IMPLEMENTED; | |
| 161 | } | ||
| 162 | |||
| 163 | 440 | return kleidicv_separable_filter_2d_stripe_s16( | |
| 164 | 220 | src, src_stride, dst, dst_stride, width, height, 0, height, channels, | |
| 165 | 220 | kernel_x, kernel_width, kernel_y, kernel_height, *fixed_border_type, | |
| 166 | 220 | context); | |
| 167 | 332 | } | |
| 168 | |||
| 169 | } // extern "C" | ||
| 170 |