/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 <stdlib.h> |
18 | | |
19 | | #include "./sharpyuv_cpu.h" |
20 | | #include "./sharpyuv_gamma.h" |
21 | | #include "src/dsp/cpu.h" |
22 | | #include "webp/types.h" |
23 | | |
24 | | //----------------------------------------------------------------------------- |
25 | | |
26 | | #if !WEBP_NEON_OMIT_C_CODE |
27 | | static uint64_t SharpYuvUpdateY_C(const uint16_t* ref, const uint16_t* src, |
28 | 171k | uint16_t* dst, int len, int bit_depth) { |
29 | 171k | uint64_t diff = 0; |
30 | 171k | int i; |
31 | 171k | const int max_y = (1 << bit_depth) - 1; |
32 | 46.5M | for (i = 0; i < len; ++i) { |
33 | 46.3M | const int diff_y = ref[i] - src[i]; |
34 | 46.3M | const int new_y = (int)dst[i] + diff_y; |
35 | 46.3M | dst[i] = SharpYuvClip16(new_y, max_y); |
36 | 46.3M | diff += (uint64_t)abs(diff_y); |
37 | 46.3M | } |
38 | 171k | return diff; |
39 | 171k | } |
40 | | |
41 | | static void SharpYuvUpdateRGB_C(const int16_t* ref, const int16_t* src, |
42 | 171k | int16_t* dst, int len) { |
43 | 171k | int i; |
44 | 34.9M | for (i = 0; i < len; ++i) { |
45 | 34.7M | const int diff_uv = ref[i] - src[i]; |
46 | 34.7M | dst[i] += diff_uv; |
47 | 34.7M | } |
48 | 171k | } |
49 | | |
50 | | static void SharpYuvFilterRow_C(const int16_t* A, const int16_t* B, int len, |
51 | | const uint16_t* best_y, uint16_t* out, |
52 | 1.02M | int bit_depth) { |
53 | 1.02M | int i; |
54 | 1.02M | const int max_y = (1 << bit_depth) - 1; |
55 | 69.5M | for (i = 0; i < len; ++i, ++A, ++B) { |
56 | 68.4M | const int v0 = (A[0] * 9 + A[1] * 3 + B[0] * 3 + B[1] + 8) >> 4; |
57 | 68.4M | const int v1 = (A[1] * 9 + A[0] * 3 + B[1] * 3 + B[0] + 8) >> 4; |
58 | 68.4M | out[2 * i + 0] = SharpYuvClip16(best_y[2 * i + 0] + v0, max_y); |
59 | 68.4M | out[2 * i + 1] = SharpYuvClip16(best_y[2 * i + 1] + v1, max_y); |
60 | 68.4M | } |
61 | 1.02M | } |
62 | | |
63 | | static void SharpYuvConvertRowY_C(const uint16_t* best_y, |
64 | | const int16_t* best_uv, int width, int uv_w, |
65 | | const int coeffs[4], int sfix, |
66 | 187k | int yuv_bit_depth, void* y_out) { |
67 | 187k | const int yuv_max = (1 << yuv_bit_depth) - 1; |
68 | 187k | int i; |
69 | 25.0M | for (i = 0; i < width; ++i) { |
70 | 24.8M | const int off = i >> 1; |
71 | 24.8M | const int W = best_y[i]; |
72 | 24.8M | const int r = best_uv[off + 0 * uv_w] + W; |
73 | 24.8M | const int g = best_uv[off + 1 * uv_w] + W; |
74 | 24.8M | const int b = best_uv[off + 2 * uv_w] + W; |
75 | 24.8M | const int y = SharpYuvConvertComponent(r, g, b, coeffs, sfix); |
76 | 24.8M | if (yuv_bit_depth <= 8) { |
77 | 24.8M | ((uint8_t*)y_out)[i] = (uint8_t)SharpYuvClip16(y, 255); |
78 | 24.8M | } else { |
79 | 0 | ((uint16_t*)y_out)[i] = SharpYuvClip16(y, yuv_max); |
80 | 0 | } |
81 | 24.8M | } |
82 | 187k | } |
83 | | |
84 | | static void SharpYuvConvertRowUV_C(const int16_t* best_uv, int uv_w, |
85 | | const int coeffs_u[4], const int coeffs_v[4], |
86 | | int sfix, int yuv_bit_depth, void* u_out, |
87 | 94.1k | void* v_out) { |
88 | 94.1k | const int yuv_max = (1 << yuv_bit_depth) - 1; |
89 | 94.1k | int i; |
90 | 6.35M | for (i = 0; i < uv_w; ++i) { |
91 | 6.25M | const int r = best_uv[i + 0 * uv_w]; |
92 | 6.25M | const int g = best_uv[i + 1 * uv_w]; |
93 | 6.25M | const int b = best_uv[i + 2 * uv_w]; |
94 | 6.25M | const int u = SharpYuvConvertComponent(r, g, b, coeffs_u, sfix); |
95 | 6.25M | const int v = SharpYuvConvertComponent(r, g, b, coeffs_v, sfix); |
96 | 6.25M | if (yuv_bit_depth <= 8) { |
97 | 6.25M | ((uint8_t*)u_out)[i] = (uint8_t)SharpYuvClip16(u, 255); |
98 | 6.25M | ((uint8_t*)v_out)[i] = (uint8_t)SharpYuvClip16(v, 255); |
99 | 6.25M | } else { |
100 | 0 | ((uint16_t*)u_out)[i] = SharpYuvClip16(u, yuv_max); |
101 | 0 | ((uint16_t*)v_out)[i] = SharpYuvClip16(v, yuv_max); |
102 | 0 | } |
103 | 6.25M | } |
104 | 94.1k | } |
105 | | |
106 | | // Fast path for the (default, most common) sRGB transfer function, used by |
107 | | // UpdateW/UpdateChroma in sharpyuv.c. |
108 | | static void SharpYuvUpdateWSrgb_C(const uint16_t* src, uint16_t* dst, int w, |
109 | 531k | int bit_depth) { |
110 | 531k | int i = 0; |
111 | 71.3M | do { |
112 | 71.3M | const uint32_t R = SharpYuvGammaToLinear(src[0 * w + i], bit_depth, |
113 | 71.3M | kSharpYuvTransferFunctionSrgb); |
114 | 71.3M | const uint32_t G = SharpYuvGammaToLinear(src[1 * w + i], bit_depth, |
115 | 71.3M | kSharpYuvTransferFunctionSrgb); |
116 | 71.3M | const uint32_t B = SharpYuvGammaToLinear(src[2 * w + i], bit_depth, |
117 | 71.3M | kSharpYuvTransferFunctionSrgb); |
118 | 71.3M | const int Y = SharpYuvRGBToGray(R, G, B); |
119 | 71.3M | dst[i] = SharpYuvLinearToGamma((uint32_t)Y, bit_depth, |
120 | 71.3M | kSharpYuvTransferFunctionSrgb); |
121 | 71.3M | } while (++i < w); |
122 | 531k | } |
123 | | |
124 | | static uint32_t ScaleDownSrgb_C(uint16_t a, uint16_t b, uint16_t c, uint16_t d, |
125 | 53.5M | int bit_depth) { |
126 | 53.5M | const uint32_t A = |
127 | 53.5M | SharpYuvGammaToLinear(a, bit_depth, kSharpYuvTransferFunctionSrgb); |
128 | 53.5M | const uint32_t B = |
129 | 53.5M | SharpYuvGammaToLinear(b, bit_depth, kSharpYuvTransferFunctionSrgb); |
130 | 53.5M | const uint32_t C = |
131 | 53.5M | SharpYuvGammaToLinear(c, bit_depth, kSharpYuvTransferFunctionSrgb); |
132 | 53.5M | const uint32_t D = |
133 | 53.5M | SharpYuvGammaToLinear(d, bit_depth, kSharpYuvTransferFunctionSrgb); |
134 | 53.5M | return SharpYuvLinearToGamma((A + B + C + D + 2) >> 2, bit_depth, |
135 | 53.5M | kSharpYuvTransferFunctionSrgb); |
136 | 53.5M | } |
137 | | |
138 | | static void SharpYuvUpdateChromaSrgb_C(const uint16_t* src1, |
139 | | const uint16_t* src2, int16_t* dst, |
140 | 265k | int uv_w, int bit_depth) { |
141 | 265k | int i = 0; |
142 | 17.8M | do { |
143 | 17.8M | const int r = |
144 | 17.8M | (int)ScaleDownSrgb_C(src1[0 * uv_w + 0], src1[0 * uv_w + 1], |
145 | 17.8M | src2[0 * uv_w + 0], src2[0 * uv_w + 1], bit_depth); |
146 | 17.8M | const int g = |
147 | 17.8M | (int)ScaleDownSrgb_C(src1[2 * uv_w + 0], src1[2 * uv_w + 1], |
148 | 17.8M | src2[2 * uv_w + 0], src2[2 * uv_w + 1], bit_depth); |
149 | 17.8M | const int b = |
150 | 17.8M | (int)ScaleDownSrgb_C(src1[4 * uv_w + 0], src1[4 * uv_w + 1], |
151 | 17.8M | src2[4 * uv_w + 0], src2[4 * uv_w + 1], bit_depth); |
152 | 17.8M | const int W = SharpYuvRGBToGray(r, g, b); |
153 | 17.8M | dst[0 * uv_w] = (int16_t)(r - W); |
154 | 17.8M | dst[1 * uv_w] = (int16_t)(g - W); |
155 | 17.8M | dst[2 * uv_w] = (int16_t)(b - W); |
156 | 17.8M | dst += 1; |
157 | 17.8M | src1 += 2; |
158 | 17.8M | src2 += 2; |
159 | 17.8M | } while (++i < uv_w); |
160 | 265k | } |
161 | | #endif // !WEBP_NEON_OMIT_C_CODE |
162 | | |
163 | | //----------------------------------------------------------------------------- |
164 | | |
165 | | uint64_t (*SharpYuvUpdateY)(const uint16_t* src, const uint16_t* ref, |
166 | | uint16_t* dst, int len, int bit_depth); |
167 | | void (*SharpYuvUpdateRGB)(const int16_t* src, const int16_t* ref, int16_t* dst, |
168 | | int len); |
169 | | void (*SharpYuvFilterRow)(const int16_t* A, const int16_t* B, int len, |
170 | | const uint16_t* best_y, uint16_t* out, int bit_depth); |
171 | | void (*SharpYuvConvertRowY)(const uint16_t* best_y, const int16_t* best_uv, |
172 | | int width, int uv_w, const int coeffs[4], int sfix, |
173 | | int yuv_bit_depth, void* y_out); |
174 | | void (*SharpYuvConvertRowUV)(const int16_t* best_uv, int uv_w, |
175 | | const int coeffs_u[4], const int coeffs_v[4], |
176 | | int sfix, int yuv_bit_depth, void* u_out, |
177 | | void* v_out); |
178 | | void (*SharpYuvUpdateWSrgb)(const uint16_t* src, uint16_t* dst, int w, |
179 | | int bit_depth); |
180 | | void (*SharpYuvUpdateChromaSrgb)(const uint16_t* src1, const uint16_t* src2, |
181 | | int16_t* dst, int uv_w, int bit_depth); |
182 | | |
183 | | extern VP8CPUInfo SharpYuvGetCPUInfo; |
184 | | extern void InitSharpYuvSSE2(void); |
185 | | extern void InitSharpYuvAVX2(void); |
186 | | extern void InitSharpYuvNEON(void); |
187 | | |
188 | 4.23k | void SharpYuvInitDsp(void) { |
189 | 4.23k | #if !WEBP_NEON_OMIT_C_CODE |
190 | 4.23k | SharpYuvUpdateY = SharpYuvUpdateY_C; |
191 | 4.23k | SharpYuvUpdateRGB = SharpYuvUpdateRGB_C; |
192 | 4.23k | SharpYuvFilterRow = SharpYuvFilterRow_C; |
193 | 4.23k | SharpYuvConvertRowY = SharpYuvConvertRowY_C; |
194 | 4.23k | SharpYuvConvertRowUV = SharpYuvConvertRowUV_C; |
195 | 4.23k | SharpYuvUpdateWSrgb = SharpYuvUpdateWSrgb_C; |
196 | 4.23k | SharpYuvUpdateChromaSrgb = SharpYuvUpdateChromaSrgb_C; |
197 | 4.23k | #endif |
198 | | |
199 | 4.23k | if (SharpYuvGetCPUInfo != NULL) { |
200 | 4.23k | #if defined(WEBP_HAVE_SSE2) |
201 | 4.23k | if (SharpYuvGetCPUInfo(kSSE2)) { |
202 | 2.87k | InitSharpYuvSSE2(); |
203 | 2.87k | } |
204 | 4.23k | #endif // WEBP_HAVE_SSE2 |
205 | 4.23k | #if defined(WEBP_HAVE_AVX2) |
206 | 4.23k | if (SharpYuvGetCPUInfo(kAVX2)) { |
207 | 2.87k | InitSharpYuvAVX2(); |
208 | 2.87k | } |
209 | 4.23k | #endif // WEBP_HAVE_AVX2 |
210 | 4.23k | } |
211 | | |
212 | | #if defined(WEBP_HAVE_NEON) |
213 | | if (WEBP_NEON_OMIT_C_CODE || |
214 | | (SharpYuvGetCPUInfo != NULL && SharpYuvGetCPUInfo(kNEON))) { |
215 | | InitSharpYuvNEON(); |
216 | | } |
217 | | #endif // WEBP_HAVE_NEON |
218 | | |
219 | 4.23k | assert(SharpYuvUpdateY != NULL); |
220 | 4.23k | assert(SharpYuvUpdateRGB != NULL); |
221 | 4.23k | assert(SharpYuvFilterRow != NULL); |
222 | 4.23k | assert(SharpYuvConvertRowY != NULL); |
223 | 4.23k | assert(SharpYuvConvertRowUV != NULL); |
224 | 4.23k | assert(SharpYuvUpdateWSrgb != NULL); |
225 | | assert(SharpYuvUpdateChromaSrgb != NULL); |
226 | 4.23k | } |