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:
parent
b772d784b2
commit
e25abacc18
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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, "");
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue