summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAdhemerval Zanella <[email protected]>2012-11-22 13:48:45 -0600
committerJosé Fonseca <[email protected]>2012-11-29 11:54:18 +0000
commite25abacc1883f1b2e09c32230e35ffae7df5e61b (patch)
tree6afc27a9233c351b69d378f88e6da1952d785779 /src
parentb772d784b25771ff939e3c0c87fdf0d8053827be (diff)
gallivm: Fix format manipulation for big-endian
This patch fixes various format manipulation for big-endian architectures. Reviewed-by: Roland Scheidegger <[email protected]> Reviewed-by: Jose Fonseca <[email protected]>
Diffstat (limited to 'src')
-rw-r--r--src/gallium/auxiliary/gallivm/lp_bld_format_aos.c18
-rw-r--r--src/gallium/auxiliary/gallivm/lp_bld_format_aos_array.c70
-rw-r--r--src/gallium/auxiliary/gallivm/lp_bld_format_yuv.c39
-rw-r--r--src/gallium/auxiliary/gallivm/lp_bld_gather.c10
-rw-r--r--src/gallium/auxiliary/gallivm/lp_bld_swizzle.c20
5 files changed, 145 insertions, 12 deletions
diff --git a/src/gallium/auxiliary/gallivm/lp_bld_format_aos.c b/src/gallium/auxiliary/gallivm/lp_bld_format_aos.c
index 9591bcfb2c7..750d54524c6 100644
--- a/src/gallium/auxiliary/gallivm/lp_bld_format_aos.c
+++ b/src/gallium/auxiliary/gallivm/lp_bld_format_aos.c
@@ -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);
}
diff --git a/src/gallium/auxiliary/gallivm/lp_bld_format_aos_array.c b/src/gallium/auxiliary/gallivm/lp_bld_format_aos_array.c
index 24fee640a82..cf296173c3e 100644
--- a/src/gallium/auxiliary/gallivm/lp_bld_format_aos_array.c
+++ b/src/gallium/auxiliary/gallivm/lp_bld_format_aos_array.c
@@ -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) {
diff --git a/src/gallium/auxiliary/gallivm/lp_bld_format_yuv.c b/src/gallium/auxiliary/gallivm/lp_bld_format_yuv.c
index f77eb1212b1..e542abce0cc 100644
--- a/src/gallium/auxiliary/gallivm/lp_bld_format_yuv.c
+++ b/src/gallium/auxiliary/gallivm/lp_bld_format_yuv.c
@@ -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, "");
diff --git a/src/gallium/auxiliary/gallivm/lp_bld_gather.c b/src/gallium/auxiliary/gallivm/lp_bld_gather.c
index 1bdd4e4845a..eefb23a946f 100644
--- a/src/gallium/auxiliary/gallivm/lp_bld_gather.c
+++ b/src/gallium/auxiliary/gallivm/lp_bld_gather.c
@@ -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;
}
diff --git a/src/gallium/auxiliary/gallivm/lp_bld_swizzle.c b/src/gallium/auxiliary/gallivm/lp_bld_swizzle.c
index ae4033b6086..08d817a28f5 100644
--- a/src/gallium/auxiliary/gallivm/lp_bld_swizzle.c
+++ b/src/gallium/auxiliary/gallivm/lp_bld_swizzle.c
@@ -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;
}