Overhaul handling of writemasks/swizzling. This fixes two problem cases:
authorBrian <brian@yutani.localnet.net>
Wed, 31 Jan 2007 23:34:54 +0000 (16:34 -0700)
committerBrian <brian@yutani.localnet.net>
Wed, 31 Jan 2007 23:34:54 +0000 (16:34 -0700)
vec2 v;  v.x = v.y = 1.0;  // chained assignment
vec4 v;  v.zx = vec2(a,b);  // swizzled writemask

src/mesa/shader/prog_instruction.h
src/mesa/shader/prog_print.c
src/mesa/shader/slang/slang_assemble_constructor.c
src/mesa/shader/slang/slang_codegen.c
src/mesa/shader/slang/slang_emit.c
src/mesa/shader/slang/slang_ir.h

index 3e88b4e6270c5c1ce171e6970208c92365d3e8f5..f018de82b37643cb7db7c659fbff8c5c0c41252f 100644 (file)
@@ -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))
index 78ce752f2a2331ec0f2383575b126200ade09903..63ff84e3450c47042b97cf9a086fb60420c0d5f6 100644 (file)
@@ -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;
 
index a41159713036574e5cfc927c484aef8704a17e57..e045f2f6d2eb0e75df0c33f716b8d560483f1c57 100644 (file)
@@ -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;
 }
 
index cc2a0b2738835e32414b8b2583b415438bb4eeee..d09883c66456d6e320805185f226934003e32abb 100644 (file)
@@ -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.
@@ -1960,6 +1924,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 (=).
  */
@@ -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;
       }
index 1c945fa0baead7fe5fb47c8ac8001f93a38a11d7..0626f7a64369060ed83895e8befcdd44ef061a33 100644 (file)
@@ -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 */
index 4b696c5c137ec79cc3917e2115d198d94f45b5ed..5fd72be36a0020db3062eaf96a8993754a7d8f1e 100644 (file)
@@ -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;