KleidiCV Coverage Report


Directory: ./
File: kleidicv/src/filters/median_blur_sorting_network_neon.cpp
Date: 2026-01-20 20:58:59
Exec Total Coverage
Lines: 92 92 100.0%
Functions: 133 133 100.0%
Branches: 42 42 100.0%

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/ctypes.h"
6 #include "kleidicv/filters/filter_2d_neon.h"
7 #include "kleidicv/filters/median_blur.h"
8 #include "kleidicv/filters/process_filter_2d.h"
9 #include "kleidicv/kleidicv.h"
10 #include "kleidicv/neon.h"
11 #include "kleidicv/workspace/border_3x3.h"
12 #include "kleidicv/workspace/border_5x5.h"
13 #include "kleidicv/workspace/border_7x7.h"
14 #include "median_blur_sorting_network_3x3.h"
15 #include "median_blur_sorting_network_5x5.h"
16 #include "median_blur_sorting_network_7x7.h"
17
18 namespace kleidicv::neon {
19
20 // Primary template for Median Blur filters.
21 template <typename ScalarType, size_t KernelSize>
22 class MedianBlurSortingNetwork;
23
24 template <typename ScalarType>
25 class VectorizedComparator {
26 public:
27 using SourceVectorType = typename VecTraits<ScalarType>::VectorType;
28
29 4255868 static void compare_and_swap(SourceVectorType& left, SourceVectorType& right,
30 Monostate&) {
31 4255868 SourceVectorType max_value = vmaxq(left, right);
32 4255868 SourceVectorType min_value = vminq(left, right);
33 4255868 left = min_value;
34 4255868 right = max_value;
35 4255868 }
36
37 470680 static void min(SourceVectorType& left, SourceVectorType& right, Monostate&) {
38 470680 left = vminq(left, right);
39 470680 }
40
41 457108 static void max(SourceVectorType& left, SourceVectorType& right, Monostate&) {
42 457108 right = vmaxq(left, right);
43 457108 }
44 16064 static SourceVectorType get_min(SourceVectorType& left,
45 SourceVectorType& right, Monostate&) {
46 16064 return vminq(left, right);
47 }
48 16064 static SourceVectorType get_max(SourceVectorType& left,
49 SourceVectorType& right, Monostate&) {
50 16064 return vmaxq(left, right);
51 }
52 };
53
54 template <typename ScalarType>
55 class ScalarComparator {
56 public:
57 15768432 static void compare_and_swap(ScalarType& left, ScalarType& right,
58 Monostate&) {
59
14/14
✓ Branch 0 taken 1136356 times.
✓ Branch 1 taken 625924 times.
✓ Branch 2 taken 1759467 times.
✓ Branch 3 taken 990469 times.
✓ Branch 4 taken 1683604 times.
✓ Branch 5 taken 965356 times.
✓ Branch 6 taken 1683149 times.
✓ Branch 7 taken 965811 times.
✓ Branch 8 taken 1125809 times.
✓ Branch 9 taken 631551 times.
✓ Branch 10 taken 1123941 times.
✓ Branch 11 taken 633419 times.
✓ Branch 12 taken 1565746 times.
✓ Branch 13 taken 877830 times.
15768432 if (left > right) {
60 5690360 std::swap(left, right);
61 5690360 }
62 15768432 }
63
64 1702560 static void min(ScalarType& left, ScalarType& right, Monostate&) {
65 1702560 left = std::min(left, right);
66 1702560 }
67
68 1648464 static void max(ScalarType& left, ScalarType& right, Monostate&) {
69 1648464 right = std::max(left, right);
70 1648464 }
71 34560 static ScalarType get_min(ScalarType& left, ScalarType& right, Monostate&) {
72 34560 return std::min(left, right);
73 }
74 34560 static ScalarType get_max(ScalarType& left, ScalarType& right, Monostate&) {
75 34560 return std::max(left, right);
76 }
77 };
78
79 // Template for Median Blur 3x3 filters.
80 template <typename ScalarType>
81 class MedianBlurSortingNetwork<ScalarType, 3> {
82 public:
83 using SourceType = ScalarType;
84 using DestinationType = SourceType;
85 using SourceVectorType = typename VecTraits<SourceType>::VectorType;
86 using DestinationVectorType = typename VecTraits<DestinationType>::VectorType;
87
88 template <typename KernelWindowFunctor>
89 1224 void vector_path(KernelWindowFunctor& KernelWindow,
90 DestinationVectorType& output_vec) const {
91 1224 Monostate ctx;
92 1224 sorting_network3x3_single_row<VectorizedComparator<ScalarType>>(
93 1224 KernelWindow, output_vec, ctx);
94 1224 }
95
96 template <typename KernelWindowFunctor>
97 3404 void vector_path_for_dual_row_handling(
98 KernelWindowFunctor& KernelWindow, DestinationVectorType& output_vec_0,
99 DestinationVectorType& output_vec_1) const {
100 3404 Monostate ctx;
101 3404 sorting_network3x3_dual_rows<VectorizedComparator<ScalarType>>(
102 3404 KernelWindow, output_vec_0, output_vec_1, ctx);
103 3404 }
104
105 template <typename KernelWindowFunctor>
106 1344 void scalar_path(KernelWindowFunctor& KernelWindow,
107 DestinationType& output_vec) const {
108 1344 Monostate ctx;
109 1344 sorting_network3x3_single_row<ScalarComparator<ScalarType>>(
110 1344 KernelWindow, output_vec, ctx);
111 1344 }
112
113 template <typename KernelWindowFunctor>
114 7968 void scalar_path_for_dual_row_handling(KernelWindowFunctor& KernelWindow,
115 DestinationType& output_vec0,
116 DestinationType& output_vec1) const {
117 7968 Monostate ctx;
118 7968 sorting_network3x3_dual_rows<ScalarComparator<ScalarType>>(
119 7968 KernelWindow, output_vec0, output_vec1, ctx);
120 7968 }
121 }; // end of class MedianBlurSortingNetwork<ScalarType, 3>
122
123 // Template for Median Blur 5x5 filters.
124 template <typename ScalarType>
125 class MedianBlurSortingNetwork<ScalarType, 5> {
126 public:
127 using SourceType = ScalarType;
128 using DestinationType = SourceType;
129 using SourceVectorType = typename VecTraits<SourceType>::VectorType;
130 using DestinationVectorType = typename VecTraits<DestinationType>::VectorType;
131
132 template <typename KernelWindowFunctor>
133 11308 void vector_path(KernelWindowFunctor& KernelWindow,
134 DestinationVectorType& output_vec) const {
135 11308 Monostate ctx;
136 22616 sorting_network5x5<VectorizedComparator<ScalarType>>(KernelWindow,
137 11308 output_vec, ctx);
138 11308 }
139
140 template <typename KernelWindowFunctor>
141 32136 void scalar_path(KernelWindowFunctor& KernelWindow,
142 DestinationType& dst) const {
143 32136 Monostate ctx;
144 32136 sorting_network5x5<ScalarComparator<ScalarType>>(KernelWindow, dst, ctx);
145 32136 }
146 }; // end of class MedianBlurSortingNetwork<ScalarType, 5>
147
148 // Template for Median Blur 7x7 filters.
149 template <typename ScalarType>
150 class MedianBlurSortingNetwork<ScalarType, 7> {
151 public:
152 using SourceType = ScalarType;
153 using DestinationType = SourceType;
154 using SourceVectorType = typename VecTraits<SourceType>::VectorType;
155 using DestinationVectorType = typename VecTraits<DestinationType>::VectorType;
156
157 template <typename KernelWindowFunctor>
158 13572 void vector_path(KernelWindowFunctor& KernelWindow,
159 DestinationVectorType& dst) const {
160 13572 Monostate ctx;
161 13572 sorting_network7x7<VectorizedComparator<ScalarType>>(KernelWindow, dst,
162 ctx);
163 13572 }
164
165 template <typename KernelWindowFunctor>
166 54096 void scalar_path(KernelWindowFunctor& KernelWindow,
167 DestinationType& dst) const {
168 54096 Monostate ctx;
169 54096 sorting_network7x7<ScalarComparator<ScalarType>>(KernelWindow, dst, ctx);
170 54096 }
171 }; // end of class MedianBlurSortingNetworkSortingNetwork<ScalarType, 7>
172
173 template <typename T>
174 1738 kleidicv_error_t median_blur_sorting_network_stripe(
175 const T* src, size_t src_stride, T* dst, size_t dst_stride, size_t width,
176 size_t height, size_t y_begin, size_t y_end, size_t channels,
177 size_t kernel_width, [[maybe_unused]] size_t kernel_height,
178 FixedBorderType border_type) {
179 1738 Rectangle rect{width, height};
180 1738 Rows<const T> src_rows{src, src_stride, channels};
181 1738 Rows<T> dst_rows{dst, dst_stride, channels};
182
183
14/14
✓ Branch 0 taken 64 times.
✓ Branch 1 taken 130 times.
✓ Branch 2 taken 111 times.
✓ Branch 3 taken 178 times.
✓ Branch 4 taken 111 times.
✓ Branch 5 taken 178 times.
✓ Branch 6 taken 111 times.
✓ Branch 7 taken 178 times.
✓ Branch 8 taken 64 times.
✓ Branch 9 taken 130 times.
✓ Branch 10 taken 64 times.
✓ Branch 11 taken 130 times.
✓ Branch 12 taken 111 times.
✓ Branch 13 taken 178 times.
1738 if (kernel_width == 3) {
184 636 MedianBlurSortingNetwork<T, 3> median_filter;
185 636 Filter2D3x3<MedianBlurSortingNetwork<T, 3>> filter{median_filter};
186 1272 process_filter2d_by_dual_rows(rect, y_begin, y_end, src_rows, dst_rows,
187 636 border_type, filter);
188 636 return KLEIDICV_OK;
189 636 }
190
191
14/14
✓ Branch 0 taken 66 times.
✓ Branch 1 taken 64 times.
✓ Branch 2 taken 94 times.
✓ Branch 3 taken 84 times.
✓ Branch 4 taken 94 times.
✓ Branch 5 taken 84 times.
✓ Branch 6 taken 94 times.
✓ Branch 7 taken 84 times.
✓ Branch 8 taken 66 times.
✓ Branch 9 taken 64 times.
✓ Branch 10 taken 66 times.
✓ Branch 11 taken 64 times.
✓ Branch 12 taken 94 times.
✓ Branch 13 taken 84 times.
1102 if (kernel_width == 5) {
192 574 MedianBlurSortingNetwork<T, 5> median_filter;
193 574 Filter2D5x5<MedianBlurSortingNetwork<T, 5>> filter{median_filter};
194 1148 process_filter2d(rect, y_begin, y_end, src_rows, dst_rows, border_type,
195 574 filter);
196 574 return KLEIDICV_OK;
197 574 }
198
199 528 MedianBlurSortingNetwork<T, 7> median_filter;
200 528 Filter2D7x7<MedianBlurSortingNetwork<T, 7>> filter{median_filter};
201 1056 process_filter2d(rect, y_begin, y_end, src_rows, dst_rows, border_type,
202 528 filter);
203 528 return KLEIDICV_OK;
204 1738 }
205
206 #define KLEIDICV_INSTANTIATE_TEMPLATE(type) \
207 template KLEIDICV_TARGET_FN_ATTRS kleidicv_error_t \
208 median_blur_sorting_network_stripe<type>( \
209 const type* src, size_t src_stride, type* dst, size_t dst_stride, \
210 size_t width, size_t height, size_t y_begin, size_t y_end, \
211 size_t channels, size_t kernel_width, size_t kernel_height, \
212 FixedBorderType border_type)
213
214 KLEIDICV_INSTANTIATE_TEMPLATE(int8_t);
215 KLEIDICV_INSTANTIATE_TEMPLATE(uint8_t);
216 KLEIDICV_INSTANTIATE_TEMPLATE(int16_t);
217 KLEIDICV_INSTANTIATE_TEMPLATE(uint16_t);
218 KLEIDICV_INSTANTIATE_TEMPLATE(int32_t);
219 KLEIDICV_INSTANTIATE_TEMPLATE(uint32_t);
220 KLEIDICV_INSTANTIATE_TEMPLATE(float);
221
222 } // namespace kleidicv::neon
223