From: Francisco Casas fcasas@codeweavers.com
Instead of mapping HLSL_IR_JUMP_DISCARD_NEG directly to texkill, we make use of the HLSL_IR_JUMP_DISCARD_NEG -> HLSL_IR_JUMP_DISCARD_NZ pass, which has the benefit of reducing the condition to a single bool, and then lower HLSL_IR_JUMP_DISCARD_NZ -> HLSL_IR_JUMP_TEXKILL for SM1. --- libs/vkd3d-shader/d3dbc.c | 2 +- libs/vkd3d-shader/hlsl.c | 5 ++++ libs/vkd3d-shader/hlsl.h | 5 ++++ libs/vkd3d-shader/hlsl_codegen.c | 45 +++++++++++++++++++++++++++++--- tests/hlsl/clip.shader_test | 2 +- 5 files changed, 53 insertions(+), 6 deletions(-)
diff --git a/libs/vkd3d-shader/d3dbc.c b/libs/vkd3d-shader/d3dbc.c index 099729fbb..09e020426 100644 --- a/libs/vkd3d-shader/d3dbc.c +++ b/libs/vkd3d-shader/d3dbc.c @@ -2369,7 +2369,7 @@ static void write_sm1_jump(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer *b
switch (jump->type) { - case HLSL_IR_JUMP_DISCARD_NEG: + case HLSL_IR_JUMP_TEXKILL: { struct hlsl_reg *reg = &jump->condition.node->reg;
diff --git a/libs/vkd3d-shader/hlsl.c b/libs/vkd3d-shader/hlsl.c index cba954c98..2ff5c4215 100644 --- a/libs/vkd3d-shader/hlsl.c +++ b/libs/vkd3d-shader/hlsl.c @@ -2382,6 +2382,7 @@ const char *hlsl_jump_type_to_string(enum hlsl_ir_jump_type type) [HLSL_IR_JUMP_DISCARD_NEG] = "HLSL_IR_JUMP_DISCARD_NEG", [HLSL_IR_JUMP_DISCARD_NZ] = "HLSL_IR_JUMP_DISCARD_NZ", [HLSL_IR_JUMP_RETURN] = "HLSL_IR_JUMP_RETURN", + [HLSL_IR_JUMP_TEXKILL] = "HLSL_IR_JUMP_TEXKILL", };
assert(type < ARRAY_SIZE(names)); @@ -2684,6 +2685,10 @@ static void dump_ir_jump(struct vkd3d_string_buffer *buffer, const struct hlsl_i vkd3d_string_buffer_printf(buffer, "return"); break;
+ case HLSL_IR_JUMP_TEXKILL: + vkd3d_string_buffer_printf(buffer, "texkill"); + break; + case HLSL_IR_JUMP_UNRESOLVED_CONTINUE: vkd3d_string_buffer_printf(buffer, "unresolved_continue"); break; diff --git a/libs/vkd3d-shader/hlsl.h b/libs/vkd3d-shader/hlsl.h index 64111f3fc..add94384c 100644 --- a/libs/vkd3d-shader/hlsl.h +++ b/libs/vkd3d-shader/hlsl.h @@ -625,8 +625,13 @@ enum hlsl_ir_jump_type HLSL_IR_JUMP_BREAK, HLSL_IR_JUMP_CONTINUE, HLSL_IR_JUMP_DISCARD_NEG, + /* DISCARD_NZ cancels rendering of the current pixel if the condition, which in HLSL IR is + expected be a bool scalar, is true. */ HLSL_IR_JUMP_DISCARD_NZ, HLSL_IR_JUMP_RETURN, + /* JUMP_TEXKILL cancels rendering of the current pixel if the condition, which in HLSL IR is + expected to be a float scalar, is negative. */ + HLSL_IR_JUMP_TEXKILL, /* UNRESOLVED_CONTINUE type is used by the parser when 'continue' statement is found, it never reaches code generation, and is resolved to CONTINUE type once iteration and loop exit logic was properly applied. */ diff --git a/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d-shader/hlsl_codegen.c index e6490265d..590d15d70 100644 --- a/libs/vkd3d-shader/hlsl_codegen.c +++ b/libs/vkd3d-shader/hlsl_codegen.c @@ -3725,6 +3725,44 @@ static bool lower_discard_neg(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, return true; }
+static bool lower_discard_nz(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, void *context) +{ + struct hlsl_ir_node *operands[HLSL_MAX_OPERANDS] = { 0 }; + struct hlsl_ir_node *cast, *neg, *condition; + struct hlsl_type *float_type; + struct hlsl_ir_jump *jump; + struct hlsl_block block; + + if (instr->type != HLSL_IR_JUMP) + return false; + jump = hlsl_ir_jump(instr); + if (jump->type != HLSL_IR_JUMP_DISCARD_NZ) + return false; + condition = jump->condition.node; + + hlsl_block_init(&block); + + assert(condition->data_type->dimx == 1 && condition->data_type->dimy == 1); + float_type = hlsl_get_scalar_type(ctx, HLSL_TYPE_FLOAT); + + if (!(cast = hlsl_new_cast(ctx, condition, float_type, &instr->loc))) + return false; + hlsl_block_add_instr(&block, cast); + + memset(operands, 0, sizeof(operands)); + operands[0] = cast; + if (!(neg = hlsl_new_expr(ctx, HLSL_OP1_NEG, operands, float_type, &instr->loc))) + return false; + hlsl_block_add_instr(&block, neg); + + list_move_tail(&instr->entry, &block.instrs); + hlsl_src_remove(&jump->condition); + hlsl_src_from_node(&jump->condition, neg); + jump->type = HLSL_IR_JUMP_TEXKILL; + + return true; +} + static bool dce(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, void *context) { switch (instr->type) @@ -5411,10 +5449,9 @@ int hlsl_emit_bytecode(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry hlsl_error(ctx, &entry_func->loc, VKD3D_SHADER_ERROR_HLSL_MISSING_ATTRIBUTE, "Entry point "%s" is missing a [numthreads] attribute.", entry_func->func->name);
- if (profile->major_version >= 4) - { - hlsl_transform_ir(ctx, lower_discard_neg, body, NULL); - } + hlsl_transform_ir(ctx, lower_discard_neg, body, NULL); + if (profile->major_version < 4) + hlsl_transform_ir(ctx, lower_discard_nz, body, NULL); lower_ir(ctx, lower_broadcasts, body); while (hlsl_transform_ir(ctx, fold_redundant_casts, body, NULL)); do diff --git a/tests/hlsl/clip.shader_test b/tests/hlsl/clip.shader_test index 68059f216..33adbda12 100644 --- a/tests/hlsl/clip.shader_test +++ b/tests/hlsl/clip.shader_test @@ -22,4 +22,4 @@ todo(glsl) draw quad probe all rgba (9, 0, 7, 6) uniform 0 float4 3 3 3 -1 todo(glsl) draw quad -todo(sm<4) probe all rgba (9, 0, 7, 6) +probe all rgba (9, 0, 7, 6)