Goes atop !583. The last two commits belong to this MR.
-- v4: vkd3d-shader/spirv: Emit a vector bitcast if necessary in spirv_compiler_emit_load_ssa_reg(). vkd3d-shader/dxil: Implement DX intrinsic TextureLoad.
From: Conor McCarthy cmccarthy@codeweavers.com
--- libs/vkd3d-shader/dxil.c | 143 +++++++++++++++++- tests/hlsl/cbuffer.shader_test | 4 +- tests/hlsl/initializer-objects.shader_test | 4 +- tests/hlsl/load-level.shader_test | 6 +- tests/hlsl/object-references.shader_test | 4 +- ...egister-reservations-resources.shader_test | 32 ++-- tests/hlsl/swizzle-constant-prop.shader_test | 6 +- tests/hlsl/texture-load-offset.shader_test | 4 +- tests/hlsl/texture-load.shader_test | 6 +- 9 files changed, 182 insertions(+), 27 deletions(-)
diff --git a/libs/vkd3d-shader/dxil.c b/libs/vkd3d-shader/dxil.c index 3e1ba3911..c48665edb 100644 --- a/libs/vkd3d-shader/dxil.c +++ b/libs/vkd3d-shader/dxil.c @@ -33,6 +33,7 @@ static const uint64_t ALLOCA_FLAG_IN_ALLOCA = 0x20; static const uint64_t ALLOCA_FLAG_EXPLICIT_TYPE = 0x40; static const uint64_t ALLOCA_ALIGNMENT_MASK = ALLOCA_FLAG_IN_ALLOCA - 1; static const unsigned int SHADER_DESCRIPTOR_TYPE_COUNT = 4; +static const size_t MAX_IR_INSTRUCTIONS_PER_DXIL_INSTRUCTION = 5;
static const unsigned int dx_max_thread_group_size[3] = {1024, 1024, 64};
@@ -362,6 +363,7 @@ enum dx_intrinsic_opcode DX_UBFE = 52, DX_CREATE_HANDLE = 57, DX_CBUFFER_LOAD_LEGACY = 59, + DX_TEXTURE_LOAD = 66, DX_BUFFER_LOAD = 68, DX_DERIV_COARSEX = 83, DX_DERIV_COARSEY = 84, @@ -2369,6 +2371,26 @@ static bool sm6_value_validate_is_handle(const struct sm6_value *value, struct s return true; }
+static bool sm6_value_validate_is_texture_handle(const struct sm6_value *value, enum dx_intrinsic_opcode op, + struct sm6_parser *sm6) +{ + enum dxil_resource_kind kind; + + if (!sm6_value_validate_is_handle(value, sm6)) + return false; + + kind = value->u.handle.d->kind; + if (kind < RESOURCE_KIND_TEXTURE1D || kind > RESOURCE_KIND_TEXTURECUBEARRAY) + { + WARN("Resource kind %u for op %u is not a texture.\n", kind, op); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_RESOURCE_HANDLE, + "Resource kind %u for texture operation %u is not a texture.", kind, op); + return false; + } + + return true; +} + static bool sm6_value_validate_is_pointer(const struct sm6_value *value, struct sm6_parser *sm6) { if (!sm6_type_is_pointer(value->type)) @@ -3197,6 +3219,7 @@ struct function_emission_state { struct sm6_block *code_block; struct vkd3d_shader_instruction *ins; + unsigned int temp_idx; };
static void sm6_parser_emit_alloca(struct sm6_parser *sm6, const struct dxil_record *record, @@ -3516,6 +3539,60 @@ static void sm6_parser_emit_br(struct sm6_parser *sm6, const struct dxil_record ins->handler_idx = VKD3DSIH_NOP; }
+static bool sm6_parser_emit_coordinate_construct(struct sm6_parser *sm6, const struct sm6_value **operands, + const struct sm6_value *z_operand, struct function_emission_state *state, + struct vkd3d_shader_register *reg) +{ + struct vkd3d_shader_instruction *ins = state->ins; + unsigned int i, component_count, src_count; + struct vkd3d_shader_src_param *src_params; + struct vkd3d_shader_dst_param *dst_param; + const unsigned int max_operands = 3; + + if (z_operand) + { + component_count = max_operands; + } + else + { + for (component_count = 0; component_count < max_operands; ++component_count) + if (operands[component_count]->is_undefined) + break; + } + + if (component_count == 1) + { + *reg = operands[0]->u.reg; + return true; + } + + register_init_with_id(reg, VKD3DSPR_TEMP, operands[0]->u.reg.data_type, state->temp_idx++); + reg->dimension = VSIR_DIMENSION_VEC4; + + src_count = component_count + !!z_operand; + for (i = 0; i < src_count; ++i, ++ins) + { + vsir_instruction_init(ins, &sm6->p.location, VKD3DSIH_MOV); + + if (!(src_params = instruction_src_params_alloc(ins, 1, sm6))) + return false; + + src_param_init(&src_params[0]); + src_params[0].reg = (i < component_count) ? operands[i]->u.reg : z_operand->u.reg; + + if (!(dst_param = instruction_dst_params_alloc(ins, 1, sm6))) + return false; + + dst_param_init_scalar(dst_param, i); + dst_param->reg = *reg; + } + + state->ins = ins; + state->code_block->instruction_count += src_count; + + return true; +} + static enum vkd3d_shader_opcode map_dx_unary_op(enum dx_intrinsic_opcode op) { switch (op) @@ -3856,6 +3933,19 @@ static void sm6_parser_emit_dx_buffer_load(struct sm6_parser *sm6, enum dx_intri instruction_dst_param_init_ssa_vector(ins, VKD3D_VEC4_SIZE, sm6); }
+static unsigned int sm6_value_get_texel_offset(const struct sm6_value *value) +{ + return sm6_value_is_undef(value) ? 0 : sm6_value_get_constant_uint(value); +} + +static void instruction_set_texel_offset(struct vkd3d_shader_instruction *ins, + const struct sm6_value **operands, struct sm6_parser *sm6) +{ + ins->texel_offset.u = sm6_value_get_texel_offset(operands[0]); + ins->texel_offset.v = sm6_value_get_texel_offset(operands[1]); + ins->texel_offset.w = sm6_value_get_texel_offset(operands[2]); +} + static void sm6_parser_emit_dx_sincos(struct sm6_parser *sm6, enum dx_intrinsic_opcode op, const struct sm6_value **operands, struct function_emission_state *state) { @@ -3932,6 +4022,50 @@ static void sm6_parser_emit_dx_store_output(struct sm6_parser *sm6, enum dx_intr src_param_init_from_value(src_param, value); }
+static void sm6_parser_emit_dx_texture_load(struct sm6_parser *sm6, enum dx_intrinsic_opcode op, + const struct sm6_value **operands, struct function_emission_state *state) +{ + const struct sm6_value *resource, *mip_level_or_sample_count; + enum vkd3d_shader_resource_type resource_type; + struct vkd3d_shader_src_param *src_params; + struct vkd3d_shader_instruction *ins; + struct vkd3d_shader_register coord; + bool is_multisample, is_uav; + unsigned int i; + + resource = operands[0]; + if (!sm6_value_validate_is_texture_handle(resource, op, sm6)) + return; + + resource_type = resource->u.handle.d->resource_type; + is_multisample = resource_type == VKD3D_SHADER_RESOURCE_TEXTURE_2DMS + || resource_type == VKD3D_SHADER_RESOURCE_TEXTURE_2DMSARRAY; + is_uav = resource->u.handle.d->type == VKD3D_SHADER_DESCRIPTOR_TYPE_UAV; + + mip_level_or_sample_count = (resource_type != VKD3D_SHADER_RESOURCE_BUFFER) ? operands[1] : NULL; + if (!sm6_parser_emit_coordinate_construct(sm6, &operands[2], + is_multisample ? NULL : mip_level_or_sample_count, state, &coord)) + { + return; + } + + ins = state->ins; + instruction_init_with_resource(ins, is_uav ? VKD3DSIH_LD_UAV_TYPED + : is_multisample ? VKD3DSIH_LD2DMS : VKD3DSIH_LD, resource, sm6); + instruction_set_texel_offset(ins, &operands[5], sm6); + + for (i = 0; i < VKD3D_VEC4_SIZE; ++i) + ins->resource_data_type[i] = resource->u.handle.d->resource_data_type; + + src_params = instruction_src_params_alloc(ins, 2 + is_multisample, sm6); + src_param_init_vector_from_reg(&src_params[0], &coord); + src_param_init_vector_from_reg(&src_params[1], &resource->u.handle.reg); + if (is_multisample) + src_param_init_from_value(&src_params[2], mip_level_or_sample_count); + + instruction_dst_param_init_ssa_vector(ins, VKD3D_VEC4_SIZE, sm6); +} + struct sm6_dx_opcode_info { const char *ret_type; @@ -3945,6 +4079,7 @@ struct sm6_dx_opcode_info 8 -> int8 b -> constant int1 c -> constant int8/16/32 + C -> constant or undefined int8/16/32 i -> int32 m -> int16/32/64 f -> float @@ -3994,6 +4129,7 @@ static const struct sm6_dx_opcode_info sm6_dx_op_table[] = [DX_SQRT ] = {"g", "R", sm6_parser_emit_dx_unary}, [DX_STORE_OUTPUT ] = {"v", "ii8o", sm6_parser_emit_dx_store_output}, [DX_TAN ] = {"g", "R", sm6_parser_emit_dx_unary}, + [DX_TEXTURE_LOAD ] = {"o", "HiiiiCCC", sm6_parser_emit_dx_texture_load}, [DX_UBFE ] = {"m", "iiR", sm6_parser_emit_dx_tertiary}, [DX_UMAX ] = {"m", "RR", sm6_parser_emit_dx_binary}, [DX_UMIN ] = {"m", "RR", sm6_parser_emit_dx_binary}, @@ -4021,6 +4157,9 @@ static bool sm6_parser_validate_operand_type(struct sm6_parser *sm6, const struc case 'c': return sm6_value_is_constant(value) && sm6_type_is_integer(type) && type->u.width >= 8 && type->u.width <= 32; + case 'C': + return (sm6_value_is_constant(value) || sm6_value_is_undef(value)) + && sm6_type_is_integer(type) && type->u.width >= 8 && type->u.width <= 32; case 'i': return sm6_type_is_i32(type); case 'm': @@ -5378,7 +5517,8 @@ static enum vkd3d_result sm6_parser_function_init(struct sm6_parser *sm6, const
/* Some instructions can emit >1 IR instruction, so extra may be used. */ if (!vkd3d_array_reserve((void **)&code_block->instructions, &code_block->instruction_capacity, - code_block->instruction_count + 1, sizeof(*code_block->instructions))) + code_block->instruction_count + MAX_IR_INSTRUCTIONS_PER_DXIL_INSTRUCTION, + sizeof(*code_block->instructions))) { ERR("Failed to allocate instructions.\n"); return VKD3D_ERROR_OUT_OF_MEMORY; @@ -5409,6 +5549,7 @@ static enum vkd3d_result sm6_parser_function_init(struct sm6_parser *sm6, const { struct function_emission_state state = {code_block, ins}; sm6_parser_emit_call(sm6, record, &state, dst); + sm6->p.program.temp_count = max(sm6->p.program.temp_count, state.temp_idx); break; } case FUNC_CODE_INST_CAST: diff --git a/tests/hlsl/cbuffer.shader_test b/tests/hlsl/cbuffer.shader_test index b4dc01edd..62f1cd28c 100644 --- a/tests/hlsl/cbuffer.shader_test +++ b/tests/hlsl/cbuffer.shader_test @@ -549,7 +549,7 @@ float4 main() : sv_target }
[test] -todo(sm>=6) draw quad +draw quad probe all rgba (1.0, 1.0, 1.0, 1.0)
@@ -726,5 +726,5 @@ uniform 0 float4 0.0 1.0 2.0 3.0 uniform 4 float4 4.0 5.0 6.0 7.0 uniform 8 float4 8.0 9.0 10.0 11.0 uniform 12 float4 12.0 13.0 14.0 15.0 -todo(sm>=6) draw quad +draw quad probe all rgba (124.0, 135.0, 146.0, 150.5) diff --git a/tests/hlsl/initializer-objects.shader_test b/tests/hlsl/initializer-objects.shader_test index 514a7cebb..d9c0bc91c 100644 --- a/tests/hlsl/initializer-objects.shader_test +++ b/tests/hlsl/initializer-objects.shader_test @@ -25,7 +25,7 @@ float4 main() : sv_target }
[test] -todo(sm>=6) draw quad +draw quad probe all rgba (0.2, 0.2, 0.2, 0.1)
@@ -48,7 +48,7 @@ float4 main() : sv_target }
[test] -todo(sm>=6) draw quad +draw quad probe all rgba (31.1, 41.1, 51.1, 61.1) 1
diff --git a/tests/hlsl/load-level.shader_test b/tests/hlsl/load-level.shader_test index 9df2f01fb..0f64bd5d5 100644 --- a/tests/hlsl/load-level.shader_test +++ b/tests/hlsl/load-level.shader_test @@ -22,10 +22,10 @@ float4 main() : sv_target
[test] uniform 0 uint 0 -todo(sm>=6) draw quad +draw quad probe all rgba (1.0, 0.0, 1.0, 0.0) uniform 0 uint 1 -todo(sm>=6) draw quad +draw quad probe all rgba (0.0, 0.0, 1.0, 0.0)
[pixel shader fail] @@ -47,5 +47,5 @@ float4 main() : sv_target }
[test] -todo(sm>=6) draw quad +draw quad probe all rgba (1.0, 0.0, 1.0, 0.0) diff --git a/tests/hlsl/object-references.shader_test b/tests/hlsl/object-references.shader_test index c857f3885..5c8070946 100644 --- a/tests/hlsl/object-references.shader_test +++ b/tests/hlsl/object-references.shader_test @@ -73,7 +73,7 @@ float4 main(float4 pos : sv_position) : sv_target }
[test] -todo(sm>=6) draw quad +draw quad probe (0, 0) rgba (0.1, 0.2, 0.3, 0.4) probe (1, 0) rgba (0.5, 0.7, 0.6, 0.8) probe (0, 1) rgba (0.6, 0.5, 0.2, 0.1) @@ -134,7 +134,7 @@ float4 main() : sv_target }
[test] -todo(sm>=6) draw quad +draw quad probe all rgba (2132, 2132, 2132, 1111)
diff --git a/tests/hlsl/register-reservations-resources.shader_test b/tests/hlsl/register-reservations-resources.shader_test index 9539b05ff..22a441026 100644 --- a/tests/hlsl/register-reservations-resources.shader_test +++ b/tests/hlsl/register-reservations-resources.shader_test @@ -50,7 +50,7 @@ float4 main() : sv_target }
[test] -todo(sm>=6) draw quad +draw quad probe all rgba (0.0, 0.0, 0.0, 99.0)
@@ -65,7 +65,7 @@ float4 main() : sv_target }
[test] -todo(sm>=6) draw quad +draw quad probe all rgba (1.0, 1.0, 1.0, 99.0)
@@ -79,10 +79,24 @@ float4 main() : sv_target return tex.Load(int3(0, 0, 0)); }
+[require] +shader model >= 4.0 +shader model < 6.0 + [test] -todo(sm>=6) draw quad +draw quad probe all rgba (0.0, 0.0, 0.0, 99.0)
+[require] +shader model >= 6.0 + +[test] +draw quad +probe all rgba (1.0, 1.0, 1.0, 99.0) + +[require] +shader model >= 4.0 +
% Register reservation with incorrect register type. [pixel shader fail(sm>=6)] @@ -109,7 +123,7 @@ float4 main() : sv_target }
[test] -todo(sm>=6) draw quad +draw quad probe all rgba (4.0, 4.0, 4.0, 99.0)
@@ -125,7 +139,7 @@ float4 main() : sv_target }
[test] -todo(sm>=6) draw quad +draw quad probe all rgba (1.0, 1.0, 1.0, 99.0)
@@ -140,7 +154,7 @@ float4 main() : sv_target }
[test] -todo(sm>=6) draw quad +draw quad probe all rgba (2.0, 2.0, 2.0, 99.0)
@@ -154,7 +168,7 @@ float4 main() : sv_target }
[test] -todo(sm>=6) draw quad +draw quad probe all rgba (2.0, 2.0, 2.0, 99.0)
@@ -227,5 +241,5 @@ float4 main() : sv_target }
[test] -todo(sm>=6) draw quad -todo probe all rgba (1.0, 1.0, 1.0, 99.0) +draw quad +todo(sm<6) probe all rgba (1.0, 1.0, 1.0, 99.0) diff --git a/tests/hlsl/swizzle-constant-prop.shader_test b/tests/hlsl/swizzle-constant-prop.shader_test index a0ec18e45..357a3496e 100644 --- a/tests/hlsl/swizzle-constant-prop.shader_test +++ b/tests/hlsl/swizzle-constant-prop.shader_test @@ -25,7 +25,7 @@ float4 main() : sv_target
[test] uniform 0 int 4 -todo(sm>=6) draw quad +draw quad probe all rgba (110, 210, 410, 410)
@@ -43,7 +43,7 @@ float4 main() : sv_target
[test] uniform 0 int 3 -todo(sm>=6) draw quad +draw quad probe all rgba (105, 5, 305, 305)
@@ -59,5 +59,5 @@ float4 main() : sv_target
[test] uniform 0 int 1 -todo(sm>=6) draw quad +draw quad probe all rgba (14.0, 14.0, 14.0, 14.0) diff --git a/tests/hlsl/texture-load-offset.shader_test b/tests/hlsl/texture-load-offset.shader_test index f32b2191f..52b6a5f93 100644 --- a/tests/hlsl/texture-load-offset.shader_test +++ b/tests/hlsl/texture-load-offset.shader_test @@ -18,7 +18,7 @@ float4 main(float4 pos : sv_position) : sv_target
[test] -todo(sm>=6) draw quad +draw quad probe (0, 0) rgba (0, 1, 0, 1) probe (1, 0) rgba (1, 1, 0, 1) probe (0, 1) rgba (0, 2, 0, 1) @@ -35,7 +35,7 @@ float4 main(float4 pos : sv_position) : sv_target
[test] -todo(sm>=6) draw quad +draw quad probe (3, 0) rgba (1, 0, 0, 1) probe (4, 0) rgba (2, 0, 0, 1) probe (3, 1) rgba (1, 1, 0, 1) diff --git a/tests/hlsl/texture-load.shader_test b/tests/hlsl/texture-load.shader_test index 30a33a4a4..0723c1384 100644 --- a/tests/hlsl/texture-load.shader_test +++ b/tests/hlsl/texture-load.shader_test @@ -15,7 +15,7 @@ float4 main(float4 pos : sv_position) : sv_target }
[test] -todo(sm>=6) draw quad +draw quad probe (0, 0) rgba (0.1, 0.2, 0.3, 0.4) probe (1, 0) rgba (0.5, 0.7, 0.6, 0.8) probe (0, 1) rgba (0.6, 0.5, 0.2, 0.1) @@ -30,7 +30,7 @@ float4 main(float4 pos : sv_position) : sv_target }
[test] -todo(sm>=6) draw quad +draw quad probe (0, 0) rgba (0.1, 0.2, 0.3, 0.4) probe (1, 0) rgba (0.6, 0.5, 0.2, 0.1) probe (0, 1) rgba (0.5, 0.7, 0.6, 0.8) @@ -46,7 +46,7 @@ float4 main(float4 pos : sv_position) : sv_target }
[test] -todo(sm>=6) draw quad +draw quad probe (0, 0) rgba (0.1, 0.2, 0.3, 0.4) probe (1, 0) rgba (0.6, 0.5, 0.2, 0.1) probe (0, 1) rgba (0.5, 0.7, 0.6, 0.8)
From: Conor McCarthy cmccarthy@codeweavers.com
--- libs/vkd3d-shader/spirv.c | 11 ++++++++++- tests/hlsl/texture-load-typed.shader_test | 2 +- 2 files changed, 11 insertions(+), 2 deletions(-)
diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c index 298ad31d9..d76ba6f96 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -3894,9 +3894,10 @@ static uint32_t spirv_compiler_emit_load_ssa_reg(struct spirv_compiler *compiler } assert(vkd3d_swizzle_is_scalar(swizzle, reg));
+ reg_component_type = vkd3d_component_type_from_data_type(ssa->data_type); + 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); @@ -3906,6 +3907,14 @@ static uint32_t spirv_compiler_emit_load_ssa_reg(struct spirv_compiler *compiler return val_id; }
+ if (component_type != reg_component_type) + { + /* Required for resource loads with sampled type int, because DXIL has no signedness. + * Only 128-bit vector sizes are used. */ + type_id = vkd3d_spirv_get_type_id(builder, component_type, VKD3D_VEC4_SIZE); + val_id = vkd3d_spirv_build_op_bitcast(builder, type_id, val_id); + } + type_id = vkd3d_spirv_get_type_id(builder, component_type, 1); component_idx = vsir_swizzle_get_component(swizzle, 0); return vkd3d_spirv_build_op_composite_extract1(builder, type_id, val_id, component_idx); diff --git a/tests/hlsl/texture-load-typed.shader_test b/tests/hlsl/texture-load-typed.shader_test index 67a13f10d..736b4ae1e 100644 --- a/tests/hlsl/texture-load-typed.shader_test +++ b/tests/hlsl/texture-load-typed.shader_test @@ -48,7 +48,7 @@ float4 main() : sv_target }
[test] -todo(sm>=6) draw quad +draw quad probe all rgba (0.8, -3.0, 4294967295.0, 123.0)
% lowercase 'texture2D'
This merge request was approved by Giovanni Mascellani.
At some point it might make sense to introduce some internal operators to represent texture operations without doing all the operands gymnastics we need to be compatible with SM4. But right now that's fine for me.