Browse Source

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
tags/mesa_20090313
Brian Paul 17 years ago
parent
commit
66b48202c2
1 changed files with 90 additions and 47 deletions
  1. 90
    47
      src/mesa/shader/slang/slang_codegen.c

+ 90
- 47
src/mesa/shader/slang/slang_codegen.c View 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);
}


Loading…
Cancel
Save