Module: vkd3d Branch: master Commit: fb730b11cfb73a0fd972ed917d074e80d86dd565 URL: https://gitlab.winehq.org/wine/vkd3d/-/commit/fb730b11cfb73a0fd972ed917d074e...
Author: Conor McCarthy cmccarthy@codeweavers.com Date: Thu Feb 15 12:08:46 2024 +1000
vkd3d-shader/dxil: Handle constexpr pointer cast.
---
libs/vkd3d-shader/dxil.c | 78 ++++++++++++++++++++++++++++++-- libs/vkd3d-shader/vkd3d_shader_private.h | 6 +++ tests/hlsl/pointer-cast.shader_test | 4 +- 3 files changed, 83 insertions(+), 5 deletions(-)
diff --git a/libs/vkd3d-shader/dxil.c b/libs/vkd3d-shader/dxil.c index 556902c2..6453eba3 100644 --- a/libs/vkd3d-shader/dxil.c +++ b/libs/vkd3d-shader/dxil.c @@ -103,6 +103,7 @@ enum bitcode_constant_code CST_CODE_INTEGER = 4, CST_CODE_FLOAT = 6, CST_CODE_STRING = 8, + CST_CODE_CE_CAST = 11, CST_CODE_CE_GEP = 12, CST_CODE_CE_INBOUNDS_GEP = 20, CST_CODE_DATA = 22, @@ -2217,6 +2218,11 @@ static bool sm6_value_is_ssa(const struct sm6_value *value) return sm6_value_is_register(value) && register_is_ssa(&value->u.reg); }
+static bool sm6_value_is_numeric_array(const struct sm6_value *value) +{ + return sm6_value_is_register(value) && register_is_numeric_array(&value->u.reg); +} + static inline unsigned int sm6_value_get_constant_uint(const struct sm6_value *value) { if (!sm6_value_is_constant(value)) @@ -3099,15 +3105,16 @@ static enum vkd3d_result sm6_parser_init_constexpr_gep(struct sm6_parser *sm6, c static enum vkd3d_result sm6_parser_constants_init(struct sm6_parser *sm6, const struct dxil_block *block) { enum vkd3d_shader_register_type reg_type = VKD3DSPR_INVALID; - const struct sm6_type *type, *elem_type; + const struct sm6_type *type, *elem_type, *ptr_type; + size_t i, base_value_idx, value_idx; enum vkd3d_data_type reg_data_type; const struct dxil_record *record; + const struct sm6_value *src; enum vkd3d_result ret; struct sm6_value *dst; - size_t i, value_idx; uint64_t value;
- for (i = 0, type = NULL; i < block->record_count; ++i) + for (i = 0, type = NULL, base_value_idx = sm6->value_count; i < block->record_count; ++i) { sm6->p.location.column = i; record = block->records[i]; @@ -3223,6 +3230,48 @@ static enum vkd3d_result sm6_parser_constants_init(struct sm6_parser *sm6, const return ret; break;
+ case CST_CODE_CE_CAST: + if (!dxil_record_validate_operand_count(record, 3, 3, sm6)) + return VKD3D_ERROR_INVALID_SHADER; + + if ((value = record->operands[0]) != CAST_BITCAST) + { + WARN("Unhandled constexpr cast op %"PRIu64".\n", value); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, + "Constexpr cast op %"PRIu64" is unhandled.", value); + return VKD3D_ERROR_INVALID_SHADER; + } + + ptr_type = sm6_parser_get_type(sm6, record->operands[1]); + if (!sm6_type_is_pointer(ptr_type)) + { + WARN("Constexpr cast at constant idx %zu is not a pointer.\n", value_idx); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, + "Constexpr cast source operand is not a pointer."); + return VKD3D_ERROR_INVALID_SHADER; + } + + if ((value = record->operands[2]) >= sm6->cur_max_value) + { + WARN("Invalid value index %"PRIu64".\n", value); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, + "Invalid value index %"PRIu64".", value); + return VKD3D_ERROR_INVALID_SHADER; + } + else if (value == value_idx) + { + WARN("Invalid value self-reference at %"PRIu64".\n", value); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, + "Invalid value self-reference for a constexpr cast."); + return VKD3D_ERROR_INVALID_SHADER; + } + + /* Resolve later in case forward refs exist. */ + dst->type = type; + dst->u.reg.type = VKD3DSPR_COUNT; + dst->u.reg.idx[0].offset = value; + break; + case CST_CODE_UNDEF: dxil_record_validate_operand_max_count(record, 0, sm6); dst->u.reg.type = VKD3DSPR_UNDEF; @@ -3248,6 +3297,29 @@ static enum vkd3d_result sm6_parser_constants_init(struct sm6_parser *sm6, const ++sm6->value_count; }
+ /* Resolve cast forward refs. */ + for (i = base_value_idx; i < sm6->value_count; ++i) + { + dst = &sm6->values[i]; + if (dst->u.reg.type != VKD3DSPR_COUNT) + continue; + + type = dst->type; + + src = &sm6->values[dst->u.reg.idx[0].offset]; + if (!sm6_value_is_numeric_array(src)) + { + WARN("Value is not an array.\n"); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, + "Constexpr cast source value is not a global array element."); + return VKD3D_ERROR_INVALID_SHADER; + } + + *dst = *src; + dst->type = type; + dst->u.reg.data_type = vkd3d_data_type_from_sm6_type(type->u.pointer.type); + } + return VKD3D_OK; }
diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h index 4bb99efe..165126b5 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -1241,6 +1241,12 @@ static inline bool register_is_scalar_constant_zero(const struct vkd3d_shader_re && (data_type_is_64_bit(reg->data_type) ? !reg->u.immconst_u64[0] : !reg->u.immconst_u32[0]); }
+static inline bool register_is_numeric_array(const struct vkd3d_shader_register *reg) +{ + return (reg->type == VKD3DSPR_IMMCONSTBUFFER || reg->type == VKD3DSPR_IDXTEMP + || reg->type == VKD3DSPR_GROUPSHAREDMEM); +} + static inline bool vsir_register_is_label(const struct vkd3d_shader_register *reg) { return reg->type == VKD3DSPR_LABEL; diff --git a/tests/hlsl/pointer-cast.shader_test b/tests/hlsl/pointer-cast.shader_test index 7cbcfc8f..6821abab 100644 --- a/tests/hlsl/pointer-cast.shader_test +++ b/tests/hlsl/pointer-cast.shader_test @@ -16,8 +16,8 @@ float4 main(float4 pos : SV_Position) : SV_Target
[test] uniform 0 uint4 0 1 0x3e000000 0 -todo draw quad +draw quad probe all rgba (0.25, 0.125, 0.0, 1.0) uniform 0 uint4 1 0 0x3e000000 0 -todo draw quad +draw quad probe all rgba (0.5, 0.75, 0.0, 1.0)