diff --git a/libs/vkd3d-shader/hlsl.c b/libs/vkd3d-shader/hlsl.c index 01be78571..dc9886b53 100644 --- a/libs/vkd3d-shader/hlsl.c +++ b/libs/vkd3d-shader/hlsl.c @@ -1976,14 +1976,15 @@ static struct hlsl_ir_node *hlsl_new_error_expr(struct hlsl_ctx *ctx) return hlsl_new_expr(ctx, HLSL_OP0_ERROR, operands, ctx->builtin_types.error, &loc); } -struct hlsl_ir_node *hlsl_new_if(struct hlsl_ctx *ctx, struct hlsl_ir_node *condition, - struct hlsl_block *then_block, struct hlsl_block *else_block, const struct vkd3d_shader_location *loc) +struct hlsl_ir_node *hlsl_new_if(struct hlsl_ctx *ctx, struct hlsl_ir_node *condition, struct hlsl_block *then_block, + struct hlsl_block *else_block, enum hlsl_if_flatten_type flatten_type, const struct vkd3d_shader_location *loc) { struct hlsl_ir_if *iff; if (!(iff = hlsl_alloc(ctx, sizeof(*iff)))) return NULL; init_node(&iff->node, HLSL_IR_IF, NULL, loc); + iff->flatten_type = flatten_type; hlsl_src_from_node(&iff->condition, condition); hlsl_block_init(&iff->then_block); hlsl_block_add_block(&iff->then_block, then_block); @@ -1993,10 +1994,11 @@ struct hlsl_ir_node *hlsl_new_if(struct hlsl_ctx *ctx, struct hlsl_ir_node *cond return &iff->node; } -void hlsl_block_add_if(struct hlsl_ctx *ctx, struct hlsl_block *block, struct hlsl_ir_node *condition, - struct hlsl_block *then_block, struct hlsl_block *else_block, const struct vkd3d_shader_location *loc) +void hlsl_block_add_if(struct hlsl_ctx *ctx, struct hlsl_block *block, + struct hlsl_ir_node *condition, struct hlsl_block *then_block, struct hlsl_block *else_block, + enum hlsl_if_flatten_type flatten_type, const struct vkd3d_shader_location *loc) { - struct hlsl_ir_node *instr = hlsl_new_if(ctx, condition, then_block, else_block, loc); + struct hlsl_ir_node *instr = hlsl_new_if(ctx, condition, then_block, else_block, flatten_type, loc); if (instr) { @@ -2674,7 +2676,8 @@ static struct hlsl_ir_node *clone_if(struct hlsl_ctx *ctx, struct clone_instr_ma return NULL; } - if (!(dst = hlsl_new_if(ctx, map_instr(map, src->condition.node), &then_block, &else_block, &src->node.loc))) + if (!(dst = hlsl_new_if(ctx, map_instr(map, src->condition.node), + &then_block, &else_block, src->flatten_type, &src->node.loc))) { hlsl_block_cleanup(&then_block); hlsl_block_cleanup(&else_block); diff --git a/libs/vkd3d-shader/hlsl.h b/libs/vkd3d-shader/hlsl.h index 4f79f2845..e52cb7e6b 100644 --- a/libs/vkd3d-shader/hlsl.h +++ b/libs/vkd3d-shader/hlsl.h @@ -661,12 +661,20 @@ struct hlsl_ir_call struct hlsl_ir_function_decl *decl; }; +enum hlsl_if_flatten_type +{ + HLSL_IF_FLATTEN_DEFAULT, + HLSL_IF_FORCE_FLATTEN, + HLSL_IF_FORCE_BRANCH +}; + struct hlsl_ir_if { struct hlsl_ir_node node; struct hlsl_src condition; struct hlsl_block then_block; struct hlsl_block else_block; + enum hlsl_if_flatten_type flatten_type; }; enum hlsl_loop_unroll_type @@ -1586,8 +1594,9 @@ struct hlsl_ir_node *hlsl_block_add_expr(struct hlsl_ctx *ctx, struct hlsl_block struct hlsl_type *data_type, const struct vkd3d_shader_location *loc); struct hlsl_ir_node *hlsl_block_add_float_constant(struct hlsl_ctx *ctx, struct hlsl_block *block, float f, const struct vkd3d_shader_location *loc); -void hlsl_block_add_if(struct hlsl_ctx *ctx, struct hlsl_block *block, struct hlsl_ir_node *condition, - struct hlsl_block *then_block, struct hlsl_block *else_block, const struct vkd3d_shader_location *loc); +void hlsl_block_add_if(struct hlsl_ctx *ctx, struct hlsl_block *block, + struct hlsl_ir_node *condition, struct hlsl_block *then_block, struct hlsl_block *else_block, + enum hlsl_if_flatten_type flatten_type, const struct vkd3d_shader_location *loc); struct hlsl_ir_node *hlsl_block_add_index(struct hlsl_ctx *ctx, struct hlsl_block *block, struct hlsl_ir_node *val, struct hlsl_ir_node *idx, const struct vkd3d_shader_location *loc); struct hlsl_ir_node *hlsl_block_add_int_constant(struct hlsl_ctx *ctx, struct hlsl_block *block, @@ -1704,8 +1713,8 @@ struct hlsl_ir_node *hlsl_new_copy(struct hlsl_ctx *ctx, struct hlsl_ir_node *no struct hlsl_ir_function_decl *hlsl_new_func_decl(struct hlsl_ctx *ctx, struct hlsl_type *return_type, const struct hlsl_func_parameters *parameters, const struct hlsl_semantic *semantic, const struct vkd3d_shader_location *loc); -struct hlsl_ir_node *hlsl_new_if(struct hlsl_ctx *ctx, struct hlsl_ir_node *condition, - struct hlsl_block *then_block, struct hlsl_block *else_block, const struct vkd3d_shader_location *loc); +struct hlsl_ir_node *hlsl_new_if(struct hlsl_ctx *ctx, struct hlsl_ir_node *condition, struct hlsl_block *then_block, + struct hlsl_block *else_block, enum hlsl_if_flatten_type flatten_type, const struct vkd3d_shader_location *loc); struct hlsl_type *hlsl_new_stream_output_type(struct hlsl_ctx *ctx, enum hlsl_so_object_type so_type, struct hlsl_type *type); struct hlsl_ir_node *hlsl_new_ternary_expr(struct hlsl_ctx *ctx, enum hlsl_ir_expr_op op, diff --git a/libs/vkd3d-shader/hlsl.y b/libs/vkd3d-shader/hlsl.y index 8ec963c86..92bfd7040 100644 --- a/libs/vkd3d-shader/hlsl.y +++ b/libs/vkd3d-shader/hlsl.y @@ -471,7 +471,7 @@ static void append_conditional_break(struct hlsl_ctx *ctx, struct hlsl_block *co hlsl_block_init(&then_block); hlsl_block_add_jump(ctx, &then_block, HLSL_IR_JUMP_BREAK, NULL, &condition->loc); - hlsl_block_add_if(ctx, cond_block, not, &then_block, NULL, &condition->loc); + hlsl_block_add_if(ctx, cond_block, not, &then_block, NULL, HLSL_IF_FLATTEN_DEFAULT, &condition->loc); } static void check_attribute_list_for_duplicates(struct hlsl_ctx *ctx, const struct parse_attribute_list *attrs) @@ -9139,6 +9139,7 @@ selection_statement: { struct hlsl_ir_node *condition = node_from_block($4); const struct parse_attribute_list *attributes = &$1; + enum hlsl_if_flatten_type flatten_type = HLSL_IF_FLATTEN_DEFAULT; unsigned int i; check_attribute_list_for_duplicates(ctx, attributes); @@ -9147,10 +9148,19 @@ selection_statement: { const struct hlsl_attribute *attr = attributes->attrs[i]; - if (!strcmp(attr->name, "branch") - || !strcmp(attr->name, "flatten")) + if (!strcmp(attr->name, "branch")) { - hlsl_warning(ctx, &@1, VKD3D_SHADER_WARNING_HLSL_IGNORED_ATTRIBUTE, "Unhandled attribute '%s'.", attr->name); + if (flatten_type == HLSL_IF_FORCE_FLATTEN) + hlsl_error(ctx, &@1, VKD3D_SHADER_ERROR_HLSL_INVALID_SYNTAX, + "The 'branch' and 'flatten' attributes are mutually exclusive."); + flatten_type = HLSL_IF_FORCE_BRANCH; + } + else if (!strcmp(attr->name, "flatten")) + { + if (flatten_type == HLSL_IF_FORCE_BRANCH) + hlsl_error(ctx, &@1, VKD3D_SHADER_ERROR_HLSL_INVALID_SYNTAX, + "The 'branch' and 'flatten' attributes are mutually exclusive."); + flatten_type = HLSL_IF_FORCE_FLATTEN; } else { @@ -9158,10 +9168,16 @@ selection_statement: } } + if (flatten_type == HLSL_IF_FORCE_BRANCH && hlsl_version_lt(ctx, 2, 1)) + { + hlsl_error(ctx, &@1, VKD3D_SHADER_ERROR_HLSL_INCOMPATIBLE_PROFILE, + "The 'branch' attribute requires shader model 2.1 or higher."); + } + check_condition_type(ctx, condition); condition = add_cast(ctx, $4, condition, hlsl_get_scalar_type(ctx, HLSL_TYPE_BOOL), &@4); - hlsl_block_add_if(ctx, $4, condition, $6.then_block, $6.else_block, &@2); + hlsl_block_add_if(ctx, $4, condition, $6.then_block, $6.else_block, flatten_type, &@2); destroy_block($6.then_block); destroy_block($6.else_block); diff --git a/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d-shader/hlsl_codegen.c index 51dd9f80f..ef0a8a802 100644 --- a/libs/vkd3d-shader/hlsl_codegen.c +++ b/libs/vkd3d-shader/hlsl_codegen.c @@ -1060,7 +1060,7 @@ static void insert_early_return_break(struct hlsl_ctx *ctx, hlsl_block_add_jump(ctx, &then_block, HLSL_IR_JUMP_BREAK, NULL, &cf_instr->loc); - if (!(iff = hlsl_new_if(ctx, &load->node, &then_block, NULL, &cf_instr->loc))) + if (!(iff = hlsl_new_if(ctx, &load->node, &then_block, NULL, HLSL_IF_FLATTEN_DEFAULT, &cf_instr->loc))) return; list_add_after(&load->node.entry, &iff->entry); } @@ -1245,7 +1245,7 @@ static bool lower_return(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *fun load = hlsl_block_add_simple_load(ctx, block, func->early_return_var, &cf_instr->loc); not = hlsl_block_add_unary_expr(ctx, block, HLSL_OP1_LOGIC_NOT, load, &cf_instr->loc); - hlsl_block_add_if(ctx, block, not, &then_block, NULL, &cf_instr->loc); + hlsl_block_add_if(ctx, block, not, &then_block, NULL, HLSL_IF_FLATTEN_DEFAULT, &cf_instr->loc); } return has_early_return; @@ -13866,7 +13866,7 @@ static struct hlsl_ir_if *loop_unrolling_generate_var_check(struct hlsl_ctx *ctx load = hlsl_block_add_simple_load(ctx, dst, var, loc); cond = hlsl_block_add_unary_expr(ctx, dst, HLSL_OP1_LOGIC_NOT, load, loc); - if (!(iff = hlsl_new_if(ctx, cond, &then_block, NULL, loc))) + if (!(iff = hlsl_new_if(ctx, cond, &then_block, NULL, HLSL_IF_FLATTEN_DEFAULT, loc))) return NULL; hlsl_block_add_instr(dst, iff); diff --git a/tests/hlsl/conditional.shader_test b/tests/hlsl/conditional.shader_test index 607fcb065..1f9d5b5db 100644 --- a/tests/hlsl/conditional.shader_test +++ b/tests/hlsl/conditional.shader_test @@ -58,7 +58,7 @@ float main() : sv_target return float4(0.9, 0.8, 0.7, 0.6); } -[pixel shader fail todo] +[pixel shader fail] float4 u; float main() : sv_target