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
This commit is contained in:
Brian 2007-01-31 16:34:54 -07:00
parent 309d5b6650
commit b63c100677
6 changed files with 197 additions and 96 deletions

View 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))

View 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;

View 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;
}

View 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;
}

View 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 */

View 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;