-- v10: vkd3d-shader/dxil: Implement the DXIL CAST instruction.
From: Conor McCarthy cmccarthy@codeweavers.com
--- libs/vkd3d-shader/spirv.c | 39 +++++++++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 10 deletions(-)
diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c index 61d757579..fe619de35 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -2277,6 +2277,12 @@ struct vkd3d_hull_shader_variables uint32_t patch_constants_id; };
+struct ssa_register_info +{ + enum vkd3d_data_type data_type; + uint32_t id; +}; + struct spirv_compiler { struct vkd3d_spirv_builder spirv_builder; @@ -2350,7 +2356,7 @@ struct spirv_compiler
struct vkd3d_string_buffer_cache string_buffers;
- uint32_t *ssa_register_ids; + struct ssa_register_info *ssa_register_info; unsigned int ssa_register_count; };
@@ -2399,7 +2405,7 @@ static void spirv_compiler_destroy(struct spirv_compiler *compiler) shader_signature_cleanup(&compiler->output_signature); shader_signature_cleanup(&compiler->patch_constant_signature);
- vkd3d_free(compiler->ssa_register_ids); + vkd3d_free(compiler->ssa_register_info);
vkd3d_free(compiler); } @@ -3730,20 +3736,21 @@ static uint32_t spirv_compiler_emit_load_scalar(struct spirv_compiler *compiler, return val_id; }
-static uint32_t spirv_compiler_get_ssa_register_id(const struct spirv_compiler *compiler, +static const struct ssa_register_info *spirv_compiler_get_ssa_register_info(const struct spirv_compiler *compiler, const struct vkd3d_shader_register *reg) { assert(reg->idx[0].offset < compiler->ssa_register_count); assert(reg->idx_count == 1); - return compiler->ssa_register_ids[reg->idx[0].offset]; + return &compiler->ssa_register_info[reg->idx[0].offset]; }
-static void spirv_compiler_set_ssa_register_id(const struct spirv_compiler *compiler, +static void spirv_compiler_set_ssa_register_info(const struct spirv_compiler *compiler, const struct vkd3d_shader_register *reg, uint32_t val_id) { unsigned int i = reg->idx[0].offset; assert(i < compiler->ssa_register_count); - compiler->ssa_register_ids[i] = val_id; + compiler->ssa_register_info[i].data_type = reg->data_type; + compiler->ssa_register_info[i].id = val_id; }
static uint32_t spirv_compiler_emit_load_ssa_reg(struct spirv_compiler *compiler, @@ -3751,15 +3758,27 @@ static uint32_t spirv_compiler_emit_load_ssa_reg(struct spirv_compiler *compiler unsigned int swizzle) { struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; + enum vkd3d_shader_component_type reg_component_type; + const struct ssa_register_info *ssa; unsigned int component_idx; uint32_t type_id, val_id;
- val_id = spirv_compiler_get_ssa_register_id(compiler, reg); + ssa = spirv_compiler_get_ssa_register_info(compiler, reg); + val_id = ssa->id; assert(val_id); assert(vkd3d_swizzle_is_scalar(swizzle));
if (reg->dimension == VSIR_DIMENSION_SCALAR) + { + reg_component_type = vkd3d_component_type_from_data_type(ssa->data_type); + if (component_type != reg_component_type) + { + type_id = vkd3d_spirv_get_type_id(builder, component_type, 1); + val_id = vkd3d_spirv_build_op_bitcast(builder, type_id, val_id); + } + return val_id; + }
type_id = vkd3d_spirv_get_type_id(builder, component_type, 1); component_idx = vkd3d_swizzle_get_component(swizzle, 0); @@ -4002,7 +4021,7 @@ static void spirv_compiler_emit_store_reg(struct spirv_compiler *compiler,
if (reg->type == VKD3DSPR_SSA) { - spirv_compiler_set_ssa_register_id(compiler, reg, val_id); + spirv_compiler_set_ssa_register_info(compiler, reg, val_id); return; }
@@ -5442,8 +5461,8 @@ static void spirv_compiler_emit_temps(struct spirv_compiler *compiler, uint32_t
static void spirv_compiler_allocate_ssa_register_ids(struct spirv_compiler *compiler, unsigned int count) { - assert(!compiler->ssa_register_ids); - if (!(compiler->ssa_register_ids = vkd3d_calloc(count, sizeof(*compiler->ssa_register_ids)))) + assert(!compiler->ssa_register_info); + if (!(compiler->ssa_register_info = vkd3d_calloc(count, sizeof(*compiler->ssa_register_info)))) { ERR("Failed to allocate SSA register value id array, count %u.\n", count); spirv_compiler_error(compiler, VKD3D_SHADER_ERROR_SPV_OUT_OF_MEMORY,
From: Conor McCarthy cmccarthy@codeweavers.com
--- libs/vkd3d-shader/spirv.c | 49 +++++++++++++++++++++++- libs/vkd3d-shader/vkd3d_shader_private.h | 1 + 2 files changed, 49 insertions(+), 1 deletion(-)
diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c index fe619de35..5ae52b69f 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -1150,6 +1150,20 @@ static uint32_t vkd3d_spirv_get_op_type_pointer(struct vkd3d_spirv_builder *buil vkd3d_spirv_build_op_type_pointer); }
+static uint32_t vkd3d_spirv_build_op_constant_bool(struct vkd3d_spirv_builder *builder, + uint32_t result_type, uint32_t value) +{ + return vkd3d_spirv_build_op_tr(builder, &builder->global_stream, + value ? SpvOpConstantTrue : SpvOpConstantFalse, result_type); +} + +static uint32_t vkd3d_spirv_get_op_constant_bool(struct vkd3d_spirv_builder *builder, + uint32_t result_type, uint32_t value) +{ + return vkd3d_spirv_build_once2(builder, value ? SpvOpConstantTrue : SpvOpConstantFalse, result_type, value, + vkd3d_spirv_build_op_constant_bool); +} + /* Types larger than 32-bits are not supported. */ static uint32_t vkd3d_spirv_build_op_constant(struct vkd3d_spirv_builder *builder, uint32_t result_type, uint32_t value) @@ -1802,6 +1816,8 @@ static uint32_t vkd3d_spirv_get_type_id_for_data_type(struct vkd3d_spirv_builder break; case VKD3D_DATA_DOUBLE: return vkd3d_spirv_get_op_type_float(builder, 64); + case VKD3D_DATA_BOOL: + return vkd3d_spirv_get_op_type_bool(builder); default: FIXME("Unhandled data type %#x.\n", data_type); return 0; @@ -2886,6 +2902,13 @@ static uint32_t spirv_compiler_get_constant(struct spirv_compiler *compiler, case VKD3D_SHADER_COMPONENT_INT: case VKD3D_SHADER_COMPONENT_FLOAT: break; + case VKD3D_SHADER_COMPONENT_BOOL: + if (component_count == 1) + return vkd3d_spirv_get_op_constant_bool(builder, type_id, *values); + FIXME("Unsupported vector of bool.\n"); + spirv_compiler_error(compiler, VKD3D_SHADER_ERROR_SPV_INVALID_TYPE, + "Vectors of bool type are not supported."); + return vkd3d_spirv_get_op_undef(builder, type_id); default: FIXME("Unhandled component_type %#x.\n", component_type); return vkd3d_spirv_get_op_undef(builder, type_id); @@ -6607,6 +6630,21 @@ static SpvOp spirv_compiler_map_alu_instruction(const struct vkd3d_shader_instru return SpvOpMax; }
+static SpvOp spirv_compiler_map_logical_instruction(const struct vkd3d_shader_instruction *instruction) +{ + switch (instruction->handler_idx) + { + case VKD3DSIH_AND: + return SpvOpLogicalAnd; + case VKD3DSIH_OR: + return SpvOpLogicalOr; + case VKD3DSIH_XOR: + return SpvOpLogicalNotEqual; + default: + return SpvOpMax; + } +} + static void spirv_compiler_emit_alu_instruction(struct spirv_compiler *compiler, const struct vkd3d_shader_instruction *instruction) { @@ -6618,7 +6656,16 @@ static void spirv_compiler_emit_alu_instruction(struct spirv_compiler *compiler, unsigned int i; SpvOp op;
- op = spirv_compiler_map_alu_instruction(instruction); + if (src->reg.data_type == VKD3D_DATA_BOOL && dst->reg.data_type == VKD3D_DATA_BOOL) + { + /* VSIR supports logic ops AND/OR/XOR on bool values. */ + op = spirv_compiler_map_logical_instruction(instruction); + } + else + { + op = spirv_compiler_map_alu_instruction(instruction); + } + if (op == SpvOpMax) { ERR("Unexpected instruction %#x.\n", instruction->handler_idx); diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h index 0871f8b1a..9b0c79679 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -93,6 +93,7 @@ enum vkd3d_shader_error VKD3D_SHADER_ERROR_SPV_DESCRIPTOR_IDX_UNSUPPORTED = 2003, VKD3D_SHADER_ERROR_SPV_STENCIL_EXPORT_UNSUPPORTED = 2004, VKD3D_SHADER_ERROR_SPV_OUT_OF_MEMORY = 2005, + VKD3D_SHADER_ERROR_SPV_INVALID_TYPE = 2006,
VKD3D_SHADER_WARNING_SPV_INVALID_SWIZZLE = 2300,
From: Conor McCarthy cmccarthy@codeweavers.com
--- libs/vkd3d-shader/spirv.c | 73 ++++++++++++++++++++++-- libs/vkd3d-shader/vkd3d_shader_private.h | 1 + 2 files changed, 70 insertions(+), 4 deletions(-)
diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c index 5ae52b69f..841c7a903 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -4255,6 +4255,30 @@ static uint32_t spirv_compiler_emit_bool_to_int(struct spirv_compiler *compiler, return vkd3d_spirv_build_op_select(builder, type_id, val_id, true_id, false_id); }
+static uint32_t spirv_compiler_emit_bool_to_float(struct spirv_compiler *compiler, + unsigned int component_count, uint32_t val_id, bool signedness) +{ + struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; + uint32_t type_id, true_id, false_id; + + true_id = spirv_compiler_get_constant_float_vector(compiler, signedness ? -1.0f : 1.0f, component_count); + false_id = spirv_compiler_get_constant_float_vector(compiler, 0.0f, component_count); + type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_FLOAT, component_count); + return vkd3d_spirv_build_op_select(builder, type_id, val_id, true_id, false_id); +} + +static uint32_t spirv_compiler_emit_bool_to_double(struct spirv_compiler *compiler, + unsigned int component_count, uint32_t val_id, bool signedness) +{ + struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; + uint32_t type_id, true_id, false_id; + + true_id = spirv_compiler_get_constant_double_vector(compiler, signedness ? -1.0 : 1.0, component_count); + false_id = spirv_compiler_get_constant_double_vector(compiler, 0.0, component_count); + type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_DOUBLE, component_count); + return vkd3d_spirv_build_op_select(builder, type_id, val_id, true_id, false_id); +} + typedef uint32_t (*vkd3d_spirv_builtin_fixup_pfn)(struct spirv_compiler *compiler, uint32_t val_id);
@@ -6645,6 +6669,35 @@ static SpvOp spirv_compiler_map_logical_instruction(const struct vkd3d_shader_in } }
+static void spirv_compiler_emit_bool_cast(struct spirv_compiler *compiler, + const struct vkd3d_shader_instruction *instruction) +{ + const struct vkd3d_shader_dst_param *dst = instruction->dst; + const struct vkd3d_shader_src_param *src = instruction->src; + uint32_t val_id; + + assert(src->reg.data_type == VKD3D_DATA_BOOL && dst->reg.data_type != VKD3D_DATA_BOOL); + + val_id = spirv_compiler_emit_load_src(compiler, src, dst->write_mask); + if (dst->reg.data_type == VKD3D_DATA_FLOAT) + { + val_id = spirv_compiler_emit_bool_to_float(compiler, 1, val_id, instruction->handler_idx == VKD3DSIH_ITOF); + } + else if (dst->reg.data_type == VKD3D_DATA_DOUBLE) + { + /* ITOD is not supported. Frontends which emit bool casts must use ITOF for double. */ + val_id = spirv_compiler_emit_bool_to_double(compiler, 1, val_id, instruction->handler_idx == VKD3DSIH_ITOF); + } + else + { + WARN("Unhandled data type %u.\n", dst->reg.data_type); + spirv_compiler_error(compiler, VKD3D_SHADER_ERROR_SPV_INVALID_TYPE, + "Register data type %u is unhandled.", dst->reg.data_type); + } + + spirv_compiler_emit_store_dst(compiler, dst, val_id); +} + static void spirv_compiler_emit_alu_instruction(struct spirv_compiler *compiler, const struct vkd3d_shader_instruction *instruction) { @@ -6653,13 +6706,23 @@ static void spirv_compiler_emit_alu_instruction(struct spirv_compiler *compiler, const struct vkd3d_shader_src_param *src = instruction->src; uint32_t src_ids[SPIRV_MAX_SRC_COUNT]; uint32_t type_id, val_id; + SpvOp op = SpvOpMax; unsigned int i; - SpvOp op;
- if (src->reg.data_type == VKD3D_DATA_BOOL && dst->reg.data_type == VKD3D_DATA_BOOL) + if (src->reg.data_type == VKD3D_DATA_BOOL) { - /* VSIR supports logic ops AND/OR/XOR on bool values. */ - op = spirv_compiler_map_logical_instruction(instruction); + if (dst->reg.data_type == VKD3D_DATA_BOOL) + { + /* VSIR supports logic ops AND/OR/XOR on bool values. */ + op = spirv_compiler_map_logical_instruction(instruction); + } + else if (instruction->handler_idx == VKD3DSIH_ITOF || instruction->handler_idx == VKD3DSIH_UTOF) + { + /* VSIR supports cast from bool to signed/unsigned integer types and floating point types, + * where bool is treated as a 1-bit integer and a signed 'true' value converts to -1. */ + spirv_compiler_emit_bool_cast(compiler, instruction); + return; + } } else { @@ -6669,6 +6732,8 @@ static void spirv_compiler_emit_alu_instruction(struct spirv_compiler *compiler, if (op == SpvOpMax) { ERR("Unexpected instruction %#x.\n", instruction->handler_idx); + spirv_compiler_error(compiler, VKD3D_SHADER_ERROR_SPV_INVALID_HANDLER, + "Encountered invalid/unhandled instruction handler %#x.", instruction->handler_idx); return; }
diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h index 9b0c79679..1a0bfb5d3 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -94,6 +94,7 @@ enum vkd3d_shader_error VKD3D_SHADER_ERROR_SPV_STENCIL_EXPORT_UNSUPPORTED = 2004, VKD3D_SHADER_ERROR_SPV_OUT_OF_MEMORY = 2005, VKD3D_SHADER_ERROR_SPV_INVALID_TYPE = 2006, + VKD3D_SHADER_ERROR_SPV_INVALID_HANDLER = 2007,
VKD3D_SHADER_WARNING_SPV_INVALID_SWIZZLE = 2300,
From: Conor McCarthy cmccarthy@codeweavers.com
ITOI and UTOU may cast from a bool to a 32-bit integer. Cast to a 64-bit integer from a smaller type will be added later. --- libs/vkd3d-shader/d3d_asm.c | 2 ++ libs/vkd3d-shader/spirv.c | 17 ++++++++++++----- libs/vkd3d-shader/vkd3d_shader_private.h | 2 ++ 3 files changed, 16 insertions(+), 5 deletions(-)
diff --git a/libs/vkd3d-shader/d3d_asm.c b/libs/vkd3d-shader/d3d_asm.c index 5cea0c0c2..0a9561d05 100644 --- a/libs/vkd3d-shader/d3d_asm.c +++ b/libs/vkd3d-shader/d3d_asm.c @@ -199,6 +199,7 @@ static const char * const shader_opcode_names[] = [VKD3DSIH_ISHR ] = "ishr", [VKD3DSIH_ITOD ] = "itod", [VKD3DSIH_ITOF ] = "itof", + [VKD3DSIH_ITOI ] = "itoi", [VKD3DSIH_LABEL ] = "label", [VKD3DSIH_LD ] = "ld", [VKD3DSIH_LD2DMS ] = "ld2dms", @@ -306,6 +307,7 @@ static const char * const shader_opcode_names[] = [VKD3DSIH_USHR ] = "ushr", [VKD3DSIH_UTOD ] = "utod", [VKD3DSIH_UTOF ] = "utof", + [VKD3DSIH_UTOU ] = "utou", [VKD3DSIH_XOR ] = "xor", };
diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c index 841c7a903..50940b5bf 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -4244,12 +4244,12 @@ static uint32_t spirv_compiler_emit_int_to_bool(struct spirv_compiler *compiler, }
static uint32_t spirv_compiler_emit_bool_to_int(struct spirv_compiler *compiler, - unsigned int component_count, uint32_t val_id) + unsigned int component_count, uint32_t val_id, bool signedness) { struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; uint32_t type_id, true_id, false_id;
- true_id = spirv_compiler_get_constant_uint_vector(compiler, 0xffffffff, component_count); + true_id = spirv_compiler_get_constant_uint_vector(compiler, signedness ? 0xffffffff : 1, component_count); false_id = spirv_compiler_get_constant_uint_vector(compiler, 0, component_count); type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_UINT, component_count); return vkd3d_spirv_build_op_select(builder, type_id, val_id, true_id, false_id); @@ -4321,7 +4321,7 @@ static uint32_t sv_instance_id_fixup(struct spirv_compiler *compiler, static uint32_t sv_front_face_fixup(struct spirv_compiler *compiler, uint32_t front_facing_id) { - return spirv_compiler_emit_bool_to_int(compiler, 1, front_facing_id); + return spirv_compiler_emit_bool_to_int(compiler, 1, front_facing_id, true); }
/* frag_coord.w = 1.0f / frag_coord.w */ @@ -6688,6 +6688,10 @@ static void spirv_compiler_emit_bool_cast(struct spirv_compiler *compiler, /* ITOD is not supported. Frontends which emit bool casts must use ITOF for double. */ val_id = spirv_compiler_emit_bool_to_double(compiler, 1, val_id, instruction->handler_idx == VKD3DSIH_ITOF); } + else if (dst->reg.data_type == VKD3D_DATA_UINT) + { + val_id = spirv_compiler_emit_bool_to_int(compiler, 1, val_id, instruction->handler_idx == VKD3DSIH_ITOI); + } else { WARN("Unhandled data type %u.\n", dst->reg.data_type); @@ -6716,7 +6720,8 @@ static void spirv_compiler_emit_alu_instruction(struct spirv_compiler *compiler, /* VSIR supports logic ops AND/OR/XOR on bool values. */ op = spirv_compiler_map_logical_instruction(instruction); } - else if (instruction->handler_idx == VKD3DSIH_ITOF || instruction->handler_idx == VKD3DSIH_UTOF) + else if (instruction->handler_idx == VKD3DSIH_ITOF || instruction->handler_idx == VKD3DSIH_UTOF + || instruction->handler_idx == VKD3DSIH_ITOI || instruction->handler_idx == VKD3DSIH_UTOU) { /* VSIR supports cast from bool to signed/unsigned integer types and floating point types, * where bool is treated as a 1-bit integer and a signed 'true' value converts to -1. */ @@ -7405,7 +7410,7 @@ static void spirv_compiler_emit_comparison_instruction(struct spirv_compiler *co result_id = vkd3d_spirv_build_op_tr2(builder, &builder->function_stream, op, type_id, src0_id, src1_id);
- result_id = spirv_compiler_emit_bool_to_int(compiler, component_count, result_id); + result_id = spirv_compiler_emit_bool_to_int(compiler, component_count, result_id, true); spirv_compiler_emit_store_reg(compiler, &dst->reg, dst->write_mask, result_id); }
@@ -9512,12 +9517,14 @@ static int spirv_compiler_handle_instruction(struct spirv_compiler *compiler, case VKD3DSIH_ISHR: case VKD3DSIH_ITOD: case VKD3DSIH_ITOF: + case VKD3DSIH_ITOI: case VKD3DSIH_MUL: case VKD3DSIH_NOT: case VKD3DSIH_OR: case VKD3DSIH_USHR: case VKD3DSIH_UTOD: case VKD3DSIH_UTOF: + case VKD3DSIH_UTOU: case VKD3DSIH_XOR: spirv_compiler_emit_alu_instruction(compiler, instruction); break; diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h index 1a0bfb5d3..30a8a7ddf 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -387,6 +387,7 @@ enum vkd3d_shader_opcode VKD3DSIH_ISHR, VKD3DSIH_ITOD, VKD3DSIH_ITOF, + VKD3DSIH_ITOI, VKD3DSIH_LABEL, VKD3DSIH_LD, VKD3DSIH_LD2DMS, @@ -494,6 +495,7 @@ enum vkd3d_shader_opcode VKD3DSIH_USHR, VKD3DSIH_UTOD, VKD3DSIH_UTOF, + VKD3DSIH_UTOU, VKD3DSIH_XOR,
VKD3DSIH_INVALID,
From: Conor McCarthy cmccarthy@codeweavers.com
--- libs/vkd3d-shader/spirv.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-)
diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c index 50940b5bf..c0d436f1a 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -2975,12 +2975,6 @@ static uint32_t spirv_compiler_get_constant_vector(struct spirv_compiler *compil return spirv_compiler_get_constant(compiler, component_type, component_count, values); }
-static uint32_t spirv_compiler_get_constant_int_vector(struct spirv_compiler *compiler, - uint32_t value, unsigned int component_count) -{ - return spirv_compiler_get_constant_vector(compiler, VKD3D_SHADER_COMPONENT_INT, component_count, value); -} - static uint32_t spirv_compiler_get_constant_uint_vector(struct spirv_compiler *compiler, uint32_t value, unsigned int component_count) { @@ -7177,6 +7171,7 @@ static void spirv_compiler_emit_ftoi(struct spirv_compiler *compiler, const struct vkd3d_shader_dst_param *dst = instruction->dst; const struct vkd3d_shader_src_param *src = instruction->src; uint32_t src_type_id, dst_type_id, condition_type_id; + enum vkd3d_shader_component_type component_type; unsigned int component_count;
assert(instruction->dst_count == 1); @@ -7194,8 +7189,11 @@ static void spirv_compiler_emit_ftoi(struct spirv_compiler *compiler, int_min_id = spirv_compiler_get_constant_float_vector(compiler, -2147483648.0f, component_count); val_id = vkd3d_spirv_build_op_glsl_std450_max(builder, src_type_id, src_id, int_min_id);
+ /* VSIR allows the destination of a signed conversion to be unsigned. */ + component_type = vkd3d_component_type_from_data_type(dst->reg.data_type); + float_max_id = spirv_compiler_get_constant_float_vector(compiler, 2147483648.0f, component_count); - int_max_id = spirv_compiler_get_constant_int_vector(compiler, INT_MAX, component_count); + int_max_id = spirv_compiler_get_constant_vector(compiler, component_type, component_count, INT_MAX); condition_type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_BOOL, component_count); condition_id = vkd3d_spirv_build_op_tr2(builder, &builder->function_stream, SpvOpFOrdGreaterThanEqual, condition_type_id, val_id, float_max_id); @@ -7203,7 +7201,7 @@ static void spirv_compiler_emit_ftoi(struct spirv_compiler *compiler, val_id = vkd3d_spirv_build_op_tr1(builder, &builder->function_stream, SpvOpConvertFToS, dst_type_id, val_id); val_id = vkd3d_spirv_build_op_select(builder, dst_type_id, condition_id, int_max_id, val_id);
- zero_id = spirv_compiler_get_constant_int_vector(compiler, 0, component_count); + zero_id = spirv_compiler_get_constant_vector(compiler, component_type, component_count, 0); condition_id = vkd3d_spirv_build_op_tr1(builder, &builder->function_stream, SpvOpIsNan, condition_type_id, src_id); val_id = vkd3d_spirv_build_op_select(builder, dst_type_id, condition_id, zero_id, val_id);
From: Conor McCarthy cmccarthy@codeweavers.com
--- libs/vkd3d-shader/spirv.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-)
diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c index c0d436f1a..253be82fa 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -7186,13 +7186,22 @@ static void spirv_compiler_emit_ftoi(struct spirv_compiler *compiler, dst_type_id = spirv_compiler_get_type_id_for_dst(compiler, dst); src_id = spirv_compiler_emit_load_src(compiler, src, dst->write_mask);
- int_min_id = spirv_compiler_get_constant_float_vector(compiler, -2147483648.0f, component_count); + if (src->reg.data_type == VKD3D_DATA_DOUBLE) + { + int_min_id = spirv_compiler_get_constant_double_vector(compiler, -2147483648.0, component_count); + float_max_id = spirv_compiler_get_constant_double_vector(compiler, 2147483648.0, component_count); + } + else + { + int_min_id = spirv_compiler_get_constant_float_vector(compiler, -2147483648.0f, component_count); + float_max_id = spirv_compiler_get_constant_float_vector(compiler, 2147483648.0f, component_count); + } + val_id = vkd3d_spirv_build_op_glsl_std450_max(builder, src_type_id, src_id, int_min_id);
/* VSIR allows the destination of a signed conversion to be unsigned. */ component_type = vkd3d_component_type_from_data_type(dst->reg.data_type);
- float_max_id = spirv_compiler_get_constant_float_vector(compiler, 2147483648.0f, component_count); int_max_id = spirv_compiler_get_constant_vector(compiler, component_type, component_count, INT_MAX); condition_type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_BOOL, component_count); condition_id = vkd3d_spirv_build_op_tr2(builder, &builder->function_stream, @@ -9505,7 +9514,6 @@ static int spirv_compiler_handle_instruction(struct spirv_compiler *compiler, case VKD3DSIH_DIV: case VKD3DSIH_DMUL: case VKD3DSIH_DTOF: - case VKD3DSIH_DTOI: case VKD3DSIH_DTOU: case VKD3DSIH_FREM: case VKD3DSIH_FTOD: @@ -9573,6 +9581,7 @@ static int spirv_compiler_handle_instruction(struct spirv_compiler *compiler, case VKD3DSIH_UDIV: spirv_compiler_emit_int_div(compiler, instruction); break; + case VKD3DSIH_DTOI: case VKD3DSIH_FTOI: spirv_compiler_emit_ftoi(compiler, instruction); break;
From: Conor McCarthy cmccarthy@codeweavers.com
--- libs/vkd3d-shader/spirv.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-)
diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c index 253be82fa..89c743e63 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -7239,10 +7239,19 @@ static void spirv_compiler_emit_ftou(struct spirv_compiler *compiler, dst_type_id = spirv_compiler_get_type_id_for_dst(compiler, dst); src_id = spirv_compiler_emit_load_src(compiler, src, dst->write_mask);
- zero_id = spirv_compiler_get_constant_float_vector(compiler, 0.0f, component_count); + if (src->reg.data_type == VKD3D_DATA_DOUBLE) + { + zero_id = spirv_compiler_get_constant_double_vector(compiler, 0.0, component_count); + float_max_id = spirv_compiler_get_constant_double_vector(compiler, 4294967296.0, component_count); + } + else + { + zero_id = spirv_compiler_get_constant_float_vector(compiler, 0.0f, component_count); + float_max_id = spirv_compiler_get_constant_float_vector(compiler, 4294967296.0f, component_count); + } + val_id = vkd3d_spirv_build_op_glsl_std450_max(builder, src_type_id, src_id, zero_id);
- float_max_id = spirv_compiler_get_constant_float_vector(compiler, 4294967296.0f, component_count); uint_max_id = spirv_compiler_get_constant_uint_vector(compiler, UINT_MAX, component_count); condition_type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_BOOL, component_count); condition_id = vkd3d_spirv_build_op_tr2(builder, &builder->function_stream, @@ -9514,7 +9523,6 @@ static int spirv_compiler_handle_instruction(struct spirv_compiler *compiler, case VKD3DSIH_DIV: case VKD3DSIH_DMUL: case VKD3DSIH_DTOF: - case VKD3DSIH_DTOU: case VKD3DSIH_FREM: case VKD3DSIH_FTOD: case VKD3DSIH_IADD: @@ -9585,6 +9593,7 @@ static int spirv_compiler_handle_instruction(struct spirv_compiler *compiler, case VKD3DSIH_FTOI: spirv_compiler_emit_ftoi(compiler, instruction); break; + case VKD3DSIH_DTOU: case VKD3DSIH_FTOU: spirv_compiler_emit_ftou(compiler, instruction); break;
From: Conor McCarthy cmccarthy@codeweavers.com
--- libs/vkd3d-shader/dxil.c | 173 ++++++++++++++++++ tests/hlsl/arithmetic-int-uniform.shader_test | 14 +- tests/hlsl/asfloat.shader_test | 2 +- tests/hlsl/asuint.shader_test | 4 +- tests/hlsl/d3dcolor-to-ubyte4.shader_test | 4 +- tests/hlsl/function-cast.shader_test | 4 +- tests/hlsl/lerp.shader_test | 2 +- tests/hlsl/non-const-indexing.shader_test | 16 +- .../shader-interstage-interface.shader_test | 2 +- 9 files changed, 197 insertions(+), 24 deletions(-)
diff --git a/libs/vkd3d-shader/dxil.c b/libs/vkd3d-shader/dxil.c index e0e242cb7..64bcccecb 100644 --- a/libs/vkd3d-shader/dxil.c +++ b/libs/vkd3d-shader/dxil.c @@ -289,6 +289,23 @@ enum dx_intrinsic_opcode DX_CBUFFER_LOAD_LEGACY = 59, };
+enum dxil_cast_code +{ + CAST_TRUNC = 0, + CAST_ZEXT = 1, + CAST_SEXT = 2, + CAST_FPTOUI = 3, + CAST_FPTOSI = 4, + CAST_UITOFP = 5, + CAST_SITOFP = 6, + CAST_FPTRUNC = 7, + CAST_FPEXT = 8, + CAST_PTRTOINT = 9, + CAST_INTTOPTR = 10, + CAST_BITCAST = 11, + CAST_ADDRSPACECAST = 12, +}; + struct sm6_pointer_info { const struct sm6_type *type; @@ -3248,6 +3265,159 @@ static void sm6_parser_emit_call(struct sm6_parser *sm6, const struct dxil_recor fn_value->u.function.name, &operands[1], operand_count - 1, ins, dst); }
+static enum vkd3d_shader_opcode sm6_map_cast_op(uint64_t code, const struct sm6_type *from, + const struct sm6_type *to, struct sm6_parser *sm6) +{ + enum vkd3d_shader_opcode op = VKD3DSIH_INVALID; + bool from_int, to_int, from_fp, to_fp; + bool is_valid = false; + + from_int = sm6_type_is_integer(from); + to_int = sm6_type_is_integer(to); + from_fp = sm6_type_is_floating_point(from); + to_fp = sm6_type_is_floating_point(to); + + /* NOTE: DXIL currently doesn't use vectors here. */ + if ((!from_int && !from_fp) || (!to_int && !to_fp)) + { + FIXME("Unhandled cast of type class %u to type class %u.\n", from->class, to->class); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, + "Cast of type class %u to type class %u is not implemented.", from->class, to->class); + return VKD3DSIH_INVALID; + } + if (to->u.width == 8 || from->u.width == 8) + { + FIXME("Unhandled 8-bit value.\n"); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, + "Cast to/from an 8-bit type is not implemented."); + return VKD3DSIH_INVALID; + } + + /* DXC emits minimum precision types as 16-bit. These must be emitted + * as 32-bit in VSIR, so all width extensions to 32 bits are no-ops. */ + switch (code) + { + case CAST_TRUNC: + /* nop or min precision. TODO: native 16-bit */ + if (to->u.width == from->u.width || (to->u.width == 16 && from->u.width == 32)) + op = VKD3DSIH_NOP; + else + op = VKD3DSIH_UTOU; + is_valid = from_int && to_int && to->u.width <= from->u.width; + break; + case CAST_ZEXT: + case CAST_SEXT: + /* nop or min precision. TODO: native 16-bit */ + if (to->u.width == from->u.width || (to->u.width == 32 && from->u.width == 16)) + { + op = VKD3DSIH_NOP; + is_valid = from_int && to_int; + } + else if (to->u.width > from->u.width) + { + op = (code == CAST_ZEXT) ? VKD3DSIH_UTOU : VKD3DSIH_ITOI; + assert(from->u.width == 1 || to->u.width == 64); + is_valid = from_int && to_int; + } + break; + case CAST_FPTOUI: + op = VKD3DSIH_FTOU; + is_valid = from_fp && to_int && to->u.width > 1; + break; + case CAST_FPTOSI: + op = VKD3DSIH_FTOI; + is_valid = from_fp && to_int && to->u.width > 1; + break; + case CAST_UITOFP: + op = VKD3DSIH_UTOF; + is_valid = from_int && to_fp; + break; + case CAST_SITOFP: + op = VKD3DSIH_ITOF; + is_valid = from_int && to_fp; + break; + case CAST_FPTRUNC: + /* TODO: native 16-bit */ + op = (from->u.width == 64) ? VKD3DSIH_DTOF : VKD3DSIH_NOP; + is_valid = from_fp && to_fp; + break; + case CAST_FPEXT: + /* TODO: native 16-bit */ + op = (to->u.width == 64) ? VKD3DSIH_FTOD : VKD3DSIH_NOP; + is_valid = from_fp && to_fp; + break; + case CAST_BITCAST: + op = VKD3DSIH_MOV; + is_valid = to->u.width == from->u.width; + break; + default: + FIXME("Unhandled cast op %"PRIu64".\n", code); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, + "Cast operation %"PRIu64" is unhandled.\n", code); + return VKD3DSIH_INVALID; + } + + if (!is_valid) + { + FIXME("Invalid types %u and/or %u for op %"PRIu64".\n", from->class, to->class, code); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, + "Cast operation %"PRIu64" from type class %u, width %u to type class %u, width %u is invalid.\n", + code, from->class, from->u.width, to->class, to->u.width); + return VKD3DSIH_INVALID; + } + + return op; +} + +static void sm6_parser_emit_cast(struct sm6_parser *sm6, const struct dxil_record *record, + struct vkd3d_shader_instruction *ins, struct sm6_value *dst) +{ + struct vkd3d_shader_src_param *src_param; + enum vkd3d_shader_opcode handler_idx; + const struct sm6_value *value; + const struct sm6_type *type; + unsigned int i = 0; + + if (!(value = sm6_parser_get_value_by_ref(sm6, record, NULL, &i))) + return; + + if (!dxil_record_validate_operand_count(record, i + 2, i + 2, sm6)) + return; + + if (!(type = sm6_parser_get_type(sm6, record->operands[i++]))) + return; + + dst->type = type; + + if (sm6_type_is_pointer(type)) + { + *dst = *value; + dst->type = type; + ins->handler_idx = VKD3DSIH_NOP; + return; + } + + if ((handler_idx = sm6_map_cast_op(record->operands[i], value->type, type, sm6)) == VKD3DSIH_INVALID) + return; + + vsir_instruction_init(ins, &sm6->p.location, handler_idx); + + if (handler_idx == VKD3DSIH_NOP) + { + dst->u.reg = value->u.reg; + return; + } + + src_param = instruction_src_params_alloc(ins, 1, sm6); + src_param_init_from_value(src_param, value); + + instruction_dst_param_init_ssa_scalar(ins, sm6); + + /* bitcast */ + if (handler_idx == VKD3DSIH_MOV) + src_param->reg.data_type = dst->u.reg.data_type; +} + static void sm6_parser_emit_extractval(struct sm6_parser *sm6, const struct dxil_record *record, struct vkd3d_shader_instruction *ins, struct sm6_value *dst) { @@ -3464,6 +3634,9 @@ static enum vkd3d_result sm6_parser_function_init(struct sm6_parser *sm6, const case FUNC_CODE_INST_CALL: sm6_parser_emit_call(sm6, record, code_block, ins, dst); break; + case FUNC_CODE_INST_CAST: + sm6_parser_emit_cast(sm6, record, ins, dst); + break; case FUNC_CODE_INST_EXTRACTVAL: sm6_parser_emit_extractval(sm6, record, ins, dst); break; diff --git a/tests/hlsl/arithmetic-int-uniform.shader_test b/tests/hlsl/arithmetic-int-uniform.shader_test index 726a191a7..7f5cdaaa6 100644 --- a/tests/hlsl/arithmetic-int-uniform.shader_test +++ b/tests/hlsl/arithmetic-int-uniform.shader_test @@ -10,7 +10,7 @@ float4 main() : SV_TARGET
[test] uniform 0 float4 5.0 16.0 0.0 0.0 -todo(sm>=6) draw quad +draw quad probe all rgba (21.0, -11.0, 80.0, 0.0)
[pixel shader] @@ -25,7 +25,7 @@ float4 main() : SV_TARGET
[test] uniform 0 float4 5.0 16.0 0.0 0.0 -todo(sm>=6) draw quad +draw quad probe all rgba (5.0, 5.0, -5.0, 3.0)
[pixel shader] @@ -40,7 +40,7 @@ float4 main() : SV_TARGET
[test] uniform 0 float4 42.0 5.0 0.0 0.0 -todo(sm>=6) draw quad +draw quad probe all rgba (8.0, -8.0, -8.0, 8.0)
[pixel shader] @@ -55,7 +55,7 @@ float4 main() : SV_TARGET
[test] uniform 0 float4 42.0 5.0 0.0 0.0 -todo(sm>=6) draw quad +draw quad probe all rgba (2.0, -2.0, 2.0, -2.0)
[pixel shader] @@ -70,7 +70,7 @@ float4 main() : SV_TARGET
[test] uniform 0 float4 45.0 5.0 0.0 0.0 -todo(sm>=6) draw quad +draw quad probe all rgba (9.0, -9.0, -9.0, 9.0)
[pixel shader] @@ -85,7 +85,7 @@ float4 main() : SV_TARGET
[test] uniform 0 float4 45.0 5.0 0.0 0.0 -todo(sm>=6) draw quad +draw quad probe all rgba (0.0, 0.0, 0.0, 0.0)
[pixel shader] @@ -117,5 +117,5 @@ float4 main() : sv_target [test] uniform 0 float4 45.0 5.0 50.0 10.0 uniform 4 float4 3.0 8.0 2.0 5.0 -todo(sm>=6) draw quad +draw quad probe all rgba (9.0, 5.0, 1.0, 3.0) diff --git a/tests/hlsl/asfloat.shader_test b/tests/hlsl/asfloat.shader_test index f43f2fdff..2184c1869 100644 --- a/tests/hlsl/asfloat.shader_test +++ b/tests/hlsl/asfloat.shader_test @@ -20,7 +20,7 @@ float4 main() : sv_target
[test] uniform 0 float4 123.0 -2.0 456 0.01 -todo(sm>=6) draw quad +draw quad probe (320,240) rgba (123.0, -2.0, 456.0, 0.01)
[pixel shader] diff --git a/tests/hlsl/asuint.shader_test b/tests/hlsl/asuint.shader_test index 0a2e39e53..50b0895e9 100644 --- a/tests/hlsl/asuint.shader_test +++ b/tests/hlsl/asuint.shader_test @@ -20,7 +20,7 @@ float4 main() : sv_target
[test] uniform 0 uint4 123 0xc0000000 456 0x7fd69345 -todo(sm>=6) draw quad +draw quad probe (320,240) rgba (123.0, 3221225472.0, 456.0, 2144768896.0)
@@ -37,7 +37,7 @@ float4 main() : sv_target uniform 0 uint4 11 12 0 0 uniform 4 uint4 13 14 0 0 uniform 8 uint4 20 21 22 23 -todo(sm>=6) draw quad +draw quad probe (320,240) rgba (13.0, 21.0, 0.0, 0.0)
diff --git a/tests/hlsl/d3dcolor-to-ubyte4.shader_test b/tests/hlsl/d3dcolor-to-ubyte4.shader_test index 01b7f2f64..dca307cdb 100644 --- a/tests/hlsl/d3dcolor-to-ubyte4.shader_test +++ b/tests/hlsl/d3dcolor-to-ubyte4.shader_test @@ -11,7 +11,7 @@ float4 main() : sv_target
[test] uniform 0 float4 -0.5 6.5 7.5 3.4 -todo(sm>=6) draw quad +draw quad probe all rgba (1912.0, 1657.0, -127.0, 867.0) 1
[pixel shader] @@ -24,5 +24,5 @@ float4 main() : sv_target
[test] uniform 0 float4 -0.5 6.5 7.5 3.4 -todo(sm>=6) draw quad +draw quad probe all rgba (-127.0, -127.0, -127.0, -127.0) 1 diff --git a/tests/hlsl/function-cast.shader_test b/tests/hlsl/function-cast.shader_test index a2b9cf4f4..c92289863 100644 --- a/tests/hlsl/function-cast.shader_test +++ b/tests/hlsl/function-cast.shader_test @@ -18,7 +18,7 @@ float4 main() : sv_target
[test] uniform 0 float4 -1.9 -1.0 2.9 4.0 -todo draw quad +todo(sm<6) draw quad probe all rgba (-1.0, -1.0, 2.0, 4.0)
% As above, but cast "x" to float4 first. @@ -89,5 +89,5 @@ float4 main() : sv_target
[test] uniform 0 int4 -2 0 1 -3000000 -todo draw quad +todo(sm<6) draw quad probe all rgba (-1.0, 0.0, 1.0, -3000000.0) diff --git a/tests/hlsl/lerp.shader_test b/tests/hlsl/lerp.shader_test index 413bfe833..15e90cef9 100644 --- a/tests/hlsl/lerp.shader_test +++ b/tests/hlsl/lerp.shader_test @@ -32,7 +32,7 @@ float4 main() : SV_TARGET uniform 0 int4 2 3 4 0 uniform 4 int4 0 -10 10 1000000 uniform 8 int4 0 1 -1 1000000 -todo(sm>=6) draw quad +draw quad probe all rgba (2.0, -10.0, -2.0, 1e12)
diff --git a/tests/hlsl/non-const-indexing.shader_test b/tests/hlsl/non-const-indexing.shader_test index bc550738c..3a1e12acc 100644 --- a/tests/hlsl/non-const-indexing.shader_test +++ b/tests/hlsl/non-const-indexing.shader_test @@ -12,17 +12,17 @@ uniform 0 float4 1.0 2.0 3.0 4.0 uniform 4 float4 5.0 6.0 7.0 8.0 uniform 8 float4 9.0 10.0 11.0 12.0 uniform 12 float4 0 0 0 0 -todo(sm>=6) draw quad -todo(sm>=6) probe all rgba (1.0, 2.0, 3.0, 4.0) +draw quad +probe all rgba (1.0, 2.0, 3.0, 4.0) uniform 12 float4 1 0 0 0 -todo(sm>=6) draw quad -todo(sm>=6) probe all rgba (5.0, 6.0, 7.0, 8.0) +draw quad +probe all rgba (5.0, 6.0, 7.0, 8.0) uniform 12 float4 0 1 0 0 -todo(sm>=6) draw quad -todo(sm>=6) probe all rgba (5.0, 6.0, 7.0, 8.0) +draw quad +probe all rgba (5.0, 6.0, 7.0, 8.0) uniform 12 float4 1 1 0 0 -todo(sm>=6) draw quad -todo(sm>=6) probe all rgba (9.0, 10.0, 11.0, 12.0) +draw quad +probe all rgba (9.0, 10.0, 11.0, 12.0)
[pixel shader] diff --git a/tests/hlsl/shader-interstage-interface.shader_test b/tests/hlsl/shader-interstage-interface.shader_test index 271eb3bbe..584b88cf9 100644 --- a/tests/hlsl/shader-interstage-interface.shader_test +++ b/tests/hlsl/shader-interstage-interface.shader_test @@ -52,5 +52,5 @@ void main(float4 position : SV_Position, float2 t0 : TEXCOORD0, }
[test] -todo(sm>=6) draw triangle strip 4 +draw triangle strip 4 probe all rgba (10.0, 8.0, 7.0, 3.0)
For consistency with later instructions I removed the calls to `is_scalar()` and instead check for int and float. It also makes the validations clearer.
I realised while preparing the `vselect` MR that we are missing validation of the source value type (function/register/handle) here and probably elsewhere. At this late stage I think it should go in a separate MR instead of revising this.
On Wed Nov 8 06:48:55 2023 +0000, Conor McCarthy wrote:
Vulkan asserts if we pass invalid SPIR-V, so to fix the runner we'd probably depend on spirv-tools. The problem with emitting errors in the backend is, after the necessary changes are upstream, we'd be handling errors which can't occur and should be handled with an assertion.
Ah, ok. When changing the frontend first would result in invalid code to be generated by the frontend, than it's appropriate to change the backend first. The ideal would be to first change the backend just enough so that it won't emit invalid code, than change the frontend and then change the backend for real. I'll appreciate when you can do this, but I understand if it turns out to be too complicated for some reason.
This merge request was approved by Henri Verbeet.