gallivm: Fix format manipulation for big-endian

This patch fixes various format manipulation for big-endian
architectures.

Reviewed-by: Roland Scheidegger <sroland@vmware.com>
Reviewed-by: Jose Fonseca <jfonseca@vmware.com>
This commit is contained in:
Adhemerval Zanella 2012-11-22 13:48:45 -06:00 committed by José Fonseca
parent b772d784b2
commit e25abacc18
5 changed files with 145 additions and 12 deletions

View File

@ -49,6 +49,7 @@
#include "lp_bld_gather.h"
#include "lp_bld_debug.h"
#include "lp_bld_format.h"
#include "lp_bld_intr.h"
/**
@ -171,6 +172,10 @@ lp_build_unpack_arith_rgba_aos(struct gallivm_state *gallivm,
* matches floating point size */
assert (LLVMTypeOf(packed) == LLVMInt32TypeInContext(gallivm->context));
#ifdef PIPE_ARCH_BIG_ENDIAN
packed = lp_build_bswap(gallivm, packed, lp_type_uint(32));
#endif
/* Broadcast the packed value to all four channels
* before: packed = BGRA
* after: packed = {BGRA, BGRA, BGRA, BGRA}
@ -396,6 +401,8 @@ lp_build_fetch_rgba_aos(struct gallivm_state *gallivm,
format_desc->block.bits <= type.width * 4 &&
util_is_power_of_two(format_desc->block.bits)) {
LLVMValueRef packed;
LLVMTypeRef dst_vec_type = lp_build_vec_type(gallivm, type);
unsigned vec_len = type.width * type.length;
/*
* The format matches the type (apart of a swizzle) so no need for
@ -406,11 +413,14 @@ lp_build_fetch_rgba_aos(struct gallivm_state *gallivm,
format_desc->block.bits, type.width*4,
base_ptr, offset);
assert(format_desc->block.bits <= type.width * type.length);
packed = LLVMBuildBitCast(gallivm->builder, packed,
lp_build_vec_type(gallivm, type), "");
assert(format_desc->block.bits <= vec_len);
packed = LLVMBuildBitCast(gallivm->builder, packed, dst_vec_type, "");
#ifdef PIPE_ARCH_BIG_ENDIAN
if (type.floating)
packed = lp_build_bswap_vec(gallivm, packed, type,
lp_type_float_vec(type.width, vec_len));
#endif
return lp_build_format_swizzle_aos(format_desc, &bld, packed);
}

View File

@ -32,11 +32,67 @@
#include "lp_bld_type.h"
#include "lp_bld_conv.h"
#include "lp_bld_pack.h"
#include "lp_bld_intr.h"
#include "lp_bld_gather.h"
#include "util/u_memory.h"
#include "util/u_format.h"
#include "pipe/p_state.h"
#ifdef PIPE_ARCH_BIG_ENDIAN
static LLVMValueRef
lp_build_read_int_bswap(struct gallivm_state *gallivm,
LLVMValueRef base_ptr,
unsigned src_width,
LLVMTypeRef src_type,
unsigned i,
LLVMTypeRef dst_type)
{
LLVMBuilderRef builder = gallivm->builder;
LLVMValueRef index = lp_build_const_int32(gallivm, i);
LLVMValueRef ptr = LLVMBuildGEP(builder, base_ptr, &index, 1, "");
LLVMValueRef res = LLVMBuildLoad(builder, ptr, "");
res = lp_build_bswap(gallivm, res, lp_type_uint(src_width));
return LLVMBuildBitCast(builder, res, dst_type, "");
}
static LLVMValueRef
lp_build_fetch_read_big_endian(struct gallivm_state *gallivm,
struct lp_type src_type,
LLVMValueRef base_ptr)
{
LLVMBuilderRef builder = gallivm->builder;
unsigned src_width = src_type.width;
unsigned length = src_type.length;
LLVMTypeRef src_elem_type = LLVMIntTypeInContext(gallivm->context, src_width);
LLVMTypeRef dst_elem_type = lp_build_elem_type (gallivm, src_type);
LLVMTypeRef src_ptr_type = LLVMPointerType(src_elem_type, 0);
LLVMValueRef res;
base_ptr = LLVMBuildPointerCast(builder, base_ptr, src_ptr_type, "");
if (length == 1) {
/* Scalar */
res = lp_build_read_int_bswap(gallivm, base_ptr, src_width, src_elem_type,
0, dst_elem_type);
} else {
/* Vector */
LLVMTypeRef dst_vec_type = LLVMVectorType(dst_elem_type, length);
unsigned i;
res = LLVMGetUndef(dst_vec_type);
for (i = 0; i < length; ++i) {
LLVMValueRef index = lp_build_const_int32(gallivm, i);
LLVMValueRef elem = lp_build_read_int_bswap(gallivm, base_ptr, src_width,
src_elem_type, i, dst_elem_type);
res = LLVMBuildInsertElement(builder, res, elem, index, "");
}
}
return res;
}
#endif
/**
* @brief lp_build_fetch_rgba_aos_array
*
@ -65,12 +121,14 @@ lp_build_fetch_rgba_aos_array(struct gallivm_state *gallivm,
src_vec_type = lp_build_vec_type(gallivm, src_type);
/* Read whole vector from memory, unaligned */
if (!res) {
ptr = LLVMBuildGEP(builder, base_ptr, &offset, 1, "");
ptr = LLVMBuildPointerCast(builder, ptr, LLVMPointerType(src_vec_type, 0), "");
res = LLVMBuildLoad(builder, ptr, "");
lp_set_load_alignment(res, src_type.width / 8);
}
ptr = LLVMBuildGEP(builder, base_ptr, &offset, 1, "");
#ifdef PIPE_ARCH_BIG_ENDIAN
res = lp_build_fetch_read_big_endian(gallivm, src_type, ptr);
#else
ptr = LLVMBuildPointerCast(builder, ptr, LLVMPointerType(src_vec_type, 0), "");
res = LLVMBuildLoad(builder, ptr, "");
lp_set_load_alignment(res, src_type.width / 8);
#endif
/* Truncate doubles to float */
if (src_type.floating && src_type.width == 64) {

View File

@ -72,9 +72,15 @@ uyvy_to_yuv_soa(struct gallivm_state *gallivm,
assert(lp_check_value(type, i));
/*
* Little endian:
* y = (uyvy >> (16*i + 8)) & 0xff
* u = (uyvy ) & 0xff
* v = (uyvy >> 16 ) & 0xff
*
* Big endian:
* y = (uyvy >> (-16*i + 16)) & 0xff
* u = (uyvy >> 24) & 0xff
* v = (uyvy >> 8) & 0xff
*/
#if defined(PIPE_ARCH_X86) || defined(PIPE_ARCH_X86_64)
@ -98,13 +104,23 @@ uyvy_to_yuv_soa(struct gallivm_state *gallivm,
#endif
{
LLVMValueRef shift;
#ifdef PIPE_ARCH_LITTLE_ENDIAN
shift = LLVMBuildMul(builder, i, lp_build_const_int_vec(gallivm, type, 16), "");
shift = LLVMBuildAdd(builder, shift, lp_build_const_int_vec(gallivm, type, 8), "");
#else
shift = LLVMBuildMul(builder, i, lp_build_const_int_vec(gallivm, type, -16), "");
shift = LLVMBuildAdd(builder, shift, lp_build_const_int_vec(gallivm, type, 16), "");
#endif
*y = LLVMBuildLShr(builder, packed, shift, "");
}
#ifdef PIPE_ARCH_LITTLE_ENDIAN
*u = packed;
*v = LLVMBuildLShr(builder, packed, lp_build_const_int_vec(gallivm, type, 16), "");
#else
*u = LLVMBuildLShr(builder, packed, lp_build_const_int_vec(gallivm, type, 24), "");
*v = LLVMBuildLShr(builder, packed, lp_build_const_int_vec(gallivm, type, 8), "");
#endif
mask = lp_build_const_int_vec(gallivm, type, 0xff);
@ -140,9 +156,15 @@ yuyv_to_yuv_soa(struct gallivm_state *gallivm,
assert(lp_check_value(type, i));
/*
* Little endian:
* y = (yuyv >> 16*i) & 0xff
* u = (yuyv >> 8 ) & 0xff
* v = (yuyv >> 24 ) & 0xff
*
* Big endian:
* y = (yuyv >> (-16*i + 24) & 0xff
* u = (yuyv >> 16) & 0xff
* v = (yuyv) & 0xff
*/
#if defined(PIPE_ARCH_X86) || defined(PIPE_ARCH_X86_64)
@ -165,12 +187,22 @@ yuyv_to_yuv_soa(struct gallivm_state *gallivm,
#endif
{
LLVMValueRef shift;
#ifdef PIPE_ARCH_LITTLE_ENDIAN
shift = LLVMBuildMul(builder, i, lp_build_const_int_vec(gallivm, type, 16), "");
#else
shift = LLVMBuildMul(builder, i, lp_build_const_int_vec(gallivm, type, -16), "");
shift = LLVMBuildAdd(builder, shift, lp_build_const_int_vec(gallivm, type, 24), "");
#endif
*y = LLVMBuildLShr(builder, packed, shift, "");
}
#ifdef PIPE_ARCH_LITTLE_ENDIAN
*u = LLVMBuildLShr(builder, packed, lp_build_const_int_vec(gallivm, type, 8), "");
*v = LLVMBuildLShr(builder, packed, lp_build_const_int_vec(gallivm, type, 24), "");
#else
*u = LLVMBuildLShr(builder, packed, lp_build_const_int_vec(gallivm, type, 16), "");
*v = packed;
#endif
mask = lp_build_const_int_vec(gallivm, type, 0xff);
@ -302,10 +334,17 @@ rgb_to_rgba_aos(struct gallivm_state *gallivm,
* Make a 4 x unorm8 vector
*/
#ifdef PIPE_ARCH_LITTLE_ENDIAN
r = r;
g = LLVMBuildShl(builder, g, lp_build_const_int_vec(gallivm, type, 8), "");
b = LLVMBuildShl(builder, b, lp_build_const_int_vec(gallivm, type, 16), "");
a = lp_build_const_int_vec(gallivm, type, 0xff000000);
#else
r = LLVMBuildShl(builder, r, lp_build_const_int_vec(gallivm, type, 24), "");
g = LLVMBuildShl(builder, g, lp_build_const_int_vec(gallivm, type, 16), "");
b = LLVMBuildShl(builder, b, lp_build_const_int_vec(gallivm, type, 8), "");
a = lp_build_const_int_vec(gallivm, type, 0x000000ff);
#endif
rgba = r;
rgba = LLVMBuildOr(builder, rgba, g, "");

View File

@ -32,6 +32,7 @@
#include "lp_bld_format.h"
#include "lp_bld_gather.h"
#include "lp_bld_init.h"
#include "lp_bld_intr.h"
/**
@ -92,10 +93,15 @@ lp_build_gather_elem(struct gallivm_state *gallivm,
res = LLVMBuildLoad(gallivm->builder, ptr, "");
assert(src_width <= dst_width);
if (src_width > dst_width)
if (src_width > dst_width) {
res = LLVMBuildTrunc(gallivm->builder, res, dst_elem_type, "");
if (src_width < dst_width)
} else if (src_width < dst_width) {
res = LLVMBuildZExt(gallivm->builder, res, dst_elem_type, "");
#ifdef PIPE_ARCH_BIG_ENDIAN
res = LLVMBuildShl(gallivm->builder, res,
LLVMConstInt(dst_elem_type, dst_width - src_width, 0), "");
#endif
}
return res;
}

View File

@ -431,10 +431,16 @@ lp_build_swizzle_aos(struct lp_build_context *bld,
*
* For example, this will convert BGRA to RGBA by doing
*
* Little endian:
* rgba = (bgra & 0x00ff0000) >> 16
* | (bgra & 0xff00ff00)
* | (bgra & 0x000000ff) << 16
*
* Big endian:A
* rgba = (bgra & 0x0000ff00) << 16
* | (bgra & 0x00ff00ff)
* | (bgra & 0xff000000) >> 16
*
* This is necessary not only for faster cause, but because X86 backend
* will refuse shuffles of <4 x i8> vectors
*/
@ -479,7 +485,11 @@ lp_build_swizzle_aos(struct lp_build_context *bld,
/* FIXME: big endian */
if (swizzles[chan] < 4 &&
chan - swizzles[chan] == shift) {
#ifdef PIPE_ARCH_LITTLE_ENDIAN
mask |= ((1ULL << type.width) - 1) << (swizzles[chan] * type.width);
#else
mask |= ((1ULL << type.width) - 1) << (type4.width - type.width) >> (swizzles[chan] * type.width);
#endif
}
}
@ -492,11 +502,21 @@ lp_build_swizzle_aos(struct lp_build_context *bld,
masked = LLVMBuildAnd(builder, a,
lp_build_const_int_vec(bld->gallivm, type4, mask), "");
if (shift > 0) {
#ifdef PIPE_ARCH_LITTLE_ENDIAN
shifted = LLVMBuildShl(builder, masked,
lp_build_const_int_vec(bld->gallivm, type4, shift*type.width), "");
#else
shifted = LLVMBuildLShr(builder, masked,
lp_build_const_int_vec(bld->gallivm, type4, shift*type.width), "");
#endif
} else if (shift < 0) {
#ifdef PIPE_ARCH_LITTLE_ENDIAN
shifted = LLVMBuildLShr(builder, masked,
lp_build_const_int_vec(bld->gallivm, type4, -shift*type.width), "");
#else
shifted = LLVMBuildShl(builder, masked,
lp_build_const_int_vec(bld->gallivm, type4, -shift*type.width), "");
#endif
} else {
shifted = masked;
}