KleidiCV Coverage Report


Directory: ./
File: kleidicv/src/conversions/yuv_sp_to_rgb_neon.cpp
Date: 2025-09-25 14:13:34
Exec Total Coverage
Lines: 64 64 100.0%
Functions: 20 20 100.0%
Branches: 96 96 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 <utility>
6
7 #include "kleidicv/conversions/yuv_420_to_rgb.h"
8 #include "kleidicv/kleidicv.h"
9 #include "kleidicv/neon.h"
10 #include "yuv420_to_rgb_neon.h"
11
12 namespace kleidicv::neon {
13 template <bool BGR, bool kAlpha>
14 class YUVSpToRGBxOrBGRx final : public YUV420XToRGBxOrBGRx<BGR, kAlpha>,
15 public UnrollOnce,
16 public TryToAvoidTailLoop {
17 public:
18 using VecTraits = neon::VecTraits<uint8_t>;
19 using ScalarType = VecTraits::ScalarType;
20 using VectorType = VecTraits::VectorType;
21 using YUV420XToRGBxOrBGRx<BGR, kAlpha>::de_interleave_indices_;
22 using YUV420XToRGBxOrBGRx<BGR, kAlpha>::yuv420x_to_rgb;
23 using YUV420XToRGBxOrBGRx<BGR, kAlpha>::v_first_;
24
25 504 explicit YUVSpToRGBxOrBGRx(bool v_first)
26 504 : YUV420XToRGBxOrBGRx<BGR, kAlpha>(v_first) {}
27
28 // Processes 2 * 16 bytes (even and odd rows) of the input YUV data, and
29 // outputs 2 * 3 (or 4) * 16 bytes of RGB (or RGBA) data per loop iteration.
30 96 void vector_path(VectorType y0, VectorType y1, VectorType uv,
31 ScalarType *rgbx_row_0, ScalarType *rgbx_row_1) {
32 // Widen U and V to 32 bits.
33 96 int32x4_t u_l = vqtbl1q_s8(uv, de_interleave_indices_.val[0]);
34 96 int32x4_t u_h = vqtbl1q_s8(uv, de_interleave_indices_.val[1]);
35
36 96 int32x4_t v_l = vqtbl1q_s8(uv, de_interleave_indices_.val[2]);
37 96 int32x4_t v_h = vqtbl1q_s8(uv, de_interleave_indices_.val[3]);
38
39 96 yuv420x_to_rgb(y0, y1, u_l, u_h, v_l, v_h, rgbx_row_0, rgbx_row_1);
40 96 }
41
42 // Processes inputs which are not long enough to fit a vector.
43 656 void scalar_path(size_t length, const ScalarType *y_row_0,
44 const ScalarType *y_row_1, const ScalarType *uv_row,
45 ScalarType *rgbx_row_0, ScalarType *rgbx_row_1) {
46 656 const uint8_t *y_rows[2] = {y_row_0, y_row_1};
47 656 uint8_t *rgbx_rows[2] = {rgbx_row_0, rgbx_row_1};
48
49 656 int32_t u_m128 = 0, v_m128 = 0;
50
8/8
✓ Branch 0 taken 164 times.
✓ Branch 1 taken 1064 times.
✓ Branch 2 taken 164 times.
✓ Branch 3 taken 1064 times.
✓ Branch 4 taken 164 times.
✓ Branch 5 taken 1064 times.
✓ Branch 6 taken 164 times.
✓ Branch 7 taken 1064 times.
4912 for (size_t index = 0; index < length; ++index) {
51 4256 disable_loop_vectorization();
52
53 // There is one {U, V} pair for 4 Y values.
54
8/8
✓ Branch 0 taken 508 times.
✓ Branch 1 taken 556 times.
✓ Branch 2 taken 508 times.
✓ Branch 3 taken 556 times.
✓ Branch 4 taken 508 times.
✓ Branch 5 taken 556 times.
✓ Branch 6 taken 508 times.
✓ Branch 7 taken 556 times.
4256 if ((index % 2) == 0) {
55 2224 u_m128 = uv_row[0] - 128;
56 2224 v_m128 = uv_row[1] - 128;
57 2224 uv_row += 2;
58
8/8
✓ Branch 0 taken 278 times.
✓ Branch 1 taken 278 times.
✓ Branch 2 taken 278 times.
✓ Branch 3 taken 278 times.
✓ Branch 4 taken 278 times.
✓ Branch 5 taken 278 times.
✓ Branch 6 taken 278 times.
✓ Branch 7 taken 278 times.
2224 if (v_first_) {
59 1112 std::swap(u_m128, v_m128);
60 1112 }
61 2224 }
62
63 4256 yuv420x_to_rgb(y_rows, index, u_m128, v_m128, rgbx_rows);
64 4256 }
65 656 }
66 }; // end of class YUVSpToRGBxOrBGRx<bool, bool>
67
68 using YUVSpToRGB = YUVSpToRGBxOrBGRx<false, false>;
69 using YUVSpToRGBA = YUVSpToRGBxOrBGRx<false, true>;
70 using YUVSpToBGR = YUVSpToRGBxOrBGRx<true, false>;
71 using YUVSpToBGRA = YUVSpToRGBxOrBGRx<true, true>;
72
73 template <typename OperationType, typename ScalarType>
74 504 kleidicv_error_t yuv2rgbx_operation(
75 OperationType &operation, const ScalarType *src_y, size_t src_y_stride,
76 const ScalarType *src_uv, size_t src_uv_stride, ScalarType *dst,
77 size_t dst_stride, size_t width, size_t height) {
78
16/16
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 116 times.
✓ Branch 2 taken 10 times.
✓ Branch 3 taken 116 times.
✓ Branch 4 taken 10 times.
✓ Branch 5 taken 116 times.
✓ Branch 6 taken 10 times.
✓ Branch 7 taken 116 times.
✓ Branch 8 taken 10 times.
✓ Branch 9 taken 116 times.
✓ Branch 10 taken 10 times.
✓ Branch 11 taken 116 times.
✓ Branch 12 taken 10 times.
✓ Branch 13 taken 116 times.
✓ Branch 14 taken 10 times.
✓ Branch 15 taken 116 times.
504 CHECK_POINTER_AND_STRIDE(src_y, src_y_stride, height);
79
16/16
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 106 times.
✓ Branch 2 taken 10 times.
✓ Branch 3 taken 106 times.
✓ Branch 4 taken 10 times.
✓ Branch 5 taken 106 times.
✓ Branch 6 taken 10 times.
✓ Branch 7 taken 106 times.
✓ Branch 8 taken 10 times.
✓ Branch 9 taken 106 times.
✓ Branch 10 taken 10 times.
✓ Branch 11 taken 106 times.
✓ Branch 12 taken 10 times.
✓ Branch 13 taken 106 times.
✓ Branch 14 taken 10 times.
✓ Branch 15 taken 106 times.
464 CHECK_POINTER_AND_STRIDE(src_uv, src_uv_stride, (height + 1) / 2);
80
16/16
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 96 times.
✓ Branch 2 taken 10 times.
✓ Branch 3 taken 96 times.
✓ Branch 4 taken 10 times.
✓ Branch 5 taken 96 times.
✓ Branch 6 taken 10 times.
✓ Branch 7 taken 96 times.
✓ Branch 8 taken 10 times.
✓ Branch 9 taken 96 times.
✓ Branch 10 taken 10 times.
✓ Branch 11 taken 96 times.
✓ Branch 12 taken 10 times.
✓ Branch 13 taken 96 times.
✓ Branch 14 taken 10 times.
✓ Branch 15 taken 96 times.
424 CHECK_POINTER_AND_STRIDE(dst, dst_stride, height);
81
24/24
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 86 times.
✓ Branch 2 taken 10 times.
✓ Branch 3 taken 76 times.
✓ Branch 4 taken 20 times.
✓ Branch 5 taken 76 times.
✓ Branch 6 taken 10 times.
✓ Branch 7 taken 86 times.
✓ Branch 8 taken 10 times.
✓ Branch 9 taken 76 times.
✓ Branch 10 taken 20 times.
✓ Branch 11 taken 76 times.
✓ Branch 12 taken 10 times.
✓ Branch 13 taken 86 times.
✓ Branch 14 taken 10 times.
✓ Branch 15 taken 76 times.
✓ Branch 16 taken 20 times.
✓ Branch 17 taken 76 times.
✓ Branch 18 taken 10 times.
✓ Branch 19 taken 86 times.
✓ Branch 20 taken 10 times.
✓ Branch 21 taken 76 times.
✓ Branch 22 taken 20 times.
✓ Branch 23 taken 76 times.
384 CHECK_IMAGE_SIZE(width, height);
82
83 304 Rectangle rect{width, height};
84 304 ParallelRows y_rows{src_y, src_y_stride};
85 304 Rows uv_rows{src_uv, src_uv_stride};
86 304 ParallelRows rgbx_rows{dst, dst_stride, operation.output_channels()};
87
88 304 RemoveContextAdapter remove_context_adapter{operation};
89 304 OperationAdapter operation_adapter{remove_context_adapter};
90 304 RemainingPathToScalarPathAdapter remaining_path_adapter{operation_adapter};
91 304 OperationContextAdapter context_adapter{remaining_path_adapter};
92 304 ParallelRowsAdapter parallel_rows_adapter{context_adapter};
93 304 RowBasedOperation row_based_operation{parallel_rows_adapter};
94 304 zip_parallel_rows(row_based_operation, rect, y_rows, uv_rows, rgbx_rows);
95 304 return KLEIDICV_OK;
96 504 }
97
98 KLEIDICV_TARGET_FN_ATTRS
99 126 kleidicv_error_t yuv_sp_to_rgb_u8(const uint8_t *src_y, size_t src_y_stride,
100 const uint8_t *src_uv, size_t src_uv_stride,
101 uint8_t *dst, size_t dst_stride, size_t width,
102 size_t height, bool is_nv21) {
103 126 YUVSpToRGB operation{is_nv21};
104 378 return yuv2rgbx_operation(operation, src_y, src_y_stride, src_uv,
105 126 src_uv_stride, dst, dst_stride, width, height);
106 126 }
107
108 KLEIDICV_TARGET_FN_ATTRS
109 126 kleidicv_error_t yuv_sp_to_rgba_u8(const uint8_t *src_y, size_t src_y_stride,
110 const uint8_t *src_uv, size_t src_uv_stride,
111 uint8_t *dst, size_t dst_stride,
112 size_t width, size_t height, bool is_nv21) {
113 126 YUVSpToRGBA operation{is_nv21};
114 378 return yuv2rgbx_operation(operation, src_y, src_y_stride, src_uv,
115 126 src_uv_stride, dst, dst_stride, width, height);
116 126 }
117 KLEIDICV_TARGET_FN_ATTRS kleidicv_error_t
118 126 yuv_sp_to_bgr_u8(const uint8_t *src_y, size_t src_y_stride,
119 const uint8_t *src_uv, size_t src_uv_stride, uint8_t *dst,
120 size_t dst_stride, size_t width, size_t height, bool is_nv21) {
121 126 YUVSpToBGR operation{is_nv21};
122 378 return yuv2rgbx_operation(operation, src_y, src_y_stride, src_uv,
123 126 src_uv_stride, dst, dst_stride, width, height);
124 126 }
125
126 126 KLEIDICV_TARGET_FN_ATTRS kleidicv_error_t yuv_sp_to_bgra_u8(
127 const uint8_t *src_y, size_t src_y_stride, const uint8_t *src_uv,
128 size_t src_uv_stride, uint8_t *dst, size_t dst_stride, size_t width,
129 size_t height, bool is_nv21) {
130 126 YUVSpToBGRA operation{is_nv21};
131 378 return yuv2rgbx_operation(operation, src_y, src_y_stride, src_uv,
132 126 src_uv_stride, dst, dst_stride, width, height);
133 126 }
134
135 } // namespace kleidicv::neon
136