KleidiCV Coverage Report


Directory: ./
File: kleidicv/src/conversions/gray_to_rgb_neon.cpp
Date: 2025-09-25 14:13:34
Exec Total Coverage
Lines: 52 52 100.0%
Functions: 8 8 100.0%
Branches: 28 28 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/conversions/gray_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 GrayToRGB final : public UnrollTwice {
13 public:
14 using VecTraits = neon::VecTraits<ScalarType>;
15 using VectorType = typename VecTraits::VectorType;
16
17 #if !KLEIDICV_PREFER_INTERLEAVING_LOAD_STORE
18 64 GrayToRGB() : indices_{} {
19 64 VecTraits::load(kGrayToRGBTableIndices, indices_);
20 64 }
21 #else
22 GrayToRGB() = default;
23 #endif
24
25 442 void vector_path(VectorType src_vect, ScalarType *dst) {
26 442 uint8x16x3_t dst_vect;
27 #if KLEIDICV_PREFER_INTERLEAVING_LOAD_STORE
28 dst_vect.val[0] = src_vect;
29 dst_vect.val[1] = src_vect;
30 dst_vect.val[2] = src_vect;
31 vst3q_u8(dst, dst_vect);
32 #else
33 442 dst_vect.val[0] = vqtbl1q_u8(src_vect, indices_.val[0]);
34 442 dst_vect.val[1] = vqtbl1q_u8(src_vect, indices_.val[1]);
35 442 dst_vect.val[2] = vqtbl1q_u8(src_vect, indices_.val[2]);
36 442 VecTraits::store(dst_vect, dst);
37 #endif
38 442 }
39
40 480 void scalar_path(const ScalarType *src, ScalarType *dst) {
41 480 dst[0] = dst[1] = dst[2] = src[0];
42 480 }
43
44 private:
45 #if !KLEIDICV_PREFER_INTERLEAVING_LOAD_STORE
46
47 static constexpr uint8_t kGrayToRGBTableIndices[48] = {
48 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5,
49 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10,
50 10, 11, 11, 11, 12, 12, 12, 13, 13, 13, 14, 14, 14, 15, 15, 15};
51 uint8x16x3_t indices_;
52 #endif
53 }; // end of class GrayToRGB<ScalarType>
54
55 template <typename ScalarType>
56 class GrayToRGBA final : public UnrollTwice {
57 public:
58 using VecTraits = neon::VecTraits<ScalarType>;
59 using VectorType = typename VecTraits::VectorType;
60
61 #if KLEIDICV_PREFER_INTERLEAVING_LOAD_STORE
62 GrayToRGBA() : alpha_{vdupq_n_u8(0xff)} {}
63 #else
64 // NOLINTBEGIN(hicpp-member-init)
65 64 GrayToRGBA() : indices_{} {
66 64 VecTraits::load(kGrayToRGBATableIndices, indices_);
67 64 src_and_alpha_.val[1] = vdupq_n_u8(0xff);
68 64 }
69 // NOLINTEND(hicpp-member-init)
70 #endif
71
72 442 void vector_path(VectorType src_vect, ScalarType *dst) {
73 442 uint8x16x4_t dst_vect;
74 #if KLEIDICV_PREFER_INTERLEAVING_LOAD_STORE
75 dst_vect.val[0] = src_vect;
76 dst_vect.val[1] = src_vect;
77 dst_vect.val[2] = src_vect;
78 dst_vect.val[3] = alpha_;
79 vst4q_u8(dst, dst_vect);
80 #else
81 442 src_and_alpha_.val[0] = src_vect;
82 442 dst_vect.val[0] = vqtbl2q_u8(src_and_alpha_, indices_.val[0]);
83 442 dst_vect.val[1] = vqtbl2q_u8(src_and_alpha_, indices_.val[1]);
84 442 dst_vect.val[2] = vqtbl2q_u8(src_and_alpha_, indices_.val[2]);
85 442 dst_vect.val[3] = vqtbl2q_u8(src_and_alpha_, indices_.val[3]);
86 442 VecTraits::store(dst_vect, dst);
87
88 #endif
89 442 }
90
91 480 void scalar_path(const ScalarType *src, ScalarType *dst) {
92 480 dst[0] = dst[1] = dst[2] = src[0];
93 480 dst[3] = 0xff;
94 480 }
95
96 private:
97 #if KLEIDICV_PREFER_INTERLEAVING_LOAD_STORE
98 uint8x16_t alpha_;
99 #else
100 uint8x16x4_t indices_;
101 uint8x16x2_t src_and_alpha_;
102
103 static constexpr uint8_t kGrayToRGBATableIndices[64] = {
104 0, 0, 0, 16, 1, 1, 1, 16, 2, 2, 2, 16, 3, 3, 3, 16,
105 4, 4, 4, 16, 5, 5, 5, 16, 6, 6, 6, 16, 7, 7, 7, 16,
106 8, 8, 8, 16, 9, 9, 9, 16, 10, 10, 10, 16, 11, 11, 11, 16,
107 12, 12, 12, 16, 13, 13, 13, 16, 14, 14, 14, 16, 15, 15, 15, 16};
108
109 #endif
110 }; // end of class GrayToRGBA<ScalarType>
111
112 KLEIDICV_TARGET_FN_ATTRS
113 76 kleidicv_error_t gray_to_rgb_u8(const uint8_t *src, size_t src_stride,
114 uint8_t *dst, size_t dst_stride, size_t width,
115 size_t height) {
116
4/4
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 73 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 73 times.
76 CHECK_POINTER_AND_STRIDE(src, src_stride, height);
117
4/4
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 70 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 70 times.
73 CHECK_POINTER_AND_STRIDE(dst, dst_stride, height);
118
6/6
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 67 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 64 times.
✓ Branch 4 taken 6 times.
✓ Branch 5 taken 64 times.
70 CHECK_IMAGE_SIZE(width, height);
119
120 64 Rectangle rect{width, height};
121 64 Rows<const uint8_t> src_rows{src, src_stride};
122 64 Rows<uint8_t> dst_rows{dst, dst_stride, 3 /* RGB */};
123 64 GrayToRGB<uint8_t> operation;
124 64 apply_operation_by_rows(operation, rect, src_rows, dst_rows);
125 64 return KLEIDICV_OK;
126 76 }
127
128 KLEIDICV_TARGET_FN_ATTRS
129 76 kleidicv_error_t gray_to_rgba_u8(const uint8_t *src, size_t src_stride,
130 uint8_t *dst, size_t dst_stride, size_t width,
131 size_t height) {
132
4/4
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 73 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 73 times.
76 CHECK_POINTER_AND_STRIDE(src, src_stride, height);
133
4/4
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 70 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 70 times.
73 CHECK_POINTER_AND_STRIDE(dst, dst_stride, height);
134
6/6
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 67 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 64 times.
✓ Branch 4 taken 6 times.
✓ Branch 5 taken 64 times.
70 CHECK_IMAGE_SIZE(width, height);
135
136 64 Rectangle rect{width, height};
137 64 Rows<const uint8_t> src_rows{src, src_stride};
138 64 Rows<uint8_t> dst_rows{dst, dst_stride, 4 /* RGBA */};
139 64 GrayToRGBA<uint8_t> operation;
140 64 apply_operation_by_rows(operation, rect, src_rows, dst_rows);
141 64 return KLEIDICV_OK;
142 76 }
143
144 } // namespace kleidicv::neon
145