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/conversions/rgb_to_rgb.h" | ||
6 | #include "kleidicv/kleidicv.h" | ||
7 | #include "kleidicv/neon.h" | ||
8 | |||
9 | namespace kleidicv::neon { | ||
10 | |||
11 | template <typename ScalarType> | ||
12 | class RGBToBGR final : public UnrollTwice { | ||
13 | public: | ||
14 | using VecTraits = neon::VecTraits<ScalarType>; | ||
15 | |||
16 | #if !KLEIDICV_PREFER_INTERLEAVING_LOAD_STORE | ||
17 | 64 | RGBToBGR() : indices_{} { VecTraits::load(kRGBToBGRTableIndices, indices_); } | |
18 | #else | ||
19 | RGBToBGR() = default; | ||
20 | #endif | ||
21 | |||
22 | 430 | void vector_path(const ScalarType *src, ScalarType *dst) { | |
23 | #if KLEIDICV_PREFER_INTERLEAVING_LOAD_STORE | ||
24 | uint8x16x3_t src_vect = vld3q_u8(src); | ||
25 | uint8x16x3_t dst_vect; | ||
26 | |||
27 | dst_vect.val[0] = src_vect.val[2]; | ||
28 | dst_vect.val[1] = src_vect.val[1]; | ||
29 | dst_vect.val[2] = src_vect.val[0]; | ||
30 | |||
31 | vst3q_u8(dst, dst_vect); | ||
32 | #else | ||
33 | |||
34 | 430 | uint8x16x3_t src_vect; | |
35 | 430 | VecTraits::load(src, src_vect); | |
36 | |||
37 | 430 | uint8x16x3_t dst_vect; | |
38 | |||
39 | 430 | uint8x16x2_t src_vect_0_1; | |
40 | 430 | src_vect_0_1.val[0] = src_vect.val[0]; | |
41 | 430 | src_vect_0_1.val[1] = src_vect.val[1]; | |
42 | |||
43 | 430 | uint8x16x2_t src_vect_1_2; | |
44 | 430 | src_vect_1_2.val[0] = src_vect.val[1]; | |
45 | 430 | src_vect_1_2.val[1] = src_vect.val[2]; | |
46 | |||
47 | 430 | dst_vect.val[0] = vqtbl2q_u8(src_vect_0_1, indices_.val[0]); | |
48 | 430 | dst_vect.val[1] = vqtbl3q_u8(src_vect, indices_.val[1]); | |
49 | 430 | dst_vect.val[2] = vqtbl2q_u8(src_vect_1_2, indices_.val[2]); | |
50 | |||
51 | 430 | VecTraits::store(dst_vect, dst); | |
52 | #endif | ||
53 | 430 | } | |
54 | |||
55 | 435 | void scalar_path(const ScalarType *src, ScalarType *dst) { | |
56 | 435 | auto tmp = src[0]; | |
57 | 435 | dst[0] = src[2]; | |
58 | 435 | dst[1] = src[1]; | |
59 | 435 | dst[2] = tmp; | |
60 | 435 | } | |
61 | |||
62 | private: | ||
63 | #if !KLEIDICV_PREFER_INTERLEAVING_LOAD_STORE | ||
64 | static constexpr uint8_t kRGBToBGRTableIndices[48] = { | ||
65 | 2, 1, 0, 5, 4, 3, 8, 7, 6, 11, 10, 9, 14, 13, 12, 17, | ||
66 | 16, 15, 20, 19, 18, 23, 22, 21, 26, 25, 24, 29, 28, 27, 32, 31, | ||
67 | 14, 19, 18, 17, 22, 21, 20, 25, 24, 23, 28, 27, 26, 31, 30, 29}; | ||
68 | uint8x16x3_t indices_; | ||
69 | #endif | ||
70 | }; // end of class RGBToBGR<ScalarType> | ||
71 | |||
72 | template <typename ScalarType> | ||
73 | class RGBAToBGRA final : public UnrollTwice { | ||
74 | public: | ||
75 | using VecTraits = neon::VecTraits<ScalarType>; | ||
76 | |||
77 | 430 | void vector_path(const ScalarType *src, ScalarType *dst) { | |
78 | 430 | uint8x16x4_t src_vect = vld4q_u8(src); | |
79 | 430 | uint8x16x4_t dst_vect; | |
80 | |||
81 | 430 | dst_vect.val[0] = src_vect.val[2]; | |
82 | 430 | dst_vect.val[1] = src_vect.val[1]; | |
83 | 430 | dst_vect.val[2] = src_vect.val[0]; | |
84 | 430 | dst_vect.val[3] = src_vect.val[3]; | |
85 | |||
86 | 430 | vst4q_u8(dst, dst_vect); | |
87 | 430 | } | |
88 | |||
89 | 435 | void scalar_path(const ScalarType *src, ScalarType *dst) { | |
90 | 435 | auto tmp = src[0]; | |
91 | 435 | dst[0] = src[2]; | |
92 | 435 | dst[1] = src[1]; | |
93 | 435 | dst[2] = tmp; | |
94 | 435 | dst[3] = src[3]; | |
95 | 435 | } | |
96 | }; // end of class RGBAToBGRA<ScalarType> | ||
97 | |||
98 | template <typename ScalarType> | ||
99 | class RGBToBGRA final : public UnrollTwice { | ||
100 | public: | ||
101 | using VecTraits = neon::VecTraits<ScalarType>; | ||
102 | |||
103 | 430 | void vector_path(const ScalarType *src, ScalarType *dst) { | |
104 | 430 | uint8x16x3_t src_vect = vld3q_u8(src); | |
105 | 430 | uint8x16x4_t dst_vect; | |
106 | |||
107 | 430 | dst_vect.val[0] = src_vect.val[2]; | |
108 | 430 | dst_vect.val[1] = src_vect.val[1]; | |
109 | 430 | dst_vect.val[2] = src_vect.val[0]; | |
110 | 430 | dst_vect.val[3] = vdupq_n_u8(0xff); | |
111 | |||
112 | 430 | vst4q_u8(dst, dst_vect); | |
113 | 430 | } | |
114 | |||
115 | 435 | void scalar_path(const ScalarType *src, ScalarType *dst) { | |
116 | 435 | auto tmp = src[0]; | |
117 | 435 | dst[0] = src[2]; | |
118 | 435 | dst[1] = src[1]; | |
119 | 435 | dst[2] = tmp; | |
120 | 435 | dst[3] = 0xff; | |
121 | 435 | } | |
122 | }; // end of class RGBToBGRA<ScalarType> | ||
123 | |||
124 | template <typename ScalarType> | ||
125 | class RGBToRGBA final : public UnrollTwice { | ||
126 | public: | ||
127 | using VecTraits = neon::VecTraits<ScalarType>; | ||
128 | |||
129 | 430 | void vector_path(const ScalarType *src, ScalarType *dst) { | |
130 | 430 | uint8x16x3_t src_vect = vld3q_u8(src); | |
131 | 430 | uint8x16x4_t dst_vect; | |
132 | |||
133 | 430 | dst_vect.val[0] = src_vect.val[0]; | |
134 | 430 | dst_vect.val[1] = src_vect.val[1]; | |
135 | 430 | dst_vect.val[2] = src_vect.val[2]; | |
136 | 430 | dst_vect.val[3] = vdupq_n_u8(0xff); | |
137 | |||
138 | 430 | vst4q_u8(dst, dst_vect); | |
139 | 430 | } | |
140 | |||
141 | 435 | void scalar_path(const ScalarType *src, ScalarType *dst) { | |
142 | 435 | memcpy(static_cast<void *>(dst), static_cast<const void *>(src), 3); | |
143 | 435 | dst[3] = 0xff; | |
144 | 435 | } | |
145 | }; // end of class RGBToRGBA<ScalarType> | ||
146 | |||
147 | template <typename ScalarType> | ||
148 | class RGBAToBGR final : public UnrollTwice { | ||
149 | public: | ||
150 | using VecTraits = neon::VecTraits<ScalarType>; | ||
151 | |||
152 | 430 | void vector_path(const ScalarType *src, ScalarType *dst) { | |
153 | 430 | uint8x16x4_t src_vect = vld4q_u8(src); | |
154 | 430 | uint8x16x3_t dst_vect; | |
155 | |||
156 | 430 | dst_vect.val[0] = src_vect.val[2]; | |
157 | 430 | dst_vect.val[1] = src_vect.val[1]; | |
158 | 430 | dst_vect.val[2] = src_vect.val[0]; | |
159 | |||
160 | 430 | vst3q_u8(dst, dst_vect); | |
161 | 430 | } | |
162 | |||
163 | 435 | void scalar_path(const ScalarType *src, ScalarType *dst) { | |
164 | 435 | auto tmp = src[0]; | |
165 | 435 | dst[0] = src[2]; | |
166 | 435 | dst[1] = src[1]; | |
167 | 435 | dst[2] = tmp; | |
168 | 435 | } | |
169 | }; // end of class RGBAToBGR<ScalarType> | ||
170 | |||
171 | template <typename ScalarType> | ||
172 | class RGBAToRGB final : public UnrollTwice { | ||
173 | public: | ||
174 | using VecTraits = neon::VecTraits<ScalarType>; | ||
175 | |||
176 | 430 | void vector_path(const ScalarType *src, ScalarType *dst) { | |
177 | 430 | uint8x16x4_t src_vect = vld4q_u8(src); | |
178 | 430 | uint8x16x3_t dst_vect; | |
179 | |||
180 | 430 | dst_vect.val[0] = src_vect.val[0]; | |
181 | 430 | dst_vect.val[1] = src_vect.val[1]; | |
182 | 430 | dst_vect.val[2] = src_vect.val[2]; | |
183 | |||
184 | 430 | vst3q_u8(dst, dst_vect); | |
185 | 430 | } | |
186 | |||
187 | 435 | void scalar_path(const ScalarType *src, ScalarType *dst) { | |
188 | 435 | memcpy(static_cast<void *>(dst), static_cast<const void *>(src), 3); | |
189 | 435 | } | |
190 | }; // end of class RGBAToRGB<ScalarType> | ||
191 | |||
192 | KLEIDICV_TARGET_FN_ATTRS | ||
193 | 68 | kleidicv_error_t rgb_to_bgr_u8(const uint8_t *src, size_t src_stride, | |
194 | uint8_t *dst, size_t dst_stride, size_t width, | ||
195 | size_t height) { | ||
196 |
4/4✓ Branch 0 taken 1 times.
✓ Branch 1 taken 67 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 67 times.
|
68 | CHECK_POINTER_AND_STRIDE(src, src_stride, height); |
197 |
4/4✓ Branch 0 taken 1 times.
✓ Branch 1 taken 66 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 66 times.
|
67 | CHECK_POINTER_AND_STRIDE(dst, dst_stride, height); |
198 |
6/6✓ Branch 0 taken 1 times.
✓ Branch 1 taken 65 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 64 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 64 times.
|
66 | CHECK_IMAGE_SIZE(width, height); |
199 | |||
200 | 64 | Rectangle rect{width, height}; | |
201 | 64 | Rows<const uint8_t> src_rows{src, src_stride, 3 /* RGB */}; | |
202 | 64 | Rows<uint8_t> dst_rows{dst, dst_stride, 3 /* BGR */}; | |
203 | 64 | RGBToBGR<uint8_t> operation; | |
204 | 64 | apply_operation_by_rows(operation, rect, src_rows, dst_rows); | |
205 | 64 | return KLEIDICV_OK; | |
206 | 68 | } | |
207 | |||
208 | KLEIDICV_TARGET_FN_ATTRS | ||
209 | 68 | kleidicv_error_t rgba_to_bgra_u8(const uint8_t *src, size_t src_stride, | |
210 | uint8_t *dst, size_t dst_stride, size_t width, | ||
211 | size_t height) { | ||
212 |
4/4✓ Branch 0 taken 1 times.
✓ Branch 1 taken 67 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 67 times.
|
68 | CHECK_POINTER_AND_STRIDE(src, src_stride, height); |
213 |
4/4✓ Branch 0 taken 1 times.
✓ Branch 1 taken 66 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 66 times.
|
67 | CHECK_POINTER_AND_STRIDE(dst, dst_stride, height); |
214 |
6/6✓ Branch 0 taken 1 times.
✓ Branch 1 taken 65 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 64 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 64 times.
|
66 | CHECK_IMAGE_SIZE(width, height); |
215 | |||
216 | 64 | Rectangle rect{width, height}; | |
217 | 64 | Rows<const uint8_t> src_rows{src, src_stride, 4 /* RGBA */}; | |
218 | 64 | Rows<uint8_t> dst_rows{dst, dst_stride, 4 /* BGRA */}; | |
219 | 64 | RGBAToBGRA<uint8_t> operation; | |
220 | 64 | apply_operation_by_rows(operation, rect, src_rows, dst_rows); | |
221 | 64 | return KLEIDICV_OK; | |
222 | 68 | } | |
223 | |||
224 | KLEIDICV_TARGET_FN_ATTRS kleidicv_error_t | ||
225 | 68 | rgb_to_bgra_u8(const uint8_t *src, size_t src_stride, uint8_t *dst, | |
226 | size_t dst_stride, size_t width, size_t height) { | ||
227 |
4/4✓ Branch 0 taken 1 times.
✓ Branch 1 taken 67 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 67 times.
|
68 | CHECK_POINTER_AND_STRIDE(src, src_stride, height); |
228 |
4/4✓ Branch 0 taken 1 times.
✓ Branch 1 taken 66 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 66 times.
|
67 | CHECK_POINTER_AND_STRIDE(dst, dst_stride, height); |
229 |
6/6✓ Branch 0 taken 1 times.
✓ Branch 1 taken 65 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 64 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 64 times.
|
66 | CHECK_IMAGE_SIZE(width, height); |
230 | |||
231 | 64 | Rectangle rect{width, height}; | |
232 | 64 | Rows<const uint8_t> src_rows{src, src_stride, 3 /* RGB */}; | |
233 | 64 | Rows<uint8_t> dst_rows{dst, dst_stride, 4 /* BGRA */}; | |
234 | 64 | RGBToBGRA<uint8_t> operation; | |
235 | 64 | apply_operation_by_rows(operation, rect, src_rows, dst_rows); | |
236 | 64 | return KLEIDICV_OK; | |
237 | 68 | } | |
238 | |||
239 | KLEIDICV_TARGET_FN_ATTRS kleidicv_error_t | ||
240 | 68 | rgb_to_rgba_u8(const uint8_t *src, size_t src_stride, uint8_t *dst, | |
241 | size_t dst_stride, size_t width, size_t height) { | ||
242 |
4/4✓ Branch 0 taken 1 times.
✓ Branch 1 taken 67 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 67 times.
|
68 | CHECK_POINTER_AND_STRIDE(src, src_stride, height); |
243 |
4/4✓ Branch 0 taken 1 times.
✓ Branch 1 taken 66 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 66 times.
|
67 | CHECK_POINTER_AND_STRIDE(dst, dst_stride, height); |
244 |
6/6✓ Branch 0 taken 1 times.
✓ Branch 1 taken 65 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 64 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 64 times.
|
66 | CHECK_IMAGE_SIZE(width, height); |
245 | |||
246 | 64 | Rectangle rect{width, height}; | |
247 | 64 | Rows<const uint8_t> src_rows{src, src_stride, 3 /* RGB */}; | |
248 | 64 | Rows<uint8_t> dst_rows{dst, dst_stride, 4 /* RGBA */}; | |
249 | 64 | RGBToRGBA<uint8_t> operation; | |
250 | 64 | apply_operation_by_rows(operation, rect, src_rows, dst_rows); | |
251 | 64 | return KLEIDICV_OK; | |
252 | 68 | } | |
253 | |||
254 | KLEIDICV_TARGET_FN_ATTRS | ||
255 | 68 | kleidicv_error_t rgba_to_bgr_u8(const uint8_t *src, size_t src_stride, | |
256 | uint8_t *dst, size_t dst_stride, size_t width, | ||
257 | size_t height) { | ||
258 |
4/4✓ Branch 0 taken 1 times.
✓ Branch 1 taken 67 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 67 times.
|
68 | CHECK_POINTER_AND_STRIDE(src, src_stride, height); |
259 |
4/4✓ Branch 0 taken 1 times.
✓ Branch 1 taken 66 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 66 times.
|
67 | CHECK_POINTER_AND_STRIDE(dst, dst_stride, height); |
260 |
6/6✓ Branch 0 taken 1 times.
✓ Branch 1 taken 65 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 64 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 64 times.
|
66 | CHECK_IMAGE_SIZE(width, height); |
261 | |||
262 | 64 | Rectangle rect{width, height}; | |
263 | 64 | Rows<const uint8_t> src_rows{src, src_stride, 4 /* RGBA */}; | |
264 | 64 | Rows<uint8_t> dst_rows{dst, dst_stride, 3 /* BGR */}; | |
265 | 64 | RGBAToBGR<uint8_t> operation; | |
266 | 64 | apply_operation_by_rows(operation, rect, src_rows, dst_rows); | |
267 | 64 | return KLEIDICV_OK; | |
268 | 68 | } | |
269 | |||
270 | KLEIDICV_TARGET_FN_ATTRS | ||
271 | 68 | kleidicv_error_t rgba_to_rgb_u8(const uint8_t *src, size_t src_stride, | |
272 | uint8_t *dst, size_t dst_stride, size_t width, | ||
273 | size_t height) { | ||
274 |
4/4✓ Branch 0 taken 1 times.
✓ Branch 1 taken 67 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 67 times.
|
68 | CHECK_POINTER_AND_STRIDE(src, src_stride, height); |
275 |
4/4✓ Branch 0 taken 1 times.
✓ Branch 1 taken 66 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 66 times.
|
67 | CHECK_POINTER_AND_STRIDE(dst, dst_stride, height); |
276 |
6/6✓ Branch 0 taken 1 times.
✓ Branch 1 taken 65 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 64 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 64 times.
|
66 | CHECK_IMAGE_SIZE(width, height); |
277 | |||
278 | 64 | Rectangle rect{width, height}; | |
279 | 64 | Rows<const uint8_t> src_rows{src, src_stride, 4 /* RGBA */}; | |
280 | 64 | Rows<uint8_t> dst_rows{dst, dst_stride, 3 /* RGB */}; | |
281 | 64 | RGBAToRGB<uint8_t> operation; | |
282 | 64 | apply_operation_by_rows(operation, rect, src_rows, dst_rows); | |
283 | 64 | return KLEIDICV_OK; | |
284 | 68 | } | |
285 | |||
286 | } // namespace kleidicv::neon | ||
287 |