d3dcompiler: Parse swizzles.

This commit is contained in:
Matteo Bruni 2012-09-17 15:32:04 +02:00 committed by Alexandre Julliard
parent e603ffd19e
commit 7cce71a0c3
3 changed files with 169 additions and 0 deletions

View File

@ -706,6 +706,7 @@ enum hlsl_ir_node_type
HLSL_IR_DEREF,
HLSL_IR_EXPR,
HLSL_IR_FUNCTION_DECL,
HLSL_IR_SWIZZLE,
};
struct hlsl_ir_node
@ -834,6 +835,13 @@ struct hlsl_ir_expr
struct list *subexpressions;
};
struct hlsl_ir_swizzle
{
struct hlsl_ir_node node;
struct hlsl_ir_node *val;
DWORD swizzle;
};
enum hlsl_ir_deref_type
{
HLSL_IR_DEREF_VAR,
@ -999,6 +1007,12 @@ static inline struct hlsl_ir_assignment *assignment_from_node(const struct hlsl_
return CONTAINING_RECORD(node, struct hlsl_ir_assignment, node);
}
static inline struct hlsl_ir_swizzle *swizzle_from_node(const struct hlsl_ir_node *node)
{
assert(node->type == HLSL_IR_SWIZZLE);
return CONTAINING_RECORD(node, struct hlsl_ir_swizzle, node);
}
static inline struct hlsl_ir_constructor *constructor_from_node(const struct hlsl_ir_node *node)
{
assert(node->type == HLSL_IR_CONSTRUCTOR);

View File

@ -187,6 +187,103 @@ static unsigned int components_count_expr_list(struct list *list)
return count;
}
static struct hlsl_ir_swizzle *new_swizzle(DWORD s, unsigned int components,
struct hlsl_ir_node *val, struct source_location *loc)
{
struct hlsl_ir_swizzle *swizzle = d3dcompiler_alloc(sizeof(*swizzle));
if (!swizzle)
return NULL;
swizzle->node.type = HLSL_IR_SWIZZLE;
swizzle->node.loc = *loc;
swizzle->node.data_type = new_hlsl_type(NULL, HLSL_CLASS_VECTOR, val->data_type->base_type, components, 1);
swizzle->val = val;
swizzle->swizzle = s;
return swizzle;
}
static struct hlsl_ir_swizzle *get_swizzle(struct hlsl_ir_node *value, const char *swizzle,
struct source_location *loc)
{
unsigned int len = strlen(swizzle), component = 0;
unsigned int i, set, swiz = 0;
BOOL valid;
if (value->data_type->type == HLSL_CLASS_MATRIX)
{
/* Matrix swizzle */
BOOL m_swizzle;
unsigned int inc, x, y;
if (len < 3 || swizzle[0] != '_')
return NULL;
m_swizzle = swizzle[1] == 'm';
inc = m_swizzle ? 4 : 3;
if (len % inc || len > inc * 4)
return NULL;
for (i = 0; i < len; i += inc)
{
if (swizzle[i] != '_')
return NULL;
if (m_swizzle)
{
if (swizzle[i + 1] != 'm')
return NULL;
x = swizzle[i + 2] - '0';
y = swizzle[i + 3] - '0';
}
else
{
x = swizzle[i + 1] - '1';
y = swizzle[i + 2] - '1';
}
if (x >= value->data_type->dimx || y >= value->data_type->dimy)
return NULL;
swiz |= (y << 4 | x) << component * 8;
component++;
}
return new_swizzle(swiz, component, value, loc);
}
/* Vector swizzle */
if (len > 4)
return NULL;
for (set = 0; set < 2; ++set)
{
valid = TRUE;
component = 0;
for (i = 0; i < len; ++i)
{
char c[2][4] = {{'x', 'y', 'z', 'w'}, {'r', 'g', 'b', 'a'}};
unsigned int s = 0;
for (s = 0; s < 4; ++s)
{
if (swizzle[i] == c[set][s])
break;
}
if (s == 4)
{
valid = FALSE;
break;
}
if (s >= value->data_type->dimx)
return NULL;
swiz |= s << component * 2;
component++;
}
if (valid)
return new_swizzle(swiz, component, value, loc);
}
return NULL;
}
%}
%locations
@ -944,6 +1041,31 @@ postfix_expr: primary_expr
set_location(&loc, &@2);
$$ = &new_expr(HLSL_IR_BINOP_POSTDEC, operands, &loc)->node;
}
| postfix_expr '.' any_identifier
{
struct source_location loc;
set_location(&loc, &@2);
if ($1->data_type->type <= HLSL_CLASS_LAST_NUMERIC)
{
struct hlsl_ir_swizzle *swizzle;
swizzle = get_swizzle($1, $3, &loc);
if (!swizzle)
{
hlsl_report_message(loc.file, loc.line, loc.col, HLSL_LEVEL_ERROR,
"invalid swizzle %s", debugstr_a($3));
return 1;
}
$$ = &swizzle->node;
}
else
{
hlsl_report_message(loc.file, loc.line, loc.col, HLSL_LEVEL_ERROR,
"invalid subscript %s", debugstr_a($3));
return 1;
}
}
/* "var_modifiers" doesn't make sense in this case, but it's needed
in the grammar to avoid shift/reduce conflicts. */
| var_modifiers type '(' initializer_expr_list ')'

View File

@ -1457,6 +1457,7 @@ struct hlsl_ir_node *make_assignment(struct hlsl_ir_node *left, enum parse_assig
struct hlsl_ir_deref *lhs_deref = new_var_deref(var_from_node(lhs));
lhs = &lhs_deref->node;
}
/* FIXME: check for invalid writemasks on the lhs. */
if (!compare_hlsl_types(type, rhs->data_type))
{
@ -1870,6 +1871,26 @@ static void debug_dump_ir_assignment(const struct hlsl_ir_assignment *assign)
TRACE(")");
}
static void debug_dump_ir_swizzle(const struct hlsl_ir_swizzle *swizzle)
{
unsigned int i;
debug_dump_instr(swizzle->val);
TRACE(".");
if (swizzle->val->data_type->dimy > 1)
{
for (i = 0; i < swizzle->node.data_type->dimx; ++i)
TRACE("_m%u%u", (swizzle->swizzle >> i * 8) & 0xf, (swizzle->swizzle >> (i * 8 + 4)) & 0xf);
}
else
{
char c[] = {'x', 'y', 'z', 'w'};
for (i = 0; i < swizzle->node.data_type->dimx; ++i)
TRACE("%c", c[(swizzle->swizzle >> i * 2) & 0x3]);
}
}
static void debug_dump_instr(const struct hlsl_ir_node *instr)
{
switch (instr->type)
@ -1886,6 +1907,9 @@ static void debug_dump_instr(const struct hlsl_ir_node *instr)
case HLSL_IR_ASSIGNMENT:
debug_dump_ir_assignment(assignment_from_node(instr));
break;
case HLSL_IR_SWIZZLE:
debug_dump_ir_swizzle(swizzle_from_node(instr));
break;
case HLSL_IR_CONSTRUCTOR:
debug_dump_ir_constructor(constructor_from_node(instr));
break;
@ -1993,6 +2017,12 @@ static void free_ir_deref(struct hlsl_ir_deref *deref)
d3dcompiler_free(deref);
}
static void free_ir_swizzle(struct hlsl_ir_swizzle *swizzle)
{
free_instr(swizzle->val);
d3dcompiler_free(swizzle);
}
static void free_ir_constructor(struct hlsl_ir_constructor *constructor)
{
free_instr_list(constructor->arguments);
@ -2033,6 +2063,9 @@ void free_instr(struct hlsl_ir_node *node)
case HLSL_IR_DEREF:
free_ir_deref(deref_from_node(node));
break;
case HLSL_IR_SWIZZLE:
free_ir_swizzle(swizzle_from_node(node));
break;
case HLSL_IR_CONSTRUCTOR:
free_ir_constructor(constructor_from_node(node));
break;