summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBrian Paul <brian.paul@tungstengraphics.com>2008-07-01 18:40:23 -0600
committerBrian Paul <brian.paul@tungstengraphics.com>2008-07-01 18:40:23 -0600
commit66b48202c221a25f3980df8f443ce63c2fb4119f (patch)
treecdeabcb747311c26bf0e736378476077c311a486 /src
parenteeefe175de8bae93b9ed2204afa9e748b205e868 (diff)
mesa: fix a GLSL vector subscript/writemask bug
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. cherry-picked from master
Diffstat (limited to 'src')
-rw-r--r--src/mesa/shader/slang/slang_codegen.c137
1 files changed, 90 insertions, 47 deletions
diff --git a/src/mesa/shader/slang/slang_codegen.c b/src/mesa/shader/slang/slang_codegen.c
index efeae283fc..4846c257f1 100644
--- a/src/mesa/shader/slang/slang_codegen.c
+++ b/src/mesa/shader/slang/slang_codegen.c
@@ -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:
@@ -1494,6 +1455,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);
}