-- v3: vkd3d-shader/hlsl: Write SM4 dcl_thread_group instructions. vkd3d-shader/hlsl: Parse the numthreads attribute.
From: Zebediah Figura zfigura@codeweavers.com
Do not rely on a draw or dispatch command to do this.
This allows more efficiently testing syntax, in cases where testing the actual shader functionality is not interesting. --- tests/cast-componentwise-equal.shader_test | 2 +- tests/cast-to-half.shader_test | 2 +- tests/compute.shader_test | 2 +- tests/hlsl-array-dimension.shader_test | 2 +- tests/hlsl-for.shader_test | 2 +- tests/hlsl-function-cast.shader_test | 8 +- tests/hlsl-function-overload.shader_test | 2 +- tests/hlsl-function.shader_test | 6 +- tests/hlsl-gather.shader_test | 2 +- tests/hlsl-initializer-objects.shader_test | 4 +- tests/hlsl-intrinsic-override.shader_test | 4 +- ...lsl-return-implicit-conversion.shader_test | 20 ++--- tests/hlsl-static-initializer.shader_test | 2 +- tests/hlsl-storage-qualifiers.shader_test | 2 +- .../hlsl-vector-indexing-uniform.shader_test | 2 +- tests/object-references.shader_test | 2 +- tests/sampler-offset.shader_test | 6 +- tests/shader_runner.c | 82 +++++++++++++------ tests/trigonometry.shader_test | 2 +- tests/uav-load.shader_test | 2 +- tests/uav.shader_test | 2 +- 21 files changed, 96 insertions(+), 62 deletions(-)
diff --git a/tests/cast-componentwise-equal.shader_test b/tests/cast-componentwise-equal.shader_test index 4c85b9ed..7fe9304b 100644 --- a/tests/cast-componentwise-equal.shader_test +++ b/tests/cast-componentwise-equal.shader_test @@ -124,7 +124,7 @@ draw quad probe all rgba (4.0, 4.0, 4.0, 4.0)
-[pixel shader] +[pixel shader todo] Texture2D tex;
struct apple diff --git a/tests/cast-to-half.shader_test b/tests/cast-to-half.shader_test index ffae9556..e2b66d4b 100644 --- a/tests/cast-to-half.shader_test +++ b/tests/cast-to-half.shader_test @@ -1,7 +1,7 @@ [require] shader model >= 4.0
-[pixel shader] +[pixel shader todo]
float4 main(uniform int i, uniform uint u, uniform bool b, uniform float f) : sv_target { diff --git a/tests/compute.shader_test b/tests/compute.shader_test index 900756e6..f5f5920f 100644 --- a/tests/compute.shader_test +++ b/tests/compute.shader_test @@ -7,7 +7,7 @@ size (1, 1)
0.1
-[compute shader] +[compute shader todo] RWTexture2D<float> u;
[numthreads(1, 1, 1)] diff --git a/tests/hlsl-array-dimension.shader_test b/tests/hlsl-array-dimension.shader_test index 89aae017..4e8bc12f 100644 --- a/tests/hlsl-array-dimension.shader_test +++ b/tests/hlsl-array-dimension.shader_test @@ -1,6 +1,6 @@ % Test what kinds of expressions are valid array dimensions.
-[pixel shader] +[pixel shader todo] float4 main() : sv_target { const int dim = 4; diff --git a/tests/hlsl-for.shader_test b/tests/hlsl-for.shader_test index e6329834..ae7146c9 100644 --- a/tests/hlsl-for.shader_test +++ b/tests/hlsl-for.shader_test @@ -4,7 +4,7 @@ void main(out float tex : texcoord, inout float4 pos : sv_position) tex = pos.x; }
-[pixel shader] +[pixel shader todo] float4 main(float tex : texcoord) : sv_target { int i; diff --git a/tests/hlsl-function-cast.shader_test b/tests/hlsl-function-cast.shader_test index ae6d1499..e6a5a96b 100644 --- a/tests/hlsl-function-cast.shader_test +++ b/tests/hlsl-function-cast.shader_test @@ -1,6 +1,6 @@ % Test implicit and explicit casts on function output parameters.
-[pixel shader] +[pixel shader todo]
uniform float4 f;
@@ -23,7 +23,7 @@ probe all rgba (-1.0, -1.0, 2.0, 4.0)
% As above, but cast "x" to float4 first.
-[pixel shader] +[pixel shader todo]
uniform float4 f;
@@ -46,7 +46,7 @@ probe all rgba (-1.0, -1.0, 2.0, 4.0)
% As above, but declare "x" as float4 and cast it to int4.
-[pixel shader] +[pixel shader todo]
uniform float4 f;
@@ -70,7 +70,7 @@ probe all rgba (-1.0, -1.0, 2.0, 4.0) [require] shader model >= 4.0
-[pixel shader] +[pixel shader todo]
void func(inout float4 a) { diff --git a/tests/hlsl-function-overload.shader_test b/tests/hlsl-function-overload.shader_test index 2410cecc..099f63f3 100644 --- a/tests/hlsl-function-overload.shader_test +++ b/tests/hlsl-function-overload.shader_test @@ -16,7 +16,7 @@ float4 main() : sv_target return 0; }
-[pixel shader] +[pixel shader todo] /* Test a basic overload. */ float func(int arg) { diff --git a/tests/hlsl-function.shader_test b/tests/hlsl-function.shader_test index 6f11e35b..da198083 100644 --- a/tests/hlsl-function.shader_test +++ b/tests/hlsl-function.shader_test @@ -9,7 +9,7 @@ float4 main() : sv_target
% It's legal to call an undefined function in unused code, though.
-[pixel shader] +[pixel shader todo]
float4 func();
@@ -118,7 +118,7 @@ void func() { }
-[pixel shader] +[pixel shader todo]
float func(in float a, out float b, inout float c) { @@ -142,7 +142,7 @@ float4 main() : sv_target todo draw quad probe all rgba (0.5, 0.6, 0.7, 0)
-[pixel shader] +[pixel shader todo]
void func(in float a, inout float2 b) { diff --git a/tests/hlsl-gather.shader_test b/tests/hlsl-gather.shader_test index be717cd9..28fd6f9a 100644 --- a/tests/hlsl-gather.shader_test +++ b/tests/hlsl-gather.shader_test @@ -73,7 +73,7 @@ draw quad probe all rgba (0.2, 0.2, 0.1, 0.1)
-[pixel shader] +[pixel shader todo] SamplerState s; Texture2D t;
diff --git a/tests/hlsl-initializer-objects.shader_test b/tests/hlsl-initializer-objects.shader_test index dcb60029..d40ede46 100644 --- a/tests/hlsl-initializer-objects.shader_test +++ b/tests/hlsl-initializer-objects.shader_test @@ -29,7 +29,7 @@ draw quad probe all rgba (0.2, 0.2, 0.2, 0.1)
-[pixel shader] +[pixel shader todo] Texture2D tex;
struct foo @@ -52,7 +52,7 @@ todo draw quad todo probe all rgba (31.1, 41.1, 51.1, 61.1) 1
-[pixel shader] +[pixel shader todo] Texture2D tex1; Texture2D tex2;
diff --git a/tests/hlsl-intrinsic-override.shader_test b/tests/hlsl-intrinsic-override.shader_test index a47f8176..f9233a5c 100644 --- a/tests/hlsl-intrinsic-override.shader_test +++ b/tests/hlsl-intrinsic-override.shader_test @@ -1,4 +1,4 @@ -[pixel shader] +[pixel shader todo]
float2 max(float2 a, float2 b) { @@ -14,7 +14,7 @@ float4 main() : sv_target todo draw quad probe all rgba (0.3, 0.3, 0.4, 0.6)
-[pixel shader] +[pixel shader todo]
float2 max(float2 a, float3 b) { diff --git a/tests/hlsl-return-implicit-conversion.shader_test b/tests/hlsl-return-implicit-conversion.shader_test index 545340eb..a276f5bd 100644 --- a/tests/hlsl-return-implicit-conversion.shader_test +++ b/tests/hlsl-return-implicit-conversion.shader_test @@ -38,7 +38,7 @@ float4x1 main() : sv_target draw quad probe all rgba (0.4, 0.3, 0.2, 0.1)
-[pixel shader] +[pixel shader todo] float3 func() { return float3x1(0.4, 0.3, 0.2); @@ -53,7 +53,7 @@ float4 main() : sv_target todo draw quad probe all rgba (0.4, 0.3, 0.2, 0.0)
-[pixel shader] +[pixel shader todo] float3 func() { return float1x3(0.4, 0.3, 0.2); @@ -68,7 +68,7 @@ float4 main() : sv_target todo draw quad probe all rgba (0.4, 0.3, 0.2, 0.0)
-[pixel shader] +[pixel shader todo] float1x3 func() { return float3(0.4, 0.3, 0.2); @@ -83,7 +83,7 @@ float4 main() : sv_target todo draw quad probe all rgba (0.4, 0.3, 0.2, 0.0)
-[pixel shader] +[pixel shader todo] float3x1 func() { return float3(0.4, 0.3, 0.2); @@ -120,7 +120,7 @@ float4 main() : sv_target return float4(func(), 0.0); }
-[pixel shader] +[pixel shader todo] float3 func() { return float4(0.4, 0.3, 0.2, 0.1); @@ -135,7 +135,7 @@ float4 main() : sv_target todo draw quad probe all rgba (0.4, 0.3, 0.2, 0.0)
-[pixel shader] +[pixel shader todo] float3 func() { return float4x1(0.4, 0.3, 0.2, 0.1); @@ -150,7 +150,7 @@ float4 main() : sv_target todo draw quad probe all rgba (0.4, 0.3, 0.2, 0.0)
-[pixel shader] +[pixel shader todo] float3 func() { return float1x4(0.4, 0.3, 0.2, 0.1); @@ -176,7 +176,7 @@ float4 main() : sv_target return float4(func(), 0.0); }
-[pixel shader] +[pixel shader todo] float3x1 func() { return float4x1(0.4, 0.3, 0.2, 0.1); @@ -202,7 +202,7 @@ float4 main() : sv_target return float4(func(), 0.0); }
-[pixel shader] +[pixel shader todo] float1x3 func() { return float4(0.4, 0.3, 0.2, 0.1); @@ -228,7 +228,7 @@ float4 main() : sv_target return float4(func(), 0.0); }
-[pixel shader] +[pixel shader todo] float1x3 func() { return float1x4(0.4, 0.3, 0.2, 0.1); diff --git a/tests/hlsl-static-initializer.shader_test b/tests/hlsl-static-initializer.shader_test index d8b85385..0f53f4d1 100644 --- a/tests/hlsl-static-initializer.shader_test +++ b/tests/hlsl-static-initializer.shader_test @@ -1,4 +1,4 @@ -[pixel shader] +[pixel shader todo] float myfunc() { return 0.6; diff --git a/tests/hlsl-storage-qualifiers.shader_test b/tests/hlsl-storage-qualifiers.shader_test index 4c590ceb..4d17c0d7 100644 --- a/tests/hlsl-storage-qualifiers.shader_test +++ b/tests/hlsl-storage-qualifiers.shader_test @@ -1,4 +1,4 @@ -[pixel shader] +[pixel shader todo] void sub2(in uniform float4 i, out float4 o) { o = i; diff --git a/tests/hlsl-vector-indexing-uniform.shader_test b/tests/hlsl-vector-indexing-uniform.shader_test index f6991040..968f570b 100644 --- a/tests/hlsl-vector-indexing-uniform.shader_test +++ b/tests/hlsl-vector-indexing-uniform.shader_test @@ -1,6 +1,6 @@ % Use a uniform to prevent the compiler from optimizing.
-[pixel shader] +[pixel shader todo] uniform float i; float4 main() : SV_TARGET { diff --git a/tests/object-references.shader_test b/tests/object-references.shader_test index 6cff351a..f3fda472 100644 --- a/tests/object-references.shader_test +++ b/tests/object-references.shader_test @@ -43,7 +43,7 @@ size (1, 1) size (1, 1) 3.0 3.0 3.0 1.0
-[pixel shader] +[pixel shader todo] Texture2D tex[3];
struct foo { diff --git a/tests/sampler-offset.shader_test b/tests/sampler-offset.shader_test index f47d5bff..2aa8f9b3 100644 --- a/tests/sampler-offset.shader_test +++ b/tests/sampler-offset.shader_test @@ -12,7 +12,7 @@ size (3, 3) 0.0 0.2 0.0 0.4 0.1 0.2 0.5 0.0 0.2 0.2 0.0 0.4
-[pixel shader] +[pixel shader todo] sampler s; Texture2D t;
@@ -26,7 +26,7 @@ todo draw quad probe all rgba (0.1, 0.2, 0.5, 0.0)
-[pixel shader] +[pixel shader todo] sampler s; Texture2D t;
@@ -40,7 +40,7 @@ todo draw quad probe all rgba (0.2, 0.2, 0.0, 0.4)
-[pixel shader] +[pixel shader todo] sampler s; Texture2D t;
diff --git a/tests/shader_runner.c b/tests/shader_runner.c index 43db4d98..fb4ece26 100644 --- a/tests/shader_runner.c +++ b/tests/shader_runner.c @@ -81,9 +81,11 @@ enum parse_state STATE_RESOURCE, STATE_SAMPLER, STATE_SHADER_COMPUTE, + STATE_SHADER_COMPUTE_TODO, STATE_SHADER_INVALID_PIXEL, STATE_SHADER_INVALID_PIXEL_TODO, STATE_SHADER_PIXEL, + STATE_SHADER_PIXEL_TODO, STATE_SHADER_VERTEX, STATE_TEST, }; @@ -657,6 +659,44 @@ unsigned int get_vb_stride(const struct shader_runner *runner, unsigned int slot return stride; }
+static void compile_shader(struct shader_runner *runner, const char *source, size_t len, const char *type, bool invalid) +{ + ID3D10Blob *blob = NULL, *errors = NULL; + char profile[7]; + HRESULT hr; + + static const char *const shader_models[] = + { + [SHADER_MODEL_2_0] = "4_0", + [SHADER_MODEL_4_0] = "4_0", + [SHADER_MODEL_4_1] = "4_1", + [SHADER_MODEL_5_0] = "5_0", + [SHADER_MODEL_5_1] = "5_1", + }; + + sprintf(profile, "%s_%s", type, shader_models[runner->minimum_shader_model]); + hr = D3DCompile(source, len, NULL, NULL, NULL, "main", profile, 0, 0, &blob, &errors); + if (invalid) + ok(hr == E_FAIL, "Got unexpected hr %#x.\n", hr); + else + ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); + if (hr == S_OK) + { + ID3D10Blob_Release(blob); + } + else + { + assert_that(!blob, "Expected no compiled shader blob.\n"); + assert_that(!!errors, "Expected non-NULL error blob.\n"); + } + if (errors) + { + if (vkd3d_test_state.debug_level) + trace("%s\n", (char *)ID3D10Blob_GetBufferPointer(errors)); + ID3D10Blob_Release(errors); + } +} + void run_shader_tests(struct shader_runner *runner, int argc, char **argv, const struct shader_runner_ops *ops) { size_t shader_source_size = 0, shader_source_len = 0; @@ -722,6 +762,9 @@ void run_shader_tests(struct shader_runner *runner, int argc, char **argv, const break;
case STATE_SHADER_COMPUTE: + case STATE_SHADER_COMPUTE_TODO: + todo_if (state == STATE_SHADER_COMPUTE_TODO) + compile_shader(runner, shader_source, shader_source_len, "cs", false); free(runner->cs_source); runner->cs_source = shader_source; shader_source = NULL; @@ -730,6 +773,9 @@ void run_shader_tests(struct shader_runner *runner, int argc, char **argv, const break;
case STATE_SHADER_PIXEL: + case STATE_SHADER_PIXEL_TODO: + todo_if (state == STATE_SHADER_PIXEL_TODO) + compile_shader(runner, shader_source, shader_source_len, "ps", false); free(runner->ps_source); runner->ps_source = shader_source; shader_source = NULL; @@ -738,6 +784,7 @@ void run_shader_tests(struct shader_runner *runner, int argc, char **argv, const break;
case STATE_SHADER_VERTEX: + compile_shader(runner, shader_source, shader_source_len, "vs", false); free(runner->vs_source); runner->vs_source = shader_source; shader_source = NULL; @@ -747,33 +794,10 @@ void run_shader_tests(struct shader_runner *runner, int argc, char **argv, const
case STATE_SHADER_INVALID_PIXEL: case STATE_SHADER_INVALID_PIXEL_TODO: - { - ID3D10Blob *blob = NULL, *errors = NULL; - HRESULT hr; - - hr = D3DCompile(shader_source, strlen(shader_source), NULL, - NULL, NULL, "main", "ps_4_0", 0, 0, &blob, &errors); todo_if (state == STATE_SHADER_INVALID_PIXEL_TODO) - ok(hr == E_FAIL, "Got unexpected hr %#x.\n", hr); - if (hr == S_OK) - { - ID3D10Blob_Release(blob); - } - else - { - ok(!blob, "Expected no compiled shader blob.\n"); - ok(!!errors, "Expected non-NULL error blob.\n"); - } - if (errors) - { - if (vkd3d_test_state.debug_level) - trace("%s\n", (char *)ID3D10Blob_GetBufferPointer(errors)); - ID3D10Blob_Release(errors); - } - + compile_shader(runner, shader_source, shader_source_len, "ps", true); shader_source_len = 0; break; - }
case STATE_PREPROC_INVALID: { @@ -840,6 +864,10 @@ void run_shader_tests(struct shader_runner *runner, int argc, char **argv, const { state = STATE_SHADER_COMPUTE; } + else if (!strcmp(line, "[compute shader todo]\n")) + { + state = STATE_SHADER_COMPUTE_TODO; + } else if (!strcmp(line, "[require]\n")) { state = STATE_REQUIRE; @@ -848,6 +876,10 @@ void run_shader_tests(struct shader_runner *runner, int argc, char **argv, const { state = STATE_SHADER_PIXEL; } + else if (!strcmp(line, "[pixel shader todo]\n")) + { + state = STATE_SHADER_PIXEL_TODO; + } else if (!strcmp(line, "[pixel shader fail]\n")) { state = STATE_SHADER_INVALID_PIXEL; @@ -962,9 +994,11 @@ void run_shader_tests(struct shader_runner *runner, int argc, char **argv, const case STATE_PREPROC: case STATE_PREPROC_INVALID: case STATE_SHADER_COMPUTE: + case STATE_SHADER_COMPUTE_TODO: case STATE_SHADER_INVALID_PIXEL: case STATE_SHADER_INVALID_PIXEL_TODO: case STATE_SHADER_PIXEL: + case STATE_SHADER_PIXEL_TODO: case STATE_SHADER_VERTEX: { size_t len = strlen(line); diff --git a/tests/trigonometry.shader_test b/tests/trigonometry.shader_test index b2e87f4a..afc09221 100644 --- a/tests/trigonometry.shader_test +++ b/tests/trigonometry.shader_test @@ -4,7 +4,7 @@ void main(out float tex : texcoord, inout float4 pos : sv_position) tex = (pos.x + 1) * 320; }
-[pixel shader] +[pixel shader todo] float4 main(float tex : texcoord) : sv_target { tex = floor(tex + 0.25); diff --git a/tests/uav-load.shader_test b/tests/uav-load.shader_test index 88adb6d5..0f622f2b 100644 --- a/tests/uav-load.shader_test +++ b/tests/uav-load.shader_test @@ -13,7 +13,7 @@ size (1, 1)
0.5
-[compute shader] +[compute shader todo] RWTexture2D<float> u, v; [numthreads(1, 1, 1)] void main() diff --git a/tests/uav.shader_test b/tests/uav.shader_test index 92ac8c4d..0c690f8e 100644 --- a/tests/uav.shader_test +++ b/tests/uav.shader_test @@ -133,7 +133,7 @@ size (1, 1)
0.5 0.6 0.7 0.8
-[pixel shader] +[pixel shader todo] RWTexture2D<float4> u[2] : register(u2);
float4 main() : sv_target1
From: Zebediah Figura zfigura@codeweavers.com
--- Makefile.am | 2 + tests/hlsl-attributes.shader_test | 120 +++++++++++++++++++ tests/hlsl-numthreads.shader_test | 192 ++++++++++++++++++++++++++++++ tests/shader_runner.c | 19 +++ 4 files changed, 333 insertions(+) create mode 100644 tests/hlsl-attributes.shader_test create mode 100644 tests/hlsl-numthreads.shader_test
diff --git a/Makefile.am b/Makefile.am index 3787389b..0db71d67 100644 --- a/Makefile.am +++ b/Makefile.am @@ -69,6 +69,7 @@ vkd3d_shader_tests = \ tests/conditional.shader_test \ tests/floor.shader_test \ tests/hlsl-array-dimension.shader_test \ + tests/hlsl-attributes.shader_test \ tests/hlsl-bool-cast.shader_test \ tests/hlsl-clamp.shader_test \ tests/hlsl-comma.shader_test \ @@ -104,6 +105,7 @@ vkd3d_shader_tests = \ tests/hlsl-normalize.shader_test \ tests/hlsl-numeric-constructor-truncation.shader_test \ tests/hlsl-numeric-types.shader_test \ + tests/hlsl-numthreads.shader_test \ tests/hlsl-return-implicit-conversion.shader_test \ tests/hlsl-return-void.shader_test \ tests/hlsl-shape.shader_test \ diff --git a/tests/hlsl-attributes.shader_test b/tests/hlsl-attributes.shader_test new file mode 100644 index 00000000..db011873 --- /dev/null +++ b/tests/hlsl-attributes.shader_test @@ -0,0 +1,120 @@ +% Test HLSL attribute syntax. The compiler ignores unrecognized attributes, so +% we need to get the parsing syntax right. Most of the following tests which +% succeed print warnings. + +[pixel shader todo] + + [numthreads] +float4 main() : sv_target { return 0; } + +[pixel shader todo] + + [ numthreads ] +float4 main() : sv_target { return 0; } + +[pixel shader todo] + + [numthreads(1)] +float4 main() : sv_target { return 0; } + +[pixel shader todo] + + [numthreads("")] +float4 main() : sv_target { return 0; } + +[pixel shader todo] + + [numthreads("one")] +float4 main() : sv_target { return 0; } + +[pixel shader todo] + +uniform float4 f; + + [numthreads(1, "one", 3 + 9, -9.8e4, -float2(1, 2), f)] +float4 main() : sv_target { return 0; } + +[pixel shader fail] + + [numthreads()] +float4 main() : sv_target { return 0; } + +[pixel shader fail] + + [numthreads(1,)] +float4 main() : sv_target { return 0; } + +[pixel shader fail] + + [numthreads(f)] +float4 main() : sv_target { return 0; } + +[pixel shader fail] + + /* Test an invalid constructor. */ + [numthreads(float2(1))] +float4 main() : sv_target { return 0; } + +[pixel shader todo] + + [not_a_real_attribute_name] +float4 main() : sv_target { return 0; } + +[pixel shader todo] + +uniform float4 f; + + [f] +float4 main() : sv_target { return 0; } + +[pixel shader fail] +% This is valid IDL syntax, but not HLSL. + [one, two] +float4 main() : sv_target { return 0; } + +[pixel shader todo] + + [one][two] +float4 main() : sv_target { return 0; } + +[pixel shader fail] + + [one][one] +float4 main() : sv_target { return 0; } + +[pixel shader fail] + + [one][one(1)] +float4 main() : sv_target { return 0; } + +[pixel shader todo] + + [one][One] +float4 main() : sv_target { return 0; } + +[pixel shader todo] + + [numthreads] +float4 main(); + + [numthreads] +float4 main() : sv_target { return 0; } + +[pixel shader todo] + +/* Expressions with side effects are forbidden in attributes—see + * hlsl-numthreads.shader_test for an example—but not if the attribute is + * ignored. */ +static int i = 1; + + [one(i++)] + [two(++i)] + [three(i = 4)] +float4 main() : sv_target { return 0; } + +[pixel shader fail] + + [one] +float4 f; + +float4 main() : sv_target { return 0; } diff --git a/tests/hlsl-numthreads.shader_test b/tests/hlsl-numthreads.shader_test new file mode 100644 index 00000000..f0ef5f62 --- /dev/null +++ b/tests/hlsl-numthreads.shader_test @@ -0,0 +1,192 @@ +% Test allowed syntax for the "numthreads" attribute. + +[require] +shader model >= 5.0 + +[compute shader todo] + + [numthreads(1, 1, 1)] +void main() {} + +[compute shader fail] + + [numthreads] +void main() {} + +[compute shader fail] + + [numthreads(1, 1)] +void main() {} + +[compute shader fail] + + [numthreads(1, 1, 1, 1)] +void main() {} + +[compute shader fail] + + [numthreads(0, 1, 1)] +void main() {} + +[compute shader fail] + + [numthreads(1, 0, 1)] +void main() {} + +[compute shader fail] + + [numthreads(1, 1, 0)] +void main() {} + +[compute shader fail] + + [numthreads(-1, 1, 1)] +void main() {} + +[compute shader fail] + + [numthreads(1, -1, 1)] +void main() {} + +[compute shader fail] + + [numthreads(1, 1, -1)] +void main() {} + +[compute shader fail] + + [numthreads(1, -1, -1)] +void main() {} + +[compute shader todo] + + [numthreads(uint(1), 1, 1)] +void main() {} + +[compute shader todo] + + [numthreads(int(1), 1, 1)] +void main() {} + +[compute shader fail] + + [numthreads(float(1), 1, 1)] +void main() {} + +[compute shader fail] + + [numthreads(uint1(1), 1, 1)] +void main() {} + +[compute shader todo] + + [numthreads(int(1), 1, 1)] +void main() {} + +[compute shader todo] + + [numthreads(1 + 1, 1, 1)] +void main() {} + +[compute shader fail] + + [numthreads("1", 1, 1)] +void main() {} + +[compute shader todo] +static int x = 1; + + [numthreads(x, 1, 1)] +void main() {} + +[compute shader fail todo] + +void main() {} + +[compute shader fail] + + [NumThreads(1, 1, 1)] +void main() {} + +[compute shader todo] + + [numthreads(1, 1, 1)] +void main(); + +void main() {} + +[compute shader fail] + +void main() {} + + [numthreads(1, 1, 1)] +void main(); + +[compute shader fail] + +void main(); + + [numthreads(1, 1, 1)] +void main() {} + +[compute shader fail] + +/* Expressions with side effects are forbidden in attributes (but not if the + * attribute is ignored). */ + +static int x = 1; + + [numthreads(x++, 1, 1)] +void main() {} + +[compute shader fail] + +static int x = 1; + + [numthreads(++x, 1, 1)] +void main() {} + +[compute shader fail] + +static int x = 1; + + [numthreads((x = 2), 1, 1)] +void main() {} + +[compute shader todo] + +static int x = 1; + + [numthreads(++x, 1, 1)] +void func() {} + + [bogus(++x)] + [numthreads(1, 1, 1)] +void main() { func(); } + +[uav 0] +format r32 float +size (2, 2) + +1.0 1.0 +1.0 1.0 + +[compute shader todo] +/* Attributes are taken from the first function, and dropped from the second. */ +RWTexture2D<float> u; + + [numthreads(2, 1, 1)] +void main(uint2 id); + + [numthreads(1, 2, 1)] +void main(uint2 id : sv_dispatchthreadid) +{ + u[id] = 2.0; +} + +[test] +todo dispatch 1 1 1 +probe uav 0 (0, 0) r (2.0) +probe uav 0 (0, 1) r (1.0) +probe uav 0 (1, 0) r (2.0) +probe uav 0 (1, 1) r (1.0) diff --git a/tests/shader_runner.c b/tests/shader_runner.c index fb4ece26..4750b946 100644 --- a/tests/shader_runner.c +++ b/tests/shader_runner.c @@ -82,6 +82,8 @@ enum parse_state STATE_SAMPLER, STATE_SHADER_COMPUTE, STATE_SHADER_COMPUTE_TODO, + STATE_SHADER_INVALID_COMPUTE, + STATE_SHADER_INVALID_COMPUTE_TODO, STATE_SHADER_INVALID_PIXEL, STATE_SHADER_INVALID_PIXEL_TODO, STATE_SHADER_PIXEL, @@ -792,6 +794,13 @@ void run_shader_tests(struct shader_runner *runner, int argc, char **argv, const shader_source_size = 0; break;
+ case STATE_SHADER_INVALID_COMPUTE: + case STATE_SHADER_INVALID_COMPUTE_TODO: + todo_if (state == STATE_SHADER_INVALID_COMPUTE_TODO) + compile_shader(runner, shader_source, shader_source_len, "cs", true); + shader_source_len = 0; + break; + case STATE_SHADER_INVALID_PIXEL: case STATE_SHADER_INVALID_PIXEL_TODO: todo_if (state == STATE_SHADER_INVALID_PIXEL_TODO) @@ -868,6 +877,14 @@ void run_shader_tests(struct shader_runner *runner, int argc, char **argv, const { state = STATE_SHADER_COMPUTE_TODO; } + else if (!strcmp(line, "[compute shader fail]\n")) + { + state = STATE_SHADER_INVALID_COMPUTE; + } + else if (!strcmp(line, "[compute shader fail todo]\n")) + { + state = STATE_SHADER_INVALID_COMPUTE_TODO; + } else if (!strcmp(line, "[require]\n")) { state = STATE_REQUIRE; @@ -995,6 +1012,8 @@ void run_shader_tests(struct shader_runner *runner, int argc, char **argv, const case STATE_PREPROC_INVALID: case STATE_SHADER_COMPUTE: case STATE_SHADER_COMPUTE_TODO: + case STATE_SHADER_INVALID_COMPUTE: + case STATE_SHADER_INVALID_COMPUTE_TODO: case STATE_SHADER_INVALID_PIXEL: case STATE_SHADER_INVALID_PIXEL_TODO: case STATE_SHADER_PIXEL:
From: Zebediah Figura zfigura@codeweavers.com
In particular so that we don't cause test crashes by outputting invalid compute shaders. --- libs/vkd3d-shader/hlsl.c | 7 +++++++ 1 file changed, 7 insertions(+)
diff --git a/libs/vkd3d-shader/hlsl.c b/libs/vkd3d-shader/hlsl.c index 1f35b1ac..3f80fcf2 100644 --- a/libs/vkd3d-shader/hlsl.c +++ b/libs/vkd3d-shader/hlsl.c @@ -2565,6 +2565,13 @@ int hlsl_compile_shader(const struct vkd3d_shader_code *hlsl, const struct vkd3d return VKD3D_ERROR_INVALID_SHADER; }
+ if (profile->type == VKD3D_SHADER_TYPE_COMPUTE) + { + const struct vkd3d_shader_location loc = {.source_name = compile_info->source_name}; + + hlsl_fixme(&ctx, &loc, "Compute shader thread count.\n"); + } + ret = hlsl_emit_bytecode(&ctx, entry_func, compile_info->target_type, out);
hlsl_ctx_cleanup(&ctx);
From: Zebediah Figura zfigura@codeweavers.com
--- libs/vkd3d-shader/hlsl.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-)
diff --git a/libs/vkd3d-shader/hlsl.c b/libs/vkd3d-shader/hlsl.c index 3f80fcf2..11cb2e7e 100644 --- a/libs/vkd3d-shader/hlsl.c +++ b/libs/vkd3d-shader/hlsl.c @@ -1193,17 +1193,12 @@ struct hlsl_ir_function_decl *hlsl_new_func_decl(struct hlsl_ctx *ctx, struct hl
if (!hlsl_types_are_equal(return_type, ctx->builtin_types.Void)) { - struct hlsl_ir_var *return_var; - char name[28]; - - sprintf(name, "<retval-%p>", decl); - if (!(return_var = hlsl_new_var(ctx, hlsl_strdup(ctx, name), return_type, loc, semantic, 0, NULL))) + if (!(decl->return_var = hlsl_new_synthetic_var(ctx, "retval", return_type, &loc))) { vkd3d_free(decl); return NULL; } - list_add_tail(&ctx->globals->vars, &return_var->scope_entry); - decl->return_var = return_var; + decl->return_var->semantic = *semantic; }
return decl;
From: Zebediah Figura zfigura@codeweavers.com
--- libs/vkd3d-shader/hlsl.c | 33 ++++++++- libs/vkd3d-shader/hlsl.h | 14 +++- libs/vkd3d-shader/hlsl.y | 87 +++++++++++++++++++++++- libs/vkd3d-shader/hlsl_codegen.c | 5 ++ libs/vkd3d-shader/vkd3d_shader_private.h | 1 + tests/hlsl-attributes.shader_test | 22 +++--- tests/hlsl-numthreads.shader_test | 36 +++++----- 7 files changed, 163 insertions(+), 35 deletions(-)
diff --git a/libs/vkd3d-shader/hlsl.c b/libs/vkd3d-shader/hlsl.c index 11cb2e7e..310560b2 100644 --- a/libs/vkd3d-shader/hlsl.c +++ b/libs/vkd3d-shader/hlsl.c @@ -1180,7 +1180,7 @@ struct hlsl_ir_loop *hlsl_new_loop(struct hlsl_ctx *ctx, struct vkd3d_shader_loc }
struct hlsl_ir_function_decl *hlsl_new_func_decl(struct hlsl_ctx *ctx, struct hlsl_type *return_type, - struct list *parameters, const struct hlsl_semantic *semantic, struct vkd3d_shader_location loc) + struct list *parameters, const struct hlsl_semantic *semantic, const struct vkd3d_shader_location *loc) { struct hlsl_ir_function_decl *decl;
@@ -1189,11 +1189,11 @@ struct hlsl_ir_function_decl *hlsl_new_func_decl(struct hlsl_ctx *ctx, struct hl list_init(&decl->body.instrs); decl->return_type = return_type; decl->parameters = parameters; - decl->loc = loc; + decl->loc = *loc;
if (!hlsl_types_are_equal(return_type, ctx->builtin_types.Void)) { - if (!(decl->return_var = hlsl_new_synthetic_var(ctx, "retval", return_type, &loc))) + if (!(decl->return_var = hlsl_new_synthetic_var(ctx, "retval", return_type, loc))) { vkd3d_free(decl); return NULL; @@ -2086,8 +2086,25 @@ void hlsl_free_instr(struct hlsl_ir_node *node) } }
+void hlsl_free_attribute(struct hlsl_attribute *attr) +{ + unsigned int i; + + for (i = 0; i < attr->args_count; ++i) + hlsl_src_remove(&attr->args[i]); + hlsl_free_instr_list(&attr->instrs); + vkd3d_free((void *)attr->name); + vkd3d_free(attr); +} + static void free_function_decl(struct hlsl_ir_function_decl *decl) { + unsigned int i; + + for (i = 0; i < decl->attr_count; ++i) + hlsl_free_attribute((void *)decl->attrs[i]); + vkd3d_free((void *)decl->attrs); + vkd3d_free(decl->parameters); hlsl_free_instr_list(&decl->body.instrs); vkd3d_free(decl); @@ -2135,6 +2152,7 @@ void hlsl_add_function(struct hlsl_ctx *ctx, char *name, struct hlsl_ir_function { struct hlsl_ir_function_decl *old_decl = RB_ENTRY_VALUE(old_entry, struct hlsl_ir_function_decl, entry); + unsigned int i;
if (!decl->has_body) { @@ -2142,6 +2160,15 @@ void hlsl_add_function(struct hlsl_ctx *ctx, char *name, struct hlsl_ir_function vkd3d_free(name); return; } + + for (i = 0; i < decl->attr_count; ++i) + hlsl_free_attribute((void *)decl->attrs[i]); + vkd3d_free((void *)decl->attrs); + decl->attr_count = old_decl->attr_count; + decl->attrs = old_decl->attrs; + old_decl->attr_count = 0; + old_decl->attrs = NULL; + rb_remove(&func->overloads, old_entry); free_function_decl(old_decl); } diff --git a/libs/vkd3d-shader/hlsl.h b/libs/vkd3d-shader/hlsl.h index 26629fcd..c7a19302 100644 --- a/libs/vkd3d-shader/hlsl.h +++ b/libs/vkd3d-shader/hlsl.h @@ -212,6 +212,15 @@ struct hlsl_src struct list entry; };
+struct hlsl_attribute +{ + const char *name; + struct list instrs; + struct vkd3d_shader_location loc; + unsigned int args_count; + struct hlsl_src args[]; +}; + #define HLSL_STORAGE_EXTERN 0x00000001 #define HLSL_STORAGE_NOINTERPOLATION 0x00000002 #define HLSL_MODIFIER_PRECISE 0x00000004 @@ -279,6 +288,8 @@ struct hlsl_ir_function_decl struct list *parameters; struct hlsl_block body; bool has_body; + unsigned int attr_count; + const struct hlsl_attribute *const *attrs; };
struct hlsl_ir_if @@ -741,6 +752,7 @@ void hlsl_cleanup_deref(struct hlsl_deref *deref);
void hlsl_replace_node(struct hlsl_ir_node *old, struct hlsl_ir_node *new);
+void hlsl_free_attribute(struct hlsl_attribute *attr); void hlsl_free_instr(struct hlsl_ir_node *node); void hlsl_free_instr_list(struct list *list); void hlsl_free_type(struct hlsl_type *type); @@ -771,7 +783,7 @@ struct hlsl_ir_node *hlsl_new_expr(struct hlsl_ctx *ctx, enum hlsl_ir_expr_op op struct hlsl_ir_constant *hlsl_new_float_constant(struct hlsl_ctx *ctx, float f, const struct vkd3d_shader_location *loc); struct hlsl_ir_function_decl *hlsl_new_func_decl(struct hlsl_ctx *ctx, struct hlsl_type *return_type, - struct list *parameters, const struct hlsl_semantic *semantic, struct vkd3d_shader_location loc); + struct list *parameters, const struct hlsl_semantic *semantic, const struct vkd3d_shader_location *loc); struct hlsl_ir_if *hlsl_new_if(struct hlsl_ctx *ctx, struct hlsl_ir_node *condition, struct vkd3d_shader_location loc); struct hlsl_ir_constant *hlsl_new_int_constant(struct hlsl_ctx *ctx, int n, const struct vkd3d_shader_location *loc); diff --git a/libs/vkd3d-shader/hlsl.y b/libs/vkd3d-shader/hlsl.y index 00842195..f87ef4df 100644 --- a/libs/vkd3d-shader/hlsl.y +++ b/libs/vkd3d-shader/hlsl.y @@ -102,6 +102,12 @@ enum parse_assign_op ASSIGN_OP_XOR, };
+struct parse_attribute_list +{ + unsigned int count; + const struct hlsl_attribute **attrs; +}; + }
%code provides @@ -3036,6 +3042,8 @@ static bool add_method_call(struct hlsl_ctx *ctx, struct list *instrs, struct hl struct hlsl_semantic semantic; enum hlsl_buffer_type buffer_type; enum hlsl_sampler_dim sampler_dim; + struct hlsl_attribute *attr; + struct parse_attribute_list attr_list; }
%token KW_BLENDSTATE @@ -3185,6 +3193,10 @@ static bool add_method_call(struct hlsl_ctx *ctx, struct list *instrs, struct hl
%type <assign_op> assign_op
+%type <attr> attribute + +%type <attr_list> attribute_list + %type <boolval> boolean
%type <buffer_type> buffer_type @@ -3196,6 +3208,7 @@ static bool add_method_call(struct hlsl_ctx *ctx, struct list *instrs, struct hl
%type <function> func_declaration %type <function> func_prototype +%type <function> func_prototype_no_attrs
%type <initializer> complex_initializer %type <initializer> complex_initializer_list @@ -3435,6 +3448,67 @@ field: YYABORT; }
+attribute: + '[' any_identifier ']' + { + if (!($$ = hlsl_alloc(ctx, offsetof(struct hlsl_attribute, args[0])))) + { + vkd3d_free($2); + YYABORT; + } + $$->name = $2; + list_init(&$$->instrs); + $$->loc = @$; + $$->args_count = 0; + } + | '[' any_identifier '(' initializer_expr_list ')' ']' + { + unsigned int i; + + if (!($$ = hlsl_alloc(ctx, offsetof(struct hlsl_attribute, args[$4.args_count])))) + { + vkd3d_free($2); + free_parse_initializer(&$4); + YYABORT; + } + $$->name = $2; + list_init(&$$->instrs); + list_move_tail(&$$->instrs, $4.instrs); + vkd3d_free($4.instrs); + $$->loc = @$; + $$->args_count = $4.args_count; + for (i = 0; i < $4.args_count; ++i) + hlsl_src_from_node(&$$->args[i], $4.args[i]); + } + +attribute_list: + attribute + { + $$.count = 1; + if (!($$.attrs = hlsl_alloc(ctx, sizeof(*$$.attrs)))) + { + hlsl_free_attribute($1); + YYABORT; + } + $$.attrs[0] = $1; + } + | attribute_list attribute + { + const struct hlsl_attribute **new_array; + + $$ = $1; + if (!(new_array = vkd3d_realloc($$.attrs, ($$.count + 1) * sizeof(*$$.attrs)))) + { + unsigned int i; + + for (i = 0; i < $$.count; ++i) + hlsl_free_attribute((void *)$$.attrs[i]); + vkd3d_free($$.attrs); + YYABORT; + } + $$.attrs[$$.count++] = $2; + } + func_declaration: func_prototype compound_statement { @@ -3450,7 +3524,7 @@ func_declaration: hlsl_pop_scope(ctx); }
-func_prototype: +func_prototype_no_attrs: /* var_modifiers is necessary to avoid shift/reduce conflicts. */ var_modifiers type var_identifier '(' parameters ')' colon_attribute { @@ -3483,12 +3557,21 @@ func_prototype: if ($7.reg_reservation.type) FIXME("Unexpected register reservation for a function.\n");
- if (!($$.decl = hlsl_new_func_decl(ctx, type, $5, &$7.semantic, @3))) + if (!($$.decl = hlsl_new_func_decl(ctx, type, $5, &$7.semantic, &@3))) YYABORT; $$.name = $3; ctx->cur_function = $$.decl; }
+func_prototype: + func_prototype_no_attrs + | attribute_list func_prototype_no_attrs + { + $2.decl->attr_count = $1.count; + $2.decl->attrs = $1.attrs; + $$ = $2; + } + compound_statement: '{' '}' { diff --git a/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d-shader/hlsl_codegen.c index 6e650db0..0df870cc 100644 --- a/libs/vkd3d-shader/hlsl_codegen.c +++ b/libs/vkd3d-shader/hlsl_codegen.c @@ -2539,6 +2539,7 @@ int hlsl_emit_bytecode(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry { struct hlsl_block *const body = &entry_func->body; struct hlsl_ir_var *var; + unsigned int i; bool progress;
list_move_head(&body->instrs, &ctx->static_initializers); @@ -2576,6 +2577,10 @@ int hlsl_emit_bytecode(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry append_output_var_copy(ctx, &body->instrs, entry_func->return_var); }
+ for (i = 0; i < entry_func->attr_count; ++i) + hlsl_warning(ctx, &entry_func->attrs[i]->loc, VKD3D_SHADER_WARNING_HLSL_UNKNOWN_ATTRIBUTE, + "Ignoring unknown attribute "%s".", entry_func->attrs[i]->name); + transform_ir(ctx, lower_broadcasts, body, NULL); while (transform_ir(ctx, fold_redundant_casts, body, NULL)); do diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h index aca5606b..cd2ff305 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -122,6 +122,7 @@ enum vkd3d_shader_error
VKD3D_SHADER_WARNING_HLSL_IMPLICIT_TRUNCATION = 5300, VKD3D_SHADER_WARNING_HLSL_DIVISION_BY_ZERO = 5301, + VKD3D_SHADER_WARNING_HLSL_UNKNOWN_ATTRIBUTE = 5302,
VKD3D_SHADER_ERROR_GLSL_INTERNAL = 6000,
diff --git a/tests/hlsl-attributes.shader_test b/tests/hlsl-attributes.shader_test index db011873..cb6c2b5e 100644 --- a/tests/hlsl-attributes.shader_test +++ b/tests/hlsl-attributes.shader_test @@ -2,17 +2,17 @@ % we need to get the parsing syntax right. Most of the following tests which % succeed print warnings.
-[pixel shader todo] +[pixel shader]
[numthreads] float4 main() : sv_target { return 0; }
-[pixel shader todo] +[pixel shader]
[ numthreads ] float4 main() : sv_target { return 0; }
-[pixel shader todo] +[pixel shader]
[numthreads(1)] float4 main() : sv_target { return 0; } @@ -55,12 +55,12 @@ float4 main() : sv_target { return 0; } [numthreads(float2(1))] float4 main() : sv_target { return 0; }
-[pixel shader todo] +[pixel shader]
[not_a_real_attribute_name] float4 main() : sv_target { return 0; }
-[pixel shader todo] +[pixel shader]
uniform float4 f;
@@ -72,27 +72,27 @@ float4 main() : sv_target { return 0; } [one, two] float4 main() : sv_target { return 0; }
-[pixel shader todo] +[pixel shader]
[one][two] float4 main() : sv_target { return 0; }
-[pixel shader fail] +[pixel shader fail todo]
[one][one] float4 main() : sv_target { return 0; }
-[pixel shader fail] +[pixel shader fail todo]
[one][one(1)] float4 main() : sv_target { return 0; }
-[pixel shader todo] +[pixel shader]
[one][One] float4 main() : sv_target { return 0; }
-[pixel shader todo] +[pixel shader]
[numthreads] float4 main(); @@ -100,7 +100,7 @@ float4 main(); [numthreads] float4 main() : sv_target { return 0; }
-[pixel shader todo] +[pixel shader]
/* Expressions with side effects are forbidden in attributes—see * hlsl-numthreads.shader_test for an example—but not if the attribute is diff --git a/tests/hlsl-numthreads.shader_test b/tests/hlsl-numthreads.shader_test index f0ef5f62..3e3973b3 100644 --- a/tests/hlsl-numthreads.shader_test +++ b/tests/hlsl-numthreads.shader_test @@ -8,52 +8,52 @@ shader model >= 5.0 [numthreads(1, 1, 1)] void main() {}
-[compute shader fail] +[compute shader fail todo]
[numthreads] void main() {}
-[compute shader fail] +[compute shader fail todo]
[numthreads(1, 1)] void main() {}
-[compute shader fail] +[compute shader fail todo]
[numthreads(1, 1, 1, 1)] void main() {}
-[compute shader fail] +[compute shader fail todo]
[numthreads(0, 1, 1)] void main() {}
-[compute shader fail] +[compute shader fail todo]
[numthreads(1, 0, 1)] void main() {}
-[compute shader fail] +[compute shader fail todo]
[numthreads(1, 1, 0)] void main() {}
-[compute shader fail] +[compute shader fail todo]
[numthreads(-1, 1, 1)] void main() {}
-[compute shader fail] +[compute shader fail todo]
[numthreads(1, -1, 1)] void main() {}
-[compute shader fail] +[compute shader fail todo]
[numthreads(1, 1, -1)] void main() {}
-[compute shader fail] +[compute shader fail todo]
[numthreads(1, -1, -1)] void main() {} @@ -68,12 +68,12 @@ void main() {} [numthreads(int(1), 1, 1)] void main() {}
-[compute shader fail] +[compute shader fail todo]
[numthreads(float(1), 1, 1)] void main() {}
-[compute shader fail] +[compute shader fail todo]
[numthreads(uint1(1), 1, 1)] void main() {} @@ -103,7 +103,7 @@ void main() {}
void main() {}
-[compute shader fail] +[compute shader fail todo]
[NumThreads(1, 1, 1)] void main() {} @@ -115,21 +115,21 @@ void main();
void main() {}
-[compute shader fail] +[compute shader fail todo]
void main() {}
[numthreads(1, 1, 1)] void main();
-[compute shader fail] +[compute shader fail todo]
void main();
[numthreads(1, 1, 1)] void main() {}
-[compute shader fail] +[compute shader fail todo]
/* Expressions with side effects are forbidden in attributes (but not if the * attribute is ignored). */ @@ -139,14 +139,14 @@ static int x = 1; [numthreads(x++, 1, 1)] void main() {}
-[compute shader fail] +[compute shader fail todo]
static int x = 1;
[numthreads(++x, 1, 1)] void main() {}
-[compute shader fail] +[compute shader fail todo]
static int x = 1;
From: Zebediah Figura zfigura@codeweavers.com
--- libs/vkd3d-shader/hlsl.h | 3 ++ libs/vkd3d-shader/hlsl_codegen.c | 68 ++++++++++++++++++++++-- libs/vkd3d-shader/vkd3d_shader_private.h | 2 + 3 files changed, 69 insertions(+), 4 deletions(-)
diff --git a/libs/vkd3d-shader/hlsl.h b/libs/vkd3d-shader/hlsl.h index c7a19302..b6a593ca 100644 --- a/libs/vkd3d-shader/hlsl.h +++ b/libs/vkd3d-shader/hlsl.h @@ -537,7 +537,10 @@ struct hlsl_ctx } constant_defs; uint32_t temp_count;
+ uint32_t thread_count[3]; + uint32_t in_state_block : 1; + uint32_t found_numthreads : 1; };
enum hlsl_error_level diff --git a/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d-shader/hlsl_codegen.c index 0df870cc..27af49cf 100644 --- a/libs/vkd3d-shader/hlsl_codegen.c +++ b/libs/vkd3d-shader/hlsl_codegen.c @@ -2534,9 +2534,58 @@ struct hlsl_reg hlsl_reg_from_deref(struct hlsl_ctx *ctx, const struct hlsl_dere return ret; }
+static void parse_numthreads_attribute(struct hlsl_ctx *ctx, const struct hlsl_attribute *attr) +{ + unsigned int i; + + ctx->found_numthreads = 1; + + if (attr->args_count != 3) + { + hlsl_error(ctx, &attr->loc, VKD3D_SHADER_ERROR_HLSL_WRONG_PARAMETER_COUNT, + "Expected 3 parameters for [numthreads] attribute, but got %u.", attr->args_count); + return; + } + + for (i = 0; i < attr->args_count; ++i) + { + const struct hlsl_ir_node *instr = attr->args[i].node; + const struct hlsl_type *type = instr->data_type; + const struct hlsl_ir_constant *constant; + + if (type->type != HLSL_CLASS_SCALAR + || (type->base_type != HLSL_TYPE_INT && type->base_type != HLSL_TYPE_UINT)) + { + struct vkd3d_string_buffer *string; + + if ((string = hlsl_type_to_string(ctx, type))) + hlsl_error(ctx, &instr->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE, + "Wrong type for argument %u of [numthreads]: expected int or uint, but got %s.", + i, string->buffer); + hlsl_release_string_buffer(ctx, string); + break; + } + + if (instr->type != HLSL_IR_CONSTANT) + { + hlsl_fixme(ctx, &instr->loc, "Non-constant expression in [numthreads] initializer."); + break; + } + constant = hlsl_ir_constant(instr); + + if ((type->base_type == HLSL_TYPE_INT && constant->value[0].i <= 0) + || (type->base_type == HLSL_TYPE_UINT && !constant->value[0].u)) + hlsl_error(ctx, &instr->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_THREAD_COUNT, + "Thread count must be a positive integer."); + + ctx->thread_count[i] = constant->value[0].u; + } +} + int hlsl_emit_bytecode(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry_func, enum vkd3d_shader_target_type target_type, struct vkd3d_shader_code *out) { + const struct hlsl_profile_info *profile = ctx->profile; struct hlsl_block *const body = &entry_func->body; struct hlsl_ir_var *var; unsigned int i; @@ -2578,8 +2627,19 @@ int hlsl_emit_bytecode(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry }
for (i = 0; i < entry_func->attr_count; ++i) - hlsl_warning(ctx, &entry_func->attrs[i]->loc, VKD3D_SHADER_WARNING_HLSL_UNKNOWN_ATTRIBUTE, - "Ignoring unknown attribute "%s".", entry_func->attrs[i]->name); + { + const struct hlsl_attribute *attr = entry_func->attrs[i]; + + if (!strcmp(attr->name, "numthreads") && profile->type == VKD3D_SHADER_TYPE_COMPUTE) + parse_numthreads_attribute(ctx, attr); + else + hlsl_warning(ctx, &entry_func->attrs[i]->loc, VKD3D_SHADER_WARNING_HLSL_UNKNOWN_ATTRIBUTE, + "Ignoring unknown attribute "%s".", entry_func->attrs[i]->name); + } + + if (profile->type == VKD3D_SHADER_TYPE_COMPUTE && !ctx->found_numthreads) + hlsl_error(ctx, &entry_func->loc, VKD3D_SHADER_ERROR_HLSL_MISSING_ATTRIBUTE, + "Entry point "%s" is missing a [numthreads] attribute.", entry_func->func->name);
transform_ir(ctx, lower_broadcasts, body, NULL); while (transform_ir(ctx, fold_redundant_casts, body, NULL)); @@ -2606,7 +2666,7 @@ int hlsl_emit_bytecode(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry } while (progress);
- if (ctx->profile->major_version < 4) + if (profile->major_version < 4) transform_ir(ctx, lower_division, body, NULL);
transform_ir(ctx, validate_static_object_references, body, NULL); @@ -2625,7 +2685,7 @@ int hlsl_emit_bytecode(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry rb_for_each_entry(&ctx->functions, dump_function, ctx);
allocate_temp_registers(ctx, entry_func); - if (ctx->profile->major_version < 4) + if (profile->major_version < 4) { allocate_const_registers(ctx, entry_func); } diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h index cd2ff305..156ed048 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -119,6 +119,8 @@ enum vkd3d_shader_error VKD3D_SHADER_ERROR_HLSL_INCOMPATIBLE_PROFILE = 5020, VKD3D_SHADER_ERROR_HLSL_DIVISION_BY_ZERO = 5021, VKD3D_SHADER_ERROR_HLSL_NON_STATIC_OBJECT_REF = 5022, + VKD3D_SHADER_ERROR_HLSL_INVALID_THREAD_COUNT = 5023, + VKD3D_SHADER_ERROR_HLSL_MISSING_ATTRIBUTE = 5024,
VKD3D_SHADER_WARNING_HLSL_IMPLICIT_TRUNCATION = 5300, VKD3D_SHADER_WARNING_HLSL_DIVISION_BY_ZERO = 5301,
From: Zebediah Figura zfigura@codeweavers.com
--- libs/vkd3d-shader/hlsl.c | 7 ------- libs/vkd3d-shader/hlsl_sm4.c | 18 +++++++++++++++++- tests/compute.shader_test | 6 +++--- tests/hlsl-numthreads.shader_test | 28 ++++++++++++++-------------- tests/uav-load.shader_test | 4 ++-- 5 files changed, 36 insertions(+), 27 deletions(-)
diff --git a/libs/vkd3d-shader/hlsl.c b/libs/vkd3d-shader/hlsl.c index 310560b2..eddbf2c8 100644 --- a/libs/vkd3d-shader/hlsl.c +++ b/libs/vkd3d-shader/hlsl.c @@ -2587,13 +2587,6 @@ int hlsl_compile_shader(const struct vkd3d_shader_code *hlsl, const struct vkd3d return VKD3D_ERROR_INVALID_SHADER; }
- if (profile->type == VKD3D_SHADER_TYPE_COMPUTE) - { - const struct vkd3d_shader_location loc = {.source_name = compile_info->source_name}; - - hlsl_fixme(&ctx, &loc, "Compute shader thread count.\n"); - } - ret = hlsl_emit_bytecode(&ctx, entry_func, compile_info->target_type, out);
hlsl_ctx_cleanup(&ctx); diff --git a/libs/vkd3d-shader/hlsl_sm4.c b/libs/vkd3d-shader/hlsl_sm4.c index d3e1cbfa..ae5bb1ac 100644 --- a/libs/vkd3d-shader/hlsl_sm4.c +++ b/libs/vkd3d-shader/hlsl_sm4.c @@ -833,7 +833,7 @@ struct sm4_instruction } srcs[4]; unsigned int src_count;
- uint32_t idx[2]; + uint32_t idx[3]; unsigned int idx_count; };
@@ -1278,6 +1278,19 @@ static void write_sm4_dcl_temps(struct vkd3d_bytecode_buffer *buffer, uint32_t t write_sm4_instruction(buffer, &instr); }
+static void write_sm4_dcl_thread_group(struct vkd3d_bytecode_buffer *buffer, const uint32_t thread_count[3]) +{ + struct sm4_instruction instr = + { + .opcode = VKD3D_SM5_OP_DCL_THREAD_GROUP, + + .idx = {thread_count[0], thread_count[1], thread_count[2]}, + .idx_count = 3, + }; + + write_sm4_instruction(buffer, &instr); +} + static void write_sm4_ret(struct vkd3d_bytecode_buffer *buffer) { struct sm4_instruction instr = @@ -2370,6 +2383,9 @@ static void write_sm4_shdr(struct hlsl_ctx *ctx, write_sm4_dcl_semantic(ctx, &buffer, var); }
+ if (profile->type == VKD3D_SHADER_TYPE_COMPUTE) + write_sm4_dcl_thread_group(&buffer, ctx->thread_count); + if (ctx->temp_count) write_sm4_dcl_temps(&buffer, ctx->temp_count);
diff --git a/tests/compute.shader_test b/tests/compute.shader_test index f5f5920f..6d2f698c 100644 --- a/tests/compute.shader_test +++ b/tests/compute.shader_test @@ -7,7 +7,7 @@ size (1, 1)
0.1
-[compute shader todo] +[compute shader] RWTexture2D<float> u;
[numthreads(1, 1, 1)] @@ -17,5 +17,5 @@ void main() }
[test] -todo dispatch 1 1 1 -todo probe uav 0 (0, 0) r (-123.0) +dispatch 1 1 1 +probe uav 0 (0, 0) r (-123.0) diff --git a/tests/hlsl-numthreads.shader_test b/tests/hlsl-numthreads.shader_test index 3e3973b3..328be664 100644 --- a/tests/hlsl-numthreads.shader_test +++ b/tests/hlsl-numthreads.shader_test @@ -3,37 +3,37 @@ [require] shader model >= 5.0
-[compute shader todo] +[compute shader]
[numthreads(1, 1, 1)] void main() {}
-[compute shader fail todo] +[compute shader fail]
[numthreads] void main() {}
-[compute shader fail todo] +[compute shader fail]
[numthreads(1, 1)] void main() {}
-[compute shader fail todo] +[compute shader fail]
[numthreads(1, 1, 1, 1)] void main() {}
-[compute shader fail todo] +[compute shader fail]
[numthreads(0, 1, 1)] void main() {}
-[compute shader fail todo] +[compute shader fail]
[numthreads(1, 0, 1)] void main() {}
-[compute shader fail todo] +[compute shader fail]
[numthreads(1, 1, 0)] void main() {} @@ -68,12 +68,12 @@ void main() {} [numthreads(int(1), 1, 1)] void main() {}
-[compute shader fail todo] +[compute shader fail]
[numthreads(float(1), 1, 1)] void main() {}
-[compute shader fail todo] +[compute shader fail]
[numthreads(uint1(1), 1, 1)] void main() {} @@ -99,30 +99,30 @@ static int x = 1; [numthreads(x, 1, 1)] void main() {}
-[compute shader fail todo] +[compute shader fail]
void main() {}
-[compute shader fail todo] +[compute shader fail]
[NumThreads(1, 1, 1)] void main() {}
-[compute shader todo] +[compute shader]
[numthreads(1, 1, 1)] void main();
void main() {}
-[compute shader fail todo] +[compute shader fail]
void main() {}
[numthreads(1, 1, 1)] void main();
-[compute shader fail todo] +[compute shader fail]
void main();
diff --git a/tests/uav-load.shader_test b/tests/uav-load.shader_test index 0f622f2b..fe6350e0 100644 --- a/tests/uav-load.shader_test +++ b/tests/uav-load.shader_test @@ -13,7 +13,7 @@ size (1, 1)
0.5
-[compute shader todo] +[compute shader] RWTexture2D<float> u, v; [numthreads(1, 1, 1)] void main() @@ -23,7 +23,7 @@ void main() }
[test] -todo dispatch 1 1 1 +dispatch 1 1 1 probe uav 0 (0, 0) r (0.6) probe uav 0 (1, 0) r (0.6) probe uav 0 (2, 0) r (0.6)
On Wed Nov 2 19:58:29 2022 +0000, Francisco Casas wrote:
Could
$$.attrs = new_array;
be missing?
Yes, thanks for catching that.
On Wed Nov 2 20:01:11 2022 +0000, Francisco Casas wrote:
I guess that the idea is to check that an invalid value constructor (`float2(1)`) makes the shader fail. But it may have been a typo.
That was the intent, yes (there's a valid constructor elsewhere). I'll add a comment to clarify.
On Wed Nov 2 20:25:34 2022 +0000, Francisco Casas wrote:
My understanding is that the first part of this block of code for the case
var_modifiers type var_identifier '(' parameters ')' colon_attribute
should be the same as the previous case:
| attribute_list var_modifiers type var_identifier '(' parameters ')' colon_attribute
but with the arguments shifted. In that case, I see a discrepancy in how modifiers are handled, since matrix majority modifiers are allowed. Also, to avoid redundancy, it is possible to put the former case on an intermediate rule for the parser? For instance, if we call this rule `func_prototype_without_attrs`:
func_prototype: func_prototype_without_attrs { return $1 } | attribute_list func_prototype_without_attrs { $2->attr_count = $1.count; $2->attrs = $1.attrs; return $2; }
Of course that would mean that it wouldn't make sense to add the `attr_count` and `attrs` parameters to `hlsl_new_func_decl()`.
Yeah, this code is old. I thought for some reason that bison wouldn't work with the rule factored out like that, but it does after all, so adjusted accordingly.
On Thu Nov 3 00:19:38 2022 +0000, Zebediah Figura wrote:
changed this line in [version 3 of the diff](/wine/vkd3d/-/merge_requests/43/diffs?diff_id=16596&start_sha=5e3e6a991a58c9f89797d05da86b35f8346e927e#3cf804f245af47d51595ff932bf817c50967eea2_2574_2576)
Fixed in v3.