Module: vkd3d Branch: master Commit: 76e42fbd214f094a46ea4a1bccc131809d9a44ce URL: https://gitlab.winehq.org/wine/vkd3d/-/commit/76e42fbd214f094a46ea4a1bccc131...
Author: Nikolay Sivov nsivov@codeweavers.com Date: Tue Sep 26 20:48:58 2023 +0200
vkd3d-shader/hlsl: Implement ternary operator for SM1.
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com
---
libs/vkd3d-shader/d3dbc.c | 35 +++++++++++++++++++++++ libs/vkd3d-shader/hlsl.c | 1 + libs/vkd3d-shader/hlsl.h | 5 +++- libs/vkd3d-shader/hlsl_codegen.c | 61 ++++++++++++++++++++++++++++------------ 4 files changed, 83 insertions(+), 19 deletions(-)
diff --git a/libs/vkd3d-shader/d3dbc.c b/libs/vkd3d-shader/d3dbc.c index b1e2dc91..8a15fc4e 100644 --- a/libs/vkd3d-shader/d3dbc.c +++ b/libs/vkd3d-shader/d3dbc.c @@ -1824,6 +1824,37 @@ static void write_sm1_dp2add(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer write_sm1_instruction(ctx, buffer, &instr); }
+static void write_sm1_ternary_op(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer *buffer, + D3DSHADER_INSTRUCTION_OPCODE_TYPE opcode, const struct hlsl_reg *dst, const struct hlsl_reg *src1, + const struct hlsl_reg *src2, const struct hlsl_reg *src3) +{ + struct sm1_instruction instr = + { + .opcode = opcode, + + .dst.type = D3DSPR_TEMP, + .dst.writemask = dst->writemask, + .dst.reg = dst->id, + .has_dst = 1, + + .srcs[0].type = D3DSPR_TEMP, + .srcs[0].swizzle = hlsl_swizzle_from_writemask(src1->writemask), + .srcs[0].reg = src1->id, + .srcs[1].type = D3DSPR_TEMP, + .srcs[1].swizzle = hlsl_swizzle_from_writemask(src2->writemask), + .srcs[1].reg = src2->id, + .srcs[2].type = D3DSPR_TEMP, + .srcs[2].swizzle = hlsl_swizzle_from_writemask(src3->writemask), + .srcs[2].reg = src3->id, + .src_count = 3, + }; + + sm1_map_src_swizzle(&instr.srcs[0], instr.dst.writemask); + sm1_map_src_swizzle(&instr.srcs[1], instr.dst.writemask); + sm1_map_src_swizzle(&instr.srcs[2], instr.dst.writemask); + write_sm1_instruction(ctx, buffer, &instr); +} + static void write_sm1_binary_op(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer *buffer, D3DSHADER_INSTRUCTION_OPCODE_TYPE opcode, const struct hlsl_reg *dst, const struct hlsl_reg *src1, const struct hlsl_reg *src2) @@ -2190,6 +2221,10 @@ static void write_sm1_expr(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer *b } break;
+ case HLSL_OP3_CMP: + write_sm1_ternary_op(ctx, buffer, D3DSIO_CMP, &instr->reg, &arg1->reg, &arg2->reg, &arg3->reg); + break; + case HLSL_OP3_DP2ADD: write_sm1_dp2add(ctx, buffer, &instr->reg, &arg1->reg, &arg2->reg, &arg3->reg); break; diff --git a/libs/vkd3d-shader/hlsl.c b/libs/vkd3d-shader/hlsl.c index 1d3fd0f7..9bae821d 100644 --- a/libs/vkd3d-shader/hlsl.c +++ b/libs/vkd3d-shader/hlsl.c @@ -2607,6 +2607,7 @@ const char *debug_hlsl_expr_op(enum hlsl_ir_expr_op op) [HLSL_OP2_NEQUAL] = "!=", [HLSL_OP2_RSHIFT] = ">>",
+ [HLSL_OP3_CMP] = "cmp", [HLSL_OP3_DP2ADD] = "dp2add", [HLSL_OP3_MOVC] = "movc", [HLSL_OP3_TERNARY] = "ternary", diff --git a/libs/vkd3d-shader/hlsl.h b/libs/vkd3d-shader/hlsl.h index 309d7080..98861f40 100644 --- a/libs/vkd3d-shader/hlsl.h +++ b/libs/vkd3d-shader/hlsl.h @@ -578,7 +578,10 @@ enum hlsl_ir_expr_op /* MOVC(a, b, c) returns c if a is bitwise zero and b otherwise. * TERNARY(a, b, c) returns c if a == 0 and b otherwise. * They differ for floating point numbers, because - * -0.0 == 0.0, but it is not bitwise zero. */ + * -0.0 == 0.0, but it is not bitwise zero. CMP(a, b, c) returns b + if a >= 0, and c otherwise. It's used only for SM1-SM3 targets, while + SM4+ is using MOVC in such cases. */ + HLSL_OP3_CMP, HLSL_OP3_MOVC, HLSL_OP3_TERNARY, }; diff --git a/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d-shader/hlsl_codegen.c index 76a010fb..570591a6 100644 --- a/libs/vkd3d-shader/hlsl_codegen.c +++ b/libs/vkd3d-shader/hlsl_codegen.c @@ -2688,7 +2688,7 @@ static bool lower_round(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, struct /* Use 'movc' for the ternary operator. */ static bool lower_ternary(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, struct hlsl_block *block) { - struct hlsl_ir_node *operands[HLSL_MAX_OPERANDS], *replacement; + struct hlsl_ir_node *operands[HLSL_MAX_OPERANDS] = { 0 }, *replacement; struct hlsl_ir_node *zero, *cond, *first, *second; struct hlsl_constant_value zero_value = { 0 }; struct hlsl_ir_expr *expr; @@ -2705,28 +2705,54 @@ static bool lower_ternary(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, stru first = expr->operands[1].node; second = expr->operands[2].node;
- if (cond->data_type->base_type == HLSL_TYPE_FLOAT) + if (ctx->profile->major_version < 4 && ctx->profile->type == VKD3D_SHADER_TYPE_PIXEL) { - if (!(zero = hlsl_new_constant(ctx, cond->data_type, &zero_value, &instr->loc))) + struct hlsl_ir_node *abs, *neg; + + if (!(abs = hlsl_new_unary_expr(ctx, HLSL_OP1_ABS, cond, &instr->loc))) return false; - hlsl_block_add_instr(block, zero); + hlsl_block_add_instr(block, abs); + + if (!(neg = hlsl_new_unary_expr(ctx, HLSL_OP1_NEG, abs, &instr->loc))) + return false; + hlsl_block_add_instr(block, neg); + + operands[0] = neg; + operands[1] = second; + operands[2] = first; + if (!(replacement = hlsl_new_expr(ctx, HLSL_OP3_CMP, operands, first->data_type, &instr->loc))) + return false; + } + else if (ctx->profile->major_version < 4 && ctx->profile->type == VKD3D_SHADER_TYPE_VERTEX) + { + hlsl_fixme(ctx, &instr->loc, "Ternary operator is not implemented for %s profile.", ctx->profile->name); + return false; + } + else + { + if (cond->data_type->base_type == HLSL_TYPE_FLOAT) + { + if (!(zero = hlsl_new_constant(ctx, cond->data_type, &zero_value, &instr->loc))) + return false; + hlsl_block_add_instr(block, zero); + + operands[0] = zero; + operands[1] = cond; + type = cond->data_type; + type = hlsl_get_numeric_type(ctx, type->class, HLSL_TYPE_BOOL, type->dimx, type->dimy); + if (!(cond = hlsl_new_expr(ctx, HLSL_OP2_NEQUAL, operands, type, &instr->loc))) + return false; + hlsl_block_add_instr(block, cond); + }
memset(operands, 0, sizeof(operands)); - operands[0] = zero; - operands[1] = cond; - type = cond->data_type; - type = hlsl_get_numeric_type(ctx, type->class, HLSL_TYPE_BOOL, type->dimx, type->dimy); - if (!(cond = hlsl_new_expr(ctx, HLSL_OP2_NEQUAL, operands, type, &instr->loc))) + operands[0] = cond; + operands[1] = first; + operands[2] = second; + if (!(replacement = hlsl_new_expr(ctx, HLSL_OP3_MOVC, operands, first->data_type, &instr->loc))) return false; - hlsl_block_add_instr(block, cond); }
- memset(operands, 0, sizeof(operands)); - operands[0] = cond; - operands[1] = first; - operands[2] = second; - if (!(replacement = hlsl_new_expr(ctx, HLSL_OP3_MOVC, operands, first->data_type, &instr->loc))) - return false; hlsl_block_add_instr(block, replacement); return true; } @@ -4818,8 +4844,7 @@ int hlsl_emit_bytecode(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry hlsl_transform_ir(ctx, track_object_components_usage, body, NULL); sort_synthetic_separated_samplers_first(ctx);
- if (profile->major_version >= 4) - lower_ir(ctx, lower_ternary, body); + lower_ir(ctx, lower_ternary, body); if (profile->major_version < 4) { lower_ir(ctx, lower_division, body);