Signed-off-by: Francisco Casas fcasas@codeweavers.com --- Makefile.am | 2 + libs/vkd3d-shader/hlsl.y | 79 ++++++++++++++++++++++++++++++++++++++++ tests/cross.shader_test | 13 +++++++ 3 files changed, 94 insertions(+) create mode 100644 tests/cross.shader_test
diff --git a/Makefile.am b/Makefile.am index d6e14cf1..307c32a0 100644 --- a/Makefile.am +++ b/Makefile.am @@ -60,6 +60,7 @@ vkd3d_shader_tests = \ tests/cast-to-int.shader_test \ tests/cast-to-uint.shader_test \ tests/conditional.shader_test \ + tests/cross.shader_test \ tests/hlsl-array-dimension.shader_test \ tests/hlsl-bool-cast.shader_test \ tests/hlsl-clamp.shader_test \ @@ -285,6 +286,7 @@ XFAIL_TESTS = \ tests/cast-to-int.shader_test \ tests/cast-to-uint.shader_test \ tests/conditional.shader_test \ + tests/cross.shader_test \ tests/hlsl-array-dimension.shader_test \ tests/hlsl-bool-cast.shader_test \ tests/hlsl-comma.shader_test \ diff --git a/libs/vkd3d-shader/hlsl.y b/libs/vkd3d-shader/hlsl.y index 2120b26f..e04b9ef0 100644 --- a/libs/vkd3d-shader/hlsl.y +++ b/libs/vkd3d-shader/hlsl.y @@ -1611,6 +1611,84 @@ static bool intrinsic_pow(struct hlsl_ctx *ctx, return true; }
+static bool intrinsic_cross(struct hlsl_ctx *ctx, + const struct parse_initializer *params, struct vkd3d_shader_location loc) +{ + struct hlsl_ir_swizzle *arg1_swzl1, *arg1_swzl2, *arg2_swzl1, *arg2_swzl2; + struct hlsl_ir_node *arg1 = params->args[0], *arg2 = params->args[1]; + struct hlsl_ir_node *arg1_cast, *arg2_cast, *mul1_neg; + struct hlsl_ir_expr *mul1, *mul2; + struct hlsl_type *cast_type; + enum hlsl_base_type base; + int wrong_arg = -1; + + if (arg2->data_type->type != HLSL_CLASS_VECTOR) + wrong_arg = 1; + if(arg2->data_type->dimx != 3 && arg2->data_type->dimx != 4) + wrong_arg = 1; + + if (arg1->data_type->type != HLSL_CLASS_VECTOR) + wrong_arg = 0; + if (arg1->data_type->dimx != 3 && arg1->data_type->dimx != 4) + wrong_arg = 0; + + if (wrong_arg != -1) + { + struct vkd3d_string_buffer *string; + if ((string = hlsl_type_to_string(ctx, params->args[wrong_arg]->data_type))) + hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE, + "Wrong type for argument %d of 'cross': '%s'.", wrong_arg, string->buffer); + hlsl_release_string_buffer(ctx, string); + return false; + } + + if (arg1->data_type->base_type == HLSL_TYPE_HALF && arg2->data_type->base_type == HLSL_TYPE_HALF){ + base = HLSL_TYPE_HALF; + } else { + base = HLSL_TYPE_FLOAT; + } + base = expr_common_base_type(base, arg1->data_type->base_type); + base = expr_common_base_type(base, arg2->data_type->base_type); + + cast_type = hlsl_get_vector_type(ctx, base, 3); + + if (!(arg1_cast = 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))) + return false; + + if (!(arg1_swzl1 = hlsl_new_swizzle(ctx, HLSL_SWIZZLE(Z, X, Y, Z), 3, arg1_cast, &loc))) + return false; + list_add_tail(params->instrs, &arg1_swzl1->node.entry); + + if (!(arg2_swzl1 = hlsl_new_swizzle(ctx, HLSL_SWIZZLE(Y, Z, X, Y), 3, arg2_cast, &loc))) + return false; + list_add_tail(params->instrs, &arg2_swzl1->node.entry); + + if (!(mul1 = add_binary_arithmetic_expr(ctx, params->instrs, HLSL_OP2_MUL, + &arg1_swzl1->node, &arg2_swzl1->node, &loc))) + return false; + + if (!(mul1_neg = hlsl_new_unary_expr(ctx, HLSL_OP1_NEG, &mul1->node, loc))) + return false; + list_add_tail(params->instrs, &mul1_neg->entry); + + if (!(arg1_swzl2 = hlsl_new_swizzle(ctx, HLSL_SWIZZLE(Y, Z, X, Y), 3, arg1_cast, &loc))) + return false; + list_add_tail(params->instrs, &arg1_swzl2->node.entry); + + if (!(arg2_swzl2 = hlsl_new_swizzle(ctx, HLSL_SWIZZLE(Z, X, Y, Z), 3, arg2_cast, &loc))) + return false; + list_add_tail(params->instrs, &arg2_swzl2->node.entry); + + if (!(mul2 = add_binary_arithmetic_expr(ctx, params->instrs, HLSL_OP2_MUL, + &arg1_swzl2->node, &arg2_swzl2->node, &loc))) + return false; + + return !!add_binary_arithmetic_expr(ctx, params->instrs, HLSL_OP2_ADD, &mul2->node, mul1_neg, &loc); +} + static bool intrinsic_saturate(struct hlsl_ctx *ctx, const struct parse_initializer *params, struct vkd3d_shader_location loc) { @@ -1628,6 +1706,7 @@ intrinsic_functions[] = { {"abs", 1, true, intrinsic_abs}, {"clamp", 3, true, intrinsic_clamp}, + {"cross", 2, true, intrinsic_cross}, {"max", 2, true, intrinsic_max}, {"pow", 2, true, intrinsic_pow}, {"saturate", 1, true, intrinsic_saturate}, diff --git a/tests/cross.shader_test b/tests/cross.shader_test new file mode 100644 index 00000000..59197db0 --- /dev/null +++ b/tests/cross.shader_test @@ -0,0 +1,13 @@ +[pixel shader] +float4 main(uniform float4 u, uniform float4 v) : sv_target +{ + float4 res = float4(0,0,0,0); + res.xyz = cross(u,v); + return res; +} + +[test] +uniform 0 float4 1 -2 3 4 +uniform 4 float4 10 100 1000 10000 +draw quad +probe all rgba (-2300, -970, 120, 0)
On 11/17/21 08:12, Francisco Casas wrote:
+static bool intrinsic_cross(struct hlsl_ctx *ctx,
const struct parse_initializer *params, struct vkd3d_shader_location loc)
+{
- struct hlsl_ir_swizzle *arg1_swzl1, *arg1_swzl2, *arg2_swzl1, *arg2_swzl2;
- struct hlsl_ir_node *arg1 = params->args[0], *arg2 = params->args[1];
- struct hlsl_ir_node *arg1_cast, *arg2_cast, *mul1_neg;
- struct hlsl_ir_expr *mul1, *mul2;
- struct hlsl_type *cast_type;
- enum hlsl_base_type base;
- int wrong_arg = -1;
- if (arg2->data_type->type != HLSL_CLASS_VECTOR)
wrong_arg = 1;
- if(arg2->data_type->dimx != 3 && arg2->data_type->dimx != 4)
Or, more simply, "dimx < 3".
This doesn't seem to be quite right, though. It's legal to pass a scalar to these functions. I suspect that what should instead happen is that we should try to implicitly convert to float3 or half3, and let that part fail (and generate the appropriate error message).
(On the other hand, this wrongly allows matrices, but HLSL function matching logic is arcane, and for the sake of simplicity I'd rather just be more lenient than native.)
wrong_arg = 1;
- if (arg1->data_type->type != HLSL_CLASS_VECTOR)
wrong_arg = 0;
- if (arg1->data_type->dimx != 3 && arg1->data_type->dimx != 4)
wrong_arg = 0;
- if (wrong_arg != -1)
- {
struct vkd3d_string_buffer *string;
if ((string = hlsl_type_to_string(ctx, params->args[wrong_arg]->data_type)))
hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE,
"Wrong type for argument %d of 'cross': '%s'.", wrong_arg, string->buffer);
hlsl_release_string_buffer(ctx, string);
return false;
- }
There's no reason we should only generate one error here; we should generate errors for each argument separately.
- if (arg1->data_type->base_type == HLSL_TYPE_HALF && arg2->data_type->base_type == HLSL_TYPE_HALF){
base = HLSL_TYPE_HALF;
- } else {
base = HLSL_TYPE_FLOAT;
- }
- base = expr_common_base_type(base, arg1->data_type->base_type);
- base = expr_common_base_type(base, arg2->data_type->base_type);
These expr_common_base_type() calls are basically redundant.