Goes atop !459. The last five commits belong to this MR.
From: Conor McCarthy cmccarthy@codeweavers.com
Where SM >= 6.0 returns different results than earlier models it is convenient to use conditional 'probe' lines containing different expected values. --- tests/hlsl/arithmetic-int.shader_test | 9 +++------ tests/hlsl/duplicate-modifiers.shader_test | 7 ++----- tests/hlsl/entry-point-semantics.shader_test | 17 ++++++----------- tests/hlsl/side-effects.shader_test | 9 +++------ tests/shader_runner.c | 5 +++++ 5 files changed, 19 insertions(+), 28 deletions(-)
diff --git a/tests/hlsl/arithmetic-int.shader_test b/tests/hlsl/arithmetic-int.shader_test index f2044c42c..1128a004f 100644 --- a/tests/hlsl/arithmetic-int.shader_test +++ b/tests/hlsl/arithmetic-int.shader_test @@ -104,8 +104,6 @@ probe all rgba (0.0, 0.0, 0.0, 0.0)
[require] shader model >= 4.0 -% dxcompiler performs this calculation on unsigned values and emits zero. -shader model < 6.0
[pixel shader] float4 main() : SV_TARGET @@ -118,10 +116,9 @@ float4 main() : SV_TARGET
[test] draw quad -probe all rgba (-2147483648.0, -2147483648.0, -2147483648.0, -2147483648.0) - -[require] -shader model >= 4.0 +if(sm<6) probe all rgba (-2147483648.0, -2147483648.0, -2147483648.0, -2147483648.0) +% dxcompiler performs this calculation on unsigned values and emits zero. +if(sm>=6) probe all rgba (0.0, 0.0, 0.0, 0.0)
[pixel shader] float4 main() : sv_target diff --git a/tests/hlsl/duplicate-modifiers.shader_test b/tests/hlsl/duplicate-modifiers.shader_test index bf1d9c1b8..8a3838ffe 100644 --- a/tests/hlsl/duplicate-modifiers.shader_test +++ b/tests/hlsl/duplicate-modifiers.shader_test @@ -1,7 +1,3 @@ -% Returns (0.1, 0.3, 0.2, 0.4) with dxcompiler -[require] -shader model < 6.0 - [pixel shader] typedef const precise row_major float2x2 mat_t; float4 main() : sv_target @@ -12,4 +8,5 @@ float4 main() : sv_target
[test] draw quad -probe all rgba (0.1, 0.2, 0.3, 0.4) +if(sm<6) probe all rgba (0.1, 0.2, 0.3, 0.4) +if(sm>=6) probe all rgba (0.1, 0.3, 0.2, 0.4) diff --git a/tests/hlsl/entry-point-semantics.shader_test b/tests/hlsl/entry-point-semantics.shader_test index d177b0376..e4854a294 100644 --- a/tests/hlsl/entry-point-semantics.shader_test +++ b/tests/hlsl/entry-point-semantics.shader_test @@ -104,11 +104,6 @@ draw quad probe (0, 0) rgba (10.0, 11.0, 30.0, 31.0)
-% dxcompiler emits correct array addressing. -[require] -shader model < 6.0 - - % Arrays (even multi-dimensional) of struct elements are allowed. The fields in the different struct % elements get the same indexes. [pixel shader] @@ -125,7 +120,9 @@ float4 main(in apple aps[2][2]) : sv_target
[test] draw quad -todo(sm>=6) probe (0, 0) rgba (10.0, 10.0, 20.0, 20.0) +if(sm<6) probe (0, 0) rgba (10.0, 10.0, 20.0, 20.0) +% dxcompiler emits correct array addressing. +if(sm>=6) probe (0, 0) rgba (10.0, 40.0, 10.0, 10.0)
[pixel shader] @@ -147,11 +144,9 @@ float4 main(in banana bans[2]) : sv_target
[test] draw quad -todo(sm>=6) probe (0, 0) rgba (10.0, 11.0, 20.0, 21.0) - - -[require] -% reset requirements +if(sm<6) probe (0, 0) rgba (10.0, 11.0, 20.0, 21.0) +% dxcompiler emits correct array addressing. +if(sm>=6) probe (0, 0) rgba (10.0, 11.0, 40.0, 41.0)
[pixel shader fail] diff --git a/tests/hlsl/side-effects.shader_test b/tests/hlsl/side-effects.shader_test index f41e98510..c49a907ba 100644 --- a/tests/hlsl/side-effects.shader_test +++ b/tests/hlsl/side-effects.shader_test @@ -27,11 +27,6 @@ draw quad probe all rgba (11.0, 11.0, 11.0, 11.0)
-% dxcompiler performs the first call to func() before the array index call. -[require] -shader model < 6.0 - - [pixel shader] float4 func(void) { @@ -49,4 +44,6 @@ float4 main() : sv_target
[test] draw quad -probe all rgba (2.2, 2.2, 2.2, 2.2) +if(sm<6) probe all rgba (2.2, 2.2, 2.2, 2.2) +% dxcompiler performs the first call to func() before the array index call. +if(sm>=6) probe all rgba (1.3, 1.3, 1.3, 1.3) diff --git a/tests/shader_runner.c b/tests/shader_runner.c index dadfe3338..def7ec877 100644 --- a/tests/shader_runner.c +++ b/tests/shader_runner.c @@ -496,6 +496,11 @@ static void parse_test_directive(struct shader_runner *runner, const char *line) char *rest; int ret;
+ if (match_string(line, "if(sm<6)", &line) && runner->maximum_shader_model >= SHADER_MODEL_6_0) + return; + else if (match_string(line, "if(sm>=6)", &line) && runner->maximum_shader_model < SHADER_MODEL_6_0) + return; + runner->is_todo = false;
if (match_string(line, "todo", &line))
From: Conor McCarthy cmccarthy@codeweavers.com
--- Makefile.am | 1 + tests/hlsl/float-comparison.shader_test | 49 +++++++++++++++++++++++++ tests/shader_runner.c | 7 +++- 3 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 tests/hlsl/float-comparison.shader_test
diff --git a/Makefile.am b/Makefile.am index 002746829..a5c5fe62f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -87,6 +87,7 @@ vkd3d_shader_tests = \ tests/hlsl/entry-point-semantics.shader_test \ tests/hlsl/exp.shader_test \ tests/hlsl/expr-indexing.shader_test \ + tests/hlsl/float-comparison.shader_test \ tests/hlsl/floor.shader_test \ tests/hlsl/fmod.shader_test \ tests/hlsl/for.shader_test \ diff --git a/tests/hlsl/float-comparison.shader_test b/tests/hlsl/float-comparison.shader_test new file mode 100644 index 000000000..b7ccf9486 --- /dev/null +++ b/tests/hlsl/float-comparison.shader_test @@ -0,0 +1,49 @@ +[pixel shader] +uniform float4 f; + +float4 main() : sv_target +{ + float4 result; + float n = f.x/f.w; + + /* '!(condition)' in SM6 forces use of the unordered instruction variant. */ + + result.x = (f.y > f.x) ? 1.0 : 0.0; + result.x += (f.y < f.x) ? 10.0 : 0.0; + result.x += (f.y >= f.x) ? 100.0 : 0.0; + result.x += (f.y <= f.x) ? 1000.0 : 0.0; + result.x += !(f.y <= f.x) ? 10000.0 : 0.0; + result.x += !(f.y >= f.x) ? 100000.0 : 0.0; + result.x += !(f.y < f.x) ? 1000000.0 : 0.0; + result.x += !(f.y > f.x) ? 10000000.0 : 0.0; + result.y = (n > f.x) ? 1.0 : 0.0; + result.y += (n < f.x) ? 10.0 : 0.0; + result.y += (n >= f.x) ? 100.0 : 0.0; + result.y += (n <= f.x) ? 1000.0 : 0.0; + result.y += !(n <= f.x) ? 10000.0 : 0.0; + result.y += !(n >= f.x) ? 100000.0 : 0.0; + result.y += !(n < f.x) ? 1000000.0 : 0.0; + result.y += !(n > f.x) ? 10000000.0 : 0.0; + result.z = (f.z == f.y) ? 1.0 : 0.0; + result.z += (f.z != f.y) ? 10.0 : 0.0; + result.z += !(f.z == f.y) ? 100.0 : 0.0; + result.z += !(f.z != f.y) ? 1000.0 : 0.0; + result.z += (n == f.y) ? 10000.0 : 0.0; + result.z += (n != f.y) ? 100000.0 : 0.0; + result.z += !(n == f.y) ? 1000000.0 : 0.0; + result.z += !(n != f.y) ? 10000000.0 : 0.0; + /* It doesn't seem possible to generate DXIL instructions for 'is ordered' or 'is unordered'. + * Expressions 'isnan(n)' and '(isnan(n) || isnan(f.x))' compile into intrinsics. */ + result.w = 0; + return result; +} + +[test] +uniform 0 float4 0.0 1.5 1.5 0.0 +todo(sm>=6) draw quad +% SM1-3 apparently treats '0/0' as zero. +if(sm<4) todo probe all rgba (1010101.0, 11001100.0, 1101001.0, 0.0) +% SM4-5 optimises away the 'not' by inverting the condition, even though this is invalid for NaN. +if(4<=sm<6) todo probe all rgba (1010101.0, 0.0, 1101001.0, 0.0) +% SM6 emits the correct ordered/unordered instructions, so comparisons are false for NaN, and are made true with 'not'. +if(sm>=6) probe all rgba (1010101.0, 11110000.0, 1101001.0, 0.0) diff --git a/tests/shader_runner.c b/tests/shader_runner.c index def7ec877..6beb4a418 100644 --- a/tests/shader_runner.c +++ b/tests/shader_runner.c @@ -496,7 +496,12 @@ static void parse_test_directive(struct shader_runner *runner, const char *line) char *rest; int ret;
- if (match_string(line, "if(sm<6)", &line) && runner->maximum_shader_model >= SHADER_MODEL_6_0) + if (match_string(line, "if(sm<4)", &line) && runner->maximum_shader_model >= SHADER_MODEL_4_0) + return; + else if (match_string(line, "if(4<=sm<6)", &line) + && (runner->maximum_shader_model < SHADER_MODEL_4_0 || runner->maximum_shader_model >= SHADER_MODEL_6_0)) + return; + else if (match_string(line, "if(sm<6)", &line) && runner->maximum_shader_model >= SHADER_MODEL_6_0) return; else if (match_string(line, "if(sm>=6)", &line) && runner->maximum_shader_model < SHADER_MODEL_6_0) return;
From: Conor McCarthy cmccarthy@codeweavers.com
Prevents assertions while handling later instructions, and prevents return of an invalid SPIR-V module. --- libs/vkd3d-shader/spirv.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c index d2621ffa1..2f88ecb31 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -6657,7 +6657,7 @@ static void spirv_compiler_emit_bool_cast(struct spirv_compiler *compiler, spirv_compiler_emit_store_dst(compiler, dst, val_id); }
-static void spirv_compiler_emit_alu_instruction(struct spirv_compiler *compiler, +static enum vkd3d_result spirv_compiler_emit_alu_instruction(struct spirv_compiler *compiler, const struct vkd3d_shader_instruction *instruction) { struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; @@ -6681,7 +6681,7 @@ static void spirv_compiler_emit_alu_instruction(struct spirv_compiler *compiler, /* 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; + return VKD3D_OK; } } else @@ -6694,7 +6694,7 @@ static void spirv_compiler_emit_alu_instruction(struct spirv_compiler *compiler, 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; + return VKD3D_ERROR_INVALID_SHADER; }
assert(instruction->dst_count == 1); @@ -6726,6 +6726,7 @@ static void spirv_compiler_emit_alu_instruction(struct spirv_compiler *compiler, vkd3d_spirv_build_op_decorate(builder, val_id, SpvDecorationNoContraction, NULL, 0);
spirv_compiler_emit_store_dst(compiler, dst, val_id); + return VKD3D_OK; }
static enum GLSLstd450 spirv_compiler_map_ext_glsl_instruction( @@ -9506,7 +9507,7 @@ static int spirv_compiler_handle_instruction(struct spirv_compiler *compiler, case VKD3DSIH_UTOF: case VKD3DSIH_UTOU: case VKD3DSIH_XOR: - spirv_compiler_emit_alu_instruction(compiler, instruction); + ret = spirv_compiler_emit_alu_instruction(compiler, instruction); break; case VKD3DSIH_DFMA: case VKD3DSIH_DMAX: @@ -9727,6 +9728,9 @@ static int spirv_compiler_handle_instruction(struct spirv_compiler *compiler, break; default: FIXME("Unhandled 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 VKD3D_ERROR_INVALID_SHADER; }
return ret;
From: Conor McCarthy cmccarthy@codeweavers.com
--- Makefile.am | 1 + tests/d3d12.c | 5 --- tests/hlsl/cast-64-bit.shader_test | 57 ++++++++++++++++++++++++++ tests/shader_runner.c | 64 ++++++++++++++++++++++++++++++ tests/utils.h | 15 +++++++ 5 files changed, 137 insertions(+), 5 deletions(-) create mode 100644 tests/hlsl/cast-64-bit.shader_test
diff --git a/Makefile.am b/Makefile.am index a5c5fe62f..2666194a6 100644 --- a/Makefile.am +++ b/Makefile.am @@ -61,6 +61,7 @@ vkd3d_shader_tests = \ tests/hlsl/bitwise.shader_test \ tests/hlsl/bool-cast.shader_test \ tests/hlsl/bool-semantics.shader_test \ + tests/hlsl/cast-64-bit.shader_test \ tests/hlsl/cast-broadcast.shader_test \ tests/hlsl/cast-componentwise-compatible.shader_test \ tests/hlsl/cast-componentwise-equal.shader_test \ diff --git a/tests/d3d12.c b/tests/d3d12.c index 8f100a5e7..f9b5c5e98 100644 --- a/tests/d3d12.c +++ b/tests/d3d12.c @@ -42,11 +42,6 @@ static ID3D10Blob *compile_shader(const char *source, size_t len, const char *pr return bytecode; }
-struct dvec2 -{ - double x, y; -}; - static bool compare_uint8(uint8_t a, uint8_t b, unsigned int max_diff) { return abs(a - b) <= max_diff; diff --git a/tests/hlsl/cast-64-bit.shader_test b/tests/hlsl/cast-64-bit.shader_test new file mode 100644 index 000000000..813cce108 --- /dev/null +++ b/tests/hlsl/cast-64-bit.shader_test @@ -0,0 +1,57 @@ +[require] +shader model >= 5.0 + +[pixel shader todo] +uniform double2 d; +uniform float2 f; + +float4 main() : sv_target +{ + double2 n = d / f; + return float4(d.x, d.y, n.x, n.y); +} + +[test] +uniform 0 double2 -4.5 8.5 +uniform 4 float4 -2.25 4.25 0.0 0.0 +todo(sm<6) draw quad +probe all rgba (-4.5, 8.5, 2.0, 2.0) + + +[require] +shader model >= 6.0 + +[pixel shader] +uniform uint64_t2 l; +uniform uint2 u; + +float4 main() : sv_target +{ + uint64_t2 n = l / u; + uint4 result = uint4(l.x, l.y, n.x, n.y); + return result; +} + +[test] +uniform 0 uint64_t2 0x500000001 0x100000002 +uniform 4 uint4 10 4 0 0 +todo draw quad +todo probe all rgba (1.0, 2.0, 2147483648.0, 1073741824.0) + + +[pixel shader] +uniform int64_t2 l; +uniform int2 i; + +float4 main() : sv_target +{ + int64_t2 n = l / i; + int4 result = int4(l.x, l.y, n.x, n.y); + return result; +} + +[test] +uniform 0 int64_t2 -21474836481 0x100000002 +uniform 4 int4 -20 8 0 0 +todo draw quad +todo probe all rgba (-1.0, 2.0, 1073741824.0, 536870912.0) diff --git a/tests/shader_runner.c b/tests/shader_runner.c index 6beb4a418..aa448a36b 100644 --- a/tests/shader_runner.c +++ b/tests/shader_runner.c @@ -491,6 +491,48 @@ static void read_uint4(const char **line, struct uvec4 *v) read_uint(line, &v->w); }
+static void read_int64(const char **line, int64_t *i) +{ + char *rest; + int64_t val; + + errno = 0; + val = strtoll(*line, &rest, 0); + + if (errno != 0 || (*rest != '\0' && !isspace((unsigned char)*rest))) + fatal_error("Malformed int64 constant '%s'.\n", *line); + + *i = val; + *line = rest; +} + +static void read_uint64(const char **line, uint64_t *u) +{ + char *rest; + uint64_t val; + + errno = 0; + val = strtoull(*line, &rest, 0); + + if (errno != 0 || (*rest != '\0' && !isspace((unsigned char)*rest))) + fatal_error("Malformed uint64 constant '%s'.\n", *line); + + *u = val; + *line = rest; +} + +static void read_int64_t2(const char **line, struct i64vec2 *v) +{ + read_int64(line, &v->x); + read_int64(line, &v->y); +} + +static void read_uint64_t2(const char **line, struct u64vec2 *v) +{ + read_uint64(line, &v->x); + read_uint64(line, &v->y); +} + static void parse_test_directive(struct shader_runner *runner, const char *line) { char *rest; @@ -736,6 +778,14 @@ static void parse_test_directive(struct shader_runner *runner, const char *line) fatal_error("Malformed float constant '%s'.\n", line); set_uniforms(runner, offset, 1, &f); } + else if (match_string(line, "double2", &line)) + { + struct dvec2 v; + + if (sscanf(line, "%lf %lf", &v.x, &v.y) < 2) + fatal_error("Malformed double2 constant '%s'.\n", line); + set_uniforms(runner, offset, 4, &v); + } else if (match_string(line, "int4", &line)) { struct ivec4 v; @@ -764,6 +814,20 @@ static void parse_test_directive(struct shader_runner *runner, const char *line) read_uint(&line, &u); set_uniforms(runner, offset, 1, &u); } + else if (match_string(line, "int64_t2", &line)) + { + struct i64vec2 v; + + read_int64_t2(&line, &v); + set_uniforms(runner, offset, 4, &v); + } + else if (match_string(line, "uint64_t2", &line)) + { + struct u64vec2 v; + + read_uint64_t2(&line, &v); + set_uniforms(runner, offset, 4, &v); + } else { fatal_error("Unknown uniform type '%s'.\n", line); diff --git a/tests/utils.h b/tests/utils.h index 670941905..e8bbacc37 100644 --- a/tests/utils.h +++ b/tests/utils.h @@ -35,6 +35,11 @@ struct vec4 float x, y, z, w; };
+struct dvec2 +{ + double x, y; +}; + struct ivec4 { int x, y, z, w; @@ -45,6 +50,16 @@ struct uvec4 unsigned int x, y, z, w; };
+struct i64vec2 +{ + int64_t x, y; +}; + +struct u64vec2 +{ + uint64_t x, y; +}; + struct resource_readback { uint64_t width;
From: Conor McCarthy cmccarthy@codeweavers.com
--- libs/vkd3d-shader/dxil.c | 63 +++++++++++++++++++++++++ tests/hlsl/conditional.shader_test | 6 +-- tests/hlsl/float-comparison.shader_test | 2 +- tests/hlsl/for.shader_test | 2 +- tests/hlsl/return.shader_test | 12 ++--- tests/hlsl/step.shader_test | 2 +- tests/hlsl/switch.shader_test | 12 ++--- tests/hlsl/ternary.shader_test | 7 +-- 8 files changed, 85 insertions(+), 21 deletions(-)
diff --git a/libs/vkd3d-shader/dxil.c b/libs/vkd3d-shader/dxil.c index 2174ba52c..4d289ab85 100644 --- a/libs/vkd3d-shader/dxil.c +++ b/libs/vkd3d-shader/dxil.c @@ -2156,6 +2156,18 @@ static size_t sm6_parser_get_value_index(struct sm6_parser *sm6, uint64_t idx) return i; }
+static bool sm6_value_validate_is_register(const struct sm6_value *value, struct sm6_parser *sm6) +{ + if (!sm6_value_is_register(value)) + { + WARN("Operand of type %u is not a register.\n", value->value_type); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, + "A register operand passed to a DXIL instruction is not a register."); + return false; + } + return true; +} + static bool sm6_value_validate_is_handle(const struct sm6_value *value, struct sm6_parser *sm6) { if (!sm6_value_is_handle(value)) @@ -2168,6 +2180,19 @@ static bool sm6_value_validate_is_handle(const struct sm6_value *value, struct s return true; }
+static bool sm6_value_validate_is_bool(const struct sm6_value *value, struct sm6_parser *sm6) +{ + const struct sm6_type *type = value->type; + if (!sm6_type_is_bool(type)) + { + WARN("Operand of type class %u is not bool.\n", type->class); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, + "A bool operand of type class %u passed to a DXIL instruction is not a bool.", type->class); + return false; + } + return true; +} + static const struct sm6_value *sm6_parser_get_value_safe(struct sm6_parser *sm6, unsigned int idx) { if (idx < sm6->value_count) @@ -3653,6 +3678,41 @@ static void sm6_parser_emit_ret(struct sm6_parser *sm6, const struct dxil_record ins->handler_idx = VKD3DSIH_NOP; }
+static void sm6_parser_emit_vselect(struct sm6_parser *sm6, const struct dxil_record *record, + struct vkd3d_shader_instruction *ins, struct sm6_value *dst) +{ + struct vkd3d_shader_src_param *src_params; + const struct sm6_value *src[3]; + unsigned int i = 0; + + if (!(src[1] = sm6_parser_get_value_by_ref(sm6, record, NULL, &i)) + || !(src[2] = sm6_parser_get_value_by_ref(sm6, record, src[1]->type, &i)) + || !(src[0] = sm6_parser_get_value_by_ref(sm6, record, NULL, &i))) + { + return; + } + dxil_record_validate_operand_max_count(record, i, sm6); + + for (i = 0; i < 3; ++i) + { + if (!sm6_value_validate_is_register(src[i], sm6)) + return; + } + + dst->type = src[1]->type; + + if (!sm6_value_validate_is_bool(src[0], sm6)) + return; + + vsir_instruction_init(ins, &sm6->p.location, VKD3DSIH_MOVC); + + src_params = instruction_src_params_alloc(ins, 3, sm6); + for (i = 0; i < 3; ++i) + src_param_init_from_value(&src_params[i], src[i]); + + instruction_dst_param_init_ssa_scalar(ins, sm6); +} + static bool sm6_metadata_value_is_node(const struct sm6_metadata_value *m) { return m && m->type == VKD3D_METADATA_NODE; @@ -3813,6 +3873,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_VSELECT: + sm6_parser_emit_vselect(sm6, record, ins, dst); + break; default: FIXME("Unhandled dxil instruction %u.\n", record->code); return VKD3D_ERROR_INVALID_SHADER; diff --git a/tests/hlsl/conditional.shader_test b/tests/hlsl/conditional.shader_test index 4175813bd..0a927a8fa 100644 --- a/tests/hlsl/conditional.shader_test +++ b/tests/hlsl/conditional.shader_test @@ -11,10 +11,10 @@ float4 main() : sv_target
[test] uniform 0 float4 0.0 0.0 0.0 0.0 -todo(sm>=6) draw quad +draw quad probe all rgba (0.9, 0.8, 0.7, 0.6) uniform 0 float4 0.1 0.0 0.0 0.0 -todo(sm>=6) draw quad +draw quad probe all rgba (0.1, 0.2, 0.3, 0.4)
[pixel shader] @@ -43,7 +43,7 @@ float4 main() : sv_target
[test] uniform 0 float4 0.0 0.0 0.0 0.0 -todo(sm>=6) draw quad +draw quad probe all rgba (0.9, 0.8, 0.7, 0.6)
[pixel shader fail(sm<6)] diff --git a/tests/hlsl/float-comparison.shader_test b/tests/hlsl/float-comparison.shader_test index b7ccf9486..4767420e9 100644 --- a/tests/hlsl/float-comparison.shader_test +++ b/tests/hlsl/float-comparison.shader_test @@ -40,7 +40,7 @@ float4 main() : sv_target
[test] uniform 0 float4 0.0 1.5 1.5 0.0 -todo(sm>=6) draw quad +draw quad % SM1-3 apparently treats '0/0' as zero. if(sm<4) todo probe all rgba (1010101.0, 11001100.0, 1101001.0, 0.0) % SM4-5 optimises away the 'not' by inverting the condition, even though this is invalid for NaN. diff --git a/tests/hlsl/for.shader_test b/tests/hlsl/for.shader_test index e5faa28fd..1392118b3 100644 --- a/tests/hlsl/for.shader_test +++ b/tests/hlsl/for.shader_test @@ -22,7 +22,7 @@ float4 main(float tex : texcoord) : sv_target }
[test] -todo(sm>=6) draw quad +draw quad probe ( 0, 0, 159, 480) rgba (10.0, 35.0, 0.0, 0.0) probe (161, 0, 479, 480) rgba (10.0, 38.0, 0.0, 0.0) probe (481, 0, 640, 480) rgba ( 5.0, 10.0, 0.0, 0.0) diff --git a/tests/hlsl/return.shader_test b/tests/hlsl/return.shader_test index 29621b006..fbea07926 100644 --- a/tests/hlsl/return.shader_test +++ b/tests/hlsl/return.shader_test @@ -38,10 +38,10 @@ float4 main() : sv_target
[test] uniform 0 float 0.2 -todo(sm>=6) draw quad +draw quad probe all rgba (0.1, 0.2, 0.3, 0.4) uniform 0 float 0.8 -todo(sm>=6) draw quad +draw quad probe all rgba (0.5, 0.6, 0.7, 0.8)
[pixel shader] @@ -65,10 +65,10 @@ void main(out float4 ret : sv_target)
[test] uniform 0 float 0.2 -todo(sm>=6) draw quad +draw quad probe all rgba (0.3, 0.4, 0.5, 0.6) uniform 0 float 0.8 -todo(sm>=6) draw quad +draw quad probe all rgba (0.1, 0.2, 0.3, 0.4)
[pixel shader] @@ -211,10 +211,10 @@ void main(out float4 ret : sv_target)
[test] uniform 0 float 0.2 -todo(sm>=6) draw quad +draw quad probe all rgba (0.2, 0.2, 0.2, 0.2) uniform 0 float 0.8 -todo(sm>=6) draw quad +draw quad probe all rgba (0.5, 0.5, 0.5, 0.5)
[pixel shader] diff --git a/tests/hlsl/step.shader_test b/tests/hlsl/step.shader_test index b857f00b2..e201e15f9 100644 --- a/tests/hlsl/step.shader_test +++ b/tests/hlsl/step.shader_test @@ -9,7 +9,7 @@ float4 main() : sv_target [test] uniform 0 float4 5.0 -2.6 3.0 2.0 uniform 4 float4 1.0 -4.3 3.0 4.0 -todo(sm>=6) draw quad +draw quad probe all rgba (0.0, 0.0, 1.0, 1.0)
diff --git a/tests/hlsl/switch.shader_test b/tests/hlsl/switch.shader_test index 243b0b117..b7edadccf 100644 --- a/tests/hlsl/switch.shader_test +++ b/tests/hlsl/switch.shader_test @@ -19,13 +19,13 @@ float4 main() : sv_target
[test] uniform 0 uint4 3 0 0 0 -todo(sm>=6) draw quad +draw quad probe all rgba (5.0, 5.0, 5.0, 5.0) uniform 0 uint4 1 0 0 0 -todo(sm>=6) draw quad +draw quad probe all rgba (4.0, 4.0, 4.0, 4.0) uniform 0 uint4 0 0 0 0 -todo(sm>=6) draw quad +draw quad probe all rgba (3.0, 3.0, 3.0, 3.0)
% falling through is only supported for empty case statements @@ -49,13 +49,13 @@ float4 main() : sv_target
[test] uniform 0 uint4 2 0 0 0 -todo(sm>=6) draw quad +draw quad probe all rgba (1.0, 2.0, 3.0, 4.0) uniform 0 uint4 1 0 0 0 -todo(sm>=6) draw quad +draw quad probe all rgba (1.1, 2.0, 3.0, 4.0) uniform 0 uint4 0 0 0 0 -todo(sm>=6) draw quad +draw quad probe all rgba (1.1, 2.0, 3.0, 4.0)
% case value evaluation diff --git a/tests/hlsl/ternary.shader_test b/tests/hlsl/ternary.shader_test index 587b3d556..757c3b653 100644 --- a/tests/hlsl/ternary.shader_test +++ b/tests/hlsl/ternary.shader_test @@ -29,7 +29,7 @@ float4 main() : sv_target
[test] uniform 0 float4 1.1 3.0 4.0 5.0 -todo(sm>=6) draw quad +draw quad probe all rgba (1.1, 2.0, 0.0, 0.0)
[pixel shader] @@ -44,8 +44,9 @@ float4 main() : sv_target
[test] uniform 0 float4 1.0 0.0 0.0 0.0 -todo(sm>=6) draw quad -probe all rgba (0.5, 0.6, 0.7, 0.0) +draw quad +if(sm<6) probe all rgba (0.5, 0.6, 0.7, 0.0) +if(sm>=6) probe all rgba (0.5, 0.2, 0.7, 0.0)
[pixel shader fail(sm>=6)] float4 x, y, z;
From: Conor McCarthy cmccarthy@codeweavers.com
Shaders parsed from DXIL contain a bool condition register, so calling spirv_compiler_emit_int_to_bool() results in an invalid bool/uint comparison. --- libs/vkd3d-shader/spirv.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c index 2f88ecb31..a19b2bf37 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -6893,8 +6893,9 @@ static void spirv_compiler_emit_movc(struct spirv_compiler *compiler, component_count = vkd3d_write_mask_component_count(dst->write_mask); type_id = spirv_compiler_get_type_id_for_dst(compiler, dst);
- condition_id = spirv_compiler_emit_int_to_bool(compiler, - VKD3D_SHADER_CONDITIONAL_OP_NZ, component_count, condition_id); + if (src[0].reg.data_type != VKD3D_DATA_BOOL) + condition_id = spirv_compiler_emit_int_to_bool(compiler, + VKD3D_SHADER_CONDITIONAL_OP_NZ, component_count, condition_id); val_id = vkd3d_spirv_build_op_select(builder, type_id, condition_id, src1_id, src2_id);
spirv_compiler_emit_store_dst(compiler, dst, val_id);
From: Conor McCarthy cmccarthy@codeweavers.com
--- libs/vkd3d-shader/vkd3d_shader_private.h | 1 - 1 file changed, 1 deletion(-)
diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h index e5d590637..db8591ab2 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -799,7 +799,6 @@ struct vkd3d_shader_immediate_constant_buffer
struct vkd3d_shader_indexable_temp { - struct list entry; unsigned int register_idx; unsigned int register_size; unsigned int component_count;
From: Conor McCarthy cmccarthy@codeweavers.com
--- libs/vkd3d-shader/d3d_asm.c | 4 + libs/vkd3d-shader/dxil.c | 176 ++++++++++++++++++++++- libs/vkd3d-shader/tpf.c | 3 + libs/vkd3d-shader/vkd3d_shader_private.h | 3 + 4 files changed, 185 insertions(+), 1 deletion(-)
diff --git a/libs/vkd3d-shader/d3d_asm.c b/libs/vkd3d-shader/d3d_asm.c index 442c1e414..749b2d351 100644 --- a/libs/vkd3d-shader/d3d_asm.c +++ b/libs/vkd3d-shader/d3d_asm.c @@ -1675,10 +1675,14 @@ static void shader_dump_instruction(struct vkd3d_d3d_asm_compiler *compiler, break;
case VKD3DSIH_DCL_INDEXABLE_TEMP: + if (ins->declaration.indexable_temp.is_constant) + vkd3d_string_buffer_printf(buffer, "_const"); vkd3d_string_buffer_printf(buffer, " %sx%u%s", compiler->colours.reg, ins->declaration.indexable_temp.register_idx, compiler->colours.reset); shader_print_subscript(compiler, ins->declaration.indexable_temp.register_size, NULL); shader_print_uint_literal(compiler, ", ", ins->declaration.indexable_temp.component_count, ""); + if (ins->declaration.indexable_temp.alignment) + shader_print_uint_literal(compiler, ", align ", ins->declaration.indexable_temp.alignment, ""); break;
case VKD3DSIH_DCL_INPUT_PS: diff --git a/libs/vkd3d-shader/dxil.c b/libs/vkd3d-shader/dxil.c index 4d289ab85..3e02bdad7 100644 --- a/libs/vkd3d-shader/dxil.c +++ b/libs/vkd3d-shader/dxil.c @@ -25,6 +25,10 @@
#define BITCODE_MAGIC VKD3D_MAKE_TAG('B', 'C', 0xc0, 0xde) #define DXIL_OP_MAX_OPERANDS 17 +static const uint64_t MAX_ALIGNMENT_EXPONENT = 29; +static const uint64_t GLOBALVAR_IS_CONSTANT_FLAG = 1; +static const uint64_t GLOBALVAR_EXPLICIT_TYPE_FLAG = 2; +static const unsigned int GLOBALVAR_ADDRESS_SPACE_SHIFT = 2; static const unsigned int SHADER_DESCRIPTOR_TYPE_COUNT = 4;
static const unsigned int dx_max_thread_group_size[3] = {1024, 1024, 64}; @@ -157,6 +161,13 @@ enum bitcode_value_symtab_code VST_CODE_BBENTRY = 2, };
+enum bitcode_linkage +{ + LINKAGE_EXTERNAL = 0, + LINKAGE_APPENDING = 2, + LINKAGE_INTERNAL = 3, +}; + enum dxil_component_type { COMPONENT_TYPE_INVALID = 0, @@ -567,6 +578,8 @@ struct sm6_parser size_t descriptor_capacity; size_t descriptor_count;
+ unsigned int indexable_temp_count; + struct sm6_value *values; size_t value_count; size_t value_capacity; @@ -2555,6 +2568,17 @@ static enum vkd3d_result sm6_parser_constants_init(struct sm6_parser *sm6, const return VKD3D_OK; }
+static bool bitcode_parse_alignment(uint64_t encoded_alignment, unsigned int *alignment) +{ + if (encoded_alignment > MAX_ALIGNMENT_EXPONENT + 1) + { + *alignment = 0; + return false; + } + *alignment = (1u << encoded_alignment) >> 1; + return true; +} + static struct vkd3d_shader_instruction *sm6_parser_require_space(struct sm6_parser *sm6, size_t extra) { if (!shader_instruction_array_reserve(&sm6->p.instructions, sm6->p.instructions.count + extra)) @@ -2576,6 +2600,155 @@ static struct vkd3d_shader_instruction *sm6_parser_add_instruction(struct sm6_pa return ins; }
+static void sm6_parser_declare_indexable_temp(struct sm6_parser *sm6, + const struct sm6_type *elem_type, unsigned int count, unsigned int alignment, bool is_constant, + 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); + ins->declaration.indexable_temp.register_idx = sm6->indexable_temp_count++; + ins->declaration.indexable_temp.register_size = count; + ins->declaration.indexable_temp.alignment = alignment; + ins->declaration.indexable_temp.is_constant = is_constant; + ins->declaration.indexable_temp.data_type = data_type; + ins->declaration.indexable_temp.component_count = 1; + + register_init_with_id(&dst->u.reg, VKD3DSPR_IDXTEMP, data_type, ins->declaration.indexable_temp.register_idx); +} + +static bool sm6_parser_declare_global(struct sm6_parser *sm6, const struct dxil_record *record) +{ + const struct sm6_type *type, *scalar_type; + unsigned int alignment, count; + uint64_t address_space; + struct sm6_value *dst; + uint64_t init = 0; + bool is_constant; + + if (!dxil_record_validate_operand_min_count(record, 6, sm6)) + return false; + + if (!(type = sm6_parser_get_type(sm6, record->operands[0]))) + return false; + if (sm6_type_is_array(type)) + { + count = type->u.array.count; + scalar_type = type->u.array.elem_type; + } + else if (sm6_type_is_scalar(type)) + { + count = 1; + scalar_type = type; + } + else + { + WARN("Unsupported type class %u.\n", type->class); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, + "Global variables of type class %u are not supported.", type->class); + return false; + } + + is_constant = record->operands[1] & GLOBALVAR_IS_CONSTANT_FLAG; + + if (record->operands[1] & GLOBALVAR_EXPLICIT_TYPE_FLAG) + { + address_space = record->operands[1] >> GLOBALVAR_ADDRESS_SPACE_SHIFT; + + if (!(type = sm6_type_get_pointer_to_type(type, address_space, sm6))) + { + WARN("Failed to get pointer type for type class %u, address space %"PRIu64".\n", + type->class, address_space); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_MODULE, + "Module does not define a pointer type for a global variable."); + return false; + } + } + else + { + if (!sm6_type_is_pointer(type)) + { + WARN("Type is not a pointer.\n"); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, + "The type of a global variable is not a pointer."); + return false; + } + address_space = type->u.pointer.addr_space; + } + + if ((init = record->operands[2])) + { + if (init - 1 >= sm6->value_capacity) + { + WARN("Invalid value index for initialiser."); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, + "The initialiser value index for a global variable is invalid."); + return false; + } + } + + if (record->operands[3] != LINKAGE_INTERNAL) + WARN("Ignoring linkage %"PRIu64".\n", record->operands[3]); + + if (!bitcode_parse_alignment(record->operands[4], &alignment)) + WARN("Invalid alignment %"PRIu64".\n", record->operands[4]); + + if (record->operands[5]) + WARN("Ignoring section code %"PRIu64".\n", record->operands[5]); + + if (!sm6_parser_get_global_symbol_name(sm6, sm6->value_count)) + WARN("Missing symbol name for global variable at index %zu.\n", sm6->value_count); + /* TODO: store global symbol names in struct vkd3d_shader_desc? */ + + if (record->operand_count > 6 && record->operands[6]) + WARN("Ignoring visibility %"PRIu64".\n", record->operands[6]); + if (record->operand_count > 7 && record->operands[7]) + WARN("Ignoring thread local mode %"PRIu64".\n", record->operands[7]); + /* record->operands[8] contains unnamed_addr, a flag indicating the address + * is not important, only the content is. This info is not relevant. */ + if (record->operand_count > 9 && record->operands[9]) + WARN("Ignoring external_init %"PRIu64".\n", record->operands[9]); + if (record->operand_count > 10 && record->operands[10]) + WARN("Ignoring dll storage class %"PRIu64".\n", record->operands[10]); + if (record->operand_count > 11 && record->operands[11]) + WARN("Ignoring comdat %"PRIu64".\n", record->operands[11]); + + dst = sm6_parser_get_current_value(sm6); + dst->type = type; + dst->value_type = VALUE_TYPE_REG; + + if (init) + { + WARN("Unsupported initialiser.\n"); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, + "Global variable initialisers are not supported."); + return false; + } + + if (address_space == ADDRESS_SPACE_DEFAULT) + { + sm6_parser_declare_indexable_temp(sm6, scalar_type, count, alignment, is_constant, dst); + } + else if (address_space == ADDRESS_SPACE_GROUPSHARED) + { + WARN("Unsupported TGSM.\n"); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, + "TGSM global variables are not supported."); + return false; + } + else + { + WARN("Unhandled address space %"PRIu64".\n", address_space); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, + "Global variables with address space %"PRIu64" are not supported.", address_space); + return false; + } + + ++sm6->value_count; + return true; +} + static enum vkd3d_result sm6_parser_globals_init(struct sm6_parser *sm6) { const struct dxil_block *block = &sm6->root_block; @@ -2603,7 +2776,8 @@ static enum vkd3d_result sm6_parser_globals_init(struct sm6_parser *sm6) break;
case MODULE_CODE_GLOBALVAR: - FIXME("Global variables are not implemented yet.\n"); + if (!sm6_parser_declare_global(sm6, record)) + return VKD3D_ERROR_INVALID_SHADER; break;
case MODULE_CODE_VERSION: diff --git a/libs/vkd3d-shader/tpf.c b/libs/vkd3d-shader/tpf.c index d0d2ea82b..c8481f9c8 100644 --- a/libs/vkd3d-shader/tpf.c +++ b/libs/vkd3d-shader/tpf.c @@ -1113,6 +1113,9 @@ static void shader_sm4_read_dcl_indexable_temp(struct vkd3d_shader_instruction * { ins->declaration.indexable_temp.register_idx = *tokens++; ins->declaration.indexable_temp.register_size = *tokens++; + ins->declaration.indexable_temp.alignment = 0; + ins->declaration.indexable_temp.is_constant = false; + ins->declaration.indexable_temp.data_type = VKD3D_DATA_FLOAT; ins->declaration.indexable_temp.component_count = *tokens; }
diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h index db8591ab2..a9c5b3d71 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -801,6 +801,9 @@ struct vkd3d_shader_indexable_temp { unsigned int register_idx; unsigned int register_size; + unsigned int alignment; + bool is_constant; + enum vkd3d_data_type data_type; unsigned int component_count; };
From: Conor McCarthy cmccarthy@codeweavers.com
--- libs/vkd3d-shader/dxil.c | 52 ++++++++++++++++++++++++++++++++-------- 1 file changed, 42 insertions(+), 10 deletions(-)
diff --git a/libs/vkd3d-shader/dxil.c b/libs/vkd3d-shader/dxil.c index 3e02bdad7..f770311b7 100644 --- a/libs/vkd3d-shader/dxil.c +++ b/libs/vkd3d-shader/dxil.c @@ -2600,7 +2600,7 @@ static struct vkd3d_shader_instruction *sm6_parser_add_instruction(struct sm6_pa return ins; }
-static void sm6_parser_declare_indexable_temp(struct sm6_parser *sm6, +static struct vkd3d_shader_instruction *sm6_parser_declare_indexable_temp(struct sm6_parser *sm6, const struct sm6_type *elem_type, unsigned int count, unsigned int alignment, bool is_constant, struct sm6_value *dst) { @@ -2616,11 +2616,15 @@ static void sm6_parser_declare_indexable_temp(struct sm6_parser *sm6, ins->declaration.indexable_temp.component_count = 1;
register_init_with_id(&dst->u.reg, VKD3DSPR_IDXTEMP, data_type, ins->declaration.indexable_temp.register_idx); + + return ins; }
static bool sm6_parser_declare_global(struct sm6_parser *sm6, const struct dxil_record *record) { + struct vkd3d_shader_src_param *initialiser; const struct sm6_type *type, *scalar_type; + struct vkd3d_shader_instruction *ins; unsigned int alignment, count; uint64_t address_space; struct sm6_value *dst; @@ -2718,17 +2722,17 @@ static bool sm6_parser_declare_global(struct sm6_parser *sm6, const struct dxil_ dst->type = type; dst->value_type = VALUE_TYPE_REG;
- if (init) - { - WARN("Unsupported initialiser.\n"); - vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, - "Global variable initialisers are not supported."); - return false; - } - if (address_space == ADDRESS_SPACE_DEFAULT) { - sm6_parser_declare_indexable_temp(sm6, scalar_type, count, alignment, is_constant, dst); + ins = sm6_parser_declare_indexable_temp(sm6, scalar_type, count, alignment, is_constant, dst); + if (init) + { + if (!(initialiser = instruction_src_params_alloc(ins, 1, sm6))) + return false; + src_param_init(initialiser); + /* The value index will be resolved later so forward references can be handled. */ + register_init_with_id(&initialiser->reg, VKD3DSPR_IMMCONSTBUFFER, VKD3D_DATA_FLOAT, init - 1); + } } else if (address_space == ADDRESS_SPACE_GROUPSHARED) { @@ -2749,9 +2753,29 @@ static bool sm6_parser_declare_global(struct sm6_parser *sm6, const struct dxil_ return true; }
+static void register_resolve_forward_initialiser(struct vkd3d_shader_register *initialiser, + struct sm6_parser *sm6) +{ + unsigned int index = initialiser->idx[0].offset; + const struct sm6_value *value; + + if (index >= sm6->value_count || !(value = sm6_parser_get_value_safe(sm6, index)) + || !sm6_value_is_register(value)) + { + WARN("Invalid initialiser index %u.\n", index); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, + "Global variable initialiser value index %u is invalid.", index); + } + else + { + *initialiser = value->u.reg; + } +} + static enum vkd3d_result sm6_parser_globals_init(struct sm6_parser *sm6) { const struct dxil_block *block = &sm6->root_block; + struct vkd3d_shader_instruction *ins; const struct dxil_record *record; enum vkd3d_result ret; uint64_t version; @@ -2804,6 +2828,14 @@ static enum vkd3d_result sm6_parser_globals_init(struct sm6_parser *sm6) return ret; }
+ /* Resolve initialiser forward references. */ + for (i = 0; i < sm6->p.instructions.count; ++i) + { + ins = &sm6->p.instructions.elements[i]; + if (ins->handler_idx == VKD3DSIH_DCL_INDEXABLE_TEMP && ins->src_count) + register_resolve_forward_initialiser((struct vkd3d_shader_register *)&ins->src->reg, sm6); + } + return VKD3D_OK; }
From: Conor McCarthy cmccarthy@codeweavers.com
--- libs/vkd3d-shader/dxil.c | 110 +++++++++++++++++++++++ libs/vkd3d-shader/ir.c | 3 + libs/vkd3d-shader/vkd3d_shader_private.h | 1 + 3 files changed, 114 insertions(+)
diff --git a/libs/vkd3d-shader/dxil.c b/libs/vkd3d-shader/dxil.c index f770311b7..bffffbffb 100644 --- a/libs/vkd3d-shader/dxil.c +++ b/libs/vkd3d-shader/dxil.c @@ -2193,6 +2193,18 @@ static bool sm6_value_validate_is_handle(const struct sm6_value *value, struct s 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)) + { + WARN("Operand result type class %u is not a pointer.\n", value->type->class); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, + "A pointer operand passed to a DXIL instruction is not a pointer."); + return false; + } + return true; +} + static bool sm6_value_validate_is_bool(const struct sm6_value *value, struct sm6_parser *sm6) { const struct sm6_type *type = value->type; @@ -3872,6 +3884,101 @@ static void sm6_parser_emit_extractval(struct sm6_parser *sm6, const struct dxil instruction_dst_param_init_ssa_scalar(ins, sm6); }
+static void sm6_parser_emit_gep(struct sm6_parser *sm6, const struct dxil_record *record, + struct vkd3d_shader_instruction *ins, struct sm6_value *dst) +{ + const struct sm6_type *type, *pointee_type; + unsigned int i, elem_idx, operand_idx = 2; + enum bitcode_address_space addr_space; + struct vkd3d_shader_register *reg; + struct sm6_value *operands[2]; + struct sm6_value *elem_value; + const struct sm6_value *src; + bool is_in_bounds; + size_t operand; + + if (!(type = sm6_parser_get_type(sm6, record->operands[1])) + || !(src = sm6_parser_get_value_by_ref(sm6, record, NULL, &operand_idx)) + || !sm6_value_validate_is_register(src, sm6) + || !sm6_value_validate_is_pointer(src, sm6) + || !dxil_record_validate_operand_min_count(record, operand_idx + 2, sm6)) + { + return; + } + + is_in_bounds = record->operands[0]; + + if ((pointee_type = src->type->u.pointer.type) != type) + { + WARN("Type mismatch, type %u width %u vs type %u width %u.\n", type->class, + type->u.width, pointee_type->class, pointee_type->u.width); + vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_TYPE_MISMATCH, + "Type mismatch in GEP operation arguments."); + } + addr_space = src->type->u.pointer.addr_space; + + if (record->operand_count > operand_idx + 2) + { + FIXME("Multiple element indices are not implemented.\n"); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, + "Multi-dimensional addressing in GEP instructions is not supported."); + return; + } + + for (type = src->type, i = 0; operand_idx < record->operand_count; ++i) + { + bool is_constant; + + if (!sm6_type_is_pointer(type) && !sm6_type_is_aggregate(type)) + { + WARN("Invalid GEP on type class %u.\n", type->class); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, + "Source type of a GEP instruction is not a pointer or aggregate."); + return; + } + + if ((operand = sm6_parser_get_value_idx_by_ref(sm6, record, NULL, &operand_idx)) == SIZE_MAX) + return; + + elem_value = &sm6->values[operand]; + is_constant = sm6_value_is_constant(elem_value); + elem_idx = is_constant ? sm6_value_get_constant_uint(elem_value) : 0; + + if (sm6_type_is_pointer(type)) + type = type->u.pointer.type; + else + type = sm6_type_get_element_type_at_index(type, elem_idx); + + /* The first index is always a simple pointer dereference, i.e. zero. */ + if (!type || (!i && (!is_constant || elem_idx))) + { + WARN("Invalid element index %u.\n", elem_idx); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, + "Element index %u for a GEP instruction is out of bounds.", elem_idx); + return; + } + + operands[i] = elem_value; + } + + if (!(dst->type = sm6_type_get_pointer_to_type(type, addr_space, sm6))) + { + FIXME("Failed to get pointer type for type %u.\n", type->class); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_MODULE, + "Module does not define a pointer type for a GEP instruction."); + return; + } + + reg = &dst->u.reg; + *reg = src->u.reg; + reg->idx[1].offset = 0; + register_index_address_init(®->idx[1], operands[1], sm6); + reg->idx[1].is_in_bounds = is_in_bounds; + reg->idx_count = 2; + + ins->handler_idx = VKD3DSIH_NOP; +} + static void sm6_parser_emit_ret(struct sm6_parser *sm6, const struct dxil_record *record, struct sm6_block *code_block, struct vkd3d_shader_instruction *ins) { @@ -4074,6 +4181,9 @@ static enum vkd3d_result sm6_parser_function_init(struct sm6_parser *sm6, const case FUNC_CODE_INST_EXTRACTVAL: sm6_parser_emit_extractval(sm6, record, ins, dst); break; + case FUNC_CODE_INST_GEP: + sm6_parser_emit_gep(sm6, record, ins, dst); + break; case FUNC_CODE_INST_RET: sm6_parser_emit_ret(sm6, record, code_block, ins); is_terminator = true; diff --git a/libs/vkd3d-shader/ir.c b/libs/vkd3d-shader/ir.c index 2a3343994..ae1610483 100644 --- a/libs/vkd3d-shader/ir.c +++ b/libs/vkd3d-shader/ir.c @@ -295,10 +295,13 @@ void vsir_register_init(struct vkd3d_shader_register *reg, enum vkd3d_shader_reg reg->data_type = data_type; reg->idx[0].offset = ~0u; reg->idx[0].rel_addr = NULL; + reg->idx[0].is_in_bounds = false; reg->idx[1].offset = ~0u; reg->idx[1].rel_addr = NULL; + reg->idx[1].is_in_bounds = false; reg->idx[2].offset = ~0u; reg->idx[2].rel_addr = NULL; + reg->idx[2].is_in_bounds = false; reg->idx_count = idx_count; reg->dimension = VSIR_DIMENSION_SCALAR; } diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h index a9c5b3d71..8dc88d9cc 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -811,6 +811,7 @@ struct vkd3d_shader_register_index { const struct vkd3d_shader_src_param *rel_addr; unsigned int offset; + bool is_in_bounds; };
struct vkd3d_shader_register
From: Conor McCarthy cmccarthy@codeweavers.com
--- libs/vkd3d-shader/dxil.c | 63 +++++++++++++++++++ libs/vkd3d-shader/ir.c | 1 + libs/vkd3d-shader/vkd3d_shader_private.h | 1 + tests/hlsl/matrix-indexing.shader_test | 6 +- tests/hlsl/non-const-indexing.shader_test | 46 +++++++------- .../hlsl/vector-indexing-uniform.shader_test | 4 +- 6 files changed, 93 insertions(+), 28 deletions(-)
diff --git a/libs/vkd3d-shader/dxil.c b/libs/vkd3d-shader/dxil.c index bffffbffb..048ba30a6 100644 --- a/libs/vkd3d-shader/dxil.c +++ b/libs/vkd3d-shader/dxil.c @@ -2205,6 +2205,18 @@ static bool sm6_value_validate_is_pointer(const struct sm6_value *value, struct return true; }
+static bool sm6_value_validate_is_numeric(const struct sm6_value *value, struct sm6_parser *sm6) +{ + if (!sm6_type_is_numeric(value->type)) + { + WARN("Operand result type %u is not numeric.\n", value->type->class); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, + "A numeric operand passed to a DXIL instruction is not numeric."); + return false; + } + return true; +} + static bool sm6_value_validate_is_bool(const struct sm6_value *value, struct sm6_parser *sm6) { const struct sm6_type *type = value->type; @@ -3979,6 +3991,54 @@ static void sm6_parser_emit_gep(struct sm6_parser *sm6, const struct dxil_record ins->handler_idx = VKD3DSIH_NOP; }
+static void sm6_parser_emit_load(struct sm6_parser *sm6, const struct dxil_record *record, + struct vkd3d_shader_instruction *ins, struct sm6_value *dst) +{ + const struct sm6_type *elem_type = NULL, *pointee_type; + struct vkd3d_shader_src_param *src_param; + unsigned int alignment, i = 0; + const struct sm6_value *ptr; + + if (!(ptr = sm6_parser_get_value_by_ref(sm6, record, NULL, &i))) + return; + if (!sm6_value_validate_is_pointer(ptr, sm6) + || !dxil_record_validate_operand_count(record, i + 2, i + 3, sm6)) + return; + + if (record->operand_count > i + 2 && !(elem_type = sm6_parser_get_type(sm6, record->operands[i++]))) + return; + + if (!elem_type) + { + elem_type = ptr->type->u.pointer.type; + } + else if (elem_type != (pointee_type = ptr->type->u.pointer.type)) + { + WARN("Type mismtach.\n"); + vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_TYPE_MISMATCH, + "Type mismatch in pointer load arguments."); + } + + dst->type = elem_type; + + if (!sm6_value_validate_is_numeric(dst, sm6)) + return; + + if (!bitcode_parse_alignment(record->operands[i++], &alignment)) + WARN("Invalid alignment %"PRIu64".\n", record->operands[i - 1]); + + 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], ptr); + src_param->reg.alignment = alignment; + + instruction_dst_param_init_ssa_scalar(ins, sm6); +} + static void sm6_parser_emit_ret(struct sm6_parser *sm6, const struct dxil_record *record, struct sm6_block *code_block, struct vkd3d_shader_instruction *ins) { @@ -4184,6 +4244,9 @@ static enum vkd3d_result sm6_parser_function_init(struct sm6_parser *sm6, const case FUNC_CODE_INST_GEP: sm6_parser_emit_gep(sm6, record, ins, dst); break; + case FUNC_CODE_INST_LOAD: + sm6_parser_emit_load(sm6, record, ins, dst); + break; case FUNC_CODE_INST_RET: sm6_parser_emit_ret(sm6, record, code_block, ins); is_terminator = true; diff --git a/libs/vkd3d-shader/ir.c b/libs/vkd3d-shader/ir.c index ae1610483..f216c82f7 100644 --- a/libs/vkd3d-shader/ir.c +++ b/libs/vkd3d-shader/ir.c @@ -304,6 +304,7 @@ void vsir_register_init(struct vkd3d_shader_register *reg, enum vkd3d_shader_reg reg->idx[2].is_in_bounds = false; reg->idx_count = idx_count; reg->dimension = VSIR_DIMENSION_SCALAR; + reg->alignment = 0; }
void vsir_instruction_init(struct vkd3d_shader_instruction *ins, const struct vkd3d_shader_location *location, diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h index 8dc88d9cc..1e9b01edc 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -823,6 +823,7 @@ struct vkd3d_shader_register struct vkd3d_shader_register_index idx[3]; unsigned int idx_count; enum vsir_dimension dimension; + unsigned int alignment; union { DWORD immconst_uint[VKD3D_VEC4_SIZE]; diff --git a/tests/hlsl/matrix-indexing.shader_test b/tests/hlsl/matrix-indexing.shader_test index b8e6dec68..bc4a46d03 100644 --- a/tests/hlsl/matrix-indexing.shader_test +++ b/tests/hlsl/matrix-indexing.shader_test @@ -120,8 +120,8 @@ float4 main() : sv_target
[test] uniform 0 float 2 -todo(sm>=6) draw quad -probe all rgba (8, 9, 10, 11) +draw quad +todo(sm>=6) probe all rgba (8, 9, 10, 11)
[pixel shader] @@ -136,5 +136,5 @@ float4 main() : sv_target
[test] uniform 0 float 3 -todo(sm>=6) draw quad +draw quad todo(sm>=6) 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..638107e79 100644 --- a/tests/hlsl/non-const-indexing.shader_test +++ b/tests/hlsl/non-const-indexing.shader_test @@ -36,17 +36,17 @@ float4 main() : SV_TARGET
[test] uniform 0 float 0 -todo(sm>=6) draw quad -probe all rgba (11.0, 11.0, 11.0, 11.0) +draw quad +todo(sm>=6) probe all rgba (11.0, 11.0, 11.0, 11.0) uniform 0 float 1 -todo(sm>=6) draw quad -probe all rgba (12.0, 12.0, 12.0, 12.0) +draw quad +todo(sm>=6) probe all rgba (12.0, 12.0, 12.0, 12.0) uniform 0 float 2 -todo(sm>=6) draw quad -probe all rgba (13.0, 13.0, 13.0, 13.0) +draw quad +todo(sm>=6) probe all rgba (13.0, 13.0, 13.0, 13.0) uniform 0 float 3 -todo(sm>=6) draw quad -probe all rgba (14.0, 14.0, 14.0, 14.0) +draw quad +todo(sm>=6) probe all rgba (14.0, 14.0, 14.0, 14.0)
[pixel shader] @@ -61,7 +61,7 @@ float4 main() : sv_target
[test] uniform 0 float 2.3 -todo(sm>=6) draw quad +draw quad todo(sm>=6) probe all rgba (3, 3, 3, 3)
@@ -77,17 +77,17 @@ float4 main() : SV_TARGET
[test] uniform 0 float 0 -todo(sm>=6) draw quad -probe all rgba (21.0, 1.0, 24.0, 0.0) +draw quad +todo(sm>=6) probe all rgba (21.0, 1.0, 24.0, 0.0) uniform 0 float 1 -todo(sm>=6) draw quad -probe all rgba (22.0, 0.0, 23.0, 1.0) +draw quad +todo(sm>=6) probe all rgba (22.0, 0.0, 23.0, 1.0) uniform 0 float 2 -todo(sm>=6) draw quad -probe all rgba (23.0, 1.0, 22.0, 0.0) +draw quad +todo(sm>=6) probe all rgba (23.0, 1.0, 22.0, 0.0) uniform 0 float 3 -todo(sm>=6) draw quad -probe all rgba (24.0, 0.0, 21.0, 1.0) +draw quad +todo(sm>=6) probe all rgba (24.0, 0.0, 21.0, 1.0)
[pixel shader] @@ -102,16 +102,16 @@ float4 main() : sv_target
[test] uniform 0 float4 0 0 0 0 -todo(sm>=6) draw quad +draw quad todo(sm>=6) probe all rgba (1.0, 2.0, 3.0, 4.0) uniform 0 float4 1 0 0 0 -todo(sm>=6) draw quad +draw quad todo(sm>=6) probe all rgba (5.0, 6.0, 7.0, 8.0) uniform 0 float4 0 1 0 0 -todo(sm>=6) draw quad +draw quad todo(sm>=6) probe all rgba (5.0, 6.0, 7.0, 8.0) uniform 0 float4 1 1 0 0 -todo(sm>=6) draw quad +draw quad todo(sm>=6) probe all rgba (9.0, 10.0, 11.0, 12.0)
@@ -130,8 +130,8 @@ float4 main() : sv_target
[test] uniform 0 float4 0 0 2.4 0 -todo(sm>=6) draw quad -probe all rgba (1.0, 120.0, 90.0, 4.0) +draw quad +todo(sm>=6) probe all rgba (1.0, 120.0, 90.0, 4.0)
% SM1 doesn't support relative addressing if it is used in a l-value. diff --git a/tests/hlsl/vector-indexing-uniform.shader_test b/tests/hlsl/vector-indexing-uniform.shader_test index 3501f3af7..d494d8626 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 -probe all rgba (0.5, 0.3, 0.8, 0.2) +draw quad +todo(sm>=6) probe all rgba (0.5, 0.3, 0.8, 0.2)
This needs spirv changes to make any tests pass, but this series is already long enough. Not sure what to do about initialisers; we can't use `DCL_IMMEDIATE_CONSTANT_BUFFER` because it emits a variable, and we are avoiding dropping things in the register structure. The `icb` objects the DXIL parser creates are currently not stored anywhere except the icb cache. Probably they should go in an array in `shader_desc`. Any thoughts @hverbeet @giomasce? Maybe @zfigura already has code for that change?
This needs spirv changes to make any tests pass, but this series is already long enough. Not sure what to do about initialisers; we can't use `DCL_IMMEDIATE_CONSTANT_BUFFER` because it emits a variable,
Is the issue purely that the shader may write to the variable, or are there other reasons that can't work? If what we want is essentially a writeable icb, we could perhaps consider adding a "data[]" field to the vkd3d_shader_indexable_temp structure, analogous to struct vkd3d_shader_immediate_constant_buffer.