Goes atop !477. The last two commits belong to this MR.
-- v2: vkd3d-shader/dxil: Implement the DXIL STORE instruction. vkd3d-shader/dxil: Implement the DXIL ALLOCA instruction. tests/shader-runner: Test an uninitialised indexable temp.
From: Conor McCarthy cmccarthy@codeweavers.com
--- libs/vkd3d-shader/spirv.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-)
diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c index be149a0cf..e6bce7f43 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -5487,14 +5487,12 @@ static void spirv_compiler_emit_dcl_indexable_temp(struct spirv_compiler *compil { const struct vkd3d_shader_indexable_temp *temp = &instruction->declaration.indexable_temp; struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; + enum vkd3d_shader_component_type component_type; struct vkd3d_shader_register reg; struct vkd3d_symbol reg_symbol; size_t function_location; uint32_t id;
- if (temp->component_count != 4) - FIXME("Unhandled component count %u.\n", temp->component_count); - vsir_register_init(®, VKD3DSPR_IDXTEMP, VKD3D_DATA_FLOAT, 1); reg.idx[0].offset = temp->register_idx;
@@ -5510,16 +5508,17 @@ static void spirv_compiler_emit_dcl_indexable_temp(struct spirv_compiler *compil function_location = spirv_compiler_get_current_function_location(compiler); vkd3d_spirv_begin_function_stream_insertion(builder, function_location);
+ component_type = vkd3d_component_type_from_data_type(temp->data_type); id = spirv_compiler_emit_array_variable(compiler, &builder->function_stream, - SpvStorageClassFunction, VKD3D_SHADER_COMPONENT_FLOAT, VKD3D_VEC4_SIZE, &temp->register_size, 1); + SpvStorageClassFunction, component_type, temp->component_count, &temp->register_size, 1);
spirv_compiler_emit_register_debug_name(builder, id, ®);
vkd3d_spirv_end_function_stream_insertion(builder);
vkd3d_symbol_make_register(®_symbol, ®); - vkd3d_symbol_set_register_info(®_symbol, id, - SpvStorageClassFunction, VKD3D_SHADER_COMPONENT_FLOAT, VKD3DSP_WRITEMASK_ALL); + vkd3d_symbol_set_register_info(®_symbol, id, SpvStorageClassFunction, + component_type, vkd3d_write_mask_from_component_count(temp->component_count)); spirv_compiler_put_symbol(compiler, ®_symbol); }
From: Conor McCarthy cmccarthy@codeweavers.com
--- libs/vkd3d-shader/dxil.c | 14 ++++++++------ libs/vkd3d-shader/tpf.c | 1 + libs/vkd3d-shader/vkd3d_shader_private.h | 1 + 3 files changed, 10 insertions(+), 6 deletions(-)
diff --git a/libs/vkd3d-shader/dxil.c b/libs/vkd3d-shader/dxil.c index 1709212fa..6b4ed3bed 100644 --- a/libs/vkd3d-shader/dxil.c +++ b/libs/vkd3d-shader/dxil.c @@ -2412,7 +2412,7 @@ static enum vkd3d_result value_allocate_constant_array(struct sm6_value *dst, co return VKD3D_ERROR_INVALID_SHADER; } size = max(size, sizeof(icb->data[0])); - count = type->u.array.count * size / sizeof(icb->data[0]); + count = operands ? type->u.array.count * size / sizeof(icb->data[0]) : 0;
if (!(icb = vkd3d_malloc(offsetof(struct vkd3d_shader_immediate_constant_buffer, data[count])))) { @@ -2436,6 +2436,10 @@ static enum vkd3d_result value_allocate_constant_array(struct sm6_value *dst, co icb->data_type = vkd3d_data_type_from_sm6_type(elem_type); icb->element_count = type->u.array.count; icb->component_count = 1; + icb->is_null = !operands; + + if (!operands) + return VKD3D_OK;
count = type->u.array.count; if (size > sizeof(icb->data[0])) @@ -2510,12 +2514,10 @@ static enum vkd3d_result sm6_parser_constants_init(struct sm6_parser *sm6, const switch (record->code) { case CST_CODE_NULL: - if (sm6_type_is_array(type)) + if (sm6_type_is_array(type) + && (ret = value_allocate_constant_array(dst, type, NULL, sm6)) < 0) { - FIXME("Constant null arrays are not supported.\n"); - vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, - "Constant null arrays are not supported."); - return VKD3D_ERROR_INVALID_SHADER; + return ret; } /* For non-aggregates, register constant data is already zero-filled. */ break; diff --git a/libs/vkd3d-shader/tpf.c b/libs/vkd3d-shader/tpf.c index 61d14e30d..a34f9042b 100644 --- a/libs/vkd3d-shader/tpf.c +++ b/libs/vkd3d-shader/tpf.c @@ -795,6 +795,7 @@ static void shader_sm4_read_shader_data(struct vkd3d_shader_instruction *ins, ui icb->data_type = VKD3D_DATA_FLOAT; icb->component_count = VKD3D_VEC4_SIZE; icb->element_count = icb_size / VKD3D_VEC4_SIZE; + icb->is_null = false; memcpy(icb->data, tokens, sizeof(*tokens) * icb_size); shader_instruction_array_add_icb(&priv->p.instructions, icb); ins->declaration.icb = icb; diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h index d3989672b..edc617948 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -797,6 +797,7 @@ struct vkd3d_shader_immediate_constant_buffer /* total count is element_count * component_count */ unsigned int element_count; unsigned int component_count; + bool is_null; uint32_t data[]; };
From: Conor McCarthy cmccarthy@codeweavers.com
--- libs/vkd3d-shader/spirv.c | 87 ++++++++++++++++--- tests/hlsl/matrix-indexing.shader_test | 4 +- tests/hlsl/non-const-indexing.shader_test | 38 ++++---- .../hlsl/vector-indexing-uniform.shader_test | 2 +- 4 files changed, 99 insertions(+), 32 deletions(-)
diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c index e6bce7f43..7d5fe2d52 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -1194,6 +1194,16 @@ static uint32_t vkd3d_spirv_get_op_constant64(struct vkd3d_spirv_builder *builde (const uint32_t *)&value, 2, vkd3d_spirv_build_op_constant64); }
+static uint32_t vkd3d_spirv_build_op_constant_null(struct vkd3d_spirv_builder *builder, uint32_t result_type) +{ + return vkd3d_spirv_build_op_tr(builder, &builder->global_stream, SpvOpConstantNull, result_type); +} + +static uint32_t vkd3d_spirv_get_op_constant_null(struct vkd3d_spirv_builder *builder, uint32_t result_type) +{ + return vkd3d_spirv_build_once1(builder, SpvOpConstantNull, result_type, vkd3d_spirv_build_op_constant_null); +} + static uint32_t vkd3d_spirv_build_op_constant_composite(struct vkd3d_spirv_builder *builder, uint32_t result_type, const uint32_t *constituents, unsigned int constituent_count) { @@ -3756,6 +3766,61 @@ static uint32_t spirv_compiler_emit_load_scalar(struct spirv_compiler *compiler, return val_id; }
+static uint32_t spirv_compiler_emit_constant_array(struct spirv_compiler *compiler, + const struct vkd3d_shader_immediate_constant_buffer *icb) +{ + uint32_t *elements, elem_type_id, length_id, type_id, const_id; + struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; + unsigned int i, element_count; + + element_count = icb->element_count; + + elem_type_id = vkd3d_spirv_get_type_id_for_data_type(builder, icb->data_type, 1); + length_id = spirv_compiler_get_constant_uint(compiler, element_count); + type_id = vkd3d_spirv_get_op_type_array(builder, elem_type_id, length_id); + + if (icb->is_null) + { + /* All values are null. Workgroup memory initialisers require OpConstantNull. */ + return vkd3d_spirv_get_op_constant_null(builder, type_id); + } + + if (!(elements = vkd3d_calloc(element_count, sizeof(*elements)))) + { + ERR("Failed to allocate %u elements.", element_count); + spirv_compiler_error(compiler, VKD3D_SHADER_ERROR_SPV_OUT_OF_MEMORY, + "Failed to allocate %u constant array elements.", element_count); + return 0; + } + + switch (icb->data_type) + { + case VKD3D_DATA_FLOAT: + case VKD3D_DATA_INT: + case VKD3D_DATA_UINT: + for (i = 0; i < element_count; ++i) + elements[i] = vkd3d_spirv_get_op_constant(builder, elem_type_id, icb->data[i]); + break; + case VKD3D_DATA_DOUBLE: + case VKD3D_DATA_UINT64: + { + uint64_t *data = (uint64_t *)icb->data; + for (i = 0; i < element_count; ++i) + elements[i] = vkd3d_spirv_get_op_constant64(builder, elem_type_id, data[i]); + break; + } + default: + FIXME("Unhandled data type %u.\n", icb->data_type); + spirv_compiler_error(compiler, VKD3D_SHADER_ERROR_SPV_INVALID_TYPE, + "Immediate constant buffer data type %u is unhandled.", icb->data_type); + break; + } + + const_id = vkd3d_spirv_build_op_constant_composite(builder, type_id, elements, element_count); + vkd3d_free(elements); + return const_id; +} + static const struct ssa_register_info *spirv_compiler_get_ssa_register_info(const struct spirv_compiler *compiler, const struct vkd3d_shader_register *reg) { @@ -5487,37 +5552,39 @@ static void spirv_compiler_emit_dcl_indexable_temp(struct spirv_compiler *compil { const struct vkd3d_shader_indexable_temp *temp = &instruction->declaration.indexable_temp; struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; + uint32_t id, type_id, length_id, ptr_type_id, init_id = 0; enum vkd3d_shader_component_type component_type; struct vkd3d_shader_register reg; struct vkd3d_symbol reg_symbol; + SpvStorageClass storage_class; size_t function_location; - uint32_t id; + + storage_class = SpvStorageClassFunction;
vsir_register_init(®, VKD3DSPR_IDXTEMP, VKD3D_DATA_FLOAT, 1); reg.idx[0].offset = temp->register_idx;
if (temp->alignment) WARN("Ignoring alignment %u.\n", temp->alignment); - if (temp->initialiser) - { - FIXME("Initialisers are not supported.\n"); - spirv_compiler_error(compiler, VKD3D_SHADER_ERROR_SPV_NOT_IMPLEMENTED, - "Initialisers for indexable temps are not supported."); - }
function_location = spirv_compiler_get_current_function_location(compiler); vkd3d_spirv_begin_function_stream_insertion(builder, function_location);
component_type = vkd3d_component_type_from_data_type(temp->data_type); - id = spirv_compiler_emit_array_variable(compiler, &builder->function_stream, - SpvStorageClassFunction, component_type, temp->component_count, &temp->register_size, 1); + type_id = vkd3d_spirv_get_type_id(builder, component_type, temp->component_count); + length_id = spirv_compiler_get_constant_uint(compiler, temp->register_size); + type_id = vkd3d_spirv_get_op_type_array(builder, type_id, length_id); + ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, storage_class, type_id); + if (temp->initialiser) + init_id = spirv_compiler_emit_constant_array(compiler, temp->initialiser); + id = vkd3d_spirv_build_op_variable(builder, &builder->function_stream, ptr_type_id, storage_class, init_id);
spirv_compiler_emit_register_debug_name(builder, id, ®);
vkd3d_spirv_end_function_stream_insertion(builder);
vkd3d_symbol_make_register(®_symbol, ®); - vkd3d_symbol_set_register_info(®_symbol, id, SpvStorageClassFunction, + vkd3d_symbol_set_register_info(®_symbol, id, storage_class, component_type, vkd3d_write_mask_from_component_count(temp->component_count)); spirv_compiler_put_symbol(compiler, ®_symbol); } diff --git a/tests/hlsl/matrix-indexing.shader_test b/tests/hlsl/matrix-indexing.shader_test index 5024c8ed3..f44ba63ef 100644 --- a/tests/hlsl/matrix-indexing.shader_test +++ b/tests/hlsl/matrix-indexing.shader_test @@ -120,7 +120,7 @@ float4 main() : sv_target
[test] uniform 0 float 2 -todo(sm>=6) draw quad +draw quad probe all rgba (8, 9, 10, 11)
@@ -136,5 +136,5 @@ float4 main() : sv_target
[test] uniform 0 float 3 -todo(sm>=6) draw quad +draw quad probe all rgba (12, 13, 14, 15) diff --git a/tests/hlsl/non-const-indexing.shader_test b/tests/hlsl/non-const-indexing.shader_test index 3a1e12acc..5c8e1db4a 100644 --- a/tests/hlsl/non-const-indexing.shader_test +++ b/tests/hlsl/non-const-indexing.shader_test @@ -36,16 +36,16 @@ float4 main() : SV_TARGET
[test] uniform 0 float 0 -todo(sm>=6) draw quad +draw quad probe all rgba (11.0, 11.0, 11.0, 11.0) uniform 0 float 1 -todo(sm>=6) draw quad +draw quad probe all rgba (12.0, 12.0, 12.0, 12.0) uniform 0 float 2 -todo(sm>=6) draw quad +draw quad probe all rgba (13.0, 13.0, 13.0, 13.0) uniform 0 float 3 -todo(sm>=6) draw quad +draw quad probe all rgba (14.0, 14.0, 14.0, 14.0)
@@ -61,8 +61,8 @@ float4 main() : sv_target
[test] uniform 0 float 2.3 -todo(sm>=6) draw quad -todo(sm>=6) probe all rgba (3, 3, 3, 3) +draw quad +probe all rgba (3, 3, 3, 3)
[pixel shader] @@ -77,16 +77,16 @@ float4 main() : SV_TARGET
[test] uniform 0 float 0 -todo(sm>=6) draw quad +draw quad probe all rgba (21.0, 1.0, 24.0, 0.0) uniform 0 float 1 -todo(sm>=6) draw quad +draw quad probe all rgba (22.0, 0.0, 23.0, 1.0) uniform 0 float 2 -todo(sm>=6) draw quad +draw quad probe all rgba (23.0, 1.0, 22.0, 0.0) uniform 0 float 3 -todo(sm>=6) draw quad +draw quad probe all rgba (24.0, 0.0, 21.0, 1.0)
@@ -102,17 +102,17 @@ float4 main() : sv_target
[test] uniform 0 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 0 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 0 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 0 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] @@ -130,7 +130,7 @@ float4 main() : sv_target
[test] uniform 0 float4 0 0 2.4 0 -todo(sm>=6) draw quad +draw quad probe all rgba (1.0, 120.0, 90.0, 4.0)
diff --git a/tests/hlsl/vector-indexing-uniform.shader_test b/tests/hlsl/vector-indexing-uniform.shader_test index 3501f3af7..e5ffbdd02 100644 --- a/tests/hlsl/vector-indexing-uniform.shader_test +++ b/tests/hlsl/vector-indexing-uniform.shader_test @@ -12,5 +12,5 @@ float4 main() : SV_TARGET
[test] uniform 0 float 2 -todo(sm>=6) draw quad +draw quad probe all rgba (0.5, 0.3, 0.8, 0.2)
From: Conor McCarthy cmccarthy@codeweavers.com
--- libs/vkd3d-shader/spirv.c | 40 ++++++++++++++++++--------------------- 1 file changed, 18 insertions(+), 22 deletions(-)
diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c index 7d5fe2d52..d77638d50 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -3767,18 +3767,24 @@ static uint32_t spirv_compiler_emit_load_scalar(struct spirv_compiler *compiler, }
static uint32_t spirv_compiler_emit_constant_array(struct spirv_compiler *compiler, - const struct vkd3d_shader_immediate_constant_buffer *icb) + const struct vkd3d_shader_immediate_constant_buffer *icb, uint32_t *type_id_out) { uint32_t *elements, elem_type_id, length_id, type_id, const_id; struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; - unsigned int i, element_count; + enum vkd3d_shader_component_type component_type; + unsigned int i, element_count, component_count;
element_count = icb->element_count;
- elem_type_id = vkd3d_spirv_get_type_id_for_data_type(builder, icb->data_type, 1); + component_type = vkd3d_component_type_from_data_type(icb->data_type); + component_count = icb->component_count; + elem_type_id = vkd3d_spirv_get_type_id_for_data_type(builder, icb->data_type, component_count); length_id = spirv_compiler_get_constant_uint(compiler, element_count); type_id = vkd3d_spirv_get_op_type_array(builder, elem_type_id, length_id);
+ if (type_id_out) + *type_id_out = type_id; + if (icb->is_null) { /* All values are null. Workgroup memory initialisers require OpConstantNull. */ @@ -3799,14 +3805,16 @@ static uint32_t spirv_compiler_emit_constant_array(struct spirv_compiler *compil case VKD3D_DATA_INT: case VKD3D_DATA_UINT: for (i = 0; i < element_count; ++i) - elements[i] = vkd3d_spirv_get_op_constant(builder, elem_type_id, icb->data[i]); + elements[i] = spirv_compiler_get_constant(compiler, component_type, component_count, + &icb->data[component_count * i]); break; case VKD3D_DATA_DOUBLE: case VKD3D_DATA_UINT64: { uint64_t *data = (uint64_t *)icb->data; for (i = 0; i < element_count; ++i) - elements[i] = vkd3d_spirv_get_op_constant64(builder, elem_type_id, data[i]); + elements[i] = spirv_compiler_get_constant64(compiler, component_type, component_count, + &data[component_count * i]); break; } default: @@ -5576,7 +5584,7 @@ static void spirv_compiler_emit_dcl_indexable_temp(struct spirv_compiler *compil type_id = vkd3d_spirv_get_op_type_array(builder, type_id, length_id); ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, storage_class, type_id); if (temp->initialiser) - init_id = spirv_compiler_emit_constant_array(compiler, temp->initialiser); + init_id = spirv_compiler_emit_constant_array(compiler, temp->initialiser, NULL); id = vkd3d_spirv_build_op_variable(builder, &builder->function_stream, ptr_type_id, storage_class, init_id);
spirv_compiler_emit_register_debug_name(builder, id, ®); @@ -5803,34 +5811,22 @@ static void spirv_compiler_emit_dcl_immediate_constant_buffer(struct spirv_compi const struct vkd3d_shader_instruction *instruction) { const struct vkd3d_shader_immediate_constant_buffer *icb = instruction->declaration.icb; - uint32_t *elements, length_id, type_id, const_id, ptr_type_id, icb_id; struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; + uint32_t type_id, const_id, ptr_type_id, icb_id; struct vkd3d_shader_register reg; struct vkd3d_symbol reg_symbol; - unsigned int i;
- assert(icb->data_type == VKD3D_DATA_FLOAT); - assert(icb->component_count == VKD3D_VEC4_SIZE); - - if (!(elements = vkd3d_calloc(icb->element_count, sizeof(*elements)))) - return; - for (i = 0; i < icb->element_count; ++i) - elements[i] = spirv_compiler_get_constant(compiler, - VKD3D_SHADER_COMPONENT_FLOAT, VKD3D_VEC4_SIZE, &icb->data[4 * i]); - type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_FLOAT, VKD3D_VEC4_SIZE); - length_id = spirv_compiler_get_constant_uint(compiler, icb->element_count); - type_id = vkd3d_spirv_get_op_type_array(builder, type_id, length_id); - const_id = vkd3d_spirv_build_op_constant_composite(builder, type_id, elements, icb->element_count); + const_id = spirv_compiler_emit_constant_array(compiler, icb, &type_id); ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, SpvStorageClassPrivate, type_id); icb_id = vkd3d_spirv_build_op_variable(builder, &builder->global_stream, ptr_type_id, SpvStorageClassPrivate, const_id); vkd3d_spirv_build_op_name(builder, icb_id, "icb"); - vkd3d_free(elements);
vsir_register_init(®, VKD3DSPR_IMMCONSTBUFFER, VKD3D_DATA_FLOAT, 0); vkd3d_symbol_make_register(®_symbol, ®); vkd3d_symbol_set_register_info(®_symbol, icb_id, SpvStorageClassPrivate, - VKD3D_SHADER_COMPONENT_FLOAT, VKD3DSP_WRITEMASK_ALL); + vkd3d_component_type_from_data_type(icb->data_type), + vkd3d_write_mask_from_component_count(icb->component_count)); spirv_compiler_put_symbol(compiler, ®_symbol); }
From: Conor McCarthy cmccarthy@codeweavers.com
--- libs/vkd3d-shader/dxil.c | 2 ++ libs/vkd3d-shader/spirv.c | 6 ++++-- libs/vkd3d-shader/tpf.c | 10 ++++++++++ libs/vkd3d-shader/vkd3d_shader_private.h | 1 + 4 files changed, 17 insertions(+), 2 deletions(-)
diff --git a/libs/vkd3d-shader/dxil.c b/libs/vkd3d-shader/dxil.c index 6b4ed3bed..4ec056aa1 100644 --- a/libs/vkd3d-shader/dxil.c +++ b/libs/vkd3d-shader/dxil.c @@ -581,6 +581,7 @@ struct sm6_parser size_t descriptor_count;
unsigned int indexable_temp_count; + unsigned int icb_count;
struct sm6_value *values; size_t value_count; @@ -2433,6 +2434,7 @@ static enum vkd3d_result value_allocate_constant_array(struct sm6_value *dst, co dst->value_type = VALUE_TYPE_ICB; dst->u.icb = icb;
+ icb->register_idx = sm6->icb_count++; icb->data_type = vkd3d_data_type_from_sm6_type(elem_type); icb->element_count = type->u.array.count; icb->component_count = 1; diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c index d77638d50..b17fe422f 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -2162,6 +2162,7 @@ static void vkd3d_symbol_make_register(struct vkd3d_symbol *symbol, break;
case VKD3DSPR_IMMCONSTBUFFER: + symbol->key.reg.idx = reg->idx[0].offset; break;
default: @@ -3508,7 +3509,7 @@ static void spirv_compiler_emit_dereference_register(struct spirv_compiler *comp } else if (reg->type == VKD3DSPR_IMMCONSTBUFFER) { - indexes[index_count++] = spirv_compiler_emit_register_addressing(compiler, ®->idx[0]); + indexes[index_count++] = spirv_compiler_emit_register_addressing(compiler, ®->idx[reg->idx_count - 1]); } else if (reg->type == VKD3DSPR_IDXTEMP) { @@ -5822,7 +5823,8 @@ static void spirv_compiler_emit_dcl_immediate_constant_buffer(struct spirv_compi ptr_type_id, SpvStorageClassPrivate, const_id); vkd3d_spirv_build_op_name(builder, icb_id, "icb");
- vsir_register_init(®, VKD3DSPR_IMMCONSTBUFFER, VKD3D_DATA_FLOAT, 0); + vsir_register_init(®, VKD3DSPR_IMMCONSTBUFFER, VKD3D_DATA_FLOAT, 1); + reg.idx[0].offset = icb->register_idx; vkd3d_symbol_make_register(®_symbol, ®); vkd3d_symbol_set_register_info(®_symbol, icb_id, SpvStorageClassPrivate, vkd3d_component_type_from_data_type(icb->data_type), diff --git a/libs/vkd3d-shader/tpf.c b/libs/vkd3d-shader/tpf.c index a34f9042b..5e89197bf 100644 --- a/libs/vkd3d-shader/tpf.c +++ b/libs/vkd3d-shader/tpf.c @@ -792,6 +792,7 @@ static void shader_sm4_read_shader_data(struct vkd3d_shader_instruction *ins, ui ins->handler_idx = VKD3DSIH_INVALID; return; } + icb->register_idx = 0; icb->data_type = VKD3D_DATA_FLOAT; icb->component_count = VKD3D_VEC4_SIZE; icb->element_count = icb_size / VKD3D_VEC4_SIZE; @@ -1931,6 +1932,15 @@ static bool shader_sm4_read_param(struct vkd3d_shader_sm4_parser *priv, const ui break; } } + else if (register_type == VKD3D_SM4_RT_IMMCONSTBUFFER) + { + if (param->idx_count != 1) + { + WARN("Unexpected idx count %u.\n", param->idx_count); + vkd3d_shader_parser_error(&priv->p, VKD3D_SHADER_ERROR_TPF_INVALID_REGISTER_INDEX_COUNT, + "Invalid index count %u for immediate const buffer register; expected count 1.", param->idx_count); + } + } else if (!shader_is_sm_5_1(priv) && vsir_register_is_descriptor(param)) { /* SM5.1 places a symbol identifier in idx[0] and moves diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h index edc617948..a57045911 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -793,6 +793,7 @@ struct vkd3d_shader_version
struct vkd3d_shader_immediate_constant_buffer { + unsigned int register_idx; enum vkd3d_data_type data_type; /* total count is element_count * component_count */ unsigned int element_count;
From: Conor McCarthy cmccarthy@codeweavers.com
--- libs/vkd3d-shader/dxil.c | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-)
diff --git a/libs/vkd3d-shader/dxil.c b/libs/vkd3d-shader/dxil.c index 4ec056aa1..c0a2955e9 100644 --- a/libs/vkd3d-shader/dxil.c +++ b/libs/vkd3d-shader/dxil.c @@ -2630,6 +2630,18 @@ static struct vkd3d_shader_instruction *sm6_parser_add_instruction(struct sm6_pa return ins; }
+static void sm6_parser_declare_icb(struct sm6_parser *sm6, const struct sm6_type *elem_type, unsigned int count, + unsigned int alignment, unsigned int init, struct sm6_value *dst) +{ + enum vkd3d_data_type data_type = vkd3d_data_type_from_sm6_type(elem_type); + struct vkd3d_shader_instruction *ins; + + ins = sm6_parser_add_instruction(sm6, VKD3DSIH_DCL_IMMEDIATE_CONSTANT_BUFFER); + /* The icb value index will be resolved later so forward references can be handled. */ + ins->declaration.icb = (void *)(intptr_t)init; + register_init_with_id(&dst->u.reg, VKD3DSPR_IMMCONSTBUFFER, data_type, init); +} + static void sm6_parser_declare_indexable_temp(struct sm6_parser *sm6, const struct sm6_type *elem_type, unsigned int count, unsigned int alignment, unsigned int init, struct sm6_value *dst) { @@ -2766,7 +2778,10 @@ static bool sm6_parser_declare_global(struct sm6_parser *sm6, const struct dxil_
if (address_space == ADDRESS_SPACE_DEFAULT) { - sm6_parser_declare_indexable_temp(sm6, scalar_type, count, alignment, init, dst); + if (is_constant) + sm6_parser_declare_icb(sm6, scalar_type, count, alignment, init, dst); + else + sm6_parser_declare_indexable_temp(sm6, scalar_type, count, alignment, init, dst); } else if (address_space == ADDRESS_SPACE_GROUPSHARED) { @@ -2810,11 +2825,11 @@ static const struct vkd3d_shader_immediate_constant_buffer *resolve_forward_init static enum vkd3d_result sm6_parser_globals_init(struct sm6_parser *sm6) { const struct dxil_block *block = &sm6->root_block; + size_t i, base_value_idx = sm6->value_count; struct vkd3d_shader_instruction *ins; const struct dxil_record *record; enum vkd3d_result ret; uint64_t version; - size_t i;
sm6->p.location.line = block->id; sm6->p.location.column = 0; @@ -2872,6 +2887,21 @@ static enum vkd3d_result sm6_parser_globals_init(struct sm6_parser *sm6) ins->declaration.indexable_temp.initialiser = resolve_forward_initialiser( (uintptr_t)ins->declaration.indexable_temp.initialiser, sm6); } + else if (ins->handler_idx == VKD3DSIH_DCL_IMMEDIATE_CONSTANT_BUFFER) + { + ins->declaration.icb = resolve_forward_initialiser((uintptr_t)ins->declaration.icb, sm6); + } + } + for (i = base_value_idx; i < sm6->value_count; ++i) + { + const struct vkd3d_shader_immediate_constant_buffer *icb; + struct sm6_value *value = &sm6->values[i]; + + if (!sm6_value_is_register(value) || value->u.reg.type != VKD3DSPR_IMMCONSTBUFFER) + continue; + + if ((icb = resolve_forward_initialiser(value->u.reg.idx[0].offset, sm6))) + value->u.reg.idx[0].offset = icb->register_idx; }
return VKD3D_OK;
From: Conor McCarthy cmccarthy@codeweavers.com
--- tests/hlsl/non-const-indexing.shader_test | 26 +++++++++++++++++++++++ 1 file changed, 26 insertions(+)
diff --git a/tests/hlsl/non-const-indexing.shader_test b/tests/hlsl/non-const-indexing.shader_test index 5c8e1db4a..27ea657c5 100644 --- a/tests/hlsl/non-const-indexing.shader_test +++ b/tests/hlsl/non-const-indexing.shader_test @@ -194,3 +194,29 @@ uniform 8 int 3 uniform 9 int 4 todo(sm>=6) draw quad todo(sm>=6) probe all rgba (1126, 3344, 5566, 3788) + + +[pixel shader] +uniform float4 f[4]; +uniform uint4 u; +uniform uint4 v; + +float4 main() : sv_target +{ + float temp[4]; + temp[0] = f[u.x]; + temp[1] = f[u.y]; + temp[2] = f[u.z]; + temp[3] = f[u.w]; + return float4(temp[v.x], temp[v.y], temp[v.z], temp[v.w]); +} + +[test] +uniform 0 float 1.0 +uniform 4 float 2.0 +uniform 8 float 3.0 +uniform 12 float 4.0 +uniform 16 uint4 3 1 0 2 +uniform 20 uint4 0 3 1 2 +todo(sm>=6) draw quad +todo(sm>=6) probe all rgba (4.0, 3.0, 2.0, 1.0)
From: Conor McCarthy cmccarthy@codeweavers.com
--- libs/vkd3d-shader/dxil.c | 90 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 86 insertions(+), 4 deletions(-)
diff --git a/libs/vkd3d-shader/dxil.c b/libs/vkd3d-shader/dxil.c index c0a2955e9..adc4e7841 100644 --- a/libs/vkd3d-shader/dxil.c +++ b/libs/vkd3d-shader/dxil.c @@ -29,6 +29,9 @@ static const uint64_t MAX_ALIGNMENT_EXPONENT = 29; static const uint64_t GLOBALVAR_FLAG_IS_CONSTANT = 1; static const uint64_t GLOBALVAR_FLAG_EXPLICIT_TYPE = 2; static const unsigned int GLOBALVAR_ADDRESS_SPACE_SHIFT = 2; +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 unsigned int dx_max_thread_group_size[3] = {1024, 1024, 64}; @@ -2643,12 +2646,15 @@ static void sm6_parser_declare_icb(struct sm6_parser *sm6, const struct sm6_type }
static void sm6_parser_declare_indexable_temp(struct sm6_parser *sm6, const struct sm6_type *elem_type, - unsigned int count, unsigned int alignment, unsigned int init, struct sm6_value *dst) + unsigned int count, unsigned int alignment, unsigned int init, struct vkd3d_shader_instruction *ins, + struct sm6_value *dst) { enum vkd3d_data_type data_type = vkd3d_data_type_from_sm6_type(elem_type); - struct vkd3d_shader_instruction *ins;
- ins = sm6_parser_add_instruction(sm6, VKD3DSIH_DCL_INDEXABLE_TEMP); + if (ins) + vsir_instruction_init(ins, &sm6->p.location, VKD3DSIH_DCL_INDEXABLE_TEMP); + else + ins = sm6_parser_add_instruction(sm6, VKD3DSIH_DCL_INDEXABLE_TEMP); ins->declaration.indexable_temp.register_idx = sm6->indexable_temp_count++; ins->declaration.indexable_temp.register_size = count; ins->declaration.indexable_temp.alignment = alignment; @@ -2781,7 +2787,7 @@ static bool sm6_parser_declare_global(struct sm6_parser *sm6, const struct dxil_ if (is_constant) sm6_parser_declare_icb(sm6, scalar_type, count, alignment, init, dst); else - sm6_parser_declare_indexable_temp(sm6, scalar_type, count, alignment, init, dst); + sm6_parser_declare_indexable_temp(sm6, scalar_type, count, alignment, init, NULL, dst); } else if (address_space == ADDRESS_SPACE_GROUPSHARED) { @@ -3025,6 +3031,79 @@ static struct sm6_block *sm6_block_create() return block; }
+static void sm6_parser_emit_alloca(struct sm6_parser *sm6, const struct dxil_record *record, + struct vkd3d_shader_instruction *ins, struct sm6_value *dst) +{ + const struct sm6_type *type[2], *elem_type; + const struct sm6_value *size; + unsigned int i, alignment; + uint64_t packed_operands; + + if (!dxil_record_validate_operand_count(record, 4, 4, sm6)) + return; + + for (i = 0; i < 2; ++i) + { + if (!(type[i] = sm6_parser_get_type(sm6, record->operands[i]))) + return; + } + + packed_operands = record->operands[3]; + if (packed_operands & ALLOCA_FLAG_IN_ALLOCA) + WARN("Ignoring in_alloca flag.\n"); + if (!(packed_operands & ALLOCA_FLAG_EXPLICIT_TYPE)) + { + FIXME("Unhandled implicit type.\n"); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, + "Implicit result type for ALLOCA instructions is not supported."); + return; + } + packed_operands &= ~(ALLOCA_FLAG_IN_ALLOCA | ALLOCA_FLAG_EXPLICIT_TYPE); + + if (!sm6_type_is_array(type[0]) || !sm6_type_is_numeric(elem_type = type[0]->u.array.elem_type)) + { + WARN("Type is not a numeric array.\n"); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, + "Result type of an ALLOCA instruction is not a numeric array."); + return; + } + if (!sm6_type_is_integer(type[1])) + { + WARN("Size operand type is not scalar integer.\n"); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, + "Size operand type of an ALLOCA instruction is not scalar integer."); + return; + } + + if (!(dst->type = sm6_type_get_pointer_to_type(type[0], ADDRESS_SPACE_DEFAULT, sm6))) + { + WARN("Failed to get pointer type for type class %u.\n", type[0]->class); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_MODULE, + "Module does not define a pointer type for an ALLOCA instruction."); + return; + } + + if (!(size = sm6_parser_get_value_safe(sm6, record->operands[2]))) + return; + /* A size of 1 means one instance of type[0], i.e. one array. */ + if (sm6_value_get_constant_uint(size) != 1) + { + FIXME("Allocation size is not 1.\n"); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, + "ALLOCA instruction allocation sizes other than 1 are not supported."); + return; + } + + if (!bitcode_parse_alignment(packed_operands & ALLOCA_ALIGNMENT_MASK, &alignment)) + WARN("Invalid alignment %"PRIu64".\n", packed_operands); + packed_operands &= ~ALLOCA_ALIGNMENT_MASK; + + if (packed_operands) + WARN("Ignoring flags %#"PRIx64".\n", packed_operands); + + sm6_parser_declare_indexable_temp(sm6, elem_type, type[0]->u.array.count, alignment, 0, ins, dst); +} + static enum vkd3d_shader_opcode map_binary_op(uint64_t code, const struct sm6_type *type_a, const struct sm6_type *type_b, struct sm6_parser *sm6) { @@ -4273,6 +4352,9 @@ static enum vkd3d_result sm6_parser_function_init(struct sm6_parser *sm6, const record = block->records[i]; switch (record->code) { + case FUNC_CODE_INST_ALLOCA: + sm6_parser_emit_alloca(sm6, record, ins, dst); + break; case FUNC_CODE_INST_BINOP: sm6_parser_emit_binop(sm6, record, ins, dst); break;
From: Conor McCarthy cmccarthy@codeweavers.com
--- libs/vkd3d-shader/dxil.c | 60 ++++++++++++++++++++++- tests/hlsl/expr-indexing.shader_test | 8 +-- tests/hlsl/non-const-indexing.shader_test | 20 ++++---- 3 files changed, 72 insertions(+), 16 deletions(-)
diff --git a/libs/vkd3d-shader/dxil.c b/libs/vkd3d-shader/dxil.c index adc4e7841..9fb6b8103 100644 --- a/libs/vkd3d-shader/dxil.c +++ b/libs/vkd3d-shader/dxil.c @@ -2815,17 +2815,19 @@ static const struct vkd3d_shader_immediate_constant_buffer *resolve_forward_init
assert(index); --index; - if (!(value = sm6_parser_get_value_safe(sm6, index)) || !sm6_value_is_icb(value)) + if (!(value = sm6_parser_get_value_safe(sm6, index)) || (!sm6_value_is_icb(value) && !sm6_value_is_undef(value))) { WARN("Invalid initialiser index %zu.\n", index); vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, "Global variable initialiser value index %zu is invalid.", index); return NULL; } - else + else if (sm6_value_is_icb(value)) { return value->u.icb; } + /* In VSIR, initialisation with undefined values of objects is implied, not explicit. */ + return NULL; }
static enum vkd3d_result sm6_parser_globals_init(struct sm6_parser *sm6) @@ -4177,6 +4179,57 @@ static void sm6_parser_emit_ret(struct sm6_parser *sm6, const struct dxil_record ins->handler_idx = VKD3DSIH_NOP; }
+static void sm6_parser_emit_store(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; + struct vkd3d_shader_dst_param *dst_param; + const struct sm6_type *pointee_type; + const struct sm6_value *ptr, *src; + unsigned int i = 0, alignment; + uint64_t alignment_code; + + if (!(ptr = sm6_parser_get_value_by_ref(sm6, record, NULL, &i)) + || !sm6_value_validate_is_register(ptr, sm6) + || !sm6_value_validate_is_pointer(ptr, sm6)) + { + return; + } + + pointee_type = ptr->type->u.pointer.type; + if (!(src = sm6_parser_get_value_by_ref(sm6, record, pointee_type, &i))) + return; + if (!sm6_value_validate_is_numeric(src, sm6)) + return; + + if (pointee_type != src->type) + { + WARN("Type mismatch.\n"); + vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_TYPE_MISMATCH, + "Type mismatch in pointer store arguments."); + } + + if (!dxil_record_validate_operand_count(record, i + 2, i + 2, sm6)) + return; + + alignment_code = record->operands[i++]; + if (!bitcode_parse_alignment(alignment_code, &alignment)) + WARN("Invalid alignment %"PRIu64".\n", alignment_code); + + if (record->operands[i]) + WARN("Ignoring volatile modifier.\n"); + + vsir_instruction_init(ins, &sm6->p.location, VKD3DSIH_MOV); + + src_param = instruction_src_params_alloc(ins, 1, sm6); + src_param_init_from_value(&src_param[0], src); + + dst_param = instruction_dst_params_alloc(ins, 1, sm6); + dst_param_init(dst_param); + dst_param->reg = ptr->u.reg; + dst_param->reg.alignment = alignment; +} + static void sm6_parser_emit_vselect(struct sm6_parser *sm6, const struct dxil_record *record, struct vkd3d_shader_instruction *ins, struct sm6_value *dst) { @@ -4381,6 +4434,9 @@ static enum vkd3d_result sm6_parser_function_init(struct sm6_parser *sm6, const is_terminator = true; ret_found = true; break; + case FUNC_CODE_INST_STORE: + sm6_parser_emit_store(sm6, record, ins, dst); + break; case FUNC_CODE_INST_VSELECT: sm6_parser_emit_vselect(sm6, record, ins, dst); break; diff --git a/tests/hlsl/expr-indexing.shader_test b/tests/hlsl/expr-indexing.shader_test index c11fa6540..3dcc5727e 100644 --- a/tests/hlsl/expr-indexing.shader_test +++ b/tests/hlsl/expr-indexing.shader_test @@ -26,7 +26,7 @@ float4 main() : sv_target uniform 0 float4 1.0 2.0 3.0 4.0 uniform 4 float4 5.0 6.0 7.0 8.0 uniform 8 float 2 -todo(sm>=6) draw quad +draw quad probe all rgba (10.0, 10.0, 10.0, 10.0)
@@ -56,10 +56,10 @@ float4 main() : sv_target [test] uniform 0 float4 1.0 2.0 3.0 4.0 uniform 4 float 0 -todo(sm>=6) draw quad +draw quad probe all rgba (4.0, 4.0, 4.0, 4.0) uniform 4 float 2 -todo(sm>=6) draw quad +draw quad probe all rgba (1.0, 1.0, 1.0, 1.0)
@@ -99,5 +99,5 @@ float4 main() : sv_target [test] uniform 0 float4 1.0 2.0 3.0 4.0 uniform 4 float 1 -todo(sm>=6) draw quad +draw quad probe all rgba (2.0, 2.0, 2.0, 2.0) diff --git a/tests/hlsl/non-const-indexing.shader_test b/tests/hlsl/non-const-indexing.shader_test index 27ea657c5..91e3d48c9 100644 --- a/tests/hlsl/non-const-indexing.shader_test +++ b/tests/hlsl/non-const-indexing.shader_test @@ -155,16 +155,16 @@ float4 main() : sv_target [test] uniform 0 int 0 uniform 1 int 0 -todo(sm>=6) draw quad -todo(sm>=6) probe all rgba (100, 6, 7, 8) +draw quad +probe all rgba (100, 6, 7, 8) uniform 0 int 2 uniform 1 int 2 -todo(sm>=6) draw quad -todo(sm>=6) probe all rgba (5, 6, 100, 8) +draw quad +probe all rgba (5, 6, 100, 8) uniform 0 int 1 uniform 1 int 3 -todo(sm>=6) draw quad -todo(sm>=6) probe all rgba (5, 6, 7, 4) +draw quad +probe all rgba (5, 6, 7, 4)
[pixel shader] @@ -192,8 +192,8 @@ uniform 0 float4 1 2 3 4 uniform 4 float4 5 6 7 8 uniform 8 int 3 uniform 9 int 4 -todo(sm>=6) draw quad -todo(sm>=6) probe all rgba (1126, 3344, 5566, 3788) +draw quad +probe all rgba (1126, 3344, 5566, 3788)
[pixel shader] @@ -218,5 +218,5 @@ uniform 8 float 3.0 uniform 12 float 4.0 uniform 16 uint4 3 1 0 2 uniform 20 uint4 0 3 1 2 -todo(sm>=6) draw quad -todo(sm>=6) probe all rgba (4.0, 3.0, 2.0, 1.0) +draw quad +probe all rgba (4.0, 3.0, 2.0, 1.0)
I added support for globals with undefined initialisers, but I have been unable to find out why dxc would compile an array as a global with an undefined initialiser instead of using `alloca`. It occurs in game shaders.