From b63c100677c76bb20a1871ea15298ca708acd04f Mon Sep 17 00:00:00 2001 From: Brian Date: Wed, 31 Jan 2007 16:34:54 -0700 Subject: 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 --- src/mesa/shader/prog_instruction.h | 1 + src/mesa/shader/prog_print.c | 2 +- src/mesa/shader/slang/slang_assemble_constructor.c | 17 +- src/mesa/shader/slang/slang_codegen.c | 198 +++++++++++++-------- src/mesa/shader/slang/slang_emit.c | 69 +++++-- src/mesa/shader/slang/slang_ir.h | 6 +- 6 files changed, 197 insertions(+), 96 deletions(-) (limited to 'src/mesa') diff --git a/src/mesa/shader/prog_instruction.h b/src/mesa/shader/prog_instruction.h index 3e88b4e627..f018de82b3 100644 --- a/src/mesa/shader/prog_instruction.h +++ b/src/mesa/shader/prog_instruction.h @@ -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)) diff --git a/src/mesa/shader/prog_print.c b/src/mesa/shader/prog_print.c index 78ce752f2a..63ff84e345 100644 --- a/src/mesa/shader/prog_print.c +++ b/src/mesa/shader/prog_print.c @@ -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; diff --git a/src/mesa/shader/slang/slang_assemble_constructor.c b/src/mesa/shader/slang/slang_assemble_constructor.c index a411597130..e045f2f6d2 100644 --- a/src/mesa/shader/slang/slang_assemble_constructor.c +++ b/src/mesa/shader/slang/slang_assemble_constructor.c @@ -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; } diff --git a/src/mesa/shader/slang/slang_codegen.c b/src/mesa/shader/slang/slang_codegen.c index cc2a0b2738..d09883c664 100644 --- a/src/mesa/shader/slang/slang_codegen.c +++ b/src/mesa/shader/slang/slang_codegen.c @@ -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; } diff --git a/src/mesa/shader/slang/slang_emit.c b/src/mesa/shader/slang/slang_emit.c index 1c945fa0ba..0626f7a643 100644 --- a/src/mesa/shader/slang/slang_emit.c +++ b/src/mesa/shader/slang/slang_emit.c @@ -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 */ diff --git a/src/mesa/shader/slang/slang_ir.h b/src/mesa/shader/slang/slang_ir.h index 4b696c5c13..5fd72be36a 100644 --- a/src/mesa/shader/slang/slang_ir.h +++ b/src/mesa/shader/slang/slang_ir.h @@ -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; -- cgit v1.2.3