aboutsummaryrefslogtreecommitdiffstats
path: root/src/mesa/shader/slang/slang_codegen.c
diff options
context:
space:
mode:
authorBrian <[email protected]>2007-01-31 16:34:54 -0700
committerBrian <[email protected]>2007-01-31 16:34:54 -0700
commitb63c100677c76bb20a1871ea15298ca708acd04f (patch)
tree531db5e2db8f313a6273548f766db850a37b9548 /src/mesa/shader/slang/slang_codegen.c
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
Diffstat (limited to 'src/mesa/shader/slang/slang_codegen.c')
-rw-r--r--src/mesa/shader/slang/slang_codegen.c198
1 files changed, 126 insertions, 72 deletions
diff --git a/src/mesa/shader/slang/slang_codegen.c b/src/mesa/shader/slang/slang_codegen.c
index cc2a0b27388..d09883c6645 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;
}