Signed-off-by: Francisco Casas fcasas@codeweavers.com --- Makefile.am | 1 + libs/vkd3d-shader/hlsl.y | 54 ++++++++++++++++++++++++++++++++++++++++ tests/cross.shader_test | 11 ++++++++ 3 files changed, 66 insertions(+) create mode 100644 tests/cross.shader_test
diff --git a/Makefile.am b/Makefile.am index d6e14cf1..3cfd90f4 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 \ diff --git a/libs/vkd3d-shader/hlsl.y b/libs/vkd3d-shader/hlsl.y index 2120b26f..3bb5cd70 100644 --- a/libs/vkd3d-shader/hlsl.y +++ b/libs/vkd3d-shader/hlsl.y @@ -1611,6 +1611,59 @@ 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_node *v0 = params->args[0], *v1 = params->args[1]; + struct hlsl_ir_swizzle *v0_swzl1, *v0_swzl2, *v1_swzl1, *v1_swzl2; + struct hlsl_ir_node *mul1_neg; + struct hlsl_ir_expr *mul1, *mul2; + int wrong_arg = -1; + + if (v1->data_type->type != HLSL_CLASS_VECTOR) + wrong_arg = 1; + if (v0->data_type->type != HLSL_CLASS_VECTOR) + 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': expected 'vector' but got '%s'.", + wrong_arg, string->buffer); + hlsl_release_string_buffer(ctx, string); + return false; + } + + if (!(v0_swzl1 = hlsl_new_swizzle(ctx, HLSL_SWIZZLE(Z, X, Y, Z), 3, v0, &loc))) + return false; + list_add_tail(params->instrs, &v0_swzl1->node.entry); + + if (!(v1_swzl1 = hlsl_new_swizzle(ctx, HLSL_SWIZZLE(Y, Z, X, Y), 3, v1, &loc))) + return false; + list_add_tail(params->instrs, &v1_swzl1->node.entry); + + if (!(mul1 = add_binary_arithmetic_expr(ctx, params->instrs, HLSL_OP2_MUL, &v0_swzl1->node, &v1_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 (!(v0_swzl2 = hlsl_new_swizzle(ctx, HLSL_SWIZZLE(Y, Z, X, Y), 3, v0, &loc))) + return false; + list_add_tail(params->instrs, &v0_swzl2->node.entry); + + if (!(v1_swzl2 = hlsl_new_swizzle(ctx, HLSL_SWIZZLE(Z, X, Y, Z), 3, v1, &loc))) + return false; + list_add_tail(params->instrs, &v1_swzl2->node.entry); + + if (!(mul2 = add_binary_arithmetic_expr(ctx, params->instrs, HLSL_OP2_MUL, &v0_swzl2->node, &v1_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 +1681,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..c49f5248 --- /dev/null +++ b/tests/cross.shader_test @@ -0,0 +1,11 @@ +[pixel shader] +float4 main(uniform float4 u, uniform float4 v) : sv_target +{ + return float4(cross(u,v),0); +} + +[test] +uniform 0 float4 1 -2 3 4 +uniform 4 float4 10 100 1000 10000 +draw quad +probe all rgba (-2300, -970, 120, 0)
Hi,
On 16/11/21 16:11, Francisco Casas wrote:
+static bool intrinsic_cross(struct hlsl_ctx *ctx,
const struct parse_initializer *params, struct vkd3d_shader_location loc) > +{
- struct hlsl_ir_node *v0 = params->args[0], *v1 = params->args[1];
- struct hlsl_ir_swizzle *v0_swzl1, *v0_swzl2, *v1_swzl1, *v1_swzl2;
- struct hlsl_ir_node *mul1_neg;
- struct hlsl_ir_expr *mul1, *mul2;
- int wrong_arg = -1;
Whenever possible, the declaration block is sorted by decreasing line length, sometimes with very funny results.
- if (v1->data_type->type != HLSL_CLASS_VECTOR)
wrong_arg = 1;
- if (v0->data_type->type != HLSL_CLASS_VECTOR)
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': expected 'vector' but got '%s'.",
wrong_arg, string->buffer);
hlsl_release_string_buffer(ctx, string);
return false;
- }
I think we need more checks on the types here (on the base type and on the vector length): from my experiments, it seems that cross() accepts vectors of length 3 or 4 (truncating them to 3 in that case, with a warning); it accepts whatever base type, but it casts non-floating point types to float. Implicitly, this means that it returns half3 when both its arguments have base type half, and float3 in every other case.
(BTW, "vector" is not a type name, use names like "float3")
En passant, I am a bit bothered by the fact that we don't have precise rules for typing in the IR, but that's not this patch's fault.
The actual cross vector computation looks fine.
Thanks, Giovanni.