This part mainly includes a compilation pass to turn non-float operations into float operations, inserting the corresponding casts on the operands and result, and writing casts from bool to float as MOV.
From: Francisco Casas fcasas@codeweavers.com
I realized that it is better to lower casts to int to FLOOR+REINTERPET instead of appending a FLOOR to all casts to int and assuming that this is the case for all of them in d3dbc.c.
This in case we introduce new passes in the future that add casts that we forget to lower, after the lower_casts_to_bool pass. --- libs/vkd3d-shader/d3dbc.c | 11 ++++++++++- libs/vkd3d-shader/hlsl_codegen.c | 15 +++++++-------- 2 files changed, 17 insertions(+), 9 deletions(-)
diff --git a/libs/vkd3d-shader/d3dbc.c b/libs/vkd3d-shader/d3dbc.c index 27f5c8104..ef33c9722 100644 --- a/libs/vkd3d-shader/d3dbc.c +++ b/libs/vkd3d-shader/d3dbc.c @@ -2002,7 +2002,10 @@ static void write_sm1_cast(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer *b { case HLSL_TYPE_HALF: case HLSL_TYPE_FLOAT: - /* A compilation pass applies a FLOOR operation to casts to int, so no change is necessary. */ + /* A compilation pass turns these into FLOOR+REINTERPRET, so we should not + * reach this case unless we are missing something. */ + hlsl_fixme(ctx, &instr->loc, "Unlowered SM1 cast from float to integer."); + break; case HLSL_TYPE_INT: case HLSL_TYPE_UINT: write_sm1_unary_op(ctx, buffer, D3DSIO_MOV, &instr->reg, &arg1->reg, 0, 0); @@ -2242,6 +2245,12 @@ static void write_sm1_expr(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer *b
assert(instr->reg.allocated);
+ if (expr->op == HLSL_OP1_REINTERPRET) + { + write_sm1_unary_op(ctx, buffer, D3DSIO_MOV, &instr->reg, &arg1->reg, 0, 0); + return; + } + if (expr->op == HLSL_OP1_CAST) { write_sm1_cast(ctx, buffer, instr); diff --git a/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d-shader/hlsl_codegen.c index 7da427796..f8e8d23d8 100644 --- a/libs/vkd3d-shader/hlsl_codegen.c +++ b/libs/vkd3d-shader/hlsl_codegen.c @@ -2647,10 +2647,11 @@ static bool sort_synthetic_separated_samplers_first(struct hlsl_ctx *ctx) return false; }
-/* Append a FLOOR before a CAST to int or uint (which is written as a mere MOV). */ +/* Turn CAST to int or uint into FLOOR + REINTERPRET (which is written as a mere MOV). */ static bool lower_casts_to_int(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, struct hlsl_block *block) { - struct hlsl_ir_node *arg, *floor, *cast2; + struct hlsl_ir_node *operands[HLSL_MAX_OPERANDS] = { 0 }; + struct hlsl_ir_node *arg, *floor, *res; struct hlsl_ir_expr *expr;
if (instr->type != HLSL_IR_EXPR) @@ -2665,17 +2666,15 @@ static bool lower_casts_to_int(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, if (arg->data_type->base_type != HLSL_TYPE_FLOAT && arg->data_type->base_type != HLSL_TYPE_HALF) return false;
- /* Check that the argument is not already a FLOOR */ - if (arg->type == HLSL_IR_EXPR && hlsl_ir_expr(arg)->op == HLSL_OP1_FLOOR) - return false; - if (!(floor = hlsl_new_unary_expr(ctx, HLSL_OP1_FLOOR, arg, &instr->loc))) return false; hlsl_block_add_instr(block, floor);
- if (!(cast2 = hlsl_new_cast(ctx, floor, instr->data_type, &instr->loc))) + memset(operands, 0, sizeof(operands)); + operands[0] = floor; + if (!(res = hlsl_new_expr(ctx, HLSL_OP1_REINTERPRET, operands, instr->data_type, &instr->loc))) return false; - hlsl_block_add_instr(block, cast2); + hlsl_block_add_instr(block, res);
return true; }
From: Francisco Casas fcasas@codeweavers.com
--- libs/vkd3d-shader/hlsl_codegen.c | 62 +++++++++++++++++++ tests/hlsl/arithmetic-int-uniform.shader_test | 4 +- 2 files changed, 64 insertions(+), 2 deletions(-)
diff --git a/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d-shader/hlsl_codegen.c index f8e8d23d8..040e0c4e4 100644 --- a/libs/vkd3d-shader/hlsl_codegen.c +++ b/libs/vkd3d-shader/hlsl_codegen.c @@ -3307,6 +3307,61 @@ static bool lower_float_modulus(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr return true; }
+static bool lower_nonfloat_exprs(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, struct hlsl_block *block) +{ + struct hlsl_ir_expr *expr; + + if (instr->type != HLSL_IR_EXPR) + return false; + expr = hlsl_ir_expr(instr); + if (expr->op == HLSL_OP1_CAST || instr->data_type->base_type == HLSL_TYPE_FLOAT) + return false; + + switch (expr->op) + { + case HLSL_OP1_ABS: + case HLSL_OP1_NEG: + case HLSL_OP2_ADD: + case HLSL_OP2_DIV: + case HLSL_OP2_MAX: + case HLSL_OP2_MIN: + case HLSL_OP2_MUL: + { + struct hlsl_ir_node *operands[HLSL_MAX_OPERANDS] = {0}; + struct hlsl_ir_node *arg, *arg_cast, *float_expr, *ret; + struct hlsl_type *float_type; + unsigned int i; + + for (i = 0; i < HLSL_MAX_OPERANDS; ++i) + { + arg = expr->operands[i].node; + if (!arg) + continue; + + float_type = hlsl_get_vector_type(ctx, HLSL_TYPE_FLOAT, arg->data_type->dimx); + if (!(arg_cast = hlsl_new_cast(ctx, arg, float_type, &instr->loc))) + return false; + hlsl_block_add_instr(block, arg_cast); + + operands[i] = arg_cast; + } + + float_type = hlsl_get_vector_type(ctx, HLSL_TYPE_FLOAT, instr->data_type->dimx); + if (!(float_expr = hlsl_new_expr(ctx, expr->op, operands, float_type, &instr->loc))) + return false; + hlsl_block_add_instr(block, float_expr); + + if (!(ret = hlsl_new_cast(ctx, float_expr, instr->data_type, &instr->loc))) + return false; + hlsl_block_add_instr(block, ret); + + return true; + } + default: + return false; + } +} + static bool lower_discard_neg(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, void *context) { struct hlsl_ir_node *zero, *bool_false, *or, *cmp, *load; @@ -5086,6 +5141,13 @@ int hlsl_emit_bytecode(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry remove_unreachable_code(ctx, body); hlsl_transform_ir(ctx, normalize_switch_cases, body, NULL);
+ if (profile-> major_version < 4) + { + lower_ir(ctx, lower_nonfloat_exprs, body); + /* Constants casted to float must be folded. */ + hlsl_transform_ir(ctx, hlsl_fold_constant_exprs, body, NULL); + } + lower_ir(ctx, lower_nonconstant_vector_derefs, body); lower_ir(ctx, lower_casts_to_bool, body); lower_ir(ctx, lower_int_dot, body); diff --git a/tests/hlsl/arithmetic-int-uniform.shader_test b/tests/hlsl/arithmetic-int-uniform.shader_test index e176d4b8c..48e1ae1a1 100644 --- a/tests/hlsl/arithmetic-int-uniform.shader_test +++ b/tests/hlsl/arithmetic-int-uniform.shader_test @@ -88,7 +88,7 @@ uniform 0 float4 45.0 5.0 0.0 0.0 todo(sm<4) draw quad probe all rgba (0.0, 0.0, 0.0, 0.0)
-[pixel shader todo(sm<4)] +[pixel shader] uniform float4 a;
float4 main() : SV_TARGET @@ -98,7 +98,7 @@ float4 main() : SV_TARGET
[test] uniform 0 float4 5.0 -7.0 0.0 -10.0 -todo(sm<4) draw quad +draw quad probe all rgba (5.0, 7.0, 0.0, 10.0)
[pixel shader todo(sm<4)]
From: Francisco Casas fcasas@codeweavers.com
In SM1, bools are always represented as either 0.0f or 1.0f at runtime. --- libs/vkd3d-shader/d3dbc.c | 7 ++----- tests/hlsl/cast-to-float.shader_test | 4 ++-- tests/hlsl/cast-to-half.shader_test | 4 ++-- 3 files changed, 6 insertions(+), 9 deletions(-)
diff --git a/libs/vkd3d-shader/d3dbc.c b/libs/vkd3d-shader/d3dbc.c index ef33c9722..8f11c48a9 100644 --- a/libs/vkd3d-shader/d3dbc.c +++ b/libs/vkd3d-shader/d3dbc.c @@ -1977,16 +1977,13 @@ static void write_sm1_cast(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer *b { case HLSL_TYPE_INT: case HLSL_TYPE_UINT: - /* Integers are internally represented as floats, so no change is necessary.*/ + case HLSL_TYPE_BOOL: + /* Integrals are internally represented as floats, so no change is necessary.*/ case HLSL_TYPE_HALF: case HLSL_TYPE_FLOAT: write_sm1_unary_op(ctx, buffer, D3DSIO_MOV, &instr->reg, &arg1->reg, 0, 0); break;
- case HLSL_TYPE_BOOL: - hlsl_fixme(ctx, &instr->loc, "SM1 cast from bool to float."); - break; - case HLSL_TYPE_DOUBLE: hlsl_fixme(ctx, &instr->loc, "SM1 cast from double to float."); break; diff --git a/tests/hlsl/cast-to-float.shader_test b/tests/hlsl/cast-to-float.shader_test index bcb546e2d..d80d42909 100644 --- a/tests/hlsl/cast-to-float.shader_test +++ b/tests/hlsl/cast-to-float.shader_test @@ -1,4 +1,4 @@ -[pixel shader todo(sm<4)] +[pixel shader] uniform int i; uniform uint u; uniform bool b; @@ -18,7 +18,7 @@ if(sm>=4) uniform 0 int -1 if(sm>=4) uniform 1 uint 3 if(sm>=4) uniform 2 int -2 if(sm>=4) uniform 3 float 0.5 -todo(sm<4) draw quad +draw quad probe all rgba (0.5, 0.5, 0.5, 0.5)
diff --git a/tests/hlsl/cast-to-half.shader_test b/tests/hlsl/cast-to-half.shader_test index 0580fe25f..8094a10a3 100644 --- a/tests/hlsl/cast-to-half.shader_test +++ b/tests/hlsl/cast-to-half.shader_test @@ -1,4 +1,4 @@ -[pixel shader todo(sm<4)] +[pixel shader] uniform int i; uniform uint u; uniform bool b; @@ -18,7 +18,7 @@ if(sm>=4) uniform 0 int -1 if(sm>=4) uniform 1 uint 3 if(sm>=4) uniform 2 int -2 if(sm>=4) uniform 3 float 0.5 -todo(sm<4) draw quad +draw quad probe all rgba (0.5, 0.5, 0.5, 0.5)
This merge request was approved by Zebediah Figura.
This merge request was approved by Giovanni Mascellani.
This merge request was approved by Henri Verbeet.