1 /**************************************************************************
2 *
3 * Copyright 2010 VMware, Inc.
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
18 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20 * USE OR OTHER DEALINGS IN THE SOFTWARE.
21 *
22 * The above copyright notice and this permission notice (including the
23 * next paragraph) shall be included in all copies or substantial portions
24 * of the Software.
25 *
26 **************************************************************************/
27
28
29 /**
30 * @file
31 * YUV pixel format manipulation.
32 *
33 * @author Jose Fonseca <jfonseca@vmware.com>
34 */
35
36
37 #include "util/u_format.h"
38 #include "util/u_cpu_detect.h"
39
40 #include "lp_bld_arit.h"
41 #include "lp_bld_type.h"
42 #include "lp_bld_const.h"
43 #include "lp_bld_conv.h"
44 #include "lp_bld_gather.h"
45 #include "lp_bld_format.h"
46 #include "lp_bld_init.h"
47 #include "lp_bld_logic.h"
48
49 /**
50 * Extract Y, U, V channels from packed UYVY.
51 * @param packed is a <n x i32> vector with the packed UYVY blocks
52 * @param i is a <n x i32> vector with the x pixel coordinate (0 or 1)
53 */
54 static void
uyvy_to_yuv_soa(struct gallivm_state * gallivm,unsigned n,LLVMValueRef packed,LLVMValueRef i,LLVMValueRef * y,LLVMValueRef * u,LLVMValueRef * v)55 uyvy_to_yuv_soa(struct gallivm_state *gallivm,
56 unsigned n,
57 LLVMValueRef packed,
58 LLVMValueRef i,
59 LLVMValueRef *y,
60 LLVMValueRef *u,
61 LLVMValueRef *v)
62 {
63 LLVMBuilderRef builder = gallivm->builder;
64 struct lp_type type;
65 LLVMValueRef mask;
66
67 memset(&type, 0, sizeof type);
68 type.width = 32;
69 type.length = n;
70
71 assert(lp_check_value(type, packed));
72 assert(lp_check_value(type, i));
73
74 /*
75 * y = (uyvy >> (16*i + 8)) & 0xff
76 * u = (uyvy ) & 0xff
77 * v = (uyvy >> 16 ) & 0xff
78 */
79
80 #if defined(PIPE_ARCH_X86) || defined(PIPE_ARCH_X86_64)
81 /*
82 * Avoid shift with per-element count.
83 * No support on x86, gets translated to roughly 5 instructions
84 * per element. Didn't measure performance but cuts shader size
85 * by quite a bit (less difference if cpu has no sse4.1 support).
86 */
87 if (util_cpu_caps.has_sse2 && n > 1) {
88 LLVMValueRef sel, tmp, tmp2;
89 struct lp_build_context bld32;
90
91 lp_build_context_init(&bld32, gallivm, type);
92
93 tmp = LLVMBuildLShr(builder, packed, lp_build_const_int_vec(gallivm, type, 8), "");
94 tmp2 = LLVMBuildLShr(builder, tmp, lp_build_const_int_vec(gallivm, type, 16), "");
95 sel = lp_build_compare(gallivm, type, PIPE_FUNC_EQUAL, i, lp_build_const_int_vec(gallivm, type, 0));
96 *y = lp_build_select(&bld32, sel, tmp, tmp2);
97 } else
98 #endif
99 {
100 LLVMValueRef shift;
101 shift = LLVMBuildMul(builder, i, lp_build_const_int_vec(gallivm, type, 16), "");
102 shift = LLVMBuildAdd(builder, shift, lp_build_const_int_vec(gallivm, type, 8), "");
103 *y = LLVMBuildLShr(builder, packed, shift, "");
104 }
105
106 *u = packed;
107 *v = LLVMBuildLShr(builder, packed, lp_build_const_int_vec(gallivm, type, 16), "");
108
109 mask = lp_build_const_int_vec(gallivm, type, 0xff);
110
111 *y = LLVMBuildAnd(builder, *y, mask, "y");
112 *u = LLVMBuildAnd(builder, *u, mask, "u");
113 *v = LLVMBuildAnd(builder, *v, mask, "v");
114 }
115
116
117 /**
118 * Extract Y, U, V channels from packed YUYV.
119 * @param packed is a <n x i32> vector with the packed YUYV blocks
120 * @param i is a <n x i32> vector with the x pixel coordinate (0 or 1)
121 */
122 static void
yuyv_to_yuv_soa(struct gallivm_state * gallivm,unsigned n,LLVMValueRef packed,LLVMValueRef i,LLVMValueRef * y,LLVMValueRef * u,LLVMValueRef * v)123 yuyv_to_yuv_soa(struct gallivm_state *gallivm,
124 unsigned n,
125 LLVMValueRef packed,
126 LLVMValueRef i,
127 LLVMValueRef *y,
128 LLVMValueRef *u,
129 LLVMValueRef *v)
130 {
131 LLVMBuilderRef builder = gallivm->builder;
132 struct lp_type type;
133 LLVMValueRef mask;
134
135 memset(&type, 0, sizeof type);
136 type.width = 32;
137 type.length = n;
138
139 assert(lp_check_value(type, packed));
140 assert(lp_check_value(type, i));
141
142 /*
143 * y = (yuyv >> 16*i) & 0xff
144 * u = (yuyv >> 8 ) & 0xff
145 * v = (yuyv >> 24 ) & 0xff
146 */
147
148 #if defined(PIPE_ARCH_X86) || defined(PIPE_ARCH_X86_64)
149 /*
150 * Avoid shift with per-element count.
151 * No support on x86, gets translated to roughly 5 instructions
152 * per element. Didn't measure performance but cuts shader size
153 * by quite a bit (less difference if cpu has no sse4.1 support).
154 */
155 if (util_cpu_caps.has_sse2 && n > 1) {
156 LLVMValueRef sel, tmp;
157 struct lp_build_context bld32;
158
159 lp_build_context_init(&bld32, gallivm, type);
160
161 tmp = LLVMBuildLShr(builder, packed, lp_build_const_int_vec(gallivm, type, 16), "");
162 sel = lp_build_compare(gallivm, type, PIPE_FUNC_EQUAL, i, lp_build_const_int_vec(gallivm, type, 0));
163 *y = lp_build_select(&bld32, sel, packed, tmp);
164 } else
165 #endif
166 {
167 LLVMValueRef shift;
168 shift = LLVMBuildMul(builder, i, lp_build_const_int_vec(gallivm, type, 16), "");
169 *y = LLVMBuildLShr(builder, packed, shift, "");
170 }
171
172 *u = LLVMBuildLShr(builder, packed, lp_build_const_int_vec(gallivm, type, 8), "");
173 *v = LLVMBuildLShr(builder, packed, lp_build_const_int_vec(gallivm, type, 24), "");
174
175 mask = lp_build_const_int_vec(gallivm, type, 0xff);
176
177 *y = LLVMBuildAnd(builder, *y, mask, "y");
178 *u = LLVMBuildAnd(builder, *u, mask, "u");
179 *v = LLVMBuildAnd(builder, *v, mask, "v");
180 }
181
182
183 static INLINE void
yuv_to_rgb_soa(struct gallivm_state * gallivm,unsigned n,LLVMValueRef y,LLVMValueRef u,LLVMValueRef v,LLVMValueRef * r,LLVMValueRef * g,LLVMValueRef * b)184 yuv_to_rgb_soa(struct gallivm_state *gallivm,
185 unsigned n,
186 LLVMValueRef y, LLVMValueRef u, LLVMValueRef v,
187 LLVMValueRef *r, LLVMValueRef *g, LLVMValueRef *b)
188 {
189 LLVMBuilderRef builder = gallivm->builder;
190 struct lp_type type;
191 struct lp_build_context bld;
192
193 LLVMValueRef c0;
194 LLVMValueRef c8;
195 LLVMValueRef c16;
196 LLVMValueRef c128;
197 LLVMValueRef c255;
198
199 LLVMValueRef cy;
200 LLVMValueRef cug;
201 LLVMValueRef cub;
202 LLVMValueRef cvr;
203 LLVMValueRef cvg;
204
205 memset(&type, 0, sizeof type);
206 type.sign = TRUE;
207 type.width = 32;
208 type.length = n;
209
210 lp_build_context_init(&bld, gallivm, type);
211
212 assert(lp_check_value(type, y));
213 assert(lp_check_value(type, u));
214 assert(lp_check_value(type, v));
215
216 /*
217 * Constants
218 */
219
220 c0 = lp_build_const_int_vec(gallivm, type, 0);
221 c8 = lp_build_const_int_vec(gallivm, type, 8);
222 c16 = lp_build_const_int_vec(gallivm, type, 16);
223 c128 = lp_build_const_int_vec(gallivm, type, 128);
224 c255 = lp_build_const_int_vec(gallivm, type, 255);
225
226 cy = lp_build_const_int_vec(gallivm, type, 298);
227 cug = lp_build_const_int_vec(gallivm, type, -100);
228 cub = lp_build_const_int_vec(gallivm, type, 516);
229 cvr = lp_build_const_int_vec(gallivm, type, 409);
230 cvg = lp_build_const_int_vec(gallivm, type, -208);
231
232 /*
233 * y -= 16;
234 * u -= 128;
235 * v -= 128;
236 */
237
238 y = LLVMBuildSub(builder, y, c16, "");
239 u = LLVMBuildSub(builder, u, c128, "");
240 v = LLVMBuildSub(builder, v, c128, "");
241
242 /*
243 * r = 298 * _y + 409 * _v + 128;
244 * g = 298 * _y - 100 * _u - 208 * _v + 128;
245 * b = 298 * _y + 516 * _u + 128;
246 */
247
248 y = LLVMBuildMul(builder, y, cy, "");
249 y = LLVMBuildAdd(builder, y, c128, "");
250
251 *r = LLVMBuildMul(builder, v, cvr, "");
252 *g = LLVMBuildAdd(builder,
253 LLVMBuildMul(builder, u, cug, ""),
254 LLVMBuildMul(builder, v, cvg, ""),
255 "");
256 *b = LLVMBuildMul(builder, u, cub, "");
257
258 *r = LLVMBuildAdd(builder, *r, y, "");
259 *g = LLVMBuildAdd(builder, *g, y, "");
260 *b = LLVMBuildAdd(builder, *b, y, "");
261
262 /*
263 * r >>= 8;
264 * g >>= 8;
265 * b >>= 8;
266 */
267
268 *r = LLVMBuildAShr(builder, *r, c8, "r");
269 *g = LLVMBuildAShr(builder, *g, c8, "g");
270 *b = LLVMBuildAShr(builder, *b, c8, "b");
271
272 /*
273 * Clamp
274 */
275
276 *r = lp_build_clamp(&bld, *r, c0, c255);
277 *g = lp_build_clamp(&bld, *g, c0, c255);
278 *b = lp_build_clamp(&bld, *b, c0, c255);
279 }
280
281
282 static LLVMValueRef
rgb_to_rgba_aos(struct gallivm_state * gallivm,unsigned n,LLVMValueRef r,LLVMValueRef g,LLVMValueRef b)283 rgb_to_rgba_aos(struct gallivm_state *gallivm,
284 unsigned n,
285 LLVMValueRef r, LLVMValueRef g, LLVMValueRef b)
286 {
287 LLVMBuilderRef builder = gallivm->builder;
288 struct lp_type type;
289 LLVMValueRef a;
290 LLVMValueRef rgba;
291
292 memset(&type, 0, sizeof type);
293 type.sign = TRUE;
294 type.width = 32;
295 type.length = n;
296
297 assert(lp_check_value(type, r));
298 assert(lp_check_value(type, g));
299 assert(lp_check_value(type, b));
300
301 /*
302 * Make a 4 x unorm8 vector
303 */
304
305 r = r;
306 g = LLVMBuildShl(builder, g, lp_build_const_int_vec(gallivm, type, 8), "");
307 b = LLVMBuildShl(builder, b, lp_build_const_int_vec(gallivm, type, 16), "");
308 a = lp_build_const_int_vec(gallivm, type, 0xff000000);
309
310 rgba = r;
311 rgba = LLVMBuildOr(builder, rgba, g, "");
312 rgba = LLVMBuildOr(builder, rgba, b, "");
313 rgba = LLVMBuildOr(builder, rgba, a, "");
314
315 rgba = LLVMBuildBitCast(builder, rgba,
316 LLVMVectorType(LLVMInt8TypeInContext(gallivm->context), 4*n), "");
317
318 return rgba;
319 }
320
321
322 /**
323 * Convert from <n x i32> packed UYVY to <4n x i8> RGBA AoS
324 */
325 static LLVMValueRef
uyvy_to_rgba_aos(struct gallivm_state * gallivm,unsigned n,LLVMValueRef packed,LLVMValueRef i)326 uyvy_to_rgba_aos(struct gallivm_state *gallivm,
327 unsigned n,
328 LLVMValueRef packed,
329 LLVMValueRef i)
330 {
331 LLVMValueRef y, u, v;
332 LLVMValueRef r, g, b;
333 LLVMValueRef rgba;
334
335 uyvy_to_yuv_soa(gallivm, n, packed, i, &y, &u, &v);
336 yuv_to_rgb_soa(gallivm, n, y, u, v, &r, &g, &b);
337 rgba = rgb_to_rgba_aos(gallivm, n, r, g, b);
338
339 return rgba;
340 }
341
342
343 /**
344 * Convert from <n x i32> packed YUYV to <4n x i8> RGBA AoS
345 */
346 static LLVMValueRef
yuyv_to_rgba_aos(struct gallivm_state * gallivm,unsigned n,LLVMValueRef packed,LLVMValueRef i)347 yuyv_to_rgba_aos(struct gallivm_state *gallivm,
348 unsigned n,
349 LLVMValueRef packed,
350 LLVMValueRef i)
351 {
352 LLVMValueRef y, u, v;
353 LLVMValueRef r, g, b;
354 LLVMValueRef rgba;
355
356 yuyv_to_yuv_soa(gallivm, n, packed, i, &y, &u, &v);
357 yuv_to_rgb_soa(gallivm, n, y, u, v, &r, &g, &b);
358 rgba = rgb_to_rgba_aos(gallivm, n, r, g, b);
359
360 return rgba;
361 }
362
363
364 /**
365 * Convert from <n x i32> packed RG_BG to <4n x i8> RGBA AoS
366 */
367 static LLVMValueRef
rgbg_to_rgba_aos(struct gallivm_state * gallivm,unsigned n,LLVMValueRef packed,LLVMValueRef i)368 rgbg_to_rgba_aos(struct gallivm_state *gallivm,
369 unsigned n,
370 LLVMValueRef packed,
371 LLVMValueRef i)
372 {
373 LLVMValueRef r, g, b;
374 LLVMValueRef rgba;
375
376 uyvy_to_yuv_soa(gallivm, n, packed, i, &g, &r, &b);
377 rgba = rgb_to_rgba_aos(gallivm, n, r, g, b);
378
379 return rgba;
380 }
381
382
383 /**
384 * Convert from <n x i32> packed GR_GB to <4n x i8> RGBA AoS
385 */
386 static LLVMValueRef
grgb_to_rgba_aos(struct gallivm_state * gallivm,unsigned n,LLVMValueRef packed,LLVMValueRef i)387 grgb_to_rgba_aos(struct gallivm_state *gallivm,
388 unsigned n,
389 LLVMValueRef packed,
390 LLVMValueRef i)
391 {
392 LLVMValueRef r, g, b;
393 LLVMValueRef rgba;
394
395 yuyv_to_yuv_soa(gallivm, n, packed, i, &g, &r, &b);
396 rgba = rgb_to_rgba_aos(gallivm, n, r, g, b);
397
398 return rgba;
399 }
400
401 /**
402 * Convert from <n x i32> packed GR_BR to <4n x i8> RGBA AoS
403 */
404 static LLVMValueRef
grbr_to_rgba_aos(struct gallivm_state * gallivm,unsigned n,LLVMValueRef packed,LLVMValueRef i)405 grbr_to_rgba_aos(struct gallivm_state *gallivm,
406 unsigned n,
407 LLVMValueRef packed,
408 LLVMValueRef i)
409 {
410 LLVMValueRef r, g, b;
411 LLVMValueRef rgba;
412
413 uyvy_to_yuv_soa(gallivm, n, packed, i, &r, &g, &b);
414 rgba = rgb_to_rgba_aos(gallivm, n, r, g, b);
415
416 return rgba;
417 }
418
419
420 /**
421 * Convert from <n x i32> packed RG_RB to <4n x i8> RGBA AoS
422 */
423 static LLVMValueRef
rgrb_to_rgba_aos(struct gallivm_state * gallivm,unsigned n,LLVMValueRef packed,LLVMValueRef i)424 rgrb_to_rgba_aos(struct gallivm_state *gallivm,
425 unsigned n,
426 LLVMValueRef packed,
427 LLVMValueRef i)
428 {
429 LLVMValueRef r, g, b;
430 LLVMValueRef rgba;
431
432 yuyv_to_yuv_soa(gallivm, n, packed, i, &r, &g, &b);
433 rgba = rgb_to_rgba_aos(gallivm, n, r, g, b);
434
435 return rgba;
436 }
437
438 /**
439 * @param n is the number of pixels processed
440 * @param packed is a <n x i32> vector with the packed YUYV blocks
441 * @param i is a <n x i32> vector with the x pixel coordinate (0 or 1)
442 * @return a <4*n x i8> vector with the pixel RGBA values in AoS
443 */
444 LLVMValueRef
lp_build_fetch_subsampled_rgba_aos(struct gallivm_state * gallivm,const struct util_format_description * format_desc,unsigned n,LLVMValueRef base_ptr,LLVMValueRef offset,LLVMValueRef i,LLVMValueRef j)445 lp_build_fetch_subsampled_rgba_aos(struct gallivm_state *gallivm,
446 const struct util_format_description *format_desc,
447 unsigned n,
448 LLVMValueRef base_ptr,
449 LLVMValueRef offset,
450 LLVMValueRef i,
451 LLVMValueRef j)
452 {
453 LLVMValueRef packed;
454 LLVMValueRef rgba;
455
456 assert(format_desc->layout == UTIL_FORMAT_LAYOUT_SUBSAMPLED);
457 assert(format_desc->block.bits == 32);
458 assert(format_desc->block.width == 2);
459 assert(format_desc->block.height == 1);
460
461 packed = lp_build_gather(gallivm, n, 32, 32, base_ptr, offset);
462
463 (void)j;
464
465 switch (format_desc->format) {
466 case PIPE_FORMAT_UYVY:
467 rgba = uyvy_to_rgba_aos(gallivm, n, packed, i);
468 break;
469 case PIPE_FORMAT_YUYV:
470 rgba = yuyv_to_rgba_aos(gallivm, n, packed, i);
471 break;
472 case PIPE_FORMAT_R8G8_B8G8_UNORM:
473 rgba = rgbg_to_rgba_aos(gallivm, n, packed, i);
474 break;
475 case PIPE_FORMAT_G8R8_G8B8_UNORM:
476 rgba = grgb_to_rgba_aos(gallivm, n, packed, i);
477 break;
478 case PIPE_FORMAT_G8R8_B8R8_UNORM:
479 rgba = grbr_to_rgba_aos(gallivm, n, packed, i);
480 break;
481 case PIPE_FORMAT_R8G8_R8B8_UNORM:
482 rgba = rgrb_to_rgba_aos(gallivm, n, packed, i);
483 break;
484 default:
485 assert(0);
486 rgba = LLVMGetUndef(LLVMVectorType(LLVMInt8TypeInContext(gallivm->context), 4*n));
487 break;
488 }
489
490 return rgba;
491 }
492
493