[PATCH v2 0/1] MR330: vkd3d-shader/hlsl: Add fwidth() function.
Signed-off-by: Nikolay Sivov <nsivov(a)codeweavers.com> -- v2: vkd3d-shader/hlsl: Add fwidth() function. https://gitlab.winehq.org/wine/vkd3d/-/merge_requests/330
From: Nikolay Sivov <nsivov(a)codeweavers.com> Signed-off-by: Nikolay Sivov <nsivov(a)codeweavers.com> --- Makefile.am | 1 + libs/vkd3d-shader/hlsl.y | 28 ++++++++++++++++++++++++++++ tests/hlsl/fwidth.shader_test | 26 ++++++++++++++++++++++++++ 3 files changed, 55 insertions(+) create mode 100644 tests/hlsl/fwidth.shader_test diff --git a/Makefile.am b/Makefile.am index b36358b2..70829398 100644 --- a/Makefile.am +++ b/Makefile.am @@ -93,6 +93,7 @@ vkd3d_shader_tests = \ tests/hlsl/function-overload.shader_test \ tests/hlsl/function-return.shader_test \ tests/hlsl/function.shader_test \ + tests/hlsl/fwidth.shader_test \ tests/hlsl/gather-offset.shader_test \ tests/hlsl/gather.shader_test \ tests/hlsl/getdimensions.shader_test \ diff --git a/libs/vkd3d-shader/hlsl.y b/libs/vkd3d-shader/hlsl.y index 161d1ab4..0793d03d 100644 --- a/libs/vkd3d-shader/hlsl.y +++ b/libs/vkd3d-shader/hlsl.y @@ -2957,6 +2957,33 @@ static bool intrinsic_frac(struct hlsl_ctx *ctx, return !!add_unary_arithmetic_expr(ctx, params->instrs, HLSL_OP1_FRACT, arg, loc); } +static bool intrinsic_fwidth(struct hlsl_ctx *ctx, + const struct parse_initializer *params, const struct vkd3d_shader_location *loc) +{ + struct hlsl_ir_function_decl *func; + struct hlsl_type *type; + char *body; + + static const char template[] = + "%s fwidth(%s x)\n" + "{\n" + " return abs(ddx(x)) + abs(ddy(x));\n" + "}"; + + if (!(type = elementwise_intrinsic_get_common_type(ctx, params, loc))) + return false; + type = hlsl_get_numeric_type(ctx, type->class, HLSL_TYPE_FLOAT, type->dimx, type->dimy); + + if (!(body = hlsl_sprintf_alloc(ctx, template, type->name, type->name))) + return false; + func = hlsl_compile_internal_function(ctx, "fwidth", body); + vkd3d_free(body); + if (!func) + return false; + + return add_user_call(ctx, func, params, loc); +} + static bool intrinsic_ldexp(struct hlsl_ctx *ctx, const struct parse_initializer *params, const struct vkd3d_shader_location *loc) { @@ -3631,6 +3658,7 @@ intrinsic_functions[] = {"floor", 1, true, intrinsic_floor}, {"fmod", 2, true, intrinsic_fmod}, {"frac", 1, true, intrinsic_frac}, + {"fwidth", 1, true, intrinsic_fwidth}, {"ldexp", 2, true, intrinsic_ldexp}, {"length", 1, true, intrinsic_length}, {"lerp", 3, true, intrinsic_lerp}, diff --git a/tests/hlsl/fwidth.shader_test b/tests/hlsl/fwidth.shader_test new file mode 100644 index 00000000..e302505f --- /dev/null +++ b/tests/hlsl/fwidth.shader_test @@ -0,0 +1,26 @@ +[require] +shader model >= 3.0 + +[pixel shader] +float4 main(float4 pos : sv_position) : sv_target +{ + // Shader models < 4 don't add 0.5 to sv_position, so this adjustment is required to get the + // same outputs. + pos.x = floor(pos.x) + 0.5; + pos.y = floor(pos.y) + 0.5; + + pos /= 10.0; + float nonlinear = pos.x * pos.y - pos.x * (pos.x + 0.5); + float4 res = fwidth(nonlinear); + + // Each device may use either the coarse or the fine derivate, so use quantization. + return round(30 * res); +} + +[test] +draw quad +probe (10, 10) rgba (8.0, 8.0, 8.0, 8.0) +probe (11, 10) rgba (8.0, 8.0, 8.0, 8.0) +probe (12, 10) rgba (10.0, 10.0, 10.0, 10.0) +probe (16, 16) rgba (12.0, 12.0, 12.0, 12.0) +probe (150, 150) rgba (92.0, 92.0, 92.0, 92.0) -- GitLab https://gitlab.winehq.org/wine/vkd3d/-/merge_requests/330
On Thu Sep 7 17:21:43 2023 +0000, Zebediah Figura wrote:
Can we have a test, please? :-) I added something based on existing ddx/ddy tests. I don't know how those derivatives work, but results match and pass for me on Windows.
-- https://gitlab.winehq.org/wine/vkd3d/-/merge_requests/330#note_44595
Giovanni Mascellani (@giomasce) commented about libs/vkd3d-shader/hlsl.y:
+static bool intrinsic_fwidth(struct hlsl_ctx *ctx, + const struct parse_initializer *params, const struct vkd3d_shader_location *loc) +{ + struct hlsl_ir_function_decl *func; + struct hlsl_type *type; + char *body; + + static const char template[] = + "%s fwidth(%s x)\n" + "{\n" + " return abs(ddx(x)) + abs(ddy(x));\n" + "}"; + + if (!(type = elementwise_intrinsic_get_common_type(ctx, params, loc))) + return false;
What's the point of this with a single parameter? Am I missing anything? -- https://gitlab.winehq.org/wine/vkd3d/-/merge_requests/330#note_44714
Giovanni Mascellani (@giomasce) commented about libs/vkd3d-shader/hlsl.y:
+static bool intrinsic_fwidth(struct hlsl_ctx *ctx, + const struct parse_initializer *params, const struct vkd3d_shader_location *loc) +{ + struct hlsl_ir_function_decl *func; + struct hlsl_type *type; + char *body; + + static const char template[] = + "%s fwidth(%s x)\n" + "{\n" + " return abs(ddx(x)) + abs(ddy(x));\n" + "}"; + + if (!(type = elementwise_intrinsic_get_common_type(ctx, params, loc))) + return false; + type = hlsl_get_numeric_type(ctx, type->class, HLSL_TYPE_FLOAT, type->dimx, type->dimy); As for the determinant, it is likely (though not necessarily true, so a test for that would be appropriate) that the right thing to do here is using `elementwise_intrinsic_float_convert_args()`.
-- https://gitlab.winehq.org/wine/vkd3d/-/merge_requests/330#note_44715
On Fri Sep 8 16:07:03 2023 +0000, Giovanni Mascellani wrote:
As for the determinant, it is likely (though not necessarily true, so a test for that would be appropriate) that the right thing to do here is using `elementwise_intrinsic_float_convert_args()`. I think the idea was to convert in add_user_call(), maybe it could be reworked.
-- https://gitlab.winehq.org/wine/vkd3d/-/merge_requests/330#note_44716
On Fri Sep 8 16:07:02 2023 +0000, Giovanni Mascellani wrote:
What's the point of this with a single parameter? Am I missing anything? Yes, it's not useful here.
-- https://gitlab.winehq.org/wine/vkd3d/-/merge_requests/330#note_44717
On Fri Sep 8 16:09:37 2023 +0000, Nikolay Sivov wrote:
I think the idea was to convert in add_user_call(), maybe it could be reworked. Yes, but you still have to detect the correct type to convert to. It seems that the general philosophy behind the HLSL compiler is that for expressions that only make sense for floating point numbers you convert every integral type (`int`, `uint` and `bool`) to `float`, and everything else doesn't need conversion. That's what `elementwise_intrinsic_float_convert_args()` does. I would assume that here the same happens, unless there is evidence of the contrary.
-- https://gitlab.winehq.org/wine/vkd3d/-/merge_requests/330#note_44726
On Fri Sep 8 16:27:48 2023 +0000, Giovanni Mascellani wrote:
Yes, but you still have to detect the correct type to convert to. It seems that the general philosophy behind the HLSL compiler is that for expressions that only make sense for floating point numbers you convert every integral type (`int`, `uint` and `bool`) to `float`, and everything else doesn't need conversion. That's what `elementwise_intrinsic_float_convert_args()` does. I would assume that here the same happens, unless there is evidence of the contrary. We probably need to fix lit() too now that you mention it.
-- https://gitlab.winehq.org/wine/vkd3d/-/merge_requests/330#note_44727
participants (4)
-
Giovanni Mascellani (@giomasce) -
Nikolay Sivov -
Nikolay Sivov (@nsivov) -
Zebediah Figura (@zfigura)