vkd3d-shader/hlsl: Specialize lowering SM1 casts to int for vertex shaders.

Vertex shaders do not have CMP, so we use SLT and MAD.

For example, this vertex shader:

    uniform float4 f;

    void main(inout float4 pos : position, out float4 t1 : TEXCOORD1)
    {
        t1 = (int4)f;
    }

results in:

    vs_2_0
    dcl_position v0
    slt r0, c0, -c0
    frc r1, c0
    add r2, -r1, c0
    slt r1, -r1, r1
    mad oT1, r0, r1, r2
    mov oPos, v0

while we have the lower_cmp() pass, each time it is applied many
instructions are generated, so this patch introduces a specialized
version of the cast-to-int lowering for efficiency.
This commit is contained in:
Francisco Casas 2025-01-15 11:59:39 -03:00 committed by Henri Verbeet
parent 2d91bd9200
commit cf19b4da49
Notes: Henri Verbeet 2025-01-16 19:29:44 +01:00
Approved-by: Elizabeth Figura (@zfigura)
Approved-by: Henri Verbeet (@hverbeet)
Merge-Request: https://gitlab.winehq.org/wine/vkd3d/-/merge_requests/1339

View File

@ -3115,16 +3115,16 @@ static bool sort_synthetic_separated_samplers_first(struct hlsl_ctx *ctx)
*
* extra = FRACT(x) > 0 && x < 0
*
* where the comparisons in the extra term are performed using CMP.
* where the comparisons in the extra term are performed using CMP or SLT
* depending on whether this is a pixel or vertex shader, respectively.
*
* A REINTERPET (which is written as a mere MOV) is also applied to the final
* result for type consistency.
*/
static bool lower_casts_to_int(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, struct hlsl_block *block)
{
struct hlsl_ir_node *arg, *fract, *neg_fract, *has_fract, *floor, *extra, *res, *zero, *one;
struct hlsl_ir_node *operands[HLSL_MAX_OPERANDS] = { 0 };
struct hlsl_constant_value zero_value, one_value;
struct hlsl_ir_node *arg, *res;
struct hlsl_ir_expr *expr;
if (instr->type != HLSL_IR_EXPR)
@ -3139,6 +3139,11 @@ static bool lower_casts_to_int(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr,
if (arg->data_type->e.numeric.type != HLSL_TYPE_FLOAT && arg->data_type->e.numeric.type != HLSL_TYPE_HALF)
return false;
if (ctx->profile->type == VKD3D_SHADER_TYPE_PIXEL)
{
struct hlsl_ir_node *fract, *neg_fract, *has_fract, *floor, *extra, *zero, *one;
struct hlsl_constant_value zero_value, one_value;
memset(&zero_value, 0, sizeof(zero_value));
if (!(zero = hlsl_new_constant(ctx, arg->data_type, &zero_value, &instr->loc)))
return false;
@ -3175,6 +3180,39 @@ static bool lower_casts_to_int(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr,
if (!(res = hlsl_new_binary_expr(ctx, HLSL_OP2_ADD, floor, extra)))
return false;
hlsl_block_add_instr(block, res);
}
else
{
struct hlsl_ir_node *neg_arg, *is_neg, *fract, *neg_fract, *has_fract, *floor;
if (!(neg_arg = hlsl_new_unary_expr(ctx, HLSL_OP1_NEG, arg, &instr->loc)))
return false;
hlsl_block_add_instr(block, neg_arg);
if (!(is_neg = hlsl_new_binary_expr(ctx, HLSL_OP2_SLT, arg, neg_arg)))
return false;
hlsl_block_add_instr(block, is_neg);
if (!(fract = hlsl_new_unary_expr(ctx, HLSL_OP1_FRACT, arg, &instr->loc)))
return false;
hlsl_block_add_instr(block, fract);
if (!(neg_fract = hlsl_new_unary_expr(ctx, HLSL_OP1_NEG, fract, &instr->loc)))
return false;
hlsl_block_add_instr(block, neg_fract);
if (!(has_fract = hlsl_new_binary_expr(ctx, HLSL_OP2_SLT, neg_fract, fract)))
return false;
hlsl_block_add_instr(block, has_fract);
if (!(floor = hlsl_new_binary_expr(ctx, HLSL_OP2_ADD, arg, neg_fract)))
return false;
hlsl_block_add_instr(block, floor);
if (!(res = hlsl_new_ternary_expr(ctx, HLSL_OP3_MAD, is_neg, has_fract, floor)))
return false;
hlsl_block_add_instr(block, res);
}
memset(operands, 0, sizeof(operands));
operands[0] = res;