From 3cc4301c146e2a6e680939456ea3df4ec2d12e3e Mon Sep 17 00:00:00 2001 From: José Fonseca Date: Fri, 2 Jul 2010 11:40:22 +0100 Subject: gallivm: Code generate YUV format unpacking. --- src/gallium/auxiliary/gallivm/lp_bld_format.h | 12 + src/gallium/auxiliary/gallivm/lp_bld_format_aos.c | 22 ++ src/gallium/auxiliary/gallivm/lp_bld_format_yuv.c | 395 ++++++++++++++++++++++ 3 files changed, 429 insertions(+) create mode 100644 src/gallium/auxiliary/gallivm/lp_bld_format_yuv.c (limited to 'src/gallium/auxiliary/gallivm') diff --git a/src/gallium/auxiliary/gallivm/lp_bld_format.h b/src/gallium/auxiliary/gallivm/lp_bld_format.h index c335ca46a7..a853d7ca41 100644 --- a/src/gallium/auxiliary/gallivm/lp_bld_format.h +++ b/src/gallium/auxiliary/gallivm/lp_bld_format.h @@ -94,5 +94,17 @@ lp_build_fetch_rgba_soa(LLVMBuilderRef builder, LLVMValueRef j, LLVMValueRef rgba_out[4]); +/* + * YUV + */ + + +LLVMValueRef +lp_build_unpack_subsampled_to_rgba_aos(LLVMBuilderRef builder, + const struct util_format_description *format_desc, + unsigned n, + LLVMValueRef packed, + LLVMValueRef i, + LLVMValueRef j); #endif /* !LP_BLD_FORMAT_H */ diff --git a/src/gallium/auxiliary/gallivm/lp_bld_format_aos.c b/src/gallium/auxiliary/gallivm/lp_bld_format_aos.c index bec2a80d76..cc72a31d72 100644 --- a/src/gallium/auxiliary/gallivm/lp_bld_format_aos.c +++ b/src/gallium/auxiliary/gallivm/lp_bld_format_aos.c @@ -366,6 +366,8 @@ lp_build_pack_rgba_aos(LLVMBuilderRef builder, } + + /** * Fetch a pixel into a 4 float AoS. * @@ -429,6 +431,26 @@ lp_build_fetch_rgba_aos(LLVMBuilderRef builder, return lp_build_unpack_rgba_aos(format_desc, &bld, packed); } } + else if (format_desc->layout == UTIL_FORMAT_LAYOUT_SUBSAMPLED) { + LLVMValueRef packed; + LLVMValueRef rgba; + + ptr = LLVMBuildBitCast(builder, ptr, + LLVMPointerType(LLVMInt32Type(), 0), + "packed_ptr"); + + packed = LLVMBuildLoad(builder, ptr, "packed"); + + rgba = lp_build_unpack_subsampled_to_rgba_aos(builder, format_desc, + 1, packed, i, j); + + lp_build_conv(builder, + lp_unorm8_vec4_type(), + type, + &rgba, 1, &rgba, 1); + + return rgba; + } else if (format_desc->fetch_rgba_float) { /* * Fallback to calling util_format_description::fetch_rgba_float. diff --git a/src/gallium/auxiliary/gallivm/lp_bld_format_yuv.c b/src/gallium/auxiliary/gallivm/lp_bld_format_yuv.c new file mode 100644 index 0000000000..5fe2ab6e3b --- /dev/null +++ b/src/gallium/auxiliary/gallivm/lp_bld_format_yuv.c @@ -0,0 +1,395 @@ +/************************************************************************** + * + * Copyright 2010 VMware, Inc. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + **************************************************************************/ + + +/** + * @file + * YUV pixel format manipulation. + * + * @author Jose Fonseca + */ + + +#include "util/u_format.h" +#include "util/u_memory.h" +#include "util/u_math.h" +#include "util/u_string.h" + +#include "lp_bld_arit.h" +#include "lp_bld_init.h" +#include "lp_bld_type.h" +#include "lp_bld_const.h" +#include "lp_bld_conv.h" +#include "lp_bld_format.h" + + +/** + * Extract Y, U, V channels from packed UYVY. + * @param packed is a vector with the packed UYVY blocks + * @param i is a vector with the x pixel coordinate (0 or 1) + */ +static void +uyvy_to_yuv_soa(LLVMBuilderRef builder, + unsigned n, + LLVMValueRef packed, + LLVMValueRef i, + LLVMValueRef *y, + LLVMValueRef *u, + LLVMValueRef *v) +{ + struct lp_type type; + LLVMValueRef shift, mask; + + memset(&type, 0, sizeof type); + type.width = 32; + type.length = n; + + assert(lp_check_value(type, packed)); + assert(lp_check_value(type, i)); + + /* + * y = (uyvy >> 16*i) & 0xff + * u = (uyvy ) & 0xff + * v = (uyvy >> 16 ) & 0xff + */ + + shift = LLVMBuildMul(builder, i, lp_build_const_int_vec(type, 16), ""); + shift = LLVMBuildAdd(builder, shift, lp_build_const_int_vec(type, 8), ""); + *y = LLVMBuildLShr(builder, packed, shift, ""); + *u = packed; + *v = LLVMBuildLShr(builder, packed, lp_build_const_int_vec(type, 16), ""); + + mask = lp_build_const_int_vec(type, 0xff); + + *y = LLVMBuildAnd(builder, *y, mask, "y"); + *u = LLVMBuildAnd(builder, *u, mask, "u"); + *v = LLVMBuildAnd(builder, *v, mask, "v"); +} + + +/** + * Extract Y, U, V channels from packed YUYV. + * @param packed is a vector with the packed YUYV blocks + * @param i is a vector with the x pixel coordinate (0 or 1) + */ +static void +yuyv_to_yuv_soa(LLVMBuilderRef builder, + unsigned n, + LLVMValueRef packed, + LLVMValueRef i, + LLVMValueRef *y, + LLVMValueRef *u, + LLVMValueRef *v) +{ + struct lp_type type; + LLVMValueRef shift, mask; + + memset(&type, 0, sizeof type); + type.width = 32; + type.length = n; + + assert(lp_check_value(type, packed)); + assert(lp_check_value(type, i)); + + /* + * y = (yuyv >> 16*i) & 0xff + * u = (yuyv >> 8 ) & 0xff + * v = (yuyv >> 24 ) & 0xff + */ + + shift = LLVMBuildMul(builder, i, lp_build_const_int_vec(type, 16), ""); + *y = LLVMBuildLShr(builder, packed, shift, ""); + *u = LLVMBuildLShr(builder, packed, lp_build_const_int_vec(type, 8), ""); + *v = LLVMBuildLShr(builder, packed, lp_build_const_int_vec(type, 24), ""); + + mask = lp_build_const_int_vec(type, 0xff); + + *y = LLVMBuildAnd(builder, *y, mask, "y"); + *u = LLVMBuildAnd(builder, *u, mask, "u"); + *v = LLVMBuildAnd(builder, *v, mask, "v"); +} + + +static INLINE void +yuv_to_rgb_soa(LLVMBuilderRef builder, + unsigned n, + LLVMValueRef y, LLVMValueRef u, LLVMValueRef v, + LLVMValueRef *r, LLVMValueRef *g, LLVMValueRef *b) +{ + struct lp_type type; + struct lp_build_context bld; + + LLVMValueRef c0; + LLVMValueRef c8; + LLVMValueRef c16; + LLVMValueRef c128; + LLVMValueRef c255; + + LLVMValueRef cy; + LLVMValueRef cug; + LLVMValueRef cub; + LLVMValueRef cvr; + LLVMValueRef cvg; + + memset(&type, 0, sizeof type); + type.sign = TRUE; + type.width = 32; + type.length = n; + + lp_build_context_init(&bld, builder, type); + + assert(lp_check_value(type, y)); + assert(lp_check_value(type, u)); + assert(lp_check_value(type, v)); + + /* + * Constants + */ + + c0 = lp_build_const_int_vec(type, 0); + c8 = lp_build_const_int_vec(type, 8); + c16 = lp_build_const_int_vec(type, 16); + c128 = lp_build_const_int_vec(type, 128); + c255 = lp_build_const_int_vec(type, 255); + + cy = lp_build_const_int_vec(type, 298); + cug = lp_build_const_int_vec(type, -100); + cub = lp_build_const_int_vec(type, 516); + cvr = lp_build_const_int_vec(type, 409); + cvg = lp_build_const_int_vec(type, -208); + + /* + * y -= 16; + * u -= 128; + * v -= 128; + */ + + y = LLVMBuildSub(builder, y, c16, ""); + u = LLVMBuildSub(builder, u, c128, ""); + v = LLVMBuildSub(builder, v, c128, ""); + + /* + * r = 298 * _y + 409 * _v + 128; + * g = 298 * _y - 100 * _u - 208 * _v + 128; + * b = 298 * _y + 516 * _u + 128; + */ + + y = LLVMBuildMul(builder, y, cy, ""); + y = LLVMBuildAdd(builder, y, c128, ""); + + *r = LLVMBuildMul(builder, v, cvr, ""); + *g = LLVMBuildAdd(builder, + LLVMBuildMul(builder, u, cug, ""), + LLVMBuildMul(builder, v, cvg, ""), + ""); + *b = LLVMBuildMul(builder, u, cub, ""); + + *r = LLVMBuildAdd(builder, *r, y, ""); + *g = LLVMBuildAdd(builder, *g, y, ""); + *b = LLVMBuildAdd(builder, *b, y, ""); + + /* + * r >>= 8; + * g >>= 8; + * b >>= 8; + */ + + *r = LLVMBuildAShr(builder, *r, c8, "r"); + *g = LLVMBuildAShr(builder, *g, c8, "g"); + *b = LLVMBuildAShr(builder, *b, c8, "b"); + + /* + * Clamp + */ + + *r = lp_build_clamp(&bld, *r, c0, c255); + *g = lp_build_clamp(&bld, *g, c0, c255); + *b = lp_build_clamp(&bld, *b, c0, c255); +} + + +static LLVMValueRef +rgb_to_rgba_aos(LLVMBuilderRef builder, + unsigned n, + LLVMValueRef r, LLVMValueRef g, LLVMValueRef b) +{ + struct lp_type type; + LLVMValueRef a; + LLVMValueRef rgba; + + memset(&type, 0, sizeof type); + type.sign = TRUE; + type.width = 32; + type.length = n; + + assert(lp_check_value(type, r)); + assert(lp_check_value(type, g)); + assert(lp_check_value(type, b)); + + /* + * Make a 4 x unorm8 vector + */ + + r = r; + g = LLVMBuildShl(builder, g, lp_build_const_int_vec(type, 8), ""); + b = LLVMBuildShl(builder, b, lp_build_const_int_vec(type, 16), ""); + a = lp_build_const_int_vec(type, 0xff000000); + + rgba = r; + rgba = LLVMBuildOr(builder, rgba, g, ""); + rgba = LLVMBuildOr(builder, rgba, b, ""); + rgba = LLVMBuildOr(builder, rgba, a, ""); + + rgba = LLVMBuildBitCast(builder, rgba, + LLVMVectorType(LLVMInt8Type(), 4*n), ""); + + return rgba; +} + + +/** + * Convert from packed UYVY to <4n x i8> RGBA AoS + */ +static LLVMValueRef +uyvy_to_rgba_aos(LLVMBuilderRef builder, + unsigned n, + LLVMValueRef packed, + LLVMValueRef i) +{ + LLVMValueRef y, u, v; + LLVMValueRef r, g, b; + LLVMValueRef rgba; + + uyvy_to_yuv_soa(builder, n, packed, i, &y, &u, &v); + yuv_to_rgb_soa(builder, n, y, u, v, &r, &g, &b); + rgba = rgb_to_rgba_aos(builder, n, r, g, b); + + return rgba; +} + + +/** + * Convert from packed YUYV to <4n x i8> RGBA AoS + */ +static LLVMValueRef +yuyv_to_rgba_aos(LLVMBuilderRef builder, + unsigned n, + LLVMValueRef packed, + LLVMValueRef i) +{ + LLVMValueRef y, u, v; + LLVMValueRef r, g, b; + LLVMValueRef rgba; + + yuyv_to_yuv_soa(builder, n, packed, i, &y, &u, &v); + yuv_to_rgb_soa(builder, n, y, u, v, &r, &g, &b); + rgba = rgb_to_rgba_aos(builder, n, r, g, b); + + return rgba; +} + + +/** + * Convert from packed RG_BG to <4n x i8> RGBA AoS + */ +static LLVMValueRef +rgbg_to_rgba_aos(LLVMBuilderRef builder, + unsigned n, + LLVMValueRef packed, + LLVMValueRef i) +{ + LLVMValueRef r, g, b; + LLVMValueRef rgba; + + uyvy_to_yuv_soa(builder, n, packed, i, &g, &r, &b); + rgba = rgb_to_rgba_aos(builder, n, r, g, b); + + return rgba; +} + + +/** + * Convert from packed GR_GB to <4n x i8> RGBA AoS + */ +static LLVMValueRef +grgb_to_rgba_aos(LLVMBuilderRef builder, + unsigned n, + LLVMValueRef packed, + LLVMValueRef i) +{ + LLVMValueRef r, g, b; + LLVMValueRef rgba; + + yuyv_to_yuv_soa(builder, n, packed, i, &g, &r, &b); + rgba = rgb_to_rgba_aos(builder, n, r, g, b); + + return rgba; +} + + +/** + * @param n is the number of pixels processed + * @param packed is a vector with the packed YUYV blocks + * @param i is a vector with the x pixel coordinate (0 or 1) + * @return a <4*n x i8> vector with the pixel RGBA values in AoS + */ +LLVMValueRef +lp_build_unpack_subsampled_to_rgba_aos(LLVMBuilderRef builder, + const struct util_format_description *format_desc, + unsigned n, + LLVMValueRef packed, + LLVMValueRef i, + LLVMValueRef j) +{ + LLVMValueRef rgba; + + assert(format_desc->layout == UTIL_FORMAT_LAYOUT_SUBSAMPLED); + + (void)j; + + switch (format_desc->format) { + case PIPE_FORMAT_UYVY: + rgba = uyvy_to_rgba_aos(builder, n, packed, i); + break; + case PIPE_FORMAT_YUYV: + rgba = yuyv_to_rgba_aos(builder, n, packed, i); + break; + case PIPE_FORMAT_R8G8_B8G8_UNORM: + rgba = rgbg_to_rgba_aos(builder, n, packed, i); + break; + case PIPE_FORMAT_G8R8_G8B8_UNORM: + rgba = grgb_to_rgba_aos(builder, n, packed, i); + break; + default: + assert(0); + rgba = LLVMGetUndef(LLVMVectorType(LLVMInt8Type(), 4*n)); + break; + } + + return rgba; +} + -- cgit v1.2.3