From a082daeb56c239b41d67b5df5abceb342c0b32b9 Mon Sep 17 00:00:00 2001 From: Nikolay Sivov Date: Thu, 9 Jan 2025 14:54:26 +0100 Subject: [PATCH] vkd3d-shader/hlsl: Implement the isinf() intrinsic. Signed-off-by: Nikolay Sivov --- Makefile.am | 1 + libs/vkd3d-shader/hlsl.c | 1 + libs/vkd3d-shader/hlsl.h | 1 + libs/vkd3d-shader/hlsl.y | 14 +++++ libs/vkd3d-shader/hlsl_codegen.c | 91 ++++++++++++++++++++++++++++++++ tests/hlsl/isinf.shader_test | 31 +++++++++++ 6 files changed, 139 insertions(+) create mode 100644 tests/hlsl/isinf.shader_test diff --git a/Makefile.am b/Makefile.am index 7d96ccd5..da9bf880 100644 --- a/Makefile.am +++ b/Makefile.am @@ -164,6 +164,7 @@ vkd3d_shader_tests = \ tests/hlsl/invalid.shader_test \ tests/hlsl/inverse-trig.shader_test \ tests/hlsl/is-front-face.shader_test \ + tests/hlsl/isinf.shader_test \ tests/hlsl/ldexp.shader_test \ tests/hlsl/length.shader_test \ tests/hlsl/lerp.shader_test \ diff --git a/libs/vkd3d-shader/hlsl.c b/libs/vkd3d-shader/hlsl.c index 858186a1..23f54d3e 100644 --- a/libs/vkd3d-shader/hlsl.c +++ b/libs/vkd3d-shader/hlsl.c @@ -3238,6 +3238,7 @@ const char *debug_hlsl_expr_op(enum hlsl_ir_expr_op op) [HLSL_OP1_F32TOF16] = "f32tof16", [HLSL_OP1_FLOOR] = "floor", [HLSL_OP1_FRACT] = "fract", + [HLSL_OP1_ISINF] = "isinf", [HLSL_OP1_LOG2] = "log2", [HLSL_OP1_LOGIC_NOT] = "!", [HLSL_OP1_NEG] = "-", diff --git a/libs/vkd3d-shader/hlsl.h b/libs/vkd3d-shader/hlsl.h index 02e1e469..2d012d95 100644 --- a/libs/vkd3d-shader/hlsl.h +++ b/libs/vkd3d-shader/hlsl.h @@ -704,6 +704,7 @@ enum hlsl_ir_expr_op HLSL_OP1_F32TOF16, HLSL_OP1_FLOOR, HLSL_OP1_FRACT, + HLSL_OP1_ISINF, HLSL_OP1_LOG2, HLSL_OP1_LOGIC_NOT, HLSL_OP1_NEG, diff --git a/libs/vkd3d-shader/hlsl.y b/libs/vkd3d-shader/hlsl.y index e6eaac78..e5a03067 100644 --- a/libs/vkd3d-shader/hlsl.y +++ b/libs/vkd3d-shader/hlsl.y @@ -4313,6 +4313,19 @@ static bool intrinsic_fwidth(struct hlsl_ctx *ctx, return !!add_user_call(ctx, func, params, false, loc); } +static bool intrinsic_isinf(struct hlsl_ctx *ctx, + const struct parse_initializer *params, const struct vkd3d_shader_location *loc) +{ + struct hlsl_type *type = params->args[0]->data_type, *bool_type; + struct hlsl_ir_node *args[HLSL_MAX_OPERANDS] = {0}; + + bool_type = hlsl_get_numeric_type(ctx, type->class, HLSL_TYPE_BOOL, + type->e.numeric.dimx, type->e.numeric.dimy); + + args[0] = params->args[0]; + return !!add_expr(ctx, params->instrs, HLSL_OP1_ISINF, args, bool_type, loc); +} + static bool intrinsic_ldexp(struct hlsl_ctx *ctx, const struct parse_initializer *params, const struct vkd3d_shader_location *loc) { @@ -5410,6 +5423,7 @@ intrinsic_functions[] = {"fmod", 2, true, intrinsic_fmod}, {"frac", 1, true, intrinsic_frac}, {"fwidth", 1, true, intrinsic_fwidth}, + {"isinf", 1, true, intrinsic_isinf}, {"ldexp", 2, true, intrinsic_ldexp}, {"length", 1, true, intrinsic_length}, {"lerp", 3, true, intrinsic_lerp}, diff --git a/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d-shader/hlsl_codegen.c index a5b53a24..1c5a0490 100644 --- a/libs/vkd3d-shader/hlsl_codegen.c +++ b/libs/vkd3d-shader/hlsl_codegen.c @@ -11825,6 +11825,95 @@ static bool lower_f32tof16(struct hlsl_ctx *ctx, struct hlsl_ir_node *node, stru return true; } +static bool lower_isinf(struct hlsl_ctx *ctx, struct hlsl_ir_node *node, struct hlsl_block *block) +{ + struct hlsl_ir_node *call, *rhs, *store; + struct hlsl_ir_function_decl *func; + unsigned int component_count; + struct hlsl_ir_load *load; + struct hlsl_ir_expr *expr; + struct hlsl_ir_var *lhs; + const char *template; + char *body; + + static const char template_sm2[] = + "typedef bool%u boolX;\n" + "typedef float%u floatX;\n" + "boolX isinf(floatX x)\n" + "{\n" + " floatX v = 1 / x;\n" + " v = v * v;\n" + " return v <= 0;\n" + "}\n"; + + static const char template_sm3[] = + "typedef bool%u boolX;\n" + "typedef float%u floatX;\n" + "boolX isinf(floatX x)\n" + "{\n" + " floatX v = 1 / x;\n" + " return v <= 0;\n" + "}\n"; + + static const char template_sm4[] = + "typedef bool%u boolX;\n" + "typedef float%u floatX;\n" + "boolX isinf(floatX x)\n" + "{\n" + " return (asuint(x) & 0x7fffffff) == 0x7f800000;\n" + "}\n"; + + static const char template_int[] = + "typedef bool%u boolX;\n" + "typedef float%u floatX;\n" + "boolX isinf(floatX x)\n" + "{\n" + " return false;\n" + "}"; + + if (node->type != HLSL_IR_EXPR) + return false; + + expr = hlsl_ir_expr(node); + + if (expr->op != HLSL_OP1_ISINF) + return false; + + rhs = expr->operands[0].node; + + if (hlsl_version_lt(ctx, 3, 0)) + template = template_sm2; + else if (hlsl_version_lt(ctx, 4, 0)) + template = template_sm3; + else if (type_is_integer(rhs->data_type)) + template = template_int; + else + template = template_sm4; + + component_count = hlsl_type_component_count(rhs->data_type); + if (!(body = hlsl_sprintf_alloc(ctx, template, component_count, component_count))) + return false; + + if (!(func = hlsl_compile_internal_function(ctx, "isinf", body))) + return false; + + lhs = func->parameters.vars[0]; + + if (!(store = hlsl_new_simple_store(ctx, lhs, rhs))) + return false; + hlsl_block_add_instr(block, store); + + if (!(call = hlsl_new_call(ctx, func, &node->loc))) + return false; + hlsl_block_add_instr(block, call); + + if (!(load = hlsl_new_var_load(ctx, func->return_var, &node->loc))) + return false; + hlsl_block_add_instr(block, &load->node); + + return true; +} + static void process_entry_function(struct hlsl_ctx *ctx, const struct hlsl_block *global_uniform_block, struct hlsl_ir_function_decl *entry_func) { @@ -11858,6 +11947,8 @@ static void process_entry_function(struct hlsl_ctx *ctx, lower_ir(ctx, lower_f32tof16, body); } + lower_ir(ctx, lower_isinf, body); + lower_return(ctx, entry_func, body, false); while (hlsl_transform_ir(ctx, lower_calls, body, NULL)); diff --git a/tests/hlsl/isinf.shader_test b/tests/hlsl/isinf.shader_test new file mode 100644 index 00000000..fe376e42 --- /dev/null +++ b/tests/hlsl/isinf.shader_test @@ -0,0 +1,31 @@ +[pixel shader] +float4 v; + +float4 main() : sv_target +{ + return isinf(1.0f / v) + 1.0f; +} + +[test] +uniform 0 float4 1.0 0.0 -0.0 0.0 +draw quad +probe (0, 0) rgba(1.0, 2.0, 2.0, 2.0) + +[require] +shader model >= 4.0 + +[pixel shader] +float4 v; + +float4 main() : sv_target +{ + return isinf(v) + 1.0f; +} + +[test] +uniform 0 float4 1.0 0.0 -1.0 2.0 +draw quad +probe (0, 0) rgba(1.0, 1.0, 1.0, 1.0) +uniform 0 uint4 0x7f800000 0xff800000 0xffc00001 0xff800001 +draw quad +probe (0, 0) rgba(2.0, 2.0, 1.0, 1.0)