-- v2: vkd3d-shader/hlsl: Write SM4 dcl_thread_group instructions. vkd3d-shader/hlsl: Parse the numthreads attribute. vkd3d-shader/hlsl: Parse function attributes. vkd3d-shader/hlsl: Use hlsl_new_synthetic_var() in hlsl_new_func_decl(). vkd3d-shader/hlsl: Add a hlsl_fixme() for compute shader thread counts. tests: Add some tests for HLSL attribute syntax.
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 | 63 ++++++++++++++++++++++-- libs/vkd3d-shader/vkd3d_shader_private.h | 2 + 3 files changed, 64 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..ed3f6349 100644 --- a/libs/vkd3d-shader/hlsl_codegen.c +++ b/libs/vkd3d-shader/hlsl_codegen.c @@ -2534,9 +2534,53 @@ 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; + + 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; + } + + if (!(ctx->thread_count[i] = hlsl_ir_constant(instr)->value[0].u)) + hlsl_error(ctx, &instr->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_THREAD_COUNT, + "Thread count must be a positive integer."); + } +} + 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 +2622,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 +2661,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 +2680,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)