summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrian <brian@yutani.localnet.net>2007-01-31 16:34:54 -0700
committerBrian <brian@yutani.localnet.net>2007-01-31 16:34:54 -0700
commitb63c100677c76bb20a1871ea15298ca708acd04f (patch)
tree531db5e2db8f313a6273548f766db850a37b9548
parent309d5b665051179b7e135d7329da1ea45bfeb8e5 (diff)
Overhaul handling of writemasks/swizzling. This fixes two problem cases:
vec2 v; v.x = v.y = 1.0; // chained assignment vec4 v; v.zx = vec2(a,b); // swizzled writemask
-rw-r--r--src/mesa/shader/prog_instruction.h1
-rw-r--r--src/mesa/shader/prog_print.c2
-rw-r--r--src/mesa/shader/slang/slang_assemble_constructor.c17
-rw-r--r--src/mesa/shader/slang/slang_codegen.c198
-rw-r--r--src/mesa/shader/slang/slang_emit.c69
-rw-r--r--src/mesa/shader/slang/slang_ir.h6
6 files changed, 197 insertions, 96 deletions
diff --git a/src/mesa/shader/prog_instruction.h b/src/mesa/shader/prog_instruction.h
index 3e88b4e627..f018de82b3 100644
--- a/src/mesa/shader/prog_instruction.h
+++ b/src/mesa/shader/prog_instruction.h
@@ -49,6 +49,7 @@
#define SWIZZLE_W 3
#define SWIZZLE_ZERO 4 /**< For SWZ instruction only */
#define SWIZZLE_ONE 5 /**< For SWZ instruction only */
+#define SWIZZLE_NIL 7 /**< used during shader code gen (undefined value) */
/*@}*/
#define MAKE_SWIZZLE4(a,b,c,d) (((a)<<0) | ((b)<<3) | ((c)<<6) | ((d)<<9))
diff --git a/src/mesa/shader/prog_print.c b/src/mesa/shader/prog_print.c
index 78ce752f2a..63ff84e345 100644
--- a/src/mesa/shader/prog_print.c
+++ b/src/mesa/shader/prog_print.c
@@ -86,7 +86,7 @@ program_file_string(enum register_file f)
static const char *
swizzle_string(GLuint swizzle, GLuint negateBase, GLboolean extended)
{
- static const char swz[] = "xyzw01";
+ static const char swz[] = "xyzw01?!";
static char s[20];
GLuint i = 0;
diff --git a/src/mesa/shader/slang/slang_assemble_constructor.c b/src/mesa/shader/slang/slang_assemble_constructor.c
index a411597130..e045f2f6d2 100644
--- a/src/mesa/shader/slang/slang_assemble_constructor.c
+++ b/src/mesa/shader/slang/slang_assemble_constructor.c
@@ -31,7 +31,7 @@
#include "imports.h"
#include "slang_assemble.h"
#include "slang_storage.h"
-
+#include "prog_instruction.h"
/**
@@ -46,9 +46,14 @@ _slang_is_swizzle(const char *field, GLuint rows, slang_swizzle * swz)
GLuint i;
GLboolean xyzw = GL_FALSE, rgba = GL_FALSE, stpq = GL_FALSE;
- /* init to default */
+ /* init to undefined.
+ * We rely on undefined/nil values to distinguish between
+ * regular swizzles and writemasks.
+ * For example, the swizzle ".xNNN" is the writemask ".x".
+ * That's different than the swizzle ".xxxx".
+ */
for (i = 0; i < 4; i++)
- swz->swizzle[i] = i;
+ swz->swizzle[i] = SWIZZLE_NIL;
/* the swizzle can be at most 4-component long */
swz->num_components = slang_string_length(field);
@@ -113,12 +118,6 @@ _slang_is_swizzle(const char *field, GLuint rows, slang_swizzle * swz)
if ((xyzw && rgba) || (xyzw && stpq) || (rgba && stpq))
return GL_FALSE;
- if (swz->num_components == 1) {
- /* smear */
- swz->swizzle[3] =
- swz->swizzle[2] =
- swz->swizzle[1] = swz->swizzle[0];
- }
return GL_TRUE;
}
diff --git a/src/mesa/shader/slang/slang_codegen.c b/src/mesa/shader/slang/slang_codegen.c
index cc2a0b2738..d09883c664 100644
--- a/src/mesa/shader/slang/slang_codegen.c
+++ b/src/mesa/shader/slang/slang_codegen.c
@@ -609,42 +609,6 @@ new_var(slang_assemble_ctx *A, slang_operation *oper, slang_atom name)
}
-static GLboolean
-slang_is_writemask(const char *field, GLuint *mask)
-{
- const GLuint n = 4;
- GLuint i, bit, c = 0;
-
- for (i = 0; i < n && field[i]; i++) {
- switch (field[i]) {
- case 'x':
- case 'r':
- bit = WRITEMASK_X;
- break;
- case 'y':
- case 'g':
- bit = WRITEMASK_Y;
- break;
- case 'z':
- case 'b':
- bit = WRITEMASK_Z;
- break;
- case 'w':
- case 'a':
- bit = WRITEMASK_W;
- break;
- default:
- return GL_FALSE;
- }
- if (c & bit)
- return GL_FALSE;
- c |= bit;
- }
- *mask = c;
- return GL_TRUE;
-}
-
-
/**
* Check if the given function is really just a wrapper for a
* basic assembly instruction.
@@ -1961,6 +1925,111 @@ _slang_gen_variable(slang_assemble_ctx * A, slang_operation *oper)
/**
+ * Some write-masked assignments are simple, but others are hard.
+ * Simple example:
+ * vec3 v;
+ * v.xy = vec2(a, b);
+ * Hard example:
+ * vec3 v;
+ * v.yz = vec2(a, b);
+ * this would have to be transformed/swizzled into:
+ * v.yz = vec2(a, b).*xy* (* = don't care)
+ * Instead, we'll effectively do this:
+ * v.y = vec2(a, b).xxxx;
+ * v.z = vec2(a, b).yyyy;
+ *
+ */
+static GLboolean
+_slang_simple_writemask(GLuint writemask)
+{
+ switch (writemask) {
+ case WRITEMASK_X:
+ case WRITEMASK_Y:
+ case WRITEMASK_Z:
+ case WRITEMASK_W:
+ case WRITEMASK_XY:
+ case WRITEMASK_XYZ:
+ case WRITEMASK_XYZW:
+ return GL_TRUE;
+ default:
+ return GL_FALSE;
+ }
+}
+
+
+/**
+ * Convert the given swizzle into a writemask. In some cases this
+ * is trivial, in other cases, we'll need to also swizzle the right
+ * hand side to put components in the right places.
+ * \param swizzle the incoming swizzle
+ * \param writemaskOut returns the writemask
+ * \param swizzleOut swizzle to apply to the right-hand-side
+ * \return GL_FALSE for simple writemasks, GL_TRUE for non-simple
+ */
+static GLboolean
+swizzle_to_writemask(GLuint swizzle,
+ GLuint *writemaskOut, GLuint *swizzleOut)
+{
+ GLuint mask = 0x0, newSwizzle[4];
+ GLint i, size;
+
+ /* make new dst writemask, compute size */
+ for (i = 0; i < 4; i++) {
+ const GLuint swz = GET_SWZ(swizzle, i);
+ if (swz == SWIZZLE_NIL) {
+ /* end */
+ break;
+ }
+ assert(swz >= 0 && swz <= 3);
+ mask |= (1 << swz);
+ }
+ assert(mask <= 0xf);
+ size = i; /* number of components in mask/swizzle */
+
+ *writemaskOut = mask;
+
+ /* make new src swizzle, by inversion */
+ for (i = 0; i < 4; i++) {
+ newSwizzle[i] = i; /*identity*/
+ }
+ for (i = 0; i < size; i++) {
+ const GLuint swz = GET_SWZ(swizzle, i);
+ newSwizzle[swz] = i;
+ }
+ *swizzleOut = MAKE_SWIZZLE4(newSwizzle[0],
+ newSwizzle[1],
+ newSwizzle[2],
+ newSwizzle[3]);
+
+ if (_slang_simple_writemask(mask)) {
+ if (size >= 1)
+ assert(GET_SWZ(*swizzleOut, 0) == SWIZZLE_X);
+ if (size >= 2)
+ assert(GET_SWZ(*swizzleOut, 1) == SWIZZLE_Y);
+ if (size >= 3)
+ assert(GET_SWZ(*swizzleOut, 2) == SWIZZLE_Z);
+ if (size >= 4)
+ assert(GET_SWZ(*swizzleOut, 3) == SWIZZLE_W);
+ return GL_TRUE;
+ }
+ else
+ return GL_FALSE;
+}
+
+
+static slang_ir_node *
+_slang_gen_swizzle(slang_ir_node *child, GLuint swizzle)
+{
+ slang_ir_node *n = new_node(IR_SWIZZLE, child, NULL);
+ if (n) {
+ n->Store = _slang_new_ir_storage(PROGRAM_UNDEFINED, -1, -1);
+ n->Store->Swizzle = swizzle;
+ }
+ return n;
+}
+
+
+/**
* Generate IR tree for an assignment (=).
*/
static slang_ir_node *
@@ -1982,26 +2051,21 @@ _slang_gen_assignment(slang_assemble_ctx * A, slang_operation *oper)
return n;
}
else {
- slang_operation *lhs = &oper->children[0];
- slang_ir_node *n, *c0, *c1;
- GLuint mask = WRITEMASK_XYZW;
- if (lhs->type == slang_oper_field) {
- /* XXXX this is a hack! */
- /* writemask */
- if (!slang_is_writemask((char *) lhs->a_id, &mask))
- mask = WRITEMASK_XYZW;
- lhs = &lhs->children[0];
- }
- c0 = _slang_gen_operation(A, lhs);
- c1 = _slang_gen_operation(A, &oper->children[1]);
- if (c0 && c1) {
- n = new_node(IR_MOVE, c0, c1);
- /*assert(c1->Opcode != IR_SEQ);*/
- if (c0->Writemask != WRITEMASK_XYZW)
- /* XXX this is a hack! */
- n->Writemask = c0->Writemask;
- else
- n->Writemask = mask;
+ slang_ir_node *n, *lhs, *rhs;
+ lhs = _slang_gen_operation(A, &oper->children[0]);
+ rhs = _slang_gen_operation(A, &oper->children[1]);
+ if (lhs && rhs) {
+ /* convert lhs swizzle into writemask */
+ GLuint writemask, newSwizzle;
+ if (!swizzle_to_writemask(lhs->Store->Swizzle,
+ &writemask, &newSwizzle)) {
+ /* Non-simple writemask, need to swizzle right hand side in
+ * order to put components into the right place.
+ */
+ rhs = _slang_gen_swizzle(rhs, newSwizzle);
+ }
+ n = new_node(IR_MOVE, lhs, rhs);
+ n->Writemask = writemask;
return n;
}
else {
@@ -2011,20 +2075,6 @@ _slang_gen_assignment(slang_assemble_ctx * A, slang_operation *oper)
}
-static slang_ir_node *
-_slang_gen_swizzle(slang_ir_node *child, GLuint swizzle)
-{
- slang_ir_node *n = new_node(IR_SWIZZLE, child, NULL);
- if (n) {
- n->Store = _slang_new_ir_storage(child->Store->File,
- child->Store->Index,
- child->Store->Size);
- n->Store->Swizzle = swizzle;
- }
- return n;
-}
-
-
/**
* Generate IR tree for referencing a field in a struct (or basic vector type)
*/
@@ -2101,13 +2151,17 @@ _slang_gen_subscript(slang_assemble_ctx * A, slang_operation *oper)
index = (GLint) oper->children[1].literal[0];
if (oper->children[1].type != slang_oper_literal_int ||
index >= max) {
- RETURN_ERROR("Invalid array index", 0);
+ RETURN_ERROR("Invalid array index for vector type", 0);
}
n = _slang_gen_operation(A, &oper->children[0]);
if (n) {
/* use swizzle to access the element */
- n = _slang_gen_swizzle(n, SWIZZLE_X + index);
+ GLuint swizzle = MAKE_SWIZZLE4(SWIZZLE_X + index,
+ SWIZZLE_NIL,
+ SWIZZLE_NIL,
+ SWIZZLE_NIL);
+ n = _slang_gen_swizzle(n, swizzle);
/*n->Store = _slang_clone_ir_storage_swz(n->Store, */
n->Writemask = WRITEMASK_X << index;
}
diff --git a/src/mesa/shader/slang/slang_emit.c b/src/mesa/shader/slang/slang_emit.c
index 1c945fa0ba..0626f7a643 100644
--- a/src/mesa/shader/slang/slang_emit.c
+++ b/src/mesa/shader/slang/slang_emit.c
@@ -424,7 +424,12 @@ storage_to_src_reg(struct prog_src_register *src, const slang_ir_storage *st)
if (st->Swizzle != SWIZZLE_NOOP)
src->Swizzle = st->Swizzle;
else
- src->Swizzle = defaultSwizzle[st->Size - 1];
+ src->Swizzle = defaultSwizzle[st->Size - 1]; /*XXX really need this?*/
+
+ assert(GET_SWZ(src->Swizzle, 0) != SWIZZLE_NIL);
+ assert(GET_SWZ(src->Swizzle, 1) != SWIZZLE_NIL);
+ assert(GET_SWZ(src->Swizzle, 2) != SWIZZLE_NIL);
+ assert(GET_SWZ(src->Swizzle, 3) != SWIZZLE_NIL);
}
@@ -975,6 +980,57 @@ emit_cond(slang_var_table *vt, slang_ir_node *n, struct gl_program *prog)
}
+/**
+ * Remove any SWIZZLE_NIL terms from given swizzle mask (smear prev term).
+ * Ex: fix_swizzle("zyNN") -> "zyyy"
+ */
+static GLuint
+fix_swizzle(GLuint swizzle)
+{
+ GLuint swz[4], i;
+ for (i = 0; i < 4; i++) {
+ swz[i] = GET_SWZ(swizzle, i);
+ if (swz[i] == SWIZZLE_NIL) {
+ swz[i] = swz[i - 1];
+ }
+ }
+ return MAKE_SWIZZLE4(swz[0], swz[1], swz[2], swz[3]);
+}
+
+
+static struct prog_instruction *
+emit_swizzle(slang_var_table *vt, slang_ir_node *n, struct gl_program *prog)
+{
+ GLuint swizzle;
+
+ /* swizzled storage access */
+ (void) emit(vt, n->Children[0], prog);
+
+ /* "pull-up" the child's storage info, applying our swizzle info */
+ n->Store->File = n->Children[0]->Store->File;
+ n->Store->Index = n->Children[0]->Store->Index;
+ n->Store->Size = n->Children[0]->Store->Size;
+ /*n->Var = n->Children[0]->Var; XXX for debug */
+ assert(n->Store->Index >= 0);
+
+ swizzle = fix_swizzle(n->Store->Swizzle);
+#ifdef DEBUG
+ {
+ GLuint s = n->Children[0]->Store->Swizzle;
+ assert(GET_SWZ(s, 0) != SWIZZLE_NIL);
+ assert(GET_SWZ(s, 1) != SWIZZLE_NIL);
+ assert(GET_SWZ(s, 2) != SWIZZLE_NIL);
+ assert(GET_SWZ(s, 3) != SWIZZLE_NIL);
+ }
+#endif
+
+ /* apply this swizzle to child's swizzle to get composed swizzle */
+ n->Store->Swizzle = swizzle_swizzle(n->Children[0]->Store->Swizzle,
+ swizzle);
+ return NULL;
+}
+
+
static struct prog_instruction *
emit(slang_var_table *vt, slang_ir_node *n, struct gl_program *prog)
{
@@ -1060,16 +1116,7 @@ emit(slang_var_table *vt, slang_ir_node *n, struct gl_program *prog)
return NULL; /* no instruction */
case IR_SWIZZLE:
- /* swizzled storage access */
- (void) emit(vt, n->Children[0], prog);
- /* "pull-up" the child's storage info, applying our swizzle info */
- n->Store->File = n->Children[0]->Store->File;
- n->Store->Index = n->Children[0]->Store->Index;
- n->Store->Size = n->Children[0]->Store->Size;
- assert(n->Store->Index >= 0);
- n->Store->Swizzle = swizzle_swizzle(n->Children[0]->Store->Swizzle,
- n->Store->Swizzle);
- return NULL;
+ return emit_swizzle(vt, n, prog);
/* Simple arithmetic */
/* unary */
diff --git a/src/mesa/shader/slang/slang_ir.h b/src/mesa/shader/slang/slang_ir.h
index 4b696c5c13..5fd72be36a 100644
--- a/src/mesa/shader/slang/slang_ir.h
+++ b/src/mesa/shader/slang/slang_ir.h
@@ -121,17 +121,17 @@ typedef struct _slang_ir_storage slang_ir_storage;
/**
* Intermediate Representation (IR) tree node
- * Basically a binary tree, but IR_LRP has three children.
+ * Basically a binary tree, but IR_LRP and IR_CLAMP have three children.
*/
typedef struct slang_ir_node_
{
slang_ir_opcode Opcode;
struct slang_ir_node_ *Children[3];
const char *Comment;
- const char *Target;
+ const char *Target; /**< Branch target string */
GLuint Writemask; /**< If Opcode == IR_MOVE */
GLfloat Value[4]; /**< If Opcode == IR_FLOAT */
- slang_variable *Var;
+ slang_variable *Var; /**< If Opcode == IR_VAR or IR_VAR_DECL */
slang_ir_storage *Store; /**< location of result of this operation */
} slang_ir_node;