summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJosé Fonseca <jfonseca@vmware.com>2009-08-02 13:52:40 +0100
committerJosé Fonseca <jfonseca@vmware.com>2009-08-29 09:21:22 +0100
commit272dadbe4ebeaeb4f942c0f3c2fd140285b0457c (patch)
tree23ffe9a1f1675139211a4c2c4f176a6420170f5f
parentf478b6fe76452ee910fa9d13ea4b78637a04e747 (diff)
llvmpipe: Introduce a custom typing system.
Straightforward representation of floating-point/fixed-point/integer, normalized/scaled, signed/unsigned SIMD vector types.
-rw-r--r--src/gallium/drivers/llvmpipe/lp_bld.h2
-rw-r--r--src/gallium/drivers/llvmpipe/lp_bld_arit.c145
-rw-r--r--src/gallium/drivers/llvmpipe/lp_bld_arit.h92
-rw-r--r--src/gallium/drivers/llvmpipe/lp_bld_blend.c19
-rw-r--r--src/gallium/drivers/llvmpipe/lp_test_blend.c12
5 files changed, 228 insertions, 42 deletions
diff --git a/src/gallium/drivers/llvmpipe/lp_bld.h b/src/gallium/drivers/llvmpipe/lp_bld.h
index 86571374b6..e9d9c25a80 100644
--- a/src/gallium/drivers/llvmpipe/lp_bld.h
+++ b/src/gallium/drivers/llvmpipe/lp_bld.h
@@ -46,6 +46,7 @@
struct pipe_blend_state;
+union lp_type;
/**
@@ -134,6 +135,7 @@ lp_build_logicop(LLVMBuilderRef builder,
LLVMValueRef
lp_build_blend(LLVMBuilderRef builder,
const struct pipe_blend_state *blend,
+ union lp_type type,
LLVMValueRef src,
LLVMValueRef dst,
LLVMValueRef const_,
diff --git a/src/gallium/drivers/llvmpipe/lp_bld_arit.c b/src/gallium/drivers/llvmpipe/lp_bld_arit.c
index 7e5af284aa..b5b4148ac2 100644
--- a/src/gallium/drivers/llvmpipe/lp_bld_arit.c
+++ b/src/gallium/drivers/llvmpipe/lp_bld_arit.c
@@ -50,56 +50,143 @@
#include "lp_bld_arit.h"
+LLVMTypeRef
+lp_build_elem_type(union lp_type type)
+{
+ if (type.kind == LP_TYPE_FLOAT) {
+ assert(type.sign);
+ switch(type.width) {
+ case 32:
+ return LLVMFloatType();
+ break;
+ case 64:
+ return LLVMDoubleType();
+ break;
+ default:
+ assert(0);
+ return LLVMFloatType();
+ }
+ }
+ else {
+ return LLVMIntType(type.width);
+ }
+}
+
+
+LLVMTypeRef
+lp_build_vec_type(union lp_type type)
+{
+ LLVMTypeRef elem_type = lp_build_elem_type(type);
+ return LLVMVectorType(elem_type, type.length);
+}
+
+
+/**
+ * This function is a mirrot of lp_build_elem_type() above.
+ *
+ * XXX: I'm not sure if it wouldn't be easier/efficient to just recreate the
+ * type and check for identity.
+ */
+boolean
+lp_check_elem_type(union lp_type type, LLVMTypeRef elem_type)
+{
+ LLVMTypeKind elem_kind = LLVMGetTypeKind(elem_type);
+
+ if (type.kind == LP_TYPE_FLOAT) {
+ switch(type.width) {
+ case 32:
+ if(elem_kind != LLVMFloatTypeKind)
+ return FALSE;
+ break;
+ case 64:
+ if(elem_kind != LLVMDoubleTypeKind)
+ return FALSE;
+ break;
+ default:
+ assert(0);
+ return FALSE;
+ }
+ }
+ else {
+ if(elem_kind != LLVMIntegerTypeKind)
+ return FALSE;
+
+ if(LLVMGetIntTypeWidth(elem_type) != type.width)
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+boolean
+lp_check_vec_type(union lp_type type, LLVMTypeRef vec_type)
+{
+ LLVMTypeRef elem_type;
+
+ if(LLVMGetTypeKind(vec_type) != LLVMVectorTypeKind)
+ return FALSE;
+
+ if(LLVMGetVectorSize(vec_type) != type.length)
+ return FALSE;
+
+ elem_type = LLVMGetElementType(vec_type);
+
+ return lp_check_elem_type(type, elem_type);
+}
+
+
LLVMValueRef
-lp_build_const_aos(LLVMTypeRef type,
+lp_build_const_aos(union lp_type type,
double r, double g, double b, double a,
const unsigned char *swizzle)
{
const unsigned char default_swizzle[4] = {0, 1, 2, 3};
LLVMTypeRef elem_type;
- unsigned num_elems;
- unsigned elem_width;
- LLVMValueRef elems[LP_MAX_VECTOR_SIZE];
- double scale;
+ LLVMValueRef elems[LP_MAX_VECTOR_LENGTH];
unsigned i;
- num_elems = LLVMGetVectorSize(type);
- assert(num_elems % 4 == 0);
- assert(num_elems < LP_MAX_VECTOR_SIZE);
+ assert(type.length % 4 == 0);
+ assert(type.length < LP_MAX_VECTOR_LENGTH);
- elem_type = LLVMGetElementType(type);
+ elem_type = lp_build_elem_type(type);
if(swizzle == NULL)
swizzle = default_swizzle;
- switch(LLVMGetTypeKind(elem_type)) {
- case LLVMFloatTypeKind:
- for(i = 0; i < num_elems; i += 4) {
+ if(type.kind == LP_TYPE_FLOAT) {
+ for(i = 0; i < type.length; i += 4) {
elems[i + swizzle[0]] = LLVMConstReal(elem_type, r);
elems[i + swizzle[1]] = LLVMConstReal(elem_type, g);
elems[i + swizzle[2]] = LLVMConstReal(elem_type, b);
elems[i + swizzle[3]] = LLVMConstReal(elem_type, a);
}
- break;
-
- case LLVMIntegerTypeKind:
- elem_width = LLVMGetIntTypeWidth(elem_type);
- assert(elem_width <= 32);
- scale = (double)((1 << elem_width) - 1);
- for(i = 0; i < num_elems; i += 4) {
- elems[i + swizzle[0]] = LLVMConstInt(elem_type, r*scale + 0.5, 0);
- elems[i + swizzle[1]] = LLVMConstInt(elem_type, g*scale + 0.5, 0);
- elems[i + swizzle[2]] = LLVMConstInt(elem_type, b*scale + 0.5, 0);
- elems[i + swizzle[3]] = LLVMConstInt(elem_type, a*scale + 0.5, 0);
+ }
+ else {
+ unsigned shift;
+ long long llscale;
+ double dscale;
+
+ if(type.kind == LP_TYPE_FIXED)
+ shift = type.width/2;
+ else if(type.norm)
+ shift = type.sign ? type.width - 1 : type.width;
+ else
+ shift = 0;
+
+ llscale = (long long)1 << shift;
+ dscale = (double)llscale;
+ assert((long long)dscale == llscale);
+
+ for(i = 0; i < type.length; i += 4) {
+ elems[i + swizzle[0]] = LLVMConstInt(elem_type, r*dscale + 0.5, 0);
+ elems[i + swizzle[1]] = LLVMConstInt(elem_type, g*dscale + 0.5, 0);
+ elems[i + swizzle[2]] = LLVMConstInt(elem_type, b*dscale + 0.5, 0);
+ elems[i + swizzle[3]] = LLVMConstInt(elem_type, a*dscale + 0.5, 0);
}
- break;
-
- default:
- assert(0);
- return LLVMGetUndef(type);
}
- return LLVMConstVector(elems, num_elems);
+ return LLVMConstVector(elems, type.length);
}
diff --git a/src/gallium/drivers/llvmpipe/lp_bld_arit.h b/src/gallium/drivers/llvmpipe/lp_bld_arit.h
index 0d2636aed9..f9a61be516 100644
--- a/src/gallium/drivers/llvmpipe/lp_bld_arit.h
+++ b/src/gallium/drivers/llvmpipe/lp_bld_arit.h
@@ -25,6 +25,14 @@
*
**************************************************************************/
+/**
+ * @file
+ * Helper arithmetic functions.
+ *
+ * @author Jose Fonseca <jfonseca@vmware.com>
+ */
+
+
#ifndef LP_BLD_ARIT_H
#define LP_BLD_ARIT_H
@@ -32,7 +40,87 @@
#include <llvm-c/Core.h>
-#define LP_MAX_VECTOR_SIZE 16
+#define LP_MAX_VECTOR_LENGTH 16
+
+
+/*
+ * Types
+ */
+
+
+enum lp_type_kind {
+ LP_TYPE_INTEGER = 0,
+ LP_TYPE_FLOAT = 1,
+ LP_TYPE_FIXED = 2
+};
+
+
+/**
+ * The LLVM type system can't conveniently express all the things we care about
+ * on the types used for intermediate computations, such as signed vs unsigned,
+ * normalized values, or fixed point.
+ */
+union lp_type {
+ struct {
+ /**
+ * Integer. floating-point, or fixed point as established by the
+ * lp_build_type_kind enum above.
+ */
+ unsigned kind:2;
+
+ /**
+ * Whether it can represent negative values or not.
+ *
+ * Floating point values
+ */
+ unsigned sign:1;
+
+ /**
+ * Whether values are normalized to fit [0, 1] interval, or [-1, 1] interval for
+ * signed types.
+ *
+ * For integer types
+ *
+ * It makes no sense to use this with fixed point values.
+ */
+ unsigned norm:1;
+
+ /**
+ * Element width.
+ *
+ * For fixed point values, the fixed point is assumed to be at half the width.
+ */
+ unsigned width:14;
+
+ /**
+ * Vector length.
+ *
+ * width*length should be a power of two greater or equal to height.
+ *
+ * Several functions can only cope with vectors of length up to
+ * LP_MAX_VECTOR_LENGTH, so you may need to increase that value if you
+ * want to represent bigger vectors.
+ */
+ unsigned length:14;
+ };
+ uint32_t value;
+};
+
+
+LLVMTypeRef
+lp_build_elem_type(union lp_type type);
+
+
+LLVMTypeRef
+lp_build_vec_type(union lp_type type);
+
+
+boolean
+lp_check_elem_type(union lp_type type, LLVMTypeRef elem_type);
+
+
+boolean
+lp_check_vec_type(union lp_type type, LLVMTypeRef vec_type);
/*
@@ -40,7 +128,7 @@
*/
LLVMValueRef
-lp_build_const_aos(LLVMTypeRef type,
+lp_build_const_aos(union lp_type type,
double r, double g, double b, double a,
const unsigned char *swizzle);
diff --git a/src/gallium/drivers/llvmpipe/lp_bld_blend.c b/src/gallium/drivers/llvmpipe/lp_bld_blend.c
index d708047202..48d1e0028a 100644
--- a/src/gallium/drivers/llvmpipe/lp_bld_blend.c
+++ b/src/gallium/drivers/llvmpipe/lp_bld_blend.c
@@ -182,7 +182,7 @@ lp_build_blend_swizzle(struct lp_build_blend_values *values,
unsigned alpha_swizzle,
unsigned n)
{
- LLVMValueRef swizzles[LP_MAX_VECTOR_SIZE];
+ LLVMValueRef swizzles[LP_MAX_VECTOR_LENGTH];
unsigned i, j;
if(rgb == alpha) {
@@ -268,6 +268,7 @@ lp_build_blend_func(struct lp_build_blend_values *values,
LLVMValueRef
lp_build_blend(LLVMBuilderRef builder,
const struct pipe_blend_state *blend,
+ union lp_type type,
LLVMValueRef src,
LLVMValueRef dst,
LLVMValueRef const_,
@@ -276,19 +277,17 @@ lp_build_blend(LLVMBuilderRef builder,
struct lp_build_blend_values values;
LLVMValueRef src_term;
LLVMValueRef dst_term;
- LLVMTypeRef type;
- unsigned n;
+ LLVMTypeRef vec_type;
- type = LLVMTypeOf(src);
- n = LLVMGetVectorSize(type);
+ vec_type = lp_build_vec_type(type);
/*
* Compute constants
*/
memset(&values, 0, sizeof values);
values.builder = builder;
- values.undef = LLVMGetUndef(type);
- values.zero = LLVMConstNull(type);
+ values.undef = LLVMGetUndef(vec_type);
+ values.zero = LLVMConstNull(vec_type);
values.one = lp_build_const_aos(type, 1.0, 1.0, 1.0, 1.0, NULL);
values.src = src;
@@ -299,8 +298,8 @@ lp_build_blend(LLVMBuilderRef builder,
* combinations it is possible to reorder the operations and therefor saving
* some instructions. */
- src_term = lp_build_blend_factor(&values, src, blend->rgb_src_factor, blend->alpha_src_factor, alpha_swizzle, n);
- dst_term = lp_build_blend_factor(&values, dst, blend->rgb_dst_factor, blend->alpha_dst_factor, alpha_swizzle, n);
+ src_term = lp_build_blend_factor(&values, src, blend->rgb_src_factor, blend->alpha_src_factor, alpha_swizzle, type.length);
+ dst_term = lp_build_blend_factor(&values, dst, blend->rgb_dst_factor, blend->alpha_dst_factor, alpha_swizzle, type.length);
if(blend->rgb_func == blend->alpha_func) {
return lp_build_blend_func(&values, blend->rgb_func, src_term, dst_term);
@@ -314,6 +313,6 @@ lp_build_blend(LLVMBuilderRef builder,
rgb = lp_build_blend_func(&values, blend->rgb_func, src_term, dst_term);
alpha = lp_build_blend_func(&values, blend->alpha_func, src_term, dst_term);
- return lp_build_blend_swizzle(&values, rgb, alpha, LP_BUILD_BLEND_SWIZZLE_RGBA, alpha_swizzle, n);
+ return lp_build_blend_swizzle(&values, rgb, alpha, LP_BUILD_BLEND_SWIZZLE_RGBA, alpha_swizzle, type.length);
}
}
diff --git a/src/gallium/drivers/llvmpipe/lp_test_blend.c b/src/gallium/drivers/llvmpipe/lp_test_blend.c
index 1621fa79ab..3becac1871 100644
--- a/src/gallium/drivers/llvmpipe/lp_test_blend.c
+++ b/src/gallium/drivers/llvmpipe/lp_test_blend.c
@@ -52,6 +52,7 @@
#include "util/u_math.h"
#include "lp_bld.h"
+#include "lp_bld_arit.h"
unsigned verbose = 0;
@@ -64,6 +65,8 @@ static LLVMValueRef
add_blend_test(LLVMModuleRef module,
const struct pipe_blend_state *blend)
{
+ union lp_type type;
+
LLVMTypeRef args[4];
LLVMValueRef func;
LLVMValueRef src_ptr;
@@ -77,6 +80,13 @@ add_blend_test(LLVMModuleRef module,
LLVMValueRef const_;
LLVMValueRef res;
+ type.value = 0;
+ type.kind = LP_TYPE_FLOAT;
+ type.sign = TRUE;
+ type.norm = TRUE;
+ type.width = 32;
+ type.length = 4;
+
args[0] = LLVMPointerType(LLVMVectorType(LLVMFloatType(), 4), 0);
args[1] = LLVMPointerType(LLVMVectorType(LLVMFloatType(), 4), 0);
args[2] = LLVMPointerType(LLVMVectorType(LLVMFloatType(), 4), 0);
@@ -96,7 +106,7 @@ add_blend_test(LLVMModuleRef module,
dst = LLVMBuildLoad(builder, dst_ptr, "dst");
const_ = LLVMBuildLoad(builder, const_ptr, "const");
- res = lp_build_blend(builder, blend, src, dst, const_, 3);
+ res = lp_build_blend(builder, blend, type, src, dst, const_, 3);
LLVMSetValueName(res, "res");