Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(888)

Side by Side Diff: media/base/yuv_convert_sse2.cc

Issue 7888012: Reorganize YUV scalers (Continued) (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 9 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "media/base/yuv_convert.h"
6 #include "media/base/yuv_convert_internal.h"
7 #include "media/base/yuv_row.h"
8
9 #if defined(_MSC_VER)
10 #include <intrin.h>
11 #else
12 #include <mmintrin.h>
13 #include <emmintrin.h>
14 #endif
15
16 namespace media {
17
18 #define FIX_SHIFT 12
19 #define FIX(x) ((x) * (1 << FIX_SHIFT))
20
21 SIMD_ALIGNED(const int16 ConvertRGBAToYUV_kTable[8 * 3]) = {
22 FIX(0.098), FIX(0.504), FIX(0.257), 0,
23 FIX(0.098), FIX(0.504), FIX(0.257), 0,
24 FIX(0.439), -FIX(0.291), -FIX(0.148), 0,
25 FIX(0.439), -FIX(0.291), -FIX(0.148), 0,
26 -FIX(0.071), -FIX(0.368), FIX(0.439), 0,
27 -FIX(0.071), -FIX(0.368), FIX(0.439), 0,
28 };
29
30 // This is the final offset for the conversion from signed yuv values to
31 // unsigned values. It is arranged so that offset of 16 is applied to Y
32 // components and 128 is added to UV components for 2 pixels.
33 SIMD_ALIGNED(const int32 kYOffset[4]) = {16, 16, 16, 16};
34
35 static inline int Clamp(int value) {
36 if (value < 0)
37 return 0;
38 if (value > 255)
39 return 255;
40 return value;
41 }
42
43 static inline int RGBToY(int r, int g, int b) {
44 int y = ConvertRGBAToYUV_kTable[0] * b +
45 ConvertRGBAToYUV_kTable[1] * g +
46 ConvertRGBAToYUV_kTable[2] * r;
47 y >>= FIX_SHIFT;
48 return Clamp(y + 16);
49 }
50
51 static inline int RGBToU(int r, int g, int b, int shift) {
52 int u = ConvertRGBAToYUV_kTable[8] * b +
53 ConvertRGBAToYUV_kTable[9] * g +
54 ConvertRGBAToYUV_kTable[10] * r;
55 u >>= FIX_SHIFT + shift;
56 return Clamp(u + 128);
57 }
58
59 static inline int RGBToV(int r, int g, int b, int shift) {
60 int v = ConvertRGBAToYUV_kTable[16] * b +
61 ConvertRGBAToYUV_kTable[17] * g +
62 ConvertRGBAToYUV_kTable[18] * r;
63 v >>= FIX_SHIFT + shift;
64 return Clamp(v + 128);
65 }
66
67 #define CONVERT_Y(rgb_buf, y_buf) \
68 b = *rgb_buf++; \
69 g = *rgb_buf++; \
70 r = *rgb_buf++; \
71 ++rgb_buf; \
72 sum_b += b; \
73 sum_g += g; \
74 sum_r += r; \
75 *y_buf++ = RGBToY(r, g, b);
76
77 static inline void ConvertRGBToYUV_V2H2(const uint8* rgb_buf_1,
78 const uint8* rgb_buf_2,
79 uint8* y_buf_1,
80 uint8* y_buf_2,
81 uint8* u_buf,
82 uint8* v_buf) {
83 int sum_b = 0;
84 int sum_g = 0;
85 int sum_r = 0;
86 int r, g, b;
87
88 CONVERT_Y(rgb_buf_1, y_buf_1);
89 CONVERT_Y(rgb_buf_1, y_buf_1);
90 CONVERT_Y(rgb_buf_2, y_buf_2);
91 CONVERT_Y(rgb_buf_2, y_buf_2);
92 *u_buf++ = RGBToU(sum_r, sum_g, sum_b, 2);
93 *v_buf++ = RGBToV(sum_r, sum_g, sum_b, 2);
94 }
95
96 static inline void ConvertRGBToYUV_V2H1(const uint8* rgb_buf_1,
97 const uint8* rgb_buf_2,
98 uint8* y_buf_1,
99 uint8* y_buf_2,
100 uint8* u_buf,
101 uint8* v_buf) {
102 int sum_b = 0;
103 int sum_g = 0;
104 int sum_r = 0;
105 int r, g, b;
106
107 CONVERT_Y(rgb_buf_1, y_buf_1);
108 CONVERT_Y(rgb_buf_2, y_buf_2);
109 *u_buf++ = RGBToU(sum_r, sum_g, sum_b, 1);
110 *v_buf++ = RGBToV(sum_r, sum_g, sum_b, 1);
111 }
112
113 static inline void ConvertRGBToYUV_V1H2(const uint8* rgb_buf,
114 uint8* y_buf,
115 uint8* u_buf,
116 uint8* v_buf) {
117 int sum_b = 0;
118 int sum_g = 0;
119 int sum_r = 0;
120 int r, g, b;
121
122 CONVERT_Y(rgb_buf, y_buf);
123 CONVERT_Y(rgb_buf, y_buf);
124 *u_buf++ = RGBToU(sum_r, sum_g, sum_b, 1);
125 *v_buf++ = RGBToV(sum_r, sum_g, sum_b, 1);
126 }
127
128 static inline void ConvertRGBToYUV_V1H1(const uint8* rgb_buf,
129 uint8* y_buf,
130 uint8* u_buf,
131 uint8* v_buf) {
132 int sum_b = 0;
133 int sum_g = 0;
134 int sum_r = 0;
135 int r, g, b;
136
137 CONVERT_Y(rgb_buf, y_buf);
138 *u_buf++ = RGBToU(r, g, b, 0);
139 *v_buf++ = RGBToV(r, g, b, 0);
140 }
141
142 static void ConvertRGB32ToYUVRow_SSE2(const uint8* rgb_buf_1,
143 const uint8* rgb_buf_2,
144 uint8* y_buf_1,
145 uint8* y_buf_2,
146 uint8* u_buf,
147 uint8* v_buf,
148 int width) {
149 while (width >= 4) {
150 // Name for the Y pixels:
151 // Row 1: a b c d
152 // Row 2: e f g h
153 //
154 // First row 4 pixels.
155 __m128i rgb_row_1 = _mm_loadu_si128(
156 reinterpret_cast<const __m128i*>(rgb_buf_1));
157 __m128i zero_1 = _mm_xor_si128(rgb_row_1, rgb_row_1);
158
159 __m128i y_table = _mm_load_si128(
160 reinterpret_cast<const __m128i*>(ConvertRGBAToYUV_kTable));
161
162 __m128i rgb_a_b = _mm_unpackhi_epi8(rgb_row_1, zero_1);
163 rgb_a_b = _mm_madd_epi16(rgb_a_b, y_table);
164
165 __m128i rgb_c_d = _mm_unpacklo_epi8(rgb_row_1, zero_1);
166 rgb_c_d = _mm_madd_epi16(rgb_c_d, y_table);
167
168 // Do a crazh shuffle so that we get:
169 // v------------ Multiply Add
170 // BG: a b c d
171 // A0: a b c d
172 __m128i bg_abcd = _mm_castps_si128(
173 _mm_shuffle_ps(
174 _mm_castsi128_ps(rgb_c_d),
175 _mm_castsi128_ps(rgb_a_b),
176 (3 << 6) | (1 << 4) | (3 << 2) | 1));
177 __m128i r_abcd = _mm_castps_si128(
178 _mm_shuffle_ps(
179 _mm_castsi128_ps(rgb_c_d),
180 _mm_castsi128_ps(rgb_a_b),
181 (2 << 6) | (2 << 2)));
182 __m128i y_abcd = _mm_add_epi32(bg_abcd, r_abcd);
183
184 // Down shift back to 8bits range.
185 __m128i y_offset = _mm_load_si128(
186 reinterpret_cast<const __m128i*>(kYOffset));
187 y_abcd = _mm_srai_epi32(y_abcd, FIX_SHIFT);
188 y_abcd = _mm_add_epi32(y_abcd, y_offset);
189 y_abcd = _mm_packs_epi32(y_abcd, y_abcd);
190 y_abcd = _mm_packus_epi16(y_abcd, y_abcd);
191 *reinterpret_cast<uint32*>(y_buf_1) = _mm_cvtsi128_si32(y_abcd);
192 y_buf_1 += 4;
193
194 // Second row 4 pixels.
195 __m128i rgb_row_2 = _mm_loadu_si128(
196 reinterpret_cast<const __m128i*>(rgb_buf_2));
197 __m128i zero_2 = _mm_xor_si128(rgb_row_2, rgb_row_2);
198 __m128i rgb_e_f = _mm_unpackhi_epi8(rgb_row_2, zero_2);
199 __m128i rgb_g_h = _mm_unpacklo_epi8(rgb_row_2, zero_2);
200
201 // Add two rows together.
202 __m128i rgb_ae_bf =
203 _mm_add_epi16(_mm_unpackhi_epi8(rgb_row_1, zero_2), rgb_e_f);
204 __m128i rgb_cg_dh =
205 _mm_add_epi16(_mm_unpacklo_epi8(rgb_row_1, zero_2), rgb_g_h);
206
207 // Multiply add like the previous row.
208 rgb_e_f = _mm_madd_epi16(rgb_e_f, y_table);
209 rgb_g_h = _mm_madd_epi16(rgb_g_h, y_table);
210
211 __m128i bg_efgh = _mm_castps_si128(
212 _mm_shuffle_ps(_mm_castsi128_ps(rgb_g_h),
213 _mm_castsi128_ps(rgb_e_f),
214 (3 << 6) | (1 << 4) | (3 << 2) | 1));
215 __m128i r_efgh = _mm_castps_si128(
216 _mm_shuffle_ps(_mm_castsi128_ps(rgb_g_h),
217 _mm_castsi128_ps(rgb_e_f),
218 (2 << 6) | (2 << 2)));
219 __m128i y_efgh = _mm_add_epi32(bg_efgh, r_efgh);
220 y_efgh = _mm_srai_epi32(y_efgh, FIX_SHIFT);
221 y_efgh = _mm_add_epi32(y_efgh, y_offset);
222 y_efgh = _mm_packs_epi32(y_efgh, y_efgh);
223 y_efgh = _mm_packus_epi16(y_efgh, y_efgh);
224 *reinterpret_cast<uint32*>(y_buf_2) = _mm_cvtsi128_si32(y_efgh);
225 y_buf_2 += 4;
226
227 __m128i rgb_ae_cg = _mm_castps_si128(
228 _mm_shuffle_ps(_mm_castsi128_ps(rgb_cg_dh),
229 _mm_castsi128_ps(rgb_ae_bf),
230 (3 << 6) | (2 << 4) | (3 << 2) | 2));
231 __m128i rgb_bf_dh = _mm_castps_si128(
232 _mm_shuffle_ps(_mm_castsi128_ps(rgb_cg_dh),
233 _mm_castsi128_ps(rgb_ae_bf),
234 (1 << 6) | (1 << 2)));
235
236 // This is a 2x2 subsampling for 2 pixels.
237 __m128i rgb_abef_cdgh = _mm_add_epi16(rgb_ae_cg, rgb_bf_dh);
238
239 // Do a multiply add with U table.
240 __m128i u_a_b = _mm_madd_epi16(
241 rgb_abef_cdgh,
242 _mm_load_si128(
243 reinterpret_cast<const __m128i*>(ConvertRGBAToYUV_kTable + 8)));
244 u_a_b = _mm_add_epi32(_mm_shuffle_epi32(u_a_b, ((3 << 2) | 1)),
245 _mm_shuffle_epi32(u_a_b, (2 << 2)));
246 // Right shift 14 because of 12 from fixed point and 2 from subsampling.
247 u_a_b = _mm_srai_epi32(u_a_b, FIX_SHIFT + 2);
248 __m128i uv_offset = _mm_slli_epi32(y_offset, 3);
249 u_a_b = _mm_add_epi32(u_a_b, uv_offset);
250 u_a_b = _mm_packs_epi32(u_a_b, u_a_b);
251 u_a_b = _mm_packus_epi16(u_a_b, u_a_b);
252 *reinterpret_cast<uint16*>(u_buf) = _mm_extract_epi16(u_a_b, 0);
253 u_buf += 2;
254
255 __m128i v_a_b = _mm_madd_epi16(
256 rgb_abef_cdgh,
257 _mm_load_si128(
258 reinterpret_cast<const __m128i*>(ConvertRGBAToYUV_kTable + 16)));
259 v_a_b = _mm_add_epi32(_mm_shuffle_epi32(v_a_b, ((3 << 2) | 1)),
260 _mm_shuffle_epi32(v_a_b, (2 << 2)));
261 v_a_b = _mm_srai_epi32(v_a_b, FIX_SHIFT + 2);
262 v_a_b = _mm_add_epi32(v_a_b, uv_offset);
263 v_a_b = _mm_packs_epi32(v_a_b, v_a_b);
264 v_a_b = _mm_packus_epi16(v_a_b, v_a_b);
265 *reinterpret_cast<uint16*>(v_buf) = _mm_extract_epi16(v_a_b, 0);
266 v_buf += 2;
267
268 rgb_buf_1 += 16;
269 rgb_buf_2 += 16;
270
271 // Move forward by 4 pixels.
272 width -= 4;
273 }
274
275 // Just use C code to convert the remaining pixels.
276 if (width >= 2) {
277 ConvertRGBToYUV_V2H2(rgb_buf_1, rgb_buf_2, y_buf_1, y_buf_2, u_buf, v_buf);
278 rgb_buf_1 += 8;
279 rgb_buf_2 += 8;
280 y_buf_1 += 2;
281 y_buf_2 += 2;
282 ++u_buf;
283 ++v_buf;
284 width -= 2;
285 }
286
287 if (width)
288 ConvertRGBToYUV_V2H1(rgb_buf_1, rgb_buf_2, y_buf_1, y_buf_2, u_buf, v_buf);
289 }
290
291 extern void ConvertRGB32ToYUV_SSE2(const uint8* rgbframe,
292 uint8* yplane,
293 uint8* uplane,
294 uint8* vplane,
295 int width,
296 int height,
297 int rgbstride,
298 int ystride,
299 int uvstride) {
300 while (height >= 2) {
301 ConvertRGB32ToYUVRow_SSE2(rgbframe,
302 rgbframe + rgbstride,
303 yplane,
304 yplane + ystride,
305 uplane,
306 vplane,
307 width);
308 rgbframe += 2 * rgbstride;
309 yplane += 2 * ystride;
310 uplane += uvstride;
311 vplane += uvstride;
312 height -= 2;
313 }
314
315 if (!height)
316 return;
317
318 // Handle the last row.
319 while (width >= 2) {
320 ConvertRGBToYUV_V1H2(rgbframe, yplane, uplane, vplane);
321 rgbframe += 8;
322 yplane += 2;
323 ++uplane;
324 ++vplane;
325 width -= 2;
326 }
327
328 if (width)
329 ConvertRGBToYUV_V1H1(rgbframe, yplane, uplane, vplane);
330 }
331
332 void ConvertRGB32ToYUV_SSE2_Reference(const uint8* rgbframe,
333 uint8* yplane,
334 uint8* uplane,
335 uint8* vplane,
336 int width,
337 int height,
338 int rgbstride,
339 int ystride,
340 int uvstride) {
341 while (height >= 2) {
342 int i = 0;
343
344 // Convert a 2x2 block.
345 while (i + 2 <= width) {
346 ConvertRGBToYUV_V2H2(rgbframe + i * 4,
347 rgbframe + rgbstride + i * 4,
348 yplane + i,
349 yplane + ystride + i,
350 uplane + i / 2,
351 vplane + i / 2);
352 i += 2;
353 }
354
355 // Convert the last pixel of two rows.
356 if (i < width) {
357 ConvertRGBToYUV_V2H1(rgbframe + i * 4,
358 rgbframe + rgbstride + i * 4,
359 yplane + i,
360 yplane + ystride + i,
361 uplane + i / 2,
362 vplane + i / 2);
363 }
364
365 rgbframe += 2 * rgbstride;
366 yplane += 2 * ystride;
367 uplane += uvstride;
368 vplane += uvstride;
369 height -= 2;
370 }
371
372 if (!height)
373 return;
374
375 // Handle the last row.
376 while (width >= 2) {
377 ConvertRGBToYUV_V1H2(rgbframe, yplane, uplane, vplane);
378 rgbframe += 8;
379 yplane += 2;
380 ++uplane;
381 ++vplane;
382 width -= 2;
383 }
384
385 // Handle the last pixel in the last row.
386 if (width)
387 ConvertRGBToYUV_V1H1(rgbframe, yplane, uplane, vplane);
388 }
389
390 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698