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 |