mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-01-24 16:50:22 +01:00
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:
parent
309d5b6650
commit
b63c100677
6 changed files with 197 additions and 96 deletions
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue