diff --git a/dlls/d3dcompiler_43/d3dcompiler_private.h b/dlls/d3dcompiler_43/d3dcompiler_private.h index 05454f19da5..01c31eff128 100644 --- a/dlls/d3dcompiler_43/d3dcompiler_private.h +++ b/dlls/d3dcompiler_43/d3dcompiler_private.h @@ -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); diff --git a/dlls/d3dcompiler_43/hlsl.y b/dlls/d3dcompiler_43/hlsl.y index c67ab541bb8..c0037542659 100644 --- a/dlls/d3dcompiler_43/hlsl.y +++ b/dlls/d3dcompiler_43/hlsl.y @@ -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 ')' diff --git a/dlls/d3dcompiler_43/utils.c b/dlls/d3dcompiler_43/utils.c index 242f5fb976a..c416060ef5f 100644 --- a/dlls/d3dcompiler_43/utils.c +++ b/dlls/d3dcompiler_43/utils.c @@ -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;