-- v3: vkd3d-shader/dxil: Implement DX intrinsic GetDimensions. vkd3d-shader/dxil: Move the resource kind helper functions up. vkd3d-shader/spirv: Introduce a sample info flag value for a scalar uint dst parameter.
From: Conor McCarthy cmccarthy@codeweavers.com
The result of sample info in Shader Model 6 is always uint, and must be a scalar for insertion into a vector temp. --- libs/vkd3d-shader/d3d_asm.c | 1 + libs/vkd3d-shader/spirv.c | 3 +++ libs/vkd3d-shader/vkd3d_shader_private.h | 1 + 3 files changed, 5 insertions(+)
diff --git a/libs/vkd3d-shader/d3d_asm.c b/libs/vkd3d-shader/d3d_asm.c index 3f86bd459..3e8ba696c 100644 --- a/libs/vkd3d-shader/d3d_asm.c +++ b/libs/vkd3d-shader/d3d_asm.c @@ -1689,6 +1689,7 @@ static void shader_dump_instruction_flags(struct vkd3d_d3d_asm_compiler *compile { case VKD3DSI_NONE: break; case VKD3DSI_SAMPLE_INFO_UINT: shader_addline(buffer, "_uint"); break; + case VKD3DSI_SAMPLE_INFO_UINT_SCALAR: shader_addline(buffer, "_uintScalar"); break; default: shader_addline(buffer, "_unrecognized(%#x)", ins->flags); } break; diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c index a3baeea75..369dce1b7 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -9199,6 +9199,9 @@ static void spirv_compiler_emit_sample_info(struct spirv_compiler *compiler,
val_id = spirv_compiler_emit_query_sample_count(compiler, src);
+ if (instruction->flags == VKD3DSI_SAMPLE_INFO_UINT_SCALAR) + return spirv_compiler_emit_store_dst(compiler, dst, val_id); + constituents[0] = val_id; for (i = 1; i < VKD3D_VEC4_SIZE; ++i) constituents[i] = spirv_compiler_get_constant_uint(compiler, 0); diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h index 1030adf98..7ed4fa1ee 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -762,6 +762,7 @@ enum vkd3d_tessellator_domain #define VKD3DSI_RESINFO_RCP_FLOAT 0x1 #define VKD3DSI_RESINFO_UINT 0x2 #define VKD3DSI_SAMPLE_INFO_UINT 0x1 +#define VKD3DSI_SAMPLE_INFO_UINT_SCALAR 0x2 #define VKD3DSI_SAMPLER_COMPARISON_MODE 0x1 #define VKD3DSI_SHIFT_UNMASKED 0x1
From: Conor McCarthy cmccarthy@codeweavers.com
--- libs/vkd3d-shader/dxil.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-)
diff --git a/libs/vkd3d-shader/dxil.c b/libs/vkd3d-shader/dxil.c index a001f6f06..f45a795d7 100644 --- a/libs/vkd3d-shader/dxil.c +++ b/libs/vkd3d-shader/dxil.c @@ -1904,6 +1904,16 @@ static const struct sm6_type *sm6_parser_get_type(struct sm6_parser *sm6, uint64 return &sm6->types[type_id]; }
+static bool resource_kind_is_texture(enum dxil_resource_kind kind) +{ + return kind >= RESOURCE_KIND_TEXTURE1D && kind <= RESOURCE_KIND_TEXTURECUBEARRAY; +} + +static bool resource_kind_is_multisampled(enum dxil_resource_kind kind) +{ + return kind == RESOURCE_KIND_TEXTURE2DMS || kind == RESOURCE_KIND_TEXTURE2DMSARRAY; +} + static int global_symbol_compare(const void *a, const void *b) { return vkd3d_u32_compare(((const struct sm6_symbol *)a)->id, ((const struct sm6_symbol *)b)->id); @@ -6380,16 +6390,6 @@ static bool sm6_parser_resources_load_register_range(struct sm6_parser *sm6, return true; }
-static bool resource_kind_is_texture(enum dxil_resource_kind kind) -{ - return kind >= RESOURCE_KIND_TEXTURE1D && kind <= RESOURCE_KIND_TEXTURECUBEARRAY; -} - -static bool resource_kind_is_multisampled(enum dxil_resource_kind kind) -{ - return kind == RESOURCE_KIND_TEXTURE2DMS || kind == RESOURCE_KIND_TEXTURE2DMSARRAY; -} - static enum vkd3d_shader_resource_type shader_resource_type_from_dxil_resource_kind(enum dxil_resource_kind kind) { if (resource_kind_is_texture(kind))
From: Conor McCarthy cmccarthy@codeweavers.com
--- libs/vkd3d-shader/dxil.c | 85 ++++++++++++++++++++++++++++ tests/hlsl/getdimensions.shader_test | 4 +- 2 files changed, 87 insertions(+), 2 deletions(-)
diff --git a/libs/vkd3d-shader/dxil.c b/libs/vkd3d-shader/dxil.c index f45a795d7..9b5e1c171 100644 --- a/libs/vkd3d-shader/dxil.c +++ b/libs/vkd3d-shader/dxil.c @@ -372,6 +372,7 @@ enum dx_intrinsic_opcode DX_TEXTURE_LOAD = 66, DX_TEXTURE_STORE = 67, DX_BUFFER_LOAD = 68, + DX_GET_DIMENSIONS = 72, DX_DERIV_COARSEX = 83, DX_DERIV_COARSEY = 84, DX_DERIV_FINEX = 85, @@ -2323,6 +2324,23 @@ static void instruction_dst_param_init_ssa_vector(struct vkd3d_shader_instructio dst->u.reg = param->reg; }
+static bool instruction_dst_param_init_temp_vector(struct vkd3d_shader_instruction *ins, struct sm6_parser *sm6) +{ + struct sm6_value *dst = sm6_parser_get_current_value(sm6); + struct vkd3d_shader_dst_param *param; + + if (!(param = instruction_dst_params_alloc(ins, 1, sm6))) + return false; + + vsir_dst_param_init(param, VKD3DSPR_TEMP, vkd3d_data_type_from_sm6_type(sm6_type_get_scalar_type(dst->type, 0)), 1); + param->write_mask = VKD3DSP_WRITEMASK_ALL; + param->reg.idx[0].offset = 0; + param->reg.dimension = VSIR_DIMENSION_VEC4; + dst->u.reg = param->reg; + + return true; +} + /* Recurse through the block tree while maintaining a current value count. The current * count is the sum of the global count plus all declarations within the current function. * Store into value_capacity the highest count seen. */ @@ -3892,6 +3910,69 @@ static void sm6_parser_emit_dx_create_handle(struct sm6_parser *sm6, enum dx_int ins->handler_idx = VKD3DSIH_NOP; }
+static void sm6_parser_emit_dx_get_dimensions(struct sm6_parser *sm6, enum dx_intrinsic_opcode op, + const struct sm6_value **operands, struct function_emission_state *state) +{ + struct vkd3d_shader_instruction *ins = state->ins; + struct vkd3d_shader_src_param *src_params; + unsigned int is_texture, component_count; + enum dxil_resource_kind resource_kind; + const struct sm6_value *resource; + + resource = operands[0]; + if (!sm6_value_validate_is_handle(resource, sm6)) + return; + is_texture = resource->u.handle.d->resource_type != VKD3D_SHADER_RESOURCE_BUFFER; + resource_kind = resource->u.handle.d->kind; + + instruction_init_with_resource(ins, is_texture ? VKD3DSIH_RESINFO : VKD3DSIH_BUFINFO, resource, sm6); + + if (!(src_params = instruction_src_params_alloc(ins, 1 + is_texture, sm6))) + return; + src_param_init_vector_from_reg(&src_params[is_texture], &resource->u.handle.reg); + + if (is_texture) + { + ins->flags = VKD3DSI_RESINFO_UINT; + src_param_init_from_value(&src_params[0], operands[1]); + component_count = VKD3D_VEC4_SIZE; + + instruction_dst_param_init_temp_vector(ins++, sm6); + state->temp_idx = 1; + + if (resource_kind_is_multisampled(resource_kind)) + { + /* DXIL does not have an instrinsic for sample info, and resinfo is expected to return + * the sample count in .w for MS textures. The result is always a struct of 4 x uint32. */ + vsir_instruction_init(ins, &sm6->p.location, VKD3DSIH_SAMPLE_INFO); + ins->flags = VKD3DSI_SAMPLE_INFO_UINT_SCALAR; + + if (!(src_params = instruction_src_params_alloc(ins, 1, sm6))) + return; + src_param_init_vector_from_reg(&src_params[0], &resource->u.handle.reg); + src_params[0].swizzle = VKD3D_SHADER_SWIZZLE(X, X, X, X); + + if (!instruction_dst_param_init_temp_vector(ins, sm6)) + return; + ins->dst->write_mask = VKD3DSP_WRITEMASK_3; + + state->ins = ins; + ++state->code_block->instruction_count; + } + } + else + { + if (!operands[1]->is_undefined) + { + WARN("Ignoring unexpected operand.\n"); + vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_IGNORING_OPERANDS, + "Ignoring an unexpected defined LOD value for buffer GetDimensions."); + } + component_count = 1 + (resource_kind == RESOURCE_KIND_STRUCTUREDBUFFER); + instruction_dst_param_init_ssa_vector(ins, component_count, sm6); + } +} + static enum vkd3d_shader_opcode sm6_dx_map_tertiary_op(enum dx_intrinsic_opcode op) { switch (op) @@ -4254,6 +4335,7 @@ struct sm6_dx_opcode_info e -> half/float g -> half/float/double H -> handle + D -> Dimensions S -> splitdouble v -> void o -> overloaded @@ -4281,6 +4363,7 @@ static const struct sm6_dx_opcode_info sm6_dx_op_table[] = [DX_FMAX ] = {"g", "RR", sm6_parser_emit_dx_binary}, [DX_FMIN ] = {"g", "RR", sm6_parser_emit_dx_binary}, [DX_FRC ] = {"g", "R", sm6_parser_emit_dx_unary}, + [DX_GET_DIMENSIONS ] = {"D", "Hi", sm6_parser_emit_dx_get_dimensions}, [DX_IBFE ] = {"m", "iiR", sm6_parser_emit_dx_tertiary}, [DX_HCOS ] = {"g", "R", sm6_parser_emit_dx_unary}, [DX_HSIN ] = {"g", "R", sm6_parser_emit_dx_unary}, @@ -4351,6 +4434,8 @@ static bool sm6_parser_validate_operand_type(struct sm6_parser *sm6, const struc return sm6_type_is_floating_point(type); case 'H': return (is_return || sm6_value_is_handle(value)) && type == sm6->handle_type; + case 'D': + return sm6_type_is_struct(type) && !strcmp(type->u.struc->name, "dx.types.Dimensions"); case 'S': return sm6_type_is_struct(type) && !strcmp(type->u.struc->name, "dx.types.splitdouble"); case 'v': diff --git a/tests/hlsl/getdimensions.shader_test b/tests/hlsl/getdimensions.shader_test index 01d12f87a..4d781b320 100644 --- a/tests/hlsl/getdimensions.shader_test +++ b/tests/hlsl/getdimensions.shader_test @@ -28,7 +28,7 @@ float4 main() : sv_target }
[test] -todo(sm>=6) draw quad +draw quad probe all rgba (2.0, 3.0, 2.0, 3.0)
[texture 1] @@ -53,5 +53,5 @@ float4 main() : sv_target }
[test] -todo(sm>=6) draw quad +draw quad probe all rgba (2.0, 2.0, 1.0, 2.0)
On Fri Feb 16 07:12:23 2024 +0000, Conor McCarthy wrote:
It relies on dxcompiler always extracting the scalars immediately after the vector result is emitted. It may be simpler to validate that than emit a `MOV`.
Mmmh, I don't think we should rely on the compiler's behavior. We don't know whether unpacking always happens immediately, whether it will in the future and whether it would happen if anybody would be writing an alternative compiler.
On Fri Feb 16 10:08:18 2024 +0000, Conor McCarthy wrote:
So long as values are extracted immediately, and temps elsewhere are only used to construct src params, there can be no temp register conflicts.
Ah, sorry, my bad, I had misunderstood how `temp_idx` is used. It is already accumulated into `temp_count` and reset at each instruction.