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 1 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 1 times.
|
8 | KLEIDICV_DEFINE_C_API(kleidicv_separable_filter_2d_stripe_u8, uint8_t); |
57 |
4/4✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 1 times.
|
8 | KLEIDICV_DEFINE_C_API(kleidicv_separable_filter_2d_stripe_u16, uint16_t); |
58 |
4/4✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 1 times.
|
8 | 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 | 2088 | 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 3 times.
✓ Branch 1 taken 2085 times.
|
2088 | CHECK_POINTERS(context); |
70 | |||
71 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 2082 times.
|
2085 | if (max_kernel_width != max_kernel_height) { |
72 | 3 | return KLEIDICV_ERROR_NOT_IMPLEMENTED; | |
73 | } | ||
74 | |||
75 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 2079 times.
|
2082 | if (max_channels > KLEIDICV_MAXIMUM_CHANNEL_COUNT) { |
76 | 3 | return KLEIDICV_ERROR_NOT_IMPLEMENTED; | |
77 | } | ||
78 | |||
79 |
6/7✓ Branch 0 taken 3 times.
✓ Branch 1 taken 2076 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 2073 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 6 times.
✓ Branch 6 taken 2073 times.
|
2079 | 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 | 2073 | constexpr size_t intermediate_size = sizeof(uint32_t); | |
84 | 4146 | auto workspace = SeparableFilterWorkspace::create( | |
85 | 2073 | Rectangle{max_image_width, max_image_height}, max_channels, | |
86 | intermediate_size); | ||
87 |
2/2✓ Branch 0 taken 2070 times.
✓ Branch 1 taken 3 times.
|
2073 | if (!workspace) { |
88 | 3 | *context = nullptr; | |
89 | 3 | return KLEIDICV_ERROR_ALLOCATION; | |
90 | } | ||
91 | |||
92 | 2070 | *context = reinterpret_cast<kleidicv_filter_context_t *>(workspace.release()); | |
93 | 2070 | return KLEIDICV_OK; | |
94 | 2088 | } | |
95 | |||
96 | 2073 | kleidicv_error_t kleidicv_filter_context_release( | |
97 | kleidicv_filter_context_t *context) { | ||
98 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 2070 times.
|
2073 | CHECK_POINTERS(context); |
99 | |||
100 | // Deliberately create and immediately destroy a unique_ptr to delete the | ||
101 | // workspace. | ||
102 | // NOLINTBEGIN(bugprone-unused-raii) | ||
103 | 2070 | SeparableFilterWorkspace::Pointer{ | |
104 | 2070 | reinterpret_cast<SeparableFilterWorkspace *>(context)}; | |
105 | // NOLINTEND(bugprone-unused-raii) | ||
106 | 2070 | return KLEIDICV_OK; | |
107 | 2073 | } | |
108 | |||
109 | 252 | 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 75 times.
✓ Branch 1 taken 177 times.
✓ Branch 2 taken 75 times.
✓ Branch 3 taken 177 times.
|
504 | if (!kleidicv::separable_filter_2d_is_implemented(width, height, kernel_width, |
115 | 252 | kernel_height)) { | |
116 | 75 | return KLEIDICV_ERROR_NOT_IMPLEMENTED; | |
117 | } | ||
118 | 177 | auto fixed_border_type = kleidicv::get_fixed_border_type(border_type); | |
119 |
2/2✓ Branch 0 taken 168 times.
✓ Branch 1 taken 9 times.
|
177 | if (!fixed_border_type) { |
120 | 9 | return KLEIDICV_ERROR_NOT_IMPLEMENTED; | |
121 | } | ||
122 | |||
123 | 336 | return kleidicv_separable_filter_2d_stripe_u8( | |
124 | 168 | src, src_stride, dst, dst_stride, width, height, 0, height, channels, | |
125 | 168 | kernel_x, kernel_width, kernel_y, kernel_height, *fixed_border_type, | |
126 | 168 | context); | |
127 | 252 | } | |
128 | |||
129 | 252 | 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 75 times.
✓ Branch 1 taken 177 times.
✓ Branch 2 taken 75 times.
✓ Branch 3 taken 177 times.
|
504 | if (!kleidicv::separable_filter_2d_is_implemented(width, height, kernel_width, |
135 | 252 | kernel_height)) { | |
136 | 75 | return KLEIDICV_ERROR_NOT_IMPLEMENTED; | |
137 | } | ||
138 | 177 | auto fixed_border_type = kleidicv::get_fixed_border_type(border_type); | |
139 |
2/2✓ Branch 0 taken 168 times.
✓ Branch 1 taken 9 times.
|
177 | if (!fixed_border_type) { |
140 | 9 | return KLEIDICV_ERROR_NOT_IMPLEMENTED; | |
141 | } | ||
142 | |||
143 | 336 | return kleidicv_separable_filter_2d_stripe_u16( | |
144 | 168 | src, src_stride, dst, dst_stride, width, height, 0, height, channels, | |
145 | 168 | kernel_x, kernel_width, kernel_y, kernel_height, *fixed_border_type, | |
146 | 168 | context); | |
147 | 252 | } | |
148 | |||
149 | 249 | 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 75 times.
✓ Branch 1 taken 174 times.
✓ Branch 2 taken 75 times.
✓ Branch 3 taken 174 times.
|
498 | if (!kleidicv::separable_filter_2d_is_implemented(width, height, kernel_width, |
155 | 249 | kernel_height)) { | |
156 | 75 | return KLEIDICV_ERROR_NOT_IMPLEMENTED; | |
157 | } | ||
158 | 174 | auto fixed_border_type = kleidicv::get_fixed_border_type(border_type); | |
159 |
2/2✓ Branch 0 taken 165 times.
✓ Branch 1 taken 9 times.
|
174 | if (!fixed_border_type) { |
160 | 9 | return KLEIDICV_ERROR_NOT_IMPLEMENTED; | |
161 | } | ||
162 | |||
163 | 330 | return kleidicv_separable_filter_2d_stripe_s16( | |
164 | 165 | src, src_stride, dst, dst_stride, width, height, 0, height, channels, | |
165 | 165 | kernel_x, kernel_width, kernel_y, kernel_height, *fixed_border_type, | |
166 | 165 | context); | |
167 | 249 | } | |
168 | |||
169 | } // extern "C" | ||
170 |