-- v5: vkd3d-shader/hlsl: Support clip() intrinsic.
From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- Makefile.am | 1 + libs/vkd3d-shader/d3dbc.c | 33 ++ libs/vkd3d-shader/hlsl.c | 458 +++++++++++++++++++++- libs/vkd3d-shader/hlsl.h | 25 +- libs/vkd3d-shader/hlsl.y | 635 ++++++------------------------- libs/vkd3d-shader/hlsl_codegen.c | 61 ++- libs/vkd3d-shader/tpf.c | 8 +- tests/hlsl-clip.shader_test | 22 ++ 8 files changed, 709 insertions(+), 534 deletions(-) create mode 100644 tests/hlsl-clip.shader_test
diff --git a/Makefile.am b/Makefile.am index 92c6d0792..9b506e44d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -80,6 +80,7 @@ vkd3d_shader_tests = \ tests/hlsl-attributes.shader_test \ tests/hlsl-bool-cast.shader_test \ tests/hlsl-clamp.shader_test \ + tests/hlsl-clip.shader_test \ tests/hlsl-comma.shader_test \ tests/hlsl-cross.shader_test \ tests/hlsl-d3dcolor-to-ubyte4.shader_test \ diff --git a/libs/vkd3d-shader/d3dbc.c b/libs/vkd3d-shader/d3dbc.c index c35f8ca0f..101b7a66d 100644 --- a/libs/vkd3d-shader/d3dbc.c +++ b/libs/vkd3d-shader/d3dbc.c @@ -1834,6 +1834,35 @@ static void write_sm1_expr(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer *b } }
+static void write_sm1_jump(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer *buffer, const struct hlsl_ir_node *instr) +{ + const struct hlsl_ir_jump *jump = hlsl_ir_jump(instr); + + switch (jump->type) + { + case HLSL_IR_JUMP_TEXKILL: + { + struct hlsl_reg *reg = &jump->arg.node->reg; + + struct sm1_instruction instr = + { + .opcode = VKD3D_SM1_OP_TEXKILL, + + .dst.type = D3DSPR_TEMP, + .dst.reg = reg->id, + .dst.writemask = reg->writemask, + .has_dst = 1, + }; + + write_sm1_instruction(ctx, buffer, &instr); + break; + } + + default: + hlsl_fixme(ctx, &jump->node.loc, "Jump type %s.\n", hlsl_jump_type_to_string(jump->type)); + } +} + static void write_sm1_load(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer *buffer, const struct hlsl_ir_node *instr) { const struct hlsl_ir_load *load = hlsl_ir_load(instr); @@ -2028,6 +2057,10 @@ static void write_sm1_instructions(struct hlsl_ctx *ctx, struct vkd3d_bytecode_b write_sm1_expr(ctx, buffer, instr); break;
+ case HLSL_IR_JUMP: + write_sm1_jump(ctx, buffer, instr); + break; + case HLSL_IR_LOAD: write_sm1_load(ctx, buffer, instr); break; diff --git a/libs/vkd3d-shader/hlsl.c b/libs/vkd3d-shader/hlsl.c index 152ec6275..10c6f8553 100644 --- a/libs/vkd3d-shader/hlsl.c +++ b/libs/vkd3d-shader/hlsl.c @@ -1430,7 +1430,7 @@ struct hlsl_ir_node *hlsl_new_index(struct hlsl_ctx *ctx, struct hlsl_ir_node *v }
struct hlsl_ir_node *hlsl_new_jump(struct hlsl_ctx *ctx, enum hlsl_ir_jump_type type, - const struct vkd3d_shader_location *loc) + struct hlsl_ir_node *arg, const struct vkd3d_shader_location *loc) { struct hlsl_ir_jump *jump;
@@ -1438,6 +1438,7 @@ struct hlsl_ir_node *hlsl_new_jump(struct hlsl_ctx *ctx, enum hlsl_ir_jump_type return NULL; init_node(&jump->node, HLSL_IR_JUMP, NULL, loc); jump->type = type; + hlsl_src_from_node(&jump->arg, arg); return &jump->node; }
@@ -1454,6 +1455,442 @@ struct hlsl_ir_node *hlsl_new_loop(struct hlsl_ctx *ctx, return &loop->node; }
+enum hlsl_base_type hlsl_expr_common_base_type(enum hlsl_base_type t1, enum hlsl_base_type t2) +{ + if (t1 > HLSL_TYPE_LAST_SCALAR || t2 > HLSL_TYPE_LAST_SCALAR) { + FIXME("Unexpected base type.\n"); + return HLSL_TYPE_FLOAT; + } + if (t1 == t2) + return t1 == HLSL_TYPE_BOOL ? HLSL_TYPE_INT : t1; + if (t1 == HLSL_TYPE_DOUBLE || t2 == HLSL_TYPE_DOUBLE) + return HLSL_TYPE_DOUBLE; + if (t1 == HLSL_TYPE_FLOAT || t2 == HLSL_TYPE_FLOAT + || t1 == HLSL_TYPE_HALF || t2 == HLSL_TYPE_HALF) + return HLSL_TYPE_FLOAT; + if (t1 == HLSL_TYPE_UINT || t2 == HLSL_TYPE_UINT) + return HLSL_TYPE_UINT; + return HLSL_TYPE_INT; +} + +static bool hlsl_expr_compatible_data_types(struct hlsl_type *t1, struct hlsl_type *t2) +{ + if (t1->base_type > HLSL_TYPE_LAST_SCALAR || t2->base_type > HLSL_TYPE_LAST_SCALAR) + return false; + + /* Scalar vars can be converted to pretty much everything */ + if ((t1->dimx == 1 && t1->dimy == 1) || (t2->dimx == 1 && t2->dimy == 1)) + return true; + + if (t1->class == HLSL_CLASS_VECTOR && t2->class == HLSL_CLASS_VECTOR) + return true; + + if (t1->class == HLSL_CLASS_MATRIX || t2->class == HLSL_CLASS_MATRIX) + { + /* Matrix-vector conversion is apparently allowed if either they have the same components + count or the matrix is nx1 or 1xn */ + if (t1->class == HLSL_CLASS_VECTOR || t2->class == HLSL_CLASS_VECTOR) + { + if (hlsl_type_component_count(t1) == hlsl_type_component_count(t2)) + return true; + + return (t1->class == HLSL_CLASS_MATRIX && (t1->dimx == 1 || t1->dimy == 1)) + || (t2->class == HLSL_CLASS_MATRIX && (t2->dimx == 1 || t2->dimy == 1)); + } + + /* Both matrices */ + if ((t1->dimx >= t2->dimx && t1->dimy >= t2->dimy) + || (t1->dimx <= t2->dimx && t1->dimy <= t2->dimy)) + return true; + } + + return false; +} + +bool hlsl_expr_common_shape(struct hlsl_ctx *ctx, struct hlsl_type *t1, struct hlsl_type *t2, + const struct vkd3d_shader_location *loc, enum hlsl_type_class *type, unsigned int *dimx, unsigned int *dimy) +{ + if (t1->class > HLSL_CLASS_LAST_NUMERIC) + { + struct vkd3d_string_buffer *string; + + if ((string = hlsl_type_to_string(ctx, t1))) + hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE, + "Expression of type "%s" cannot be used in a numeric expression.", string->buffer); + hlsl_release_string_buffer(ctx, string); + return false; + } + + if (t2->class > HLSL_CLASS_LAST_NUMERIC) + { + struct vkd3d_string_buffer *string; + + if ((string = hlsl_type_to_string(ctx, t2))) + hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE, + "Expression of type "%s" cannot be used in a numeric expression.", string->buffer); + hlsl_release_string_buffer(ctx, string); + return false; + } + + if (!hlsl_expr_compatible_data_types(t1, t2)) + { + struct vkd3d_string_buffer *t1_string = hlsl_type_to_string(ctx, t1); + struct vkd3d_string_buffer *t2_string = hlsl_type_to_string(ctx, t2); + + if (t1_string && t2_string) + hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE, + "Expression data types "%s" and "%s" are incompatible.", + t1_string->buffer, t2_string->buffer); + hlsl_release_string_buffer(ctx, t1_string); + hlsl_release_string_buffer(ctx, t2_string); + return false; + } + + if (t1->dimx == 1 && t1->dimy == 1) + { + *type = t2->class; + *dimx = t2->dimx; + *dimy = t2->dimy; + } + else if (t2->dimx == 1 && t2->dimy == 1) + { + *type = t1->class; + *dimx = t1->dimx; + *dimy = t1->dimy; + } + else if (t1->class == HLSL_CLASS_MATRIX && t2->class == HLSL_CLASS_MATRIX) + { + *type = HLSL_CLASS_MATRIX; + *dimx = min(t1->dimx, t2->dimx); + *dimy = min(t1->dimy, t2->dimy); + } + else + { + if (t1->dimx * t1->dimy <= t2->dimx * t2->dimy) + { + *type = t1->class; + *dimx = t1->dimx; + *dimy = t1->dimy; + } + else + { + *type = t2->class; + *dimx = t2->dimx; + *dimy = t2->dimy; + } + } + + return true; +} + +static bool hlsl_types_are_componentwise_equal(struct hlsl_ctx *ctx, struct hlsl_type *src, + struct hlsl_type *dst) +{ + unsigned int k, count = hlsl_type_component_count(src); + + if (count != hlsl_type_component_count(dst)) + return false; + + for (k = 0; k < count; ++k) + { + struct hlsl_type *src_comp_type, *dst_comp_type; + + src_comp_type = hlsl_type_get_component_type(ctx, src, k); + dst_comp_type = hlsl_type_get_component_type(ctx, dst, k); + + if (!hlsl_types_are_equal(src_comp_type, dst_comp_type)) + return false; + } + return true; +} + +bool hlsl_implicit_compatible_data_types(struct hlsl_ctx *ctx, struct hlsl_type *src, struct hlsl_type *dst) +{ + if ((src->class <= HLSL_CLASS_LAST_NUMERIC) != (dst->class <= HLSL_CLASS_LAST_NUMERIC)) + return false; + + if (src->class <= HLSL_CLASS_LAST_NUMERIC) + { + /* Scalar vars can be converted to any other numeric data type */ + if (src->dimx == 1 && src->dimy == 1) + return true; + /* The other way around is true too */ + if (dst->dimx == 1 && dst->dimy == 1) + return true; + + if (src->class == HLSL_CLASS_MATRIX || dst->class == HLSL_CLASS_MATRIX) + { + if (src->class == HLSL_CLASS_MATRIX && dst->class == HLSL_CLASS_MATRIX) + return src->dimx >= dst->dimx && src->dimy >= dst->dimy; + + /* Matrix-vector conversion is apparently allowed if they have + * the same components count, or if the matrix is 1xN or Nx1 + * and we are reducing the component count */ + if (src->class == HLSL_CLASS_VECTOR || dst->class == HLSL_CLASS_VECTOR) + { + if (hlsl_type_component_count(src) == hlsl_type_component_count(dst)) + return true; + + if ((src->class == HLSL_CLASS_VECTOR || src->dimx == 1 || src->dimy == 1) && + (dst->class == HLSL_CLASS_VECTOR || dst->dimx == 1 || dst->dimy == 1)) + return hlsl_type_component_count(src) >= hlsl_type_component_count(dst); + } + + return false; + } + else + { + return src->dimx >= dst->dimx; + } + } + + return hlsl_types_are_componentwise_equal(ctx, src, dst); +} + +struct hlsl_ir_node *hlsl_add_implicit_conversion(struct hlsl_ctx *ctx, struct list *instrs, + struct hlsl_ir_node *node, struct hlsl_type *dst_type, const struct vkd3d_shader_location *loc) +{ + struct hlsl_type *src_type = node->data_type; + + if (hlsl_types_are_equal(src_type, dst_type)) + return node; + + if (!hlsl_implicit_compatible_data_types(ctx, src_type, dst_type)) + { + struct vkd3d_string_buffer *src_string, *dst_string; + + src_string = hlsl_type_to_string(ctx, src_type); + dst_string = hlsl_type_to_string(ctx, dst_type); + if (src_string && dst_string) + hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE, + "Can't implicitly convert from %s to %s.", src_string->buffer, dst_string->buffer); + hlsl_release_string_buffer(ctx, src_string); + hlsl_release_string_buffer(ctx, dst_string); + return NULL; + } + + if (dst_type->dimx * dst_type->dimy < src_type->dimx * src_type->dimy) + hlsl_warning(ctx, loc, VKD3D_SHADER_WARNING_HLSL_IMPLICIT_TRUNCATION, "Implicit truncation of %s type.", + src_type->class == HLSL_CLASS_VECTOR ? "vector" : "matrix"); + + return hlsl_add_cast(ctx, instrs, node, dst_type, loc); +} + +struct hlsl_ir_node *hlsl_add_cast(struct hlsl_ctx *ctx, struct list *instrs, + struct hlsl_ir_node *node, struct hlsl_type *dst_type, const struct vkd3d_shader_location *loc) +{ + struct hlsl_type *src_type = node->data_type; + struct hlsl_ir_node *cast; + + if (hlsl_types_are_equal(src_type, dst_type)) + return node; + + if (src_type->class > HLSL_CLASS_VECTOR || dst_type->class > HLSL_CLASS_VECTOR) + { + unsigned int src_comp_count = hlsl_type_component_count(src_type); + unsigned int dst_comp_count = hlsl_type_component_count(dst_type); + struct hlsl_deref var_deref; + bool broadcast, matrix_cast; + struct hlsl_ir_load *load; + struct hlsl_ir_var *var; + unsigned int dst_idx; + + broadcast = src_type->class <= HLSL_CLASS_LAST_NUMERIC && src_type->dimx == 1 && src_type->dimy == 1; + matrix_cast = !broadcast && dst_comp_count != src_comp_count + && src_type->class == HLSL_CLASS_MATRIX && dst_type->class == HLSL_CLASS_MATRIX; + assert(src_comp_count >= dst_comp_count || broadcast); + if (matrix_cast) + { + assert(dst_type->dimx <= src_type->dimx); + assert(dst_type->dimy <= src_type->dimy); + } + + if (!(var = hlsl_new_synthetic_var(ctx, "cast", dst_type, loc))) + return NULL; + hlsl_init_simple_deref_from_var(&var_deref, var); + + for (dst_idx = 0; dst_idx < dst_comp_count; ++dst_idx) + { + struct hlsl_ir_node *component_load; + struct hlsl_type *dst_comp_type; + struct hlsl_block block; + unsigned int src_idx; + + if (broadcast) + { + src_idx = 0; + } + else if (matrix_cast) + { + unsigned int x = dst_idx % dst_type->dimx, y = dst_idx / dst_type->dimx; + + src_idx = y * src_type->dimx + x; + } + else + { + src_idx = dst_idx; + } + + dst_comp_type = hlsl_type_get_component_type(ctx, dst_type, dst_idx); + + if (!(component_load = hlsl_add_load_component(ctx, instrs, node, src_idx, loc))) + return NULL; + + if (!(cast = hlsl_new_cast(ctx, component_load, dst_comp_type, loc))) + return NULL; + list_add_tail(instrs, &cast->entry); + + if (!hlsl_new_store_component(ctx, &block, &var_deref, dst_idx, cast)) + return NULL; + list_move_tail(instrs, &block.instrs); + } + + if (!(load = hlsl_new_var_load(ctx, var, loc))) + return NULL; + list_add_tail(instrs, &load->node.entry); + + return &load->node; + } + else + { + if (!(cast = hlsl_new_cast(ctx, node, dst_type, loc))) + return NULL; + list_add_tail(instrs, &cast->entry); + return cast; + } +} + +struct hlsl_ir_node *hlsl_add_load_component(struct hlsl_ctx *ctx, struct list *instrs, struct hlsl_ir_node *var_instr, + unsigned int comp, const struct vkd3d_shader_location *loc) +{ + struct hlsl_ir_node *load, *store; + struct hlsl_block block; + struct hlsl_ir_var *var; + struct hlsl_deref src; + + if (!(var = hlsl_new_synthetic_var(ctx, "deref", var_instr->data_type, &var_instr->loc))) + return NULL; + + if (!(store = hlsl_new_simple_store(ctx, var, var_instr))) + return NULL; + list_add_tail(instrs, &store->entry); + + hlsl_init_simple_deref_from_var(&src, var); + if (!(load = hlsl_new_load_component(ctx, &block, &src, comp, loc))) + return NULL; + list_move_tail(instrs, &block.instrs); + + return load; +} + +struct hlsl_ir_node *hlsl_add_expr(struct hlsl_ctx *ctx, struct list *instrs, + enum hlsl_ir_expr_op op, struct hlsl_ir_node *operands[HLSL_MAX_OPERANDS], + struct hlsl_type *type, const struct vkd3d_shader_location *loc) +{ + struct hlsl_ir_node *expr; + unsigned int i; + + if (type->class == HLSL_CLASS_MATRIX) + { + struct hlsl_type *scalar_type; + struct hlsl_ir_load *var_load; + struct hlsl_deref var_deref; + struct hlsl_ir_node *load; + struct hlsl_ir_var *var; + + scalar_type = hlsl_get_scalar_type(ctx, type->base_type); + + if (!(var = hlsl_new_synthetic_var(ctx, "split_op", type, loc))) + return NULL; + hlsl_init_simple_deref_from_var(&var_deref, var); + + for (i = 0; i < type->dimy * type->dimx; ++i) + { + struct hlsl_ir_node *value, *cell_operands[HLSL_MAX_OPERANDS] = { NULL }; + struct hlsl_block block; + unsigned int j; + + for (j = 0; j < HLSL_MAX_OPERANDS; j++) + { + if (operands[j]) + { + if (!(load = hlsl_add_load_component(ctx, instrs, operands[j], i, loc))) + return NULL; + + cell_operands[j] = load; + } + } + + if (!(value = hlsl_add_expr(ctx, instrs, op, cell_operands, scalar_type, loc))) + return NULL; + + if (!hlsl_new_store_component(ctx, &block, &var_deref, i, value)) + return NULL; + list_move_tail(instrs, &block.instrs); + } + + if (!(var_load = hlsl_new_var_load(ctx, var, loc))) + return NULL; + list_add_tail(instrs, &var_load->node.entry); + + return &var_load->node; + } + + if (!(expr = hlsl_new_expr(ctx, op, operands, type, loc))) + return NULL; + list_add_tail(instrs, &expr->entry); + + return expr; +} + +struct hlsl_ir_node *hlsl_add_binary_comparison_expr(struct hlsl_ctx *ctx, struct list *instrs, + enum hlsl_ir_expr_op op, struct hlsl_ir_node *arg1, struct hlsl_ir_node *arg2, + const struct vkd3d_shader_location *loc) +{ + struct hlsl_type *common_type, *return_type; + enum hlsl_base_type base = hlsl_expr_common_base_type(arg1->data_type->base_type, arg2->data_type->base_type); + enum hlsl_type_class type; + unsigned int dimx, dimy; + struct hlsl_ir_node *args[HLSL_MAX_OPERANDS] = {0}; + + if (!hlsl_expr_common_shape(ctx, arg1->data_type, arg2->data_type, loc, &type, &dimx, &dimy)) + return NULL; + + common_type = hlsl_get_numeric_type(ctx, type, base, dimx, dimy); + return_type = hlsl_get_numeric_type(ctx, type, HLSL_TYPE_BOOL, dimx, dimy); + + if (!(args[0] = hlsl_add_implicit_conversion(ctx, instrs, arg1, common_type, loc))) + return NULL; + + if (!(args[1] = hlsl_add_implicit_conversion(ctx, instrs, arg2, common_type, loc))) + return NULL; + + return hlsl_add_expr(ctx, instrs, op, args, return_type, loc); +} + +struct hlsl_ir_node *hlsl_add_binary_logical_expr(struct hlsl_ctx *ctx, struct list *instrs, + enum hlsl_ir_expr_op op, struct hlsl_ir_node *arg1, struct hlsl_ir_node *arg2, + const struct vkd3d_shader_location *loc) +{ + struct hlsl_ir_node *args[HLSL_MAX_OPERANDS] = {0}; + struct hlsl_type *common_type; + enum hlsl_type_class type; + unsigned int dimx, dimy; + + if (!hlsl_expr_common_shape(ctx, arg1->data_type, arg2->data_type, loc, &type, &dimx, &dimy)) + return NULL; + + common_type = hlsl_get_numeric_type(ctx, type, HLSL_TYPE_BOOL, dimx, dimy); + + if (!(args[0] = hlsl_add_implicit_conversion(ctx, instrs, arg1, common_type, loc))) + return NULL; + + if (!(args[1] = hlsl_add_implicit_conversion(ctx, instrs, arg2, common_type, loc))) + return NULL; + + return hlsl_add_expr(ctx, instrs, op, args, common_type, loc); +} + struct clone_instr_map { struct @@ -1588,9 +2025,16 @@ static struct hlsl_ir_node *clone_if(struct hlsl_ctx *ctx, struct clone_instr_ma return dst; }
-static struct hlsl_ir_node *clone_jump(struct hlsl_ctx *ctx, struct hlsl_ir_jump *src) +static struct hlsl_ir_node *clone_jump(struct hlsl_ctx *ctx, struct clone_instr_map *map, struct hlsl_ir_jump *src) { - return hlsl_new_jump(ctx, src->type, &src->node.loc); + struct hlsl_ir_node *node; + struct hlsl_ir_jump *jump; + + if (!(node = hlsl_new_jump(ctx, src->type, NULL, &src->node.loc))) + return NULL; + jump = hlsl_ir_jump(node); + clone_src(map, &jump->arg, &src->arg); + return &jump->node; }
static struct hlsl_ir_node *clone_load(struct hlsl_ctx *ctx, struct clone_instr_map *map, struct hlsl_ir_load *src) @@ -1731,7 +2175,7 @@ static struct hlsl_ir_node *clone_instr(struct hlsl_ctx *ctx, return clone_index(ctx, map, hlsl_ir_index(instr));
case HLSL_IR_JUMP: - return clone_jump(ctx, hlsl_ir_jump(instr)); + return clone_jump(ctx, map, hlsl_ir_jump(instr));
case HLSL_IR_LOAD: return clone_load(ctx, map, hlsl_ir_load(instr)); @@ -2151,6 +2595,7 @@ const char *hlsl_jump_type_to_string(enum hlsl_ir_jump_type type) { "HLSL_IR_JUMP_BREAK", "HLSL_IR_JUMP_CONTINUE", + "HLSL_IR_JUMP_TEXKILL", "HLSL_IR_JUMP_DISCARD", "HLSL_IR_JUMP_RETURN", }; @@ -2428,6 +2873,10 @@ static void dump_ir_jump(struct vkd3d_string_buffer *buffer, const struct hlsl_i case HLSL_IR_JUMP_RETURN: vkd3d_string_buffer_printf(buffer, "return"); break; + + case HLSL_IR_JUMP_TEXKILL: + vkd3d_string_buffer_printf(buffer, "texkill"); + break; } }
@@ -2706,6 +3155,7 @@ static void free_ir_if(struct hlsl_ir_if *if_node)
static void free_ir_jump(struct hlsl_ir_jump *jump) { + hlsl_src_remove(&jump->arg); vkd3d_free(jump); }
diff --git a/libs/vkd3d-shader/hlsl.h b/libs/vkd3d-shader/hlsl.h index 7d02448e0..e7aafa7e2 100644 --- a/libs/vkd3d-shader/hlsl.h +++ b/libs/vkd3d-shader/hlsl.h @@ -558,6 +558,7 @@ enum hlsl_ir_jump_type { HLSL_IR_JUMP_BREAK, HLSL_IR_JUMP_CONTINUE, + HLSL_IR_JUMP_TEXKILL, HLSL_IR_JUMP_DISCARD, HLSL_IR_JUMP_RETURN, }; @@ -566,6 +567,8 @@ struct hlsl_ir_jump { struct hlsl_ir_node node; enum hlsl_ir_jump_type type; + /* Argument used for DISCARD/TEXKILL. */ + struct hlsl_src arg; };
struct hlsl_ir_swizzle @@ -1121,7 +1124,27 @@ struct hlsl_ir_node *hlsl_new_if(struct hlsl_ctx *ctx, struct hlsl_ir_node *cond struct hlsl_block *then_block, struct hlsl_block *else_block, const struct vkd3d_shader_location *loc); struct hlsl_ir_node *hlsl_new_int_constant(struct hlsl_ctx *ctx, int32_t n, const struct vkd3d_shader_location *loc); struct hlsl_ir_node *hlsl_new_jump(struct hlsl_ctx *ctx, - enum hlsl_ir_jump_type type, const struct vkd3d_shader_location *loc); + enum hlsl_ir_jump_type type, struct hlsl_ir_node *arg, const struct vkd3d_shader_location *loc); + +enum hlsl_base_type hlsl_expr_common_base_type(enum hlsl_base_type t1, enum hlsl_base_type t2); +bool hlsl_expr_common_shape(struct hlsl_ctx *ctx, struct hlsl_type *t1, struct hlsl_type *t2, + const struct vkd3d_shader_location *loc, enum hlsl_type_class *type, unsigned int *dimx, unsigned int *dimy); +struct hlsl_ir_node *hlsl_add_binary_comparison_expr(struct hlsl_ctx *ctx, struct list *instrs, + enum hlsl_ir_expr_op op, struct hlsl_ir_node *arg1, struct hlsl_ir_node *arg2, + const struct vkd3d_shader_location *loc); +bool hlsl_implicit_compatible_data_types(struct hlsl_ctx *ctx, struct hlsl_type *src, struct hlsl_type *dst); +struct hlsl_ir_node *hlsl_add_implicit_conversion(struct hlsl_ctx *ctx, struct list *instrs, + struct hlsl_ir_node *node, struct hlsl_type *dst_type, const struct vkd3d_shader_location *loc); +struct hlsl_ir_node *hlsl_add_cast(struct hlsl_ctx *ctx, struct list *instrs, + struct hlsl_ir_node *node, struct hlsl_type *dst_type, const struct vkd3d_shader_location *loc); +struct hlsl_ir_node *hlsl_add_load_component(struct hlsl_ctx *ctx, struct list *instrs, struct hlsl_ir_node *var_instr, + unsigned int comp, const struct vkd3d_shader_location *loc); +struct hlsl_ir_node *hlsl_add_expr(struct hlsl_ctx *ctx, struct list *instrs, + enum hlsl_ir_expr_op op, struct hlsl_ir_node *operands[HLSL_MAX_OPERANDS], + struct hlsl_type *type, const struct vkd3d_shader_location *loc); +struct hlsl_ir_node *hlsl_add_binary_logical_expr(struct hlsl_ctx *ctx, struct list *instrs, + enum hlsl_ir_expr_op op, struct hlsl_ir_node *arg1, struct hlsl_ir_node *arg2, + const struct vkd3d_shader_location *loc);
void hlsl_init_simple_deref_from_var(struct hlsl_deref *deref, struct hlsl_ir_var *var);
diff --git a/libs/vkd3d-shader/hlsl.y b/libs/vkd3d-shader/hlsl.y index cf483d82c..29eba2faf 100644 --- a/libs/vkd3d-shader/hlsl.y +++ b/libs/vkd3d-shader/hlsl.y @@ -171,27 +171,6 @@ static bool hlsl_types_are_componentwise_compatible(struct hlsl_ctx *ctx, struct return true; }
-static bool hlsl_types_are_componentwise_equal(struct hlsl_ctx *ctx, struct hlsl_type *src, - struct hlsl_type *dst) -{ - unsigned int k, count = hlsl_type_component_count(src); - - if (count != hlsl_type_component_count(dst)) - return false; - - for (k = 0; k < count; ++k) - { - struct hlsl_type *src_comp_type, *dst_comp_type; - - src_comp_type = hlsl_type_get_component_type(ctx, src, k); - dst_comp_type = hlsl_type_get_component_type(ctx, dst, k); - - if (!hlsl_types_are_equal(src_comp_type, dst_comp_type)) - return false; - } - return true; -} - static bool type_contains_only_numerics(struct hlsl_type *type) { unsigned int i; @@ -230,165 +209,6 @@ static bool explicit_compatible_data_types(struct hlsl_ctx *ctx, struct hlsl_typ return hlsl_types_are_componentwise_compatible(ctx, src, dst); }
-static bool implicit_compatible_data_types(struct hlsl_ctx *ctx, struct hlsl_type *src, struct hlsl_type *dst) -{ - if ((src->class <= HLSL_CLASS_LAST_NUMERIC) != (dst->class <= HLSL_CLASS_LAST_NUMERIC)) - return false; - - if (src->class <= HLSL_CLASS_LAST_NUMERIC) - { - /* Scalar vars can be converted to any other numeric data type */ - if (src->dimx == 1 && src->dimy == 1) - return true; - /* The other way around is true too */ - if (dst->dimx == 1 && dst->dimy == 1) - return true; - - if (src->class == HLSL_CLASS_MATRIX || dst->class == HLSL_CLASS_MATRIX) - { - if (src->class == HLSL_CLASS_MATRIX && dst->class == HLSL_CLASS_MATRIX) - return src->dimx >= dst->dimx && src->dimy >= dst->dimy; - - /* Matrix-vector conversion is apparently allowed if they have - * the same components count, or if the matrix is 1xN or Nx1 - * and we are reducing the component count */ - if (src->class == HLSL_CLASS_VECTOR || dst->class == HLSL_CLASS_VECTOR) - { - if (hlsl_type_component_count(src) == hlsl_type_component_count(dst)) - return true; - - if ((src->class == HLSL_CLASS_VECTOR || src->dimx == 1 || src->dimy == 1) && - (dst->class == HLSL_CLASS_VECTOR || dst->dimx == 1 || dst->dimy == 1)) - return hlsl_type_component_count(src) >= hlsl_type_component_count(dst); - } - - return false; - } - else - { - return src->dimx >= dst->dimx; - } - } - - return hlsl_types_are_componentwise_equal(ctx, src, dst); -} - -static struct hlsl_ir_node *add_load_component(struct hlsl_ctx *ctx, struct list *instrs, struct hlsl_ir_node *var_instr, - unsigned int comp, const struct vkd3d_shader_location *loc); - -static struct hlsl_ir_node *add_cast(struct hlsl_ctx *ctx, struct list *instrs, - struct hlsl_ir_node *node, struct hlsl_type *dst_type, const struct vkd3d_shader_location *loc) -{ - struct hlsl_type *src_type = node->data_type; - struct hlsl_ir_node *cast; - - if (hlsl_types_are_equal(src_type, dst_type)) - return node; - - if (src_type->class > HLSL_CLASS_VECTOR || dst_type->class > HLSL_CLASS_VECTOR) - { - unsigned int src_comp_count = hlsl_type_component_count(src_type); - unsigned int dst_comp_count = hlsl_type_component_count(dst_type); - struct hlsl_deref var_deref; - bool broadcast, matrix_cast; - struct hlsl_ir_load *load; - struct hlsl_ir_var *var; - unsigned int dst_idx; - - broadcast = src_type->class <= HLSL_CLASS_LAST_NUMERIC && src_type->dimx == 1 && src_type->dimy == 1; - matrix_cast = !broadcast && dst_comp_count != src_comp_count - && src_type->class == HLSL_CLASS_MATRIX && dst_type->class == HLSL_CLASS_MATRIX; - assert(src_comp_count >= dst_comp_count || broadcast); - if (matrix_cast) - { - assert(dst_type->dimx <= src_type->dimx); - assert(dst_type->dimy <= src_type->dimy); - } - - if (!(var = hlsl_new_synthetic_var(ctx, "cast", dst_type, loc))) - return NULL; - hlsl_init_simple_deref_from_var(&var_deref, var); - - for (dst_idx = 0; dst_idx < dst_comp_count; ++dst_idx) - { - struct hlsl_ir_node *component_load; - struct hlsl_type *dst_comp_type; - struct hlsl_block block; - unsigned int src_idx; - - if (broadcast) - { - src_idx = 0; - } - else if (matrix_cast) - { - unsigned int x = dst_idx % dst_type->dimx, y = dst_idx / dst_type->dimx; - - src_idx = y * src_type->dimx + x; - } - else - { - src_idx = dst_idx; - } - - dst_comp_type = hlsl_type_get_component_type(ctx, dst_type, dst_idx); - - if (!(component_load = add_load_component(ctx, instrs, node, src_idx, loc))) - return NULL; - - if (!(cast = hlsl_new_cast(ctx, component_load, dst_comp_type, loc))) - return NULL; - list_add_tail(instrs, &cast->entry); - - if (!hlsl_new_store_component(ctx, &block, &var_deref, dst_idx, cast)) - return NULL; - list_move_tail(instrs, &block.instrs); - } - - if (!(load = hlsl_new_var_load(ctx, var, loc))) - return NULL; - list_add_tail(instrs, &load->node.entry); - - return &load->node; - } - else - { - if (!(cast = hlsl_new_cast(ctx, node, dst_type, loc))) - return NULL; - list_add_tail(instrs, &cast->entry); - return cast; - } -} - -static struct hlsl_ir_node *add_implicit_conversion(struct hlsl_ctx *ctx, struct list *instrs, - struct hlsl_ir_node *node, struct hlsl_type *dst_type, const struct vkd3d_shader_location *loc) -{ - struct hlsl_type *src_type = node->data_type; - - if (hlsl_types_are_equal(src_type, dst_type)) - return node; - - if (!implicit_compatible_data_types(ctx, src_type, dst_type)) - { - struct vkd3d_string_buffer *src_string, *dst_string; - - src_string = hlsl_type_to_string(ctx, src_type); - dst_string = hlsl_type_to_string(ctx, dst_type); - if (src_string && dst_string) - hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE, - "Can't implicitly convert from %s to %s.", src_string->buffer, dst_string->buffer); - hlsl_release_string_buffer(ctx, src_string); - hlsl_release_string_buffer(ctx, dst_string); - return NULL; - } - - if (dst_type->dimx * dst_type->dimy < src_type->dimx * src_type->dimy) - hlsl_warning(ctx, loc, VKD3D_SHADER_WARNING_HLSL_IMPLICIT_TRUNCATION, "Implicit truncation of %s type.", - src_type->class == HLSL_CLASS_VECTOR ? "vector" : "matrix"); - - return add_cast(ctx, instrs, node, dst_type, loc); -} - static DWORD add_modifiers(struct hlsl_ctx *ctx, DWORD modifiers, DWORD mod, const struct vkd3d_shader_location *loc) { @@ -421,7 +241,7 @@ static bool append_conditional_break(struct hlsl_ctx *ctx, struct list *cond_lis
hlsl_block_init(&then_block);
- if (!(jump = hlsl_new_jump(ctx, HLSL_IR_JUMP_BREAK, &condition->loc))) + if (!(jump = hlsl_new_jump(ctx, HLSL_IR_JUMP_BREAK, NULL, &condition->loc))) return false; hlsl_block_add_instr(&then_block, jump);
@@ -637,7 +457,7 @@ static bool add_return(struct hlsl_ctx *ctx, struct list *instrs, { struct hlsl_ir_node *store;
- if (!(return_value = add_implicit_conversion(ctx, instrs, return_value, return_type, loc))) + if (!(return_value = hlsl_add_implicit_conversion(ctx, instrs, return_value, return_type, loc))) return false;
if (!(store = hlsl_new_simple_store(ctx, ctx->cur_function->return_var, return_value))) @@ -656,36 +476,13 @@ static bool add_return(struct hlsl_ctx *ctx, struct list *instrs, hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_INVALID_RETURN, "Void functions cannot return a value."); }
- if (!(jump = hlsl_new_jump(ctx, HLSL_IR_JUMP_RETURN, loc))) + if (!(jump = hlsl_new_jump(ctx, HLSL_IR_JUMP_RETURN, NULL, loc))) return false; list_add_tail(instrs, &jump->entry);
return true; }
-static struct hlsl_ir_node *add_load_component(struct hlsl_ctx *ctx, struct list *instrs, struct hlsl_ir_node *var_instr, - unsigned int comp, const struct vkd3d_shader_location *loc) -{ - struct hlsl_ir_node *load, *store; - struct hlsl_block block; - struct hlsl_ir_var *var; - struct hlsl_deref src; - - if (!(var = hlsl_new_synthetic_var(ctx, "deref", var_instr->data_type, &var_instr->loc))) - return NULL; - - if (!(store = hlsl_new_simple_store(ctx, var, var_instr))) - return NULL; - list_add_tail(instrs, &store->entry); - - hlsl_init_simple_deref_from_var(&src, var); - if (!(load = hlsl_new_load_component(ctx, &block, &src, comp, loc))) - return NULL; - list_move_tail(instrs, &block.instrs); - - return load; -} - static bool add_record_access(struct hlsl_ctx *ctx, struct list *instrs, struct hlsl_ir_node *record, unsigned int idx, const struct vkd3d_shader_location *loc) { @@ -731,7 +528,7 @@ static bool add_array_access(struct hlsl_ctx *ctx, struct list *instrs, struct h return false; }
- if (!(index = add_implicit_conversion(ctx, instrs, index, + if (!(index = hlsl_add_implicit_conversion(ctx, instrs, index, hlsl_get_vector_type(ctx, HLSL_TYPE_UINT, dim_count), &index->loc))) return false;
@@ -1099,7 +896,7 @@ static unsigned int evaluate_static_expression_as_uint(struct hlsl_ctx *ctx, str struct hlsl_ir_node *node; unsigned int ret = 0;
- if (!add_implicit_conversion(ctx, &block->instrs, node_from_list(&block->instrs), + if (!hlsl_add_implicit_conversion(ctx, &block->instrs, node_from_list(&block->instrs), hlsl_get_scalar_type(ctx, HLSL_TYPE_UINT), loc)) return 0;
@@ -1120,194 +917,6 @@ static unsigned int evaluate_static_expression_as_uint(struct hlsl_ctx *ctx, str return ret; }
-static bool expr_compatible_data_types(struct hlsl_type *t1, struct hlsl_type *t2) -{ - if (t1->base_type > HLSL_TYPE_LAST_SCALAR || t2->base_type > HLSL_TYPE_LAST_SCALAR) - return false; - - /* Scalar vars can be converted to pretty much everything */ - if ((t1->dimx == 1 && t1->dimy == 1) || (t2->dimx == 1 && t2->dimy == 1)) - return true; - - if (t1->class == HLSL_CLASS_VECTOR && t2->class == HLSL_CLASS_VECTOR) - return true; - - if (t1->class == HLSL_CLASS_MATRIX || t2->class == HLSL_CLASS_MATRIX) - { - /* Matrix-vector conversion is apparently allowed if either they have the same components - count or the matrix is nx1 or 1xn */ - if (t1->class == HLSL_CLASS_VECTOR || t2->class == HLSL_CLASS_VECTOR) - { - if (hlsl_type_component_count(t1) == hlsl_type_component_count(t2)) - return true; - - return (t1->class == HLSL_CLASS_MATRIX && (t1->dimx == 1 || t1->dimy == 1)) - || (t2->class == HLSL_CLASS_MATRIX && (t2->dimx == 1 || t2->dimy == 1)); - } - - /* Both matrices */ - if ((t1->dimx >= t2->dimx && t1->dimy >= t2->dimy) - || (t1->dimx <= t2->dimx && t1->dimy <= t2->dimy)) - return true; - } - - return false; -} - -static enum hlsl_base_type expr_common_base_type(enum hlsl_base_type t1, enum hlsl_base_type t2) -{ - if (t1 > HLSL_TYPE_LAST_SCALAR || t2 > HLSL_TYPE_LAST_SCALAR) { - FIXME("Unexpected base type.\n"); - return HLSL_TYPE_FLOAT; - } - if (t1 == t2) - return t1 == HLSL_TYPE_BOOL ? HLSL_TYPE_INT : t1; - if (t1 == HLSL_TYPE_DOUBLE || t2 == HLSL_TYPE_DOUBLE) - return HLSL_TYPE_DOUBLE; - if (t1 == HLSL_TYPE_FLOAT || t2 == HLSL_TYPE_FLOAT - || t1 == HLSL_TYPE_HALF || t2 == HLSL_TYPE_HALF) - return HLSL_TYPE_FLOAT; - if (t1 == HLSL_TYPE_UINT || t2 == HLSL_TYPE_UINT) - return HLSL_TYPE_UINT; - return HLSL_TYPE_INT; -} - -static bool expr_common_shape(struct hlsl_ctx *ctx, struct hlsl_type *t1, struct hlsl_type *t2, - const struct vkd3d_shader_location *loc, enum hlsl_type_class *type, unsigned int *dimx, unsigned int *dimy) -{ - if (t1->class > HLSL_CLASS_LAST_NUMERIC) - { - struct vkd3d_string_buffer *string; - - if ((string = hlsl_type_to_string(ctx, t1))) - hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE, - "Expression of type "%s" cannot be used in a numeric expression.", string->buffer); - hlsl_release_string_buffer(ctx, string); - return false; - } - - if (t2->class > HLSL_CLASS_LAST_NUMERIC) - { - struct vkd3d_string_buffer *string; - - if ((string = hlsl_type_to_string(ctx, t2))) - hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE, - "Expression of type "%s" cannot be used in a numeric expression.", string->buffer); - hlsl_release_string_buffer(ctx, string); - return false; - } - - if (!expr_compatible_data_types(t1, t2)) - { - struct vkd3d_string_buffer *t1_string = hlsl_type_to_string(ctx, t1); - struct vkd3d_string_buffer *t2_string = hlsl_type_to_string(ctx, t2); - - if (t1_string && t2_string) - hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE, - "Expression data types "%s" and "%s" are incompatible.", - t1_string->buffer, t2_string->buffer); - hlsl_release_string_buffer(ctx, t1_string); - hlsl_release_string_buffer(ctx, t2_string); - return false; - } - - if (t1->dimx == 1 && t1->dimy == 1) - { - *type = t2->class; - *dimx = t2->dimx; - *dimy = t2->dimy; - } - else if (t2->dimx == 1 && t2->dimy == 1) - { - *type = t1->class; - *dimx = t1->dimx; - *dimy = t1->dimy; - } - else if (t1->class == HLSL_CLASS_MATRIX && t2->class == HLSL_CLASS_MATRIX) - { - *type = HLSL_CLASS_MATRIX; - *dimx = min(t1->dimx, t2->dimx); - *dimy = min(t1->dimy, t2->dimy); - } - else - { - if (t1->dimx * t1->dimy <= t2->dimx * t2->dimy) - { - *type = t1->class; - *dimx = t1->dimx; - *dimy = t1->dimy; - } - else - { - *type = t2->class; - *dimx = t2->dimx; - *dimy = t2->dimy; - } - } - - return true; -} - -static struct hlsl_ir_node *add_expr(struct hlsl_ctx *ctx, struct list *instrs, - enum hlsl_ir_expr_op op, struct hlsl_ir_node *operands[HLSL_MAX_OPERANDS], - struct hlsl_type *type, const struct vkd3d_shader_location *loc) -{ - struct hlsl_ir_node *expr; - unsigned int i; - - if (type->class == HLSL_CLASS_MATRIX) - { - struct hlsl_type *scalar_type; - struct hlsl_ir_load *var_load; - struct hlsl_deref var_deref; - struct hlsl_ir_node *load; - struct hlsl_ir_var *var; - - scalar_type = hlsl_get_scalar_type(ctx, type->base_type); - - if (!(var = hlsl_new_synthetic_var(ctx, "split_op", type, loc))) - return NULL; - hlsl_init_simple_deref_from_var(&var_deref, var); - - for (i = 0; i < type->dimy * type->dimx; ++i) - { - struct hlsl_ir_node *value, *cell_operands[HLSL_MAX_OPERANDS] = { NULL }; - struct hlsl_block block; - unsigned int j; - - for (j = 0; j < HLSL_MAX_OPERANDS; j++) - { - if (operands[j]) - { - if (!(load = add_load_component(ctx, instrs, operands[j], i, loc))) - return NULL; - - cell_operands[j] = load; - } - } - - if (!(value = add_expr(ctx, instrs, op, cell_operands, scalar_type, loc))) - return NULL; - - if (!hlsl_new_store_component(ctx, &block, &var_deref, i, value)) - return NULL; - list_move_tail(instrs, &block.instrs); - } - - if (!(var_load = hlsl_new_var_load(ctx, var, loc))) - return NULL; - list_add_tail(instrs, &var_load->node.entry); - - return &var_load->node; - } - - if (!(expr = hlsl_new_expr(ctx, op, operands, type, loc))) - return NULL; - list_add_tail(instrs, &expr->entry); - - return expr; -} - static void check_integer_type(struct hlsl_ctx *ctx, const struct hlsl_ir_node *instr) { const struct hlsl_type *type = instr->data_type; @@ -1334,7 +943,7 @@ static struct hlsl_ir_node *add_unary_arithmetic_expr(struct hlsl_ctx *ctx, stru { struct hlsl_ir_node *args[HLSL_MAX_OPERANDS] = {arg};
- return add_expr(ctx, instrs, op, args, arg->data_type, loc); + return hlsl_add_expr(ctx, instrs, op, args, arg->data_type, loc); }
static struct hlsl_ir_node *add_unary_bitwise_expr(struct hlsl_ctx *ctx, struct list *instrs, @@ -1354,20 +963,20 @@ static struct hlsl_ir_node *add_unary_logical_expr(struct hlsl_ctx *ctx, struct bool_type = hlsl_get_numeric_type(ctx, arg->data_type->class, HLSL_TYPE_BOOL, arg->data_type->dimx, arg->data_type->dimy);
- if (!(args[0] = add_implicit_conversion(ctx, instrs, arg, bool_type, loc))) + if (!(args[0] = hlsl_add_implicit_conversion(ctx, instrs, arg, bool_type, loc))) return NULL;
- return add_expr(ctx, instrs, op, args, bool_type, loc); + return hlsl_add_expr(ctx, instrs, op, args, bool_type, loc); }
static struct hlsl_type *get_common_numeric_type(struct hlsl_ctx *ctx, const struct hlsl_ir_node *arg1, const struct hlsl_ir_node *arg2, const struct vkd3d_shader_location *loc) { - enum hlsl_base_type base = expr_common_base_type(arg1->data_type->base_type, arg2->data_type->base_type); + enum hlsl_base_type base = hlsl_expr_common_base_type(arg1->data_type->base_type, arg2->data_type->base_type); enum hlsl_type_class type; unsigned int dimx, dimy;
- if (!expr_common_shape(ctx, arg1->data_type, arg2->data_type, loc, &type, &dimx, &dimy)) + if (!hlsl_expr_common_shape(ctx, arg1->data_type, arg2->data_type, loc, &type, &dimx, &dimy)) return NULL;
return hlsl_get_numeric_type(ctx, type, base, dimx, dimy); @@ -1382,13 +991,13 @@ static struct hlsl_ir_node *add_binary_arithmetic_expr(struct hlsl_ctx *ctx, str
common_type = get_common_numeric_type(ctx, arg1, arg2, loc);
- if (!(args[0] = add_implicit_conversion(ctx, instrs, arg1, common_type, loc))) + if (!(args[0] = hlsl_add_implicit_conversion(ctx, instrs, arg1, common_type, loc))) return NULL;
- if (!(args[1] = add_implicit_conversion(ctx, instrs, arg2, common_type, loc))) + if (!(args[1] = hlsl_add_implicit_conversion(ctx, instrs, arg2, common_type, loc))) return NULL;
- return add_expr(ctx, instrs, op, args, common_type, loc); + return hlsl_add_expr(ctx, instrs, op, args, common_type, loc); }
static struct list *add_binary_arithmetic_expr_merge(struct hlsl_ctx *ctx, struct list *list1, struct list *list2, @@ -1424,31 +1033,6 @@ static struct list *add_binary_bitwise_expr_merge(struct hlsl_ctx *ctx, struct l return list1; }
-static struct hlsl_ir_node *add_binary_comparison_expr(struct hlsl_ctx *ctx, struct list *instrs, - enum hlsl_ir_expr_op op, struct hlsl_ir_node *arg1, struct hlsl_ir_node *arg2, - const struct vkd3d_shader_location *loc) -{ - struct hlsl_type *common_type, *return_type; - enum hlsl_base_type base = expr_common_base_type(arg1->data_type->base_type, arg2->data_type->base_type); - enum hlsl_type_class type; - unsigned int dimx, dimy; - struct hlsl_ir_node *args[HLSL_MAX_OPERANDS] = {0}; - - if (!expr_common_shape(ctx, arg1->data_type, arg2->data_type, loc, &type, &dimx, &dimy)) - return NULL; - - common_type = hlsl_get_numeric_type(ctx, type, base, dimx, dimy); - return_type = hlsl_get_numeric_type(ctx, type, HLSL_TYPE_BOOL, dimx, dimy); - - if (!(args[0] = add_implicit_conversion(ctx, instrs, arg1, common_type, loc))) - return NULL; - - if (!(args[1] = add_implicit_conversion(ctx, instrs, arg2, common_type, loc))) - return NULL; - - return add_expr(ctx, instrs, op, args, return_type, loc); -} - static struct list *add_binary_comparison_expr_merge(struct hlsl_ctx *ctx, struct list *list1, struct list *list2, enum hlsl_ir_expr_op op, const struct vkd3d_shader_location *loc) { @@ -1456,33 +1040,10 @@ static struct list *add_binary_comparison_expr_merge(struct hlsl_ctx *ctx, struc
list_move_tail(list1, list2); vkd3d_free(list2); - add_binary_comparison_expr(ctx, list1, op, arg1, arg2, loc); + hlsl_add_binary_comparison_expr(ctx, list1, op, arg1, arg2, loc); return list1; }
-static struct hlsl_ir_node *add_binary_logical_expr(struct hlsl_ctx *ctx, struct list *instrs, - enum hlsl_ir_expr_op op, struct hlsl_ir_node *arg1, struct hlsl_ir_node *arg2, - const struct vkd3d_shader_location *loc) -{ - struct hlsl_ir_node *args[HLSL_MAX_OPERANDS] = {0}; - struct hlsl_type *common_type; - enum hlsl_type_class type; - unsigned int dimx, dimy; - - if (!expr_common_shape(ctx, arg1->data_type, arg2->data_type, loc, &type, &dimx, &dimy)) - return NULL; - - common_type = hlsl_get_numeric_type(ctx, type, HLSL_TYPE_BOOL, dimx, dimy); - - if (!(args[0] = add_implicit_conversion(ctx, instrs, arg1, common_type, loc))) - return NULL; - - if (!(args[1] = add_implicit_conversion(ctx, instrs, arg2, common_type, loc))) - return NULL; - - return add_expr(ctx, instrs, op, args, common_type, loc); -} - static struct list *add_binary_logical_expr_merge(struct hlsl_ctx *ctx, struct list *list1, struct list *list2, enum hlsl_ir_expr_op op, const struct vkd3d_shader_location *loc) { @@ -1490,7 +1051,7 @@ static struct list *add_binary_logical_expr_merge(struct hlsl_ctx *ctx, struct l
list_move_tail(list1, list2); vkd3d_free(list2); - add_binary_logical_expr(ctx, list1, op, arg1, arg2, loc); + hlsl_add_binary_logical_expr(ctx, list1, op, arg1, arg2, loc);
return list1; } @@ -1511,19 +1072,19 @@ static struct hlsl_ir_node *add_binary_shift_expr(struct hlsl_ctx *ctx, struct l if (base == HLSL_TYPE_BOOL) base = HLSL_TYPE_INT;
- if (!expr_common_shape(ctx, arg1->data_type, arg2->data_type, loc, &type, &dimx, &dimy)) + if (!hlsl_expr_common_shape(ctx, arg1->data_type, arg2->data_type, loc, &type, &dimx, &dimy)) return NULL;
return_type = hlsl_get_numeric_type(ctx, type, base, dimx, dimy); integer_type = hlsl_get_numeric_type(ctx, type, HLSL_TYPE_INT, dimx, dimy);
- if (!(args[0] = add_implicit_conversion(ctx, instrs, arg1, return_type, loc))) + if (!(args[0] = hlsl_add_implicit_conversion(ctx, instrs, arg1, return_type, loc))) return NULL;
- if (!(args[1] = add_implicit_conversion(ctx, instrs, arg2, integer_type, loc))) + if (!(args[1] = hlsl_add_implicit_conversion(ctx, instrs, arg2, integer_type, loc))) return NULL;
- return add_expr(ctx, instrs, op, args, return_type, loc); + return hlsl_add_expr(ctx, instrs, op, args, return_type, loc); }
static struct list *add_binary_shift_expr_merge(struct hlsl_ctx *ctx, struct list *list1, struct list *list2, @@ -1541,7 +1102,7 @@ static struct list *add_binary_shift_expr_merge(struct hlsl_ctx *ctx, struct lis static struct hlsl_ir_node *add_binary_dot_expr(struct hlsl_ctx *ctx, struct list *instrs, struct hlsl_ir_node *arg1, struct hlsl_ir_node *arg2, const struct vkd3d_shader_location *loc) { - enum hlsl_base_type base = expr_common_base_type(arg1->data_type->base_type, arg2->data_type->base_type); + enum hlsl_base_type base = hlsl_expr_common_base_type(arg1->data_type->base_type, arg2->data_type->base_type); struct hlsl_ir_node *args[HLSL_MAX_OPERANDS] = {0}; struct hlsl_type *common_type, *ret_type; enum hlsl_ir_expr_op op; @@ -1584,13 +1145,13 @@ static struct hlsl_ir_node *add_binary_dot_expr(struct hlsl_ctx *ctx, struct lis common_type = hlsl_get_vector_type(ctx, base, dim); ret_type = hlsl_get_scalar_type(ctx, base);
- if (!(args[0] = add_implicit_conversion(ctx, instrs, arg1, common_type, loc))) + if (!(args[0] = hlsl_add_implicit_conversion(ctx, instrs, arg1, common_type, loc))) return NULL;
- if (!(args[1] = add_implicit_conversion(ctx, instrs, arg2, common_type, loc))) + if (!(args[1] = hlsl_add_implicit_conversion(ctx, instrs, arg2, common_type, loc))) return NULL;
- return add_expr(ctx, instrs, op, args, ret_type, loc); + return hlsl_add_expr(ctx, instrs, op, args, ret_type, loc); }
static enum hlsl_ir_expr_op op_from_assignment(enum parse_assign_op op) @@ -1674,7 +1235,7 @@ static struct hlsl_ir_node *add_assignment(struct hlsl_ctx *ctx, struct list *in if (lhs_type->class <= HLSL_CLASS_LAST_NUMERIC) writemask = (1 << lhs_type->dimx) - 1;
- if (!(rhs = add_implicit_conversion(ctx, instrs, rhs, lhs_type, &rhs->loc))) + if (!(rhs = hlsl_add_implicit_conversion(ctx, instrs, rhs, lhs_type, &rhs->loc))) return NULL;
while (lhs->type != HLSL_IR_LOAD && lhs->type != HLSL_IR_INDEX) @@ -1774,7 +1335,7 @@ static struct hlsl_ir_node *add_assignment(struct hlsl_ctx *ctx, struct list *in return NULL; list_add_tail(instrs, &cell->entry);
- if (!(load = add_load_component(ctx, instrs, rhs, k++, &rhs->loc))) + if (!(load = hlsl_add_load_component(ctx, instrs, rhs, k++, &rhs->loc))) return NULL;
if (!hlsl_init_deref_from_index_chain(ctx, &deref, cell)) @@ -1863,12 +1424,12 @@ static void initialize_var_components(struct hlsl_ctx *ctx, struct list *instrs, struct hlsl_type *dst_comp_type; struct hlsl_block block;
- if (!(load = add_load_component(ctx, instrs, src, k, &src->loc))) + if (!(load = hlsl_add_load_component(ctx, instrs, src, k, &src->loc))) return;
dst_comp_type = hlsl_type_get_component_type(ctx, dst->data_type, *store_index);
- if (!(conv = add_implicit_conversion(ctx, instrs, load, dst_comp_type, &src->loc))) + if (!(conv = hlsl_add_implicit_conversion(ctx, instrs, load, dst_comp_type, &src->loc))) return;
if (!hlsl_new_store_component(ctx, &block, &dst_deref, *store_index, conv)) @@ -2184,7 +1745,7 @@ static struct list *declare_vars(struct hlsl_ctx *ctx, struct hlsl_type *basic_t } list_add_tail(&ctx->static_initializers, &zero->entry);
- if (!(cast = add_cast(ctx, &ctx->static_initializers, zero, var->data_type, &var->loc))) + if (!(cast = hlsl_add_cast(ctx, &ctx->static_initializers, zero, var->data_type, &var->loc))) { vkd3d_free(v); continue; @@ -2239,7 +1800,7 @@ static void find_function_call_compatible(struct rb_entry *entry, void *context)
for (i = 0; i < decl->parameters.count; ++i) { - if (!implicit_compatible_data_types(args->ctx, args->params->args[i]->data_type, + if (!hlsl_implicit_compatible_data_types(args->ctx, args->params->args[i]->data_type, decl->parameters.vars[i]->data_type)) return; } @@ -2281,7 +1842,7 @@ static struct hlsl_ir_node *intrinsic_float_convert_arg(struct hlsl_ctx *ctx, return arg;
type = hlsl_get_numeric_type(ctx, type->class, HLSL_TYPE_FLOAT, type->dimx, type->dimy); - return add_implicit_conversion(ctx, params->instrs, arg, type, loc); + return hlsl_add_implicit_conversion(ctx, params->instrs, arg, type, loc); }
static bool convert_args(struct hlsl_ctx *ctx, const struct parse_initializer *params, @@ -2293,7 +1854,7 @@ static bool convert_args(struct hlsl_ctx *ctx, const struct parse_initializer *p { struct hlsl_ir_node *new_arg;
- if (!(new_arg = add_implicit_conversion(ctx, params->instrs, params->args[i], type, loc))) + if (!(new_arg = hlsl_add_implicit_conversion(ctx, params->instrs, params->args[i], type, loc))) return false; params->args[i] = new_arg; } @@ -2314,7 +1875,7 @@ static struct hlsl_type *elementwise_intrinsic_get_common_type(struct hlsl_ctx * { struct hlsl_type *arg_type = params->args[i]->data_type;
- base = expr_common_base_type(base, arg_type->base_type); + base = hlsl_expr_common_base_type(base, arg_type->base_type);
if (arg_type->class == HLSL_CLASS_VECTOR) { @@ -2400,14 +1961,14 @@ static bool intrinsic_all(struct hlsl_ctx *ctx, count = hlsl_type_component_count(arg->data_type); for (i = 0; i < count; ++i) { - if (!(load = add_load_component(ctx, params->instrs, arg, i, loc))) + if (!(load = hlsl_add_load_component(ctx, params->instrs, arg, i, loc))) return false;
if (!(mul = add_binary_arithmetic_expr(ctx, params->instrs, HLSL_OP2_MUL, load, mul, loc))) return false; }
- return !!add_binary_comparison_expr(ctx, params->instrs, HLSL_OP2_NEQUAL, mul, zero, loc); + return !!hlsl_add_binary_comparison_expr(ctx, params->instrs, HLSL_OP2_NEQUAL, mul, zero, loc); }
static bool intrinsic_any(struct hlsl_ctx *ctx, @@ -2431,7 +1992,7 @@ static bool intrinsic_any(struct hlsl_ctx *ctx, if (!(dot = add_binary_dot_expr(ctx, params->instrs, arg, arg, loc))) return false;
- return !!add_binary_comparison_expr(ctx, params->instrs, HLSL_OP2_NEQUAL, dot, zero, loc); + return !!hlsl_add_binary_comparison_expr(ctx, params->instrs, HLSL_OP2_NEQUAL, dot, zero, loc); } else if (arg->data_type->base_type == HLSL_TYPE_BOOL) { @@ -2444,7 +2005,7 @@ static bool intrinsic_any(struct hlsl_ctx *ctx, count = hlsl_type_component_count(arg->data_type); for (i = 0; i < count; ++i) { - if (!(load = add_load_component(ctx, params->instrs, arg, i, loc))) + if (!(load = hlsl_add_load_component(ctx, params->instrs, arg, i, loc))) return false;
if (!(or = add_binary_bitwise_expr(ctx, params->instrs, HLSL_OP2_BIT_OR, or, load, loc))) @@ -2486,7 +2047,7 @@ static bool intrinsic_asfloat(struct hlsl_ctx *ctx, data_type = convert_numeric_type(ctx, data_type, HLSL_TYPE_FLOAT);
operands[0] = params->args[0]; - return add_expr(ctx, params->instrs, HLSL_OP1_REINTERPRET, operands, data_type, loc); + return hlsl_add_expr(ctx, params->instrs, HLSL_OP1_REINTERPRET, operands, data_type, loc); }
static bool intrinsic_asuint(struct hlsl_ctx *ctx, @@ -2522,7 +2083,7 @@ static bool intrinsic_asuint(struct hlsl_ctx *ctx, data_type = convert_numeric_type(ctx, data_type, HLSL_TYPE_UINT);
operands[0] = params->args[0]; - return add_expr(ctx, params->instrs, HLSL_OP1_REINTERPRET, operands, data_type, loc); + return hlsl_add_expr(ctx, params->instrs, HLSL_OP1_REINTERPRET, operands, data_type, loc); }
static bool intrinsic_clamp(struct hlsl_ctx *ctx, @@ -2539,6 +2100,34 @@ static bool intrinsic_clamp(struct hlsl_ctx *ctx, return !!add_binary_arithmetic_expr(ctx, params->instrs, HLSL_OP2_MIN, max, params->args[2], loc); }
+static bool intrinsic_clip(struct hlsl_ctx *ctx, + const struct parse_initializer *params, const struct vkd3d_shader_location *loc) +{ + struct hlsl_ir_node *arg, *jump; + + if (!elementwise_intrinsic_float_convert_args(ctx, params, loc)) + return false; + + arg = params->args[0]; + + if (ctx->profile->major_version < 4 && hlsl_type_component_count(arg->data_type) > 4) + { + struct vkd3d_string_buffer *string; + + if ((string = hlsl_type_to_string(ctx, arg->data_type))) + hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE, + "Argument type cannot exceed 4 components, got type "%s".", string->buffer); + hlsl_release_string_buffer(ctx, string); + return false; + } + + if (!(jump = hlsl_new_jump(ctx, HLSL_IR_JUMP_TEXKILL, arg, loc))) + return false; + list_add_tail(params->instrs, &jump->entry); + + return true; +} + static bool intrinsic_cos(struct hlsl_ctx *ctx, const struct parse_initializer *params, const struct vkd3d_shader_location *loc) { @@ -2566,10 +2155,10 @@ static bool intrinsic_cross(struct hlsl_ctx *ctx,
cast_type = hlsl_get_vector_type(ctx, base, 3);
- if (!(arg1_cast = add_implicit_conversion(ctx, params->instrs, arg1, cast_type, loc))) + if (!(arg1_cast = hlsl_add_implicit_conversion(ctx, params->instrs, arg1, cast_type, loc))) return false;
- if (!(arg2_cast = add_implicit_conversion(ctx, params->instrs, arg2, cast_type, loc))) + if (!(arg2_cast = hlsl_add_implicit_conversion(ctx, params->instrs, arg2, cast_type, loc))) return false;
if (!(arg1_swzl1 = hlsl_new_swizzle(ctx, HLSL_SWIZZLE(Z, X, Y, Z), 3, arg1_cast, loc))) @@ -2726,7 +2315,7 @@ static bool intrinsic_fmod(struct hlsl_ctx *ctx, const struct parse_initializer if (!(neg_frac = add_unary_arithmetic_expr(ctx, params->instrs, HLSL_OP1_NEG, frac, loc))) return false;
- if (!(ge = add_binary_comparison_expr(ctx, params->instrs, HLSL_OP2_GEQUAL, div, &zero->node, loc))) + if (!(ge = hlsl_add_binary_comparison_expr(ctx, params->instrs, HLSL_OP2_GEQUAL, div, &zero->node, loc))) return false;
if (!(select = hlsl_add_conditional(ctx, params->instrs, ge, frac, neg_frac))) @@ -2880,13 +2469,13 @@ static bool intrinsic_lit(struct hlsl_ctx *ctx, list_move_tail(params->instrs, &block.instrs);
/* Specular component. */ - if (!(n_h_neg = add_binary_comparison_expr(ctx, params->instrs, HLSL_OP2_LESS, n_h, zero, loc))) + if (!(n_h_neg = hlsl_add_binary_comparison_expr(ctx, params->instrs, HLSL_OP2_LESS, n_h, zero, loc))) return false;
- if (!(n_l_neg = add_binary_comparison_expr(ctx, params->instrs, HLSL_OP2_LESS, n_l, zero, loc))) + if (!(n_l_neg = hlsl_add_binary_comparison_expr(ctx, params->instrs, HLSL_OP2_LESS, n_l, zero, loc))) return false;
- if (!(specular_or = add_binary_logical_expr(ctx, params->instrs, HLSL_OP2_LOGIC_OR, n_l_neg, n_h_neg, loc))) + if (!(specular_or = hlsl_add_binary_logical_expr(ctx, params->instrs, HLSL_OP2_LOGIC_OR, n_l_neg, n_h_neg, loc))) return false;
if (!(specular_pow = add_pow_expr(ctx, params->instrs, n_h, m, loc))) @@ -2975,7 +2564,7 @@ static bool intrinsic_mul(struct hlsl_ctx *ctx, const struct parse_initializer *params, const struct vkd3d_shader_location *loc) { struct hlsl_ir_node *arg1 = params->args[0], *arg2 = params->args[1], *cast1, *cast2; - enum hlsl_base_type base = expr_common_base_type(arg1->data_type->base_type, arg2->data_type->base_type); + enum hlsl_base_type base = hlsl_expr_common_base_type(arg1->data_type->base_type, arg2->data_type->base_type); struct hlsl_type *cast_type1 = arg1->data_type, *cast_type2 = arg2->data_type, *matrix_type, *ret_type; unsigned int i, j, k, vect_count = 0; struct hlsl_deref var_deref; @@ -3013,10 +2602,10 @@ static bool intrinsic_mul(struct hlsl_ctx *ctx, ret_type = hlsl_get_scalar_type(ctx, base); }
- if (!(cast1 = add_implicit_conversion(ctx, params->instrs, arg1, cast_type1, loc))) + if (!(cast1 = hlsl_add_implicit_conversion(ctx, params->instrs, arg1, cast_type1, loc))) return false;
- if (!(cast2 = add_implicit_conversion(ctx, params->instrs, arg2, cast_type2, loc))) + if (!(cast2 = hlsl_add_implicit_conversion(ctx, params->instrs, arg2, cast_type2, loc))) return false;
if (!(var = hlsl_new_synthetic_var(ctx, "mul", matrix_type, loc))) @@ -3034,10 +2623,10 @@ static bool intrinsic_mul(struct hlsl_ctx *ctx, { struct hlsl_ir_node *value1, *value2, *mul;
- if (!(value1 = add_load_component(ctx, params->instrs, cast1, j * cast1->data_type->dimx + k, loc))) + if (!(value1 = hlsl_add_load_component(ctx, params->instrs, cast1, j * cast1->data_type->dimx + k, loc))) return false;
- if (!(value2 = add_load_component(ctx, params->instrs, cast2, k * cast2->data_type->dimx + i, loc))) + if (!(value2 = hlsl_add_load_component(ctx, params->instrs, cast2, k * cast2->data_type->dimx + i, loc))) return false;
if (!(mul = add_binary_arithmetic_expr(ctx, params->instrs, HLSL_OP2_MUL, value1, value2, loc))) @@ -3064,7 +2653,7 @@ static bool intrinsic_mul(struct hlsl_ctx *ctx, return false; list_add_tail(params->instrs, &load->node.entry);
- return !!add_implicit_conversion(ctx, params->instrs, &load->node, ret_type, loc); + return !!hlsl_add_implicit_conversion(ctx, params->instrs, &load->node, ret_type, loc); }
static bool intrinsic_normalize(struct hlsl_ctx *ctx, @@ -3173,18 +2762,18 @@ static bool intrinsic_sign(struct hlsl_ctx *ctx,
/* Check if 0 < arg, cast bool to int */
- if (!(lt = add_binary_comparison_expr(ctx, params->instrs, HLSL_OP2_LESS, &zero->node, arg, loc))) + if (!(lt = hlsl_add_binary_comparison_expr(ctx, params->instrs, HLSL_OP2_LESS, &zero->node, arg, loc))) return false;
- if (!(op1 = add_implicit_conversion(ctx, params->instrs, lt, int_type, loc))) + if (!(op1 = hlsl_add_implicit_conversion(ctx, params->instrs, lt, int_type, loc))) return false;
/* Check if arg < 0, cast bool to int and invert (meaning true is -1) */
- if (!(lt = add_binary_comparison_expr(ctx, params->instrs, HLSL_OP2_LESS, arg, &zero->node, loc))) + if (!(lt = hlsl_add_binary_comparison_expr(ctx, params->instrs, HLSL_OP2_LESS, arg, &zero->node, loc))) return false;
- if (!(op2 = add_implicit_conversion(ctx, params->instrs, lt, int_type, loc))) + if (!(op2 = hlsl_add_implicit_conversion(ctx, params->instrs, lt, int_type, loc))) return false;
if (!(neg = add_unary_arithmetic_expr(ctx, params->instrs, HLSL_OP1_NEG, op2, loc))) @@ -3283,13 +2872,13 @@ static bool intrinsic_step(struct hlsl_ctx *ctx, if (!elementwise_intrinsic_float_convert_args(ctx, params, loc)) return false;
- if (!(ge = add_binary_comparison_expr(ctx, params->instrs, HLSL_OP2_GEQUAL, + if (!(ge = hlsl_add_binary_comparison_expr(ctx, params->instrs, HLSL_OP2_GEQUAL, params->args[1], params->args[0], loc))) return false;
type = ge->data_type; type = hlsl_get_numeric_type(ctx, type->class, HLSL_TYPE_FLOAT, type->dimx, type->dimy); - return !!add_implicit_conversion(ctx, params->instrs, ge, type, loc); + return !!hlsl_add_implicit_conversion(ctx, params->instrs, ge, type, loc); }
static bool intrinsic_tex(struct hlsl_ctx *ctx, const struct parse_initializer *params, @@ -3324,7 +2913,7 @@ static bool intrinsic_tex(struct hlsl_ctx *ctx, const struct parse_initializer * hlsl_release_string_buffer(ctx, string); }
- if (!(coords = add_implicit_conversion(ctx, params->instrs, params->args[1], + if (!(coords = hlsl_add_implicit_conversion(ctx, params->instrs, params->args[1], hlsl_get_vector_type(ctx, HLSL_TYPE_FLOAT, hlsl_sampler_dim_count(dim)), loc))) coords = params->args[1];
@@ -3393,7 +2982,7 @@ static bool intrinsic_transpose(struct hlsl_ctx *ctx, { struct hlsl_block block;
- if (!(load = add_load_component(ctx, params->instrs, arg, j * arg->data_type->dimx + i, loc))) + if (!(load = hlsl_add_load_component(ctx, params->instrs, arg, j * arg->data_type->dimx + i, loc))) return false;
if (!hlsl_new_store_component(ctx, &block, &var_deref, i * var->data_type->dimx + j, load)) @@ -3482,6 +3071,7 @@ intrinsic_functions[] = {"asfloat", 1, true, intrinsic_asfloat}, {"asuint", -1, true, intrinsic_asuint}, {"clamp", 3, true, intrinsic_clamp}, + {"clip", 1, true, intrinsic_clip}, {"cos", 1, true, intrinsic_cos}, {"cross", 2, true, intrinsic_cross}, {"ddx", 1, true, intrinsic_ddx}, @@ -3549,7 +3139,7 @@ static struct list *add_call(struct hlsl_ctx *ctx, const char *name, { struct hlsl_ir_node *cast;
- if (!(cast = add_cast(ctx, args->instrs, arg, param->data_type, &arg->loc))) + if (!(cast = hlsl_add_cast(ctx, args->instrs, arg, param->data_type, &arg->loc))) goto fail; args->args[i] = cast; arg = cast; @@ -3761,7 +3351,7 @@ static bool add_load_method_call(struct hlsl_ctx *ctx, struct list *instrs, stru } if (multisampled) { - if (!(load_params.sample_index = add_implicit_conversion(ctx, instrs, params->args[1], + if (!(load_params.sample_index = hlsl_add_implicit_conversion(ctx, instrs, params->args[1], hlsl_get_scalar_type(ctx, HLSL_TYPE_INT), loc))) return false; } @@ -3769,7 +3359,7 @@ static bool add_load_method_call(struct hlsl_ctx *ctx, struct list *instrs, stru assert(offset_dim); if (params->args_count > 1 + multisampled) { - if (!(load_params.texel_offset = add_implicit_conversion(ctx, instrs, params->args[1 + multisampled], + if (!(load_params.texel_offset = hlsl_add_implicit_conversion(ctx, instrs, params->args[1 + multisampled], hlsl_get_vector_type(ctx, HLSL_TYPE_INT, offset_dim), loc))) return false; } @@ -3779,7 +3369,7 @@ static bool add_load_method_call(struct hlsl_ctx *ctx, struct list *instrs, stru }
/* +1 for the mipmap level for non-multisampled textures */ - if (!(load_params.coords = add_implicit_conversion(ctx, instrs, params->args[0], + if (!(load_params.coords = hlsl_add_implicit_conversion(ctx, instrs, params->args[0], hlsl_get_vector_type(ctx, HLSL_TYPE_INT, sampler_dim + !multisampled), loc))) return false;
@@ -3829,13 +3419,13 @@ static bool add_sample_method_call(struct hlsl_ctx *ctx, struct list *instrs, st return false; }
- if (!(load_params.coords = add_implicit_conversion(ctx, instrs, params->args[1], + if (!(load_params.coords = hlsl_add_implicit_conversion(ctx, instrs, params->args[1], hlsl_get_vector_type(ctx, HLSL_TYPE_FLOAT, sampler_dim), loc))) return false;
if (offset_dim && params->args_count > 2) { - if (!(load_params.texel_offset = add_implicit_conversion(ctx, instrs, params->args[2], + if (!(load_params.texel_offset = hlsl_add_implicit_conversion(ctx, instrs, params->args[2], hlsl_get_vector_type(ctx, HLSL_TYPE_INT, offset_dim), loc))) return false; } @@ -3899,17 +3489,17 @@ static bool add_sample_cmp_method_call(struct hlsl_ctx *ctx, struct list *instrs return false; }
- if (!(load_params.coords = add_implicit_conversion(ctx, instrs, params->args[1], + if (!(load_params.coords = hlsl_add_implicit_conversion(ctx, instrs, params->args[1], hlsl_get_vector_type(ctx, HLSL_TYPE_FLOAT, sampler_dim), loc))) return false;
- if (!(load_params.cmp = add_implicit_conversion(ctx, instrs, params->args[2], + if (!(load_params.cmp = hlsl_add_implicit_conversion(ctx, instrs, params->args[2], hlsl_get_scalar_type(ctx, HLSL_TYPE_FLOAT), loc))) load_params.cmp = params->args[2];
if (offset_dim && params->args_count > 3) { - if (!(load_params.texel_offset = add_implicit_conversion(ctx, instrs, params->args[2], + if (!(load_params.texel_offset = hlsl_add_implicit_conversion(ctx, instrs, params->args[2], hlsl_get_vector_type(ctx, HLSL_TYPE_INT, offset_dim), loc))) return false; } @@ -3997,7 +3587,7 @@ static bool add_gather_method_call(struct hlsl_ctx *ctx, struct list *instrs, st } else if (offset_dim && params->args_count > 2) { - if (!(load_params.texel_offset = add_implicit_conversion(ctx, instrs, params->args[2], + if (!(load_params.texel_offset = hlsl_add_implicit_conversion(ctx, instrs, params->args[2], hlsl_get_vector_type(ctx, HLSL_TYPE_INT, offset_dim), loc))) return false; } @@ -4022,7 +3612,7 @@ static bool add_gather_method_call(struct hlsl_ctx *ctx, struct list *instrs, st return false; }
- if (!(load_params.coords = add_implicit_conversion(ctx, instrs, params->args[1], + if (!(load_params.coords = hlsl_add_implicit_conversion(ctx, instrs, params->args[1], hlsl_get_vector_type(ctx, HLSL_TYPE_FLOAT, sampler_dim), loc))) return false;
@@ -4078,17 +3668,17 @@ static bool add_sample_lod_method_call(struct hlsl_ctx *ctx, struct list *instrs return false; }
- if (!(load_params.coords = add_implicit_conversion(ctx, instrs, params->args[1], + if (!(load_params.coords = hlsl_add_implicit_conversion(ctx, instrs, params->args[1], hlsl_get_vector_type(ctx, HLSL_TYPE_FLOAT, sampler_dim), loc))) load_params.coords = params->args[1];
- if (!(load_params.lod = add_implicit_conversion(ctx, instrs, params->args[2], + if (!(load_params.lod = hlsl_add_implicit_conversion(ctx, instrs, params->args[2], hlsl_get_scalar_type(ctx, HLSL_TYPE_FLOAT), loc))) load_params.lod = params->args[2];
if (offset_dim && params->args_count > 3) { - if (!(load_params.texel_offset = add_implicit_conversion(ctx, instrs, params->args[3], + if (!(load_params.texel_offset = hlsl_add_implicit_conversion(ctx, instrs, params->args[3], hlsl_get_vector_type(ctx, HLSL_TYPE_INT, offset_dim), loc))) return false; } @@ -4145,21 +3735,21 @@ static bool add_sample_grad_method_call(struct hlsl_ctx *ctx, struct list *instr return false; }
- if (!(load_params.coords = add_implicit_conversion(ctx, instrs, params->args[1], + if (!(load_params.coords = hlsl_add_implicit_conversion(ctx, instrs, params->args[1], hlsl_get_vector_type(ctx, HLSL_TYPE_FLOAT, sampler_dim), loc))) load_params.coords = params->args[1];
- if (!(load_params.ddx = add_implicit_conversion(ctx, instrs, params->args[2], + if (!(load_params.ddx = hlsl_add_implicit_conversion(ctx, instrs, params->args[2], hlsl_get_vector_type(ctx, HLSL_TYPE_FLOAT, sampler_dim), loc))) load_params.ddx = params->args[2];
- if (!(load_params.ddy = add_implicit_conversion(ctx, instrs, params->args[3], + if (!(load_params.ddy = hlsl_add_implicit_conversion(ctx, instrs, params->args[3], hlsl_get_vector_type(ctx, HLSL_TYPE_FLOAT, sampler_dim), loc))) load_params.ddy = params->args[3];
if (offset_dim && params->args_count > 4) { - if (!(load_params.texel_offset = add_implicit_conversion(ctx, instrs, params->args[4], + if (!(load_params.texel_offset = hlsl_add_implicit_conversion(ctx, instrs, params->args[4], hlsl_get_vector_type(ctx, HLSL_TYPE_INT, offset_dim), loc))) return false; } @@ -5736,11 +5326,16 @@ jump_statement: discard_statement: KW_DISCARD ';' { - struct hlsl_ir_node *discard; + struct hlsl_ir_node *discard, *c;
if (!($$ = make_empty_list(ctx))) YYABORT; - if (!(discard = hlsl_new_jump(ctx, HLSL_IR_JUMP_DISCARD, &@1))) + + if (!(c = hlsl_new_uint_constant(ctx, ~0u, &@1))) + return false; + list_add_tail($$, &c->entry); + + if (!(discard = hlsl_new_jump(ctx, HLSL_IR_JUMP_DISCARD, c, &@1))) return false; list_add_tail($$, &discard->entry); } @@ -6118,7 +5713,7 @@ unary_expr: YYABORT; }
- if (!add_cast(ctx, $6, node_from_list($6), dst_type, &@3)) + if (!hlsl_add_cast(ctx, $6, node_from_list($6), dst_type, &@3)) { hlsl_free_instr_list($6); YYABORT; @@ -6248,10 +5843,10 @@ conditional_expr: if (!(common_type = get_common_numeric_type(ctx, first, second, &@3))) YYABORT;
- if (!(first = add_implicit_conversion(ctx, $1, first, common_type, &@3))) + if (!(first = hlsl_add_implicit_conversion(ctx, $1, first, common_type, &@3))) YYABORT;
- if (!(second = add_implicit_conversion(ctx, $1, second, common_type, &@5))) + if (!(second = hlsl_add_implicit_conversion(ctx, $1, second, common_type, &@5))) YYABORT;
if (!hlsl_add_conditional(ctx, $1, cond, first, second)) diff --git a/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d-shader/hlsl_codegen.c index 2b6c595a1..6a19cd679 100644 --- a/libs/vkd3d-shader/hlsl_codegen.c +++ b/libs/vkd3d-shader/hlsl_codegen.c @@ -655,7 +655,7 @@ static void insert_early_return_break(struct hlsl_ctx *ctx, return; list_add_after(&cf_instr->entry, &load->node.entry);
- if (!(jump = hlsl_new_jump(ctx, HLSL_IR_JUMP_BREAK, &cf_instr->loc))) + if (!(jump = hlsl_new_jump(ctx, HLSL_IR_JUMP_BREAK, NULL, &cf_instr->loc))) return; hlsl_block_add_instr(&then_block, jump);
@@ -2446,6 +2446,52 @@ static bool lower_float_modulus(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr return true; }
+static bool lower_texkill(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, void *context) +{ + struct hlsl_ir_node *zero, *bool_false, *or, *cmp, *load; + struct hlsl_ir_jump *jump; + unsigned int i, count; + struct list instrs; + + if (instr->type != HLSL_IR_JUMP) + return false; + jump = hlsl_ir_jump(instr); + if (jump->type != HLSL_IR_JUMP_TEXKILL) + return false; + + list_init(&instrs); + + if (!(zero = hlsl_new_float_constant(ctx, 0.0f, &instr->loc))) + return false; + list_add_tail(&instrs, &zero->entry); + + if (!(cmp = hlsl_add_binary_comparison_expr(ctx, &instrs, HLSL_OP2_LESS, jump->arg.node, zero, &instr->loc))) + return false; + + if (!(bool_false = hlsl_new_bool_constant(ctx, false, &instr->loc))) + return false; + list_add_tail(&instrs, &bool_false->entry); + + or = bool_false; + + count = hlsl_type_component_count(cmp->data_type); + for (i = 0; i < count; ++i) + { + if (!(load = hlsl_add_load_component(ctx, &instrs, cmp, i, &instr->loc))) + return false; + + if (!(or = hlsl_add_binary_logical_expr(ctx, &instrs, HLSL_OP2_LOGIC_OR, or, load, &instr->loc))) + return false; + } + + list_move_tail(&instr->entry, &instrs); + hlsl_src_remove(&jump->arg); + hlsl_src_from_node(&jump->arg, or); + jump->type = HLSL_IR_JUMP_DISCARD; + + return true; +} + static bool dce(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, void *context) { switch (instr->type) @@ -2711,8 +2757,15 @@ static void compute_liveness_recurse(struct hlsl_block *block, unsigned int loop index->idx.node->last_read = last_read; break; } - case HLSL_IR_CONSTANT: case HLSL_IR_JUMP: + { + struct hlsl_ir_jump *jump = hlsl_ir_jump(instr); + + if (jump->arg.node) + jump->arg.node->last_read = last_read; + break; + } + case HLSL_IR_CONSTANT: break; } } @@ -3913,6 +3966,10 @@ int hlsl_emit_bytecode(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry hlsl_error(ctx, &entry_func->loc, VKD3D_SHADER_ERROR_HLSL_MISSING_ATTRIBUTE, "Entry point "%s" is missing a [numthreads] attribute.", entry_func->func->name);
+ if (profile->major_version >= 4) + { + hlsl_transform_ir(ctx, lower_texkill, body, NULL); + } hlsl_transform_ir(ctx, lower_broadcasts, body, NULL); while (hlsl_transform_ir(ctx, fold_redundant_casts, body, NULL)); do diff --git a/libs/vkd3d-shader/tpf.c b/libs/vkd3d-shader/tpf.c index 60948d649..8256aaa06 100644 --- a/libs/vkd3d-shader/tpf.c +++ b/libs/vkd3d-shader/tpf.c @@ -4777,17 +4777,11 @@ static void write_sm4_jump(struct hlsl_ctx *ctx,
case HLSL_IR_JUMP_DISCARD: { - struct sm4_register *reg = &instr.srcs[0].reg; - instr.opcode = VKD3D_SM4_OP_DISCARD | VKD3D_SM4_CONDITIONAL_NZ;
memset(&instr.srcs[0], 0, sizeof(*instr.srcs)); - instr.srcs[0].swizzle_type = VKD3D_SM4_SWIZZLE_NONE; instr.src_count = 1; - reg->type = VKD3D_SM4_RT_IMMCONST; - reg->dim = VKD3D_SM4_DIMENSION_SCALAR; - reg->immconst_uint[0] = ~0u; - + sm4_src_from_node(&instr.srcs[0], jump->arg.node, VKD3DSP_WRITEMASK_ALL); break; }
diff --git a/tests/hlsl-clip.shader_test b/tests/hlsl-clip.shader_test new file mode 100644 index 000000000..f9859e1b8 --- /dev/null +++ b/tests/hlsl-clip.shader_test @@ -0,0 +1,22 @@ +[pixel shader] +uniform float4 x; + +float4 main() : sv_target +{ + clip(x); + return x; +} + +[test] +uniform 0 float4 1 2 3 4 +draw quad +probe all rgba (1, 2, 3, 4) +uniform 0 float4 9 8 7 6 +draw quad +probe all rgba (9, 8, 7, 6) +uniform 0 float4 -1 8 7 6 +draw quad +probe all rgba (9, 8, 7, 6) +uniform 0 float4 9 0 7 6 +draw quad +probe all rgba (9, 0, 7, 6)
Now pushed variant that's using TEXKILL initially, turning it to DISCARD_NZ for sm4+, with additional logic to produce conditional argument.
On Mon Jun 5 12:48:10 2023 +0000, Nikolay Sivov wrote:
Now pushed variant that's using TEXKILL initially, turning it to DISCARD_NZ for sm4+, with additional logic to produce conditional argument.
Please, don't make commits that large, and don't mix refactoring and development changes in the same commit. If you could also split the introduction of a test and the implementation required to satisfy that test, that would be even better.
Also, even if we really want to have that field, do not call it `arg`; rather use some more descriptive name like `condition`. I still think it's inconsistent with the choice we made about the conditional statement, but at least one can understand what it means.
WRT having both `TEXKILL` and `DISCARD`, I think it's better than before, as at least the IR makes sense even without context. OTOH, the two names do not make much sense from the point of view of the IR itself. Maybe something like `DISCARD_NNEG` (for "discard on non-negative") and `DISCARD_NZ` would be more consistent?
Please, don't make commits that large, and don't mix refactoring and development changes in the same commit. If you could also split the introduction of a test and the implementation required to satisfy that test, that would be even better.
I can spend time on that later, once it's decided how to proceed.
Also, even if we really want to have that field, do not call it `arg`; rather use some more descriptive name like `condition`. I still think it's inconsistent with the choice we made about the conditional statement, but at least one can understand what it means.
I don't see a big difference between arg and condition, and then again it's a cosmetic difference.
WRT having both `TEXKILL` and `DISCARD`, I think it's better than before, as at least the IR makes sense even without context. OTOH, the two names do not make much sense from the point of view of the IR itself. Maybe something like `DISCARD_NNEG` (for "discard on non-negative") and `DISCARD_NZ` would be more consistent?
Again, how to call it is another question. Important question is whether transform pass is better than creating separate paths in advance. Regarding names, having that closer to actual language elements seems easier to read, than NNEG.
I can spend time on that later, once it's decided how to proceed.
As you wish, but I won't review that patch until it's reviewable.
Again, how to call it is another question. Important question is whether transform pass is better than creating separate paths in advance. Regarding names, having that closer to actual language elements seems easier to read, than NNEG.
I don't agree. Maybe `NON_NEGATIVE` is better than `NNEG`, but the fact that the difference between `TEXKILL` and `DISCARD` is how the condition is evaluated is quite opaque to me.
As for having a transform pass rather than immediately creating two different codes, I don't have strong feelings. As I already said, I think it is more consistent with what we already do for the conditional operator to initially create an `if` block, and later possibly raising it to `DISCARD` (or whatever of its variants). That's also what @Mystral suggested and possibly what @zfigura suggested saying that we don't want the same transformation in both directions. But I'll leave to them to stress their point of view if they so wish.
I can spend time on that later, once it's decided how to proceed.
As you wish, but I won't review that patch until it's reviewable.
What needs to be reviewed is intrinsic_clip() and lower_texkill(), whether that conceptually correct, not renames or variable names. The rest of the diff, as you can see, is there to be able to build and test.
As for having a transform pass rather than immediately creating two different codes, I don't have strong feelings. As I already said, I think it is more consistent with what we already do for the conditional operator to initially create an `if` block, and later possibly raising it to `DISCARD` (or whatever of its variants). That's also what @Mystral suggested and possibly what @zfigura suggested saying that we don't want the same transformation in both directions. But I'll leave to them to stress their point of view if they so wish.
I could use a strong feeling exactly, but about important part of the patch. Native compiler does not collapse such if blocks, as far as I remember, nor does it use unconditional discard instruction. So far I see it only using discard_nz at all times.
There is an option to do:
clip -> 'if (arg<0) then discard;' -> for sm1 turn discard to texkill with initialized register.
Not only this is unnecessarily more complicated, but it also does not match what happens for sm1, where clip is mapped directly to texkill. And then it will need additional work for get rid of conditional branching for SM1. It looks more like going out of the way to produce different output for no reason.
So yes, @Mystral, @zfigura, I'd like another opinion on this - is it critical to have one DISCARD without an argument as a jump type that is used for all profiles?
On Mon Jun 5 20:00:00 2023 +0000, Nikolay Sivov wrote:
I can spend time on that later, once it's decided how to proceed.
As you wish, but I won't review that patch until it's reviewable.
What needs to be reviewed is intrinsic_clip() and lower_texkill(), whether that conceptually correct, not renames or variable names. The rest of the diff, as you can see, is there to be able to build and test.
As for having a transform pass rather than immediately creating two
different codes, I don't have strong feelings. As I already said, I think it is more consistent with what we already do for the conditional operator to initially create an `if` block, and later possibly raising it to `DISCARD` (or whatever of its variants). That's also what @Mystral suggested and possibly what @zfigura suggested saying that we don't want the same transformation in both directions. But I'll leave to them to stress their point of view if they so wish. I could use a strong feeling exactly, but about important part of the patch. Native compiler does not collapse such if blocks, as far as I remember, nor does it use unconditional discard instruction. So far I see it only using discard_nz at all times. There is an option to do: clip -> 'if (arg<0) then discard;' -> for sm1 turn discard to texkill with initialized register. Not only this is unnecessarily more complicated, but it also does not match what happens for sm1, where clip is mapped directly to texkill. And then it will need additional work for get rid of conditional branching for SM1. It looks more like going out of the way to produce different output for no reason. So yes, @Mystral, @zfigura, I'd like another opinion on this - is it critical to have one DISCARD without an argument as a jump type that is used for all profiles?
I don't have a very strong opinion. Multiple discard types are fine; v1 of this patch was also fine. I mostly just want the IR to have the same semantics regardless of profile version.
I don't have a very strong opinion. Multiple discard types are fine; v1 of this patch was also fine. I mostly just want the IR to have the same semantics regardless of profile version.
I don't disagree, but it's perhaps worth pointing out that technically that would imply having two variants of things like "mul" and "dot" as well, because those follow different floating-point rules in the pre-4.0 and the later profiles. (And that has implications for whether you can e.g. fold "0.0 * x" to "0.0" without additional information or not.)
On Tue Jun 6 16:42:42 2023 +0000, Henri Verbeet wrote:
I don't have a very strong opinion. Multiple discard types are fine;
v1 of this patch was also fine. I mostly just want the IR to have the same semantics regardless of profile version. I don't disagree, but it's perhaps worth pointing out that technically that would imply having two variants of things like "mul" and "dot" as well, because those follow different floating-point rules in the pre-4.0 and the later profiles. (And that has implications for whether you can e.g. fold "0.0 * x" to "0.0" without additional information or not.)
I'm tentatively willing to call that a minor enough difference to justify not splitting that up. At least it seems to me more minor than the difference between discard_nz and texkill, or D3DCOLORtoUBYTE4...
On Tue Jun 6 16:42:42 2023 +0000, Zebediah Figura wrote:
I'm tentatively willing to call that a minor enough difference to justify not splitting that up. At least it seems to me more minor than the difference between discard_nz and texkill, or D3DCOLORtoUBYTE4...
I agree with @zfigura. And if, for some reason, we want to be consistent on this choice, I'd rather duplicate the arithmetic operators the require it rather than conflate the discard operators.
On Mon Jun 5 20:16:34 2023 +0000, Zebediah Figura wrote:
I don't have a very strong opinion. Multiple discard types are fine; v1 of this patch was also fine. I mostly just want the IR to have the same semantics regardless of profile version.
Ok, I won't push it further about the multiple discard types, or its names. I'd still ask that the argument is called `condition`, that says something about what it's for.
I'm tentatively willing to call that a minor enough difference to justify not splitting that up. At least it seems to me more minor than the difference between discard_nz and texkill, or D3DCOLORtoUBYTE4...
Sure, and to be clear, having e.g. "mul_ieee" and "mul_sm3" variants would certainly be fine with me; just making sure we're all fine with the implications.