/src/libwebp/sharpyuv/sharpyuv_dsp.c
Line | Count | Source |
1 | | // Copyright 2022 Google Inc. All Rights Reserved. |
2 | | // |
3 | | // Use of this source code is governed by a BSD-style license |
4 | | // that can be found in the COPYING file in the root of the source |
5 | | // tree. An additional intellectual property rights grant can be found |
6 | | // in the file PATENTS. All contributing project authors may |
7 | | // be found in the AUTHORS file in the root of the source tree. |
8 | | // ----------------------------------------------------------------------------- |
9 | | // |
10 | | // Speed-critical functions for Sharp YUV. |
11 | | // |
12 | | // Author: Skal (pascal.massimino@gmail.com) |
13 | | |
14 | | #include "./sharpyuv_dsp.h" |
15 | | |
16 | | #include <assert.h> |
17 | | #include <stdint.h> |
18 | | #include <stdlib.h> |
19 | | |
20 | | #include "./sharpyuv.h" |
21 | | #include "./sharpyuv_cpu.h" |
22 | | #include "./sharpyuv_gamma.h" |
23 | | #include "src/dsp/cpu.h" |
24 | | #include "webp/types.h" |
25 | | |
26 | | //----------------------------------------------------------------------------- |
27 | | |
28 | | #if !WEBP_NEON_OMIT_C_CODE |
29 | | static uint64_t SharpYuvUpdateY_C(const uint16_t* ref, const uint16_t* src, |
30 | 0 | uint16_t* dst, int len, int bit_depth) { |
31 | 0 | uint64_t diff = 0; |
32 | 0 | int i; |
33 | 0 | const int max_y = (1 << bit_depth) - 1; |
34 | 0 | for (i = 0; i < len; ++i) { |
35 | 0 | const int diff_y = ref[i] - src[i]; |
36 | 0 | const int new_y = (int)dst[i] + diff_y; |
37 | 0 | dst[i] = SharpYuvClip16(new_y, max_y); |
38 | 0 | diff += (uint64_t)abs(diff_y); |
39 | 0 | } |
40 | 0 | return diff; |
41 | 0 | } |
42 | | |
43 | | static void SharpYuvUpdateRGB_C(const int16_t* ref, const int16_t* src, |
44 | 0 | int16_t* dst, int len) { |
45 | 0 | int i; |
46 | 0 | for (i = 0; i < len; ++i) { |
47 | 0 | const int diff_uv = ref[i] - src[i]; |
48 | 0 | dst[i] += diff_uv; |
49 | 0 | } |
50 | 0 | } |
51 | | |
52 | | static void SharpYuvFilterRow_C(const int16_t* A, const int16_t* B, int len, |
53 | | const uint16_t* best_y, uint16_t* out, |
54 | 0 | int bit_depth) { |
55 | 0 | int i; |
56 | 0 | const int max_y = (1 << bit_depth) - 1; |
57 | 0 | for (i = 0; i < len; ++i, ++A, ++B) { |
58 | 0 | const int v0 = (A[0] * 9 + A[1] * 3 + B[0] * 3 + B[1] + 8) >> 4; |
59 | 0 | const int v1 = (A[1] * 9 + A[0] * 3 + B[1] * 3 + B[0] + 8) >> 4; |
60 | 0 | out[2 * i + 0] = SharpYuvClip16(best_y[2 * i + 0] + v0, max_y); |
61 | 0 | out[2 * i + 1] = SharpYuvClip16(best_y[2 * i + 1] + v1, max_y); |
62 | 0 | } |
63 | 0 | } |
64 | | |
65 | | static void SharpYuvConvertRowY_C(const uint16_t* best_y, |
66 | | const int16_t* best_uv, int width, int uv_w, |
67 | | const int coeffs[4], int sfix, |
68 | 0 | int yuv_bit_depth, void* y_out) { |
69 | 0 | const int yuv_max = (1 << yuv_bit_depth) - 1; |
70 | 0 | int i; |
71 | 0 | for (i = 0; i < width; ++i) { |
72 | 0 | const int off = i >> 1; |
73 | 0 | const int W = best_y[i]; |
74 | 0 | const int r = best_uv[off + 0 * uv_w] + W; |
75 | 0 | const int g = best_uv[off + 1 * uv_w] + W; |
76 | 0 | const int b = best_uv[off + 2 * uv_w] + W; |
77 | 0 | const int y = SharpYuvConvertComponent(r, g, b, coeffs, sfix); |
78 | 0 | if (yuv_bit_depth <= 8) { |
79 | 0 | ((uint8_t*)y_out)[i] = (uint8_t)SharpYuvClip16(y, 255); |
80 | 0 | } else { |
81 | 0 | ((uint16_t*)y_out)[i] = SharpYuvClip16(y, yuv_max); |
82 | 0 | } |
83 | 0 | } |
84 | 0 | } |
85 | | |
86 | | static void SharpYuvConvertRowUV_C(const int16_t* best_uv, int uv_w, |
87 | | const int coeffs_u[4], const int coeffs_v[4], |
88 | | int sfix, int yuv_bit_depth, void* u_out, |
89 | 0 | void* v_out) { |
90 | 0 | const int yuv_max = (1 << yuv_bit_depth) - 1; |
91 | 0 | int i; |
92 | 0 | for (i = 0; i < uv_w; ++i) { |
93 | 0 | const int r = best_uv[i + 0 * uv_w]; |
94 | 0 | const int g = best_uv[i + 1 * uv_w]; |
95 | 0 | const int b = best_uv[i + 2 * uv_w]; |
96 | 0 | const int u = SharpYuvConvertComponent(r, g, b, coeffs_u, sfix); |
97 | 0 | const int v = SharpYuvConvertComponent(r, g, b, coeffs_v, sfix); |
98 | 0 | if (yuv_bit_depth <= 8) { |
99 | 0 | ((uint8_t*)u_out)[i] = (uint8_t)SharpYuvClip16(u, 255); |
100 | 0 | ((uint8_t*)v_out)[i] = (uint8_t)SharpYuvClip16(v, 255); |
101 | 0 | } else { |
102 | 0 | ((uint16_t*)u_out)[i] = SharpYuvClip16(u, yuv_max); |
103 | 0 | ((uint16_t*)v_out)[i] = SharpYuvClip16(v, yuv_max); |
104 | 0 | } |
105 | 0 | } |
106 | 0 | } |
107 | | |
108 | | // Fast paths for the BT.709 and sRGB transfer functions, used by |
109 | | // UpdateW/UpdateChroma in sharpyuv.c. |
110 | | static void UpdateW_C(const uint16_t* src, uint16_t* dst, int w, int bit_depth, |
111 | 0 | SharpYuvTransferFunctionType transfer_type) { |
112 | 0 | int i = 0; |
113 | 0 | do { |
114 | 0 | const uint32_t R = |
115 | 0 | SharpYuvGammaToLinear(src[0 * w + i], bit_depth, transfer_type); |
116 | 0 | const uint32_t G = |
117 | 0 | SharpYuvGammaToLinear(src[1 * w + i], bit_depth, transfer_type); |
118 | 0 | const uint32_t B = |
119 | 0 | SharpYuvGammaToLinear(src[2 * w + i], bit_depth, transfer_type); |
120 | 0 | const int Y = SharpYuvRGBToGray(R, G, B); |
121 | 0 | dst[i] = SharpYuvLinearToGamma((uint32_t)Y, bit_depth, transfer_type); |
122 | 0 | } while (++i < w); |
123 | 0 | } |
124 | | |
125 | | static uint32_t ScaleDown_C(uint16_t a, uint16_t b, uint16_t c, uint16_t d, |
126 | | int bit_depth, |
127 | 0 | SharpYuvTransferFunctionType transfer_type) { |
128 | 0 | const uint32_t A = SharpYuvGammaToLinear(a, bit_depth, transfer_type); |
129 | 0 | const uint32_t B = SharpYuvGammaToLinear(b, bit_depth, transfer_type); |
130 | 0 | const uint32_t C = SharpYuvGammaToLinear(c, bit_depth, transfer_type); |
131 | 0 | const uint32_t D = SharpYuvGammaToLinear(d, bit_depth, transfer_type); |
132 | 0 | return SharpYuvLinearToGamma((A + B + C + D + 2) >> 2, bit_depth, |
133 | 0 | transfer_type); |
134 | 0 | } |
135 | | |
136 | | static void UpdateChroma_C(const uint16_t* src1, const uint16_t* src2, |
137 | | int16_t* dst, int uv_w, int bit_depth, |
138 | 0 | SharpYuvTransferFunctionType transfer_type) { |
139 | 0 | int i = 0; |
140 | 0 | do { |
141 | 0 | const int r = (int)ScaleDown_C(src1[0 * uv_w + 0], src1[0 * uv_w + 1], |
142 | 0 | src2[0 * uv_w + 0], src2[0 * uv_w + 1], |
143 | 0 | bit_depth, transfer_type); |
144 | 0 | const int g = (int)ScaleDown_C(src1[2 * uv_w + 0], src1[2 * uv_w + 1], |
145 | 0 | src2[2 * uv_w + 0], src2[2 * uv_w + 1], |
146 | 0 | bit_depth, transfer_type); |
147 | 0 | const int b = (int)ScaleDown_C(src1[4 * uv_w + 0], src1[4 * uv_w + 1], |
148 | 0 | src2[4 * uv_w + 0], src2[4 * uv_w + 1], |
149 | 0 | bit_depth, transfer_type); |
150 | 0 | const int W = SharpYuvRGBToGray(r, g, b); |
151 | 0 | dst[0 * uv_w] = (int16_t)(r - W); |
152 | 0 | dst[1 * uv_w] = (int16_t)(g - W); |
153 | 0 | dst[2 * uv_w] = (int16_t)(b - W); |
154 | 0 | dst += 1; |
155 | 0 | src1 += 2; |
156 | 0 | src2 += 2; |
157 | 0 | } while (++i < uv_w); |
158 | 0 | } |
159 | | |
160 | | static void SharpYuvUpdateW709_C(const uint16_t* src, uint16_t* dst, int w, |
161 | 0 | int bit_depth) { |
162 | 0 | UpdateW_C(src, dst, w, bit_depth, kSharpYuvTransferFunctionBt709); |
163 | 0 | } |
164 | | |
165 | | static void SharpYuvUpdateChroma709_C(const uint16_t* src1, |
166 | | const uint16_t* src2, int16_t* dst, |
167 | 0 | int uv_w, int bit_depth) { |
168 | 0 | UpdateChroma_C(src1, src2, dst, uv_w, bit_depth, |
169 | 0 | kSharpYuvTransferFunctionBt709); |
170 | 0 | } |
171 | | |
172 | | static void SharpYuvUpdateWSrgb_C(const uint16_t* src, uint16_t* dst, int w, |
173 | 0 | int bit_depth) { |
174 | 0 | UpdateW_C(src, dst, w, bit_depth, kSharpYuvTransferFunctionSrgb); |
175 | 0 | } |
176 | | |
177 | | static void SharpYuvUpdateChromaSrgb_C(const uint16_t* src1, |
178 | | const uint16_t* src2, int16_t* dst, |
179 | 0 | int uv_w, int bit_depth) { |
180 | 0 | UpdateChroma_C(src1, src2, dst, uv_w, bit_depth, |
181 | 0 | kSharpYuvTransferFunctionSrgb); |
182 | 0 | } |
183 | | #endif // !WEBP_NEON_OMIT_C_CODE |
184 | | |
185 | | //----------------------------------------------------------------------------- |
186 | | |
187 | | uint64_t (*SharpYuvUpdateY)(const uint16_t* src, const uint16_t* ref, |
188 | | uint16_t* dst, int len, int bit_depth); |
189 | | void (*SharpYuvUpdateRGB)(const int16_t* src, const int16_t* ref, int16_t* dst, |
190 | | int len); |
191 | | void (*SharpYuvFilterRow)(const int16_t* A, const int16_t* B, int len, |
192 | | const uint16_t* best_y, uint16_t* out, int bit_depth); |
193 | | void (*SharpYuvConvertRowY)(const uint16_t* best_y, const int16_t* best_uv, |
194 | | int width, int uv_w, const int coeffs[4], int sfix, |
195 | | int yuv_bit_depth, void* y_out); |
196 | | void (*SharpYuvConvertRowUV)(const int16_t* best_uv, int uv_w, |
197 | | const int coeffs_u[4], const int coeffs_v[4], |
198 | | int sfix, int yuv_bit_depth, void* u_out, |
199 | | void* v_out); |
200 | | void (*SharpYuvUpdateW709)(const uint16_t* src, uint16_t* dst, int w, |
201 | | int bit_depth); |
202 | | void (*SharpYuvUpdateChroma709)(const uint16_t* src1, const uint16_t* src2, |
203 | | int16_t* dst, int uv_w, int bit_depth); |
204 | | void (*SharpYuvUpdateWSrgb)(const uint16_t* src, uint16_t* dst, int w, |
205 | | int bit_depth); |
206 | | void (*SharpYuvUpdateChromaSrgb)(const uint16_t* src1, const uint16_t* src2, |
207 | | int16_t* dst, int uv_w, int bit_depth); |
208 | | |
209 | | extern VP8CPUInfo SharpYuvGetCPUInfo; |
210 | | extern void InitSharpYuvSSE2(void); |
211 | | extern void InitSharpYuvAVX2(void); |
212 | | extern void InitSharpYuvNEON(void); |
213 | | |
214 | 0 | void SharpYuvInitDsp(void) { |
215 | 0 | #if !WEBP_NEON_OMIT_C_CODE |
216 | 0 | SharpYuvUpdateY = SharpYuvUpdateY_C; |
217 | 0 | SharpYuvUpdateRGB = SharpYuvUpdateRGB_C; |
218 | 0 | SharpYuvFilterRow = SharpYuvFilterRow_C; |
219 | 0 | SharpYuvConvertRowY = SharpYuvConvertRowY_C; |
220 | 0 | SharpYuvConvertRowUV = SharpYuvConvertRowUV_C; |
221 | 0 | SharpYuvUpdateW709 = SharpYuvUpdateW709_C; |
222 | 0 | SharpYuvUpdateChroma709 = SharpYuvUpdateChroma709_C; |
223 | 0 | SharpYuvUpdateWSrgb = SharpYuvUpdateWSrgb_C; |
224 | 0 | SharpYuvUpdateChromaSrgb = SharpYuvUpdateChromaSrgb_C; |
225 | 0 | #endif |
226 | |
|
227 | 0 | if (SharpYuvGetCPUInfo != NULL) { |
228 | 0 | #if defined(WEBP_HAVE_SSE2) |
229 | 0 | if (SharpYuvGetCPUInfo(kSSE2)) { |
230 | 0 | InitSharpYuvSSE2(); |
231 | 0 | } |
232 | 0 | #endif // WEBP_HAVE_SSE2 |
233 | 0 | #if defined(WEBP_HAVE_AVX2) |
234 | 0 | if (SharpYuvGetCPUInfo(kAVX2)) { |
235 | 0 | InitSharpYuvAVX2(); |
236 | 0 | } |
237 | 0 | #endif // WEBP_HAVE_AVX2 |
238 | 0 | } |
239 | |
|
240 | | #if defined(WEBP_HAVE_NEON) |
241 | | if (WEBP_NEON_OMIT_C_CODE || |
242 | | (SharpYuvGetCPUInfo != NULL && SharpYuvGetCPUInfo(kNEON))) { |
243 | | InitSharpYuvNEON(); |
244 | | } |
245 | | #endif // WEBP_HAVE_NEON |
246 | |
|
247 | 0 | assert(SharpYuvUpdateY != NULL); |
248 | 0 | assert(SharpYuvUpdateRGB != NULL); |
249 | 0 | assert(SharpYuvFilterRow != NULL); |
250 | 0 | assert(SharpYuvConvertRowY != NULL); |
251 | 0 | assert(SharpYuvConvertRowUV != NULL); |
252 | 0 | assert(SharpYuvUpdateW709 != NULL); |
253 | 0 | assert(SharpYuvUpdateChroma709 != NULL); |
254 | 0 | assert(SharpYuvUpdateWSrgb != NULL); |
255 | | assert(SharpYuvUpdateChromaSrgb != NULL); |
256 | 0 | } |