mesa: fix a GLSL vector subscript/writemask bug
authorBrian Paul <brian.paul@tungstengraphics.com>
Tue, 1 Jul 2008 23:59:07 +0000 (17:59 -0600)
committerBrian Paul <brian.paul@tungstengraphics.com>
Tue, 1 Jul 2008 23:59:07 +0000 (17:59 -0600)
This fixes a failure for cases like:
   vec4 v;
   v[1] *= 2.0;

The v[1] actually acts like a writemask, equivalent to v.y
The fix is a bit convoluted, but will do for now.

src/mesa/shader/slang/slang_codegen.c

index efeae283fca6e2306d42ee89f33ca88fea31f986..4846c257f16f755149f5393e0c8dbdbb3db7fa40 100644 (file)
@@ -1355,45 +1355,6 @@ slang_find_asm_info(const char *name)
 }
 
 
-static GLuint
-make_writemask(const char *field)
-{
-   GLuint mask = 0x0;
-   while (*field) {
-      switch (*field) {
-      case 'x':
-      case 's':
-      case 'r':
-         mask |= WRITEMASK_X;
-         break;
-      case 'y':
-      case 't':
-      case 'g':
-         mask |= WRITEMASK_Y;
-         break;
-      case 'z':
-      case 'p':
-      case 'b':
-         mask |= WRITEMASK_Z;
-         break;
-      case 'w':
-      case 'q':
-      case 'a':
-         mask |= WRITEMASK_W;
-         break;
-      default:
-         _mesa_problem(NULL, "invalid writemask in make_writemask()");
-         return 0;
-      }
-      field++;
-   }
-   if (mask == 0x0)
-      return WRITEMASK_XYZW;
-   else
-      return mask;
-}
-
-
 /**
  * Some write-masked assignments are simple, but others are hard.
  * Simple example:
@@ -1493,6 +1454,88 @@ swizzle_to_writemask(GLuint swizzle,
 }
 
 
+/**
+ * Recursively traverse 'oper' to produce a swizzle mask in the event
+ * of any vector subscripts and swizzle suffixes.
+ * Ex:  for "vec4 v",  "v[2].x" resolves to v.z
+ */
+static GLuint
+resolve_swizzle(const slang_operation *oper)
+{
+   if (oper->type == SLANG_OPER_FIELD) {
+      /* writemask from .xyzw suffix */
+      slang_swizzle swz;
+      if (_slang_is_swizzle((char*) oper->a_id, 4, &swz)) {
+         GLuint swizzle = MAKE_SWIZZLE4(swz.swizzle[0],
+                                        swz.swizzle[1],
+                                        swz.swizzle[2],
+                                        swz.swizzle[3]);
+         GLuint child_swizzle = resolve_swizzle(&oper->children[0]);
+         GLuint s = _slang_swizzle_swizzle(child_swizzle, swizzle);
+         return s;
+      }
+      else
+         return SWIZZLE_XYZW;
+   }
+   else if (oper->type == SLANG_OPER_SUBSCRIPT &&
+            oper->children[1].type == SLANG_OPER_LITERAL_INT) {
+      /* writemask from [index] */
+      GLuint child_swizzle = resolve_swizzle(&oper->children[0]);
+      GLuint i = (GLuint) oper->children[1].literal[0];
+      GLuint swizzle;
+      GLuint s;
+      switch (i) {
+      case 0:
+         swizzle = SWIZZLE_XXXX;
+         break;
+      case 1:
+         swizzle = SWIZZLE_YYYY;
+         break;
+      case 2:
+         swizzle = SWIZZLE_ZZZZ;
+         break;
+      case 3:
+         swizzle = SWIZZLE_WWWW;
+         break;
+      default:
+         swizzle = SWIZZLE_XYZW;
+      }
+      s = _slang_swizzle_swizzle(child_swizzle, swizzle);
+      return s;
+   }
+   else {
+      return SWIZZLE_XYZW;
+   }
+}
+
+
+/**
+ * As above, but produce a writemask.
+ */
+static GLuint
+resolve_writemask(const slang_operation *oper)
+{
+   GLuint swizzle = resolve_swizzle(oper);
+   GLuint writemask, swizzleOut;
+   swizzle_to_writemask(swizzle, &writemask, &swizzleOut);
+   return writemask;
+}
+
+
+/**
+ * Recursively descend through swizzle nodes to find the node's storage info.
+ */
+static slang_ir_storage *
+get_store(const slang_ir_node *n)
+{
+   if (n->Opcode == IR_SWIZZLE) {
+      return get_store(n->Children[0]);
+   }
+   return n->Store;
+}
+
+
+
 /**
  * Generate IR tree for an asm instruction/operation such as:
  *    __asm vec4_dot __retVal.x, v1, v2;
@@ -1547,19 +1590,19 @@ _slang_gen_asm(slang_assemble_ctx *A, slang_operation *oper,
       slang_ir_node *n0;
 
       dest_oper = &oper->children[0];
-      while (dest_oper->type == SLANG_OPER_FIELD) {
-         /* writemask */
-         writemask &= make_writemask((char*) dest_oper->a_id);
-         dest_oper = &dest_oper->children[0];
-      }
+
+      writemask = resolve_writemask(dest_oper);
 
       n0 = _slang_gen_operation(A, dest_oper);
-      assert(n0->Var);
-      assert(n0->Store);
+      if (!n0)
+         return NULL;
+
       assert(!n->Store);
-      n->Store = n0->Store;
+      n->Store = get_store(n0);
       n->Writemask = writemask;
 
+      assert(n->Store->File != PROGRAM_UNDEFINED);
+
       _slang_free(n0);
    }