diff options
| author | Ellie Hermaszewska <ellieh@nvidia.com> | 2023-09-12 11:13:11 +0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-09-11 20:13:11 -0700 |
| commit | 09854a4596019ddb3bb315b8836b5c88e718cdc7 (patch) | |
| tree | 1556ae3e00da0fac91343f159b52cee1231a7fab /tests/pipeline | |
| parent | 87bb0b503544f1b8c6ec818e25c695b31cda24b7 (diff) | |
Add Mesh and Task shader support to GFX (#3190)
* Bump vulkan headers
Also just use vulkan-headers as a submodule
* Add drawMeshTasks to gfx graphics pipelines
* Add DispatchMesh overload with no payload, with GLSL intrinsic
* Require spirv 1.4 for mesh shaders
* Add vulkan mesh shader feature discovery
* Add mesh shader stage bits to vk-util
* Add mesh and task shader support to render-test
* Add mesh and task tests
* Preserve "payload" specifier in task shaders
* Add mesh shader pipeline support to gfx
* Add TODO
* Add numThreads attribute for amplification stage
* Add payload to task shader test
* Drop dependency on d3dx12
* Allow passing payloads from task to mesh shaders
* regenerate vs projects
* check DispatchMesh name correctly
* Add mesh shader tests to failing tests
* Detect wave-ops feature on vulkan
* Add fuse-product to expected failures
This fails because the global varaible `count` is not initialized
* Add required extension to WaveMaskMatch SPIR-V impl
* Remove meshShader member from pipeline desc
* Identify mesh shader support on d3d12
Diffstat (limited to 'tests/pipeline')
| -rw-r--r-- | tests/pipeline/rasterization/mesh/simple.slang | 86 | ||||
| -rw-r--r-- | tests/pipeline/rasterization/mesh/task-groupshared.slang | 109 | ||||
| -rw-r--r-- | tests/pipeline/rasterization/mesh/task-simple.slang | 106 |
3 files changed, 301 insertions, 0 deletions
diff --git a/tests/pipeline/rasterization/mesh/simple.slang b/tests/pipeline/rasterization/mesh/simple.slang new file mode 100644 index 000000000..00047aaad --- /dev/null +++ b/tests/pipeline/rasterization/mesh/simple.slang @@ -0,0 +1,86 @@ +//TEST(compute):COMPARE_COMPUTE_EX(filecheck-buffer=CHECK): -mesh -output-using-type -dx12 -use-dxil -profile sm_6_6 -render-features mesh-shader +//TEST(compute):COMPARE_COMPUTE_EX(filecheck-buffer=CHECK): -mesh -output-using-type -vk -profile glsl_450+spirv_1_4 -render-features mesh-shader + +// To test a simple mesh shader, we'll generate 4 triangles, the vertices of +// each one will hold the triangle index and a value (the square). The fragment +// shader will write the value to the specified index of the output buffer. + +// CHECK: 0 +// CHECK-NEXT: 1 +// CHECK-NEXT: 4 +// CHECK-NEXT: 9 + +//TEST_INPUT: ubuffer(data=[0 0 0 0], stride=4):out,name outputBuffer + +RWStructuredBuffer<float> outputBuffer; + +cbuffer Uniforms +{ + float4x4 modelViewProjection; +} + +// +// Mesh shader +// + +const static float2 positions[3] = { + float2(0.0, -0.5), + float2(0.5, 0.5), + float2(-0.5, 0.5) +}; + +const static float3 colors[3] = { + float3(1.0, 1.0, 0.0), + float3(0.0, 1.0, 1.0), + float3(1.0, 0.0, 1.0) +}; + +struct Vertex +{ + float4 pos : SV_Position; + float3 color : Color; + int index : Index; + int value : Value; +}; + +const static uint MAX_VERTS = 12; +const static uint MAX_PRIMS = 4; + +[outputtopology("triangle")] +[numthreads(12, 1, 1)] +void meshMain( + in uint tig : SV_GroupIndex, + out Vertices<Vertex, MAX_VERTS> verts, + out Indices<uint3, MAX_PRIMS> triangles) +{ + const uint numVertices = 12; + const uint numPrimitives = 4; + SetMeshOutputCounts(numVertices, numPrimitives); + + if(tig < numVertices) + { + const int tri = tig / 3; + verts[tig] = {float4(positions[tig % 3], 0, 1), colors[tig % 3], tri, tri*tri}; + } + + if(tig < numPrimitives) + triangles[tig] = tig * 3 + uint3(0,1,2); +} + +// +// Fragment Shader +// + +struct Fragment +{ + float4 color : SV_Target; +}; + +Fragment fragmentMain(Vertex input) +{ + outputBuffer[input.index] = input.value; + + Fragment output; + output.color = float4(input.color, 1.0); + return output; +} diff --git a/tests/pipeline/rasterization/mesh/task-groupshared.slang b/tests/pipeline/rasterization/mesh/task-groupshared.slang new file mode 100644 index 000000000..5690735cd --- /dev/null +++ b/tests/pipeline/rasterization/mesh/task-groupshared.slang @@ -0,0 +1,109 @@ +//TEST(compute):COMPARE_COMPUTE_EX(filecheck-buffer=CHECK): -task -output-using-type -dx12 -use-dxil -profile sm_6_6 -render-features mesh-shader +//TEST(compute):COMPARE_COMPUTE_EX(filecheck-buffer=CHECK): -task -output-using-type -vk -profile glsl_450+spirv_1_4 -render-features mesh-shader + +// Similar to task-simple, except that the payload is declared as a groupshared +// variable. During lowerin to GLSL and SPIR-V we'll have to identify this as +// the variable being passed to DispatchMesh and emit it using the +// taskPayloadSharedEXT rate. + +// CHECK: 0 +// CHECK-NEXT: 1 +// CHECK-NEXT: 8 +// CHECK-NEXT: 27 + +//TEST_INPUT: ubuffer(data=[0 0 0 0], stride=4):out,name outputBuffer + +RWStructuredBuffer<float> outputBuffer; + +cbuffer Uniforms +{ + float4x4 modelViewProjection; +} + +// +// Task shader +// + +struct MeshPayload +{ + int exponent; +}; + +groupshared MeshPayload p; + +[outputtopology("triangle")] +[numthreads(1, 1, 1)] +void taskMain(in uint tig : SV_GroupIndex) +{ + p.exponent = 3; + DispatchMesh(1,1,1,p); +} + + +// +// Mesh shader +// + +const static float2 positions[3] = { + float2(0.0, -0.5), + float2(0.5, 0.5), + float2(-0.5, 0.5) +}; + +const static float3 colors[3] = { + float3(1.0, 1.0, 0.0), + float3(0.0, 1.0, 1.0), + float3(1.0, 0.0, 1.0) +}; + +struct Vertex +{ + float4 pos : SV_Position; + float3 color : Color; + int index : Index; + int value : Value; +}; + +const static uint MAX_VERTS = 12; +const static uint MAX_PRIMS = 4; + +[outputtopology("triangle")] +[numthreads(12, 1, 1)] +void meshMain( + in uint tig : SV_GroupIndex, + in payload MeshPayload meshPayload, + out Vertices<Vertex, MAX_VERTS> verts, + out Indices<uint3, MAX_PRIMS> triangles) +{ + const uint numVertices = 12; + const uint numPrimitives = 4; + SetMeshOutputCounts(numVertices, numPrimitives); + + if(tig < numVertices) + { + const int tri = tig / 3; + verts[tig] = {float4(positions[tig % 3], 0, 1), colors[tig % 3], tri, int(pow(tri, meshPayload.exponent))}; + } + + if(tig < numPrimitives) + triangles[tig] = tig * 3 + uint3(0,1,2); +} + +// +// Fragment Shader +// + +struct Fragment +{ + float4 color : SV_Target; +}; + +Fragment fragmentMain(Vertex input) +{ + outputBuffer[input.index] = input.value; + + Fragment output; + output.color = float4(input.color, 1.0); + return output; +} + diff --git a/tests/pipeline/rasterization/mesh/task-simple.slang b/tests/pipeline/rasterization/mesh/task-simple.slang new file mode 100644 index 000000000..7da9ed32b --- /dev/null +++ b/tests/pipeline/rasterization/mesh/task-simple.slang @@ -0,0 +1,106 @@ +//TEST(compute):COMPARE_COMPUTE_EX(filecheck-buffer=CHECK): -task -output-using-type -dx12 -use-dxil -profile sm_6_6 -render-features mesh-shader +//TEST(compute):COMPARE_COMPUTE_EX(filecheck-buffer=CHECK): -task -output-using-type -vk -profile glsl_450+spirv_1_4 -render-features mesh-shader + +// To test a simple mesh shader, we'll generate 4 triangles, the vertices of +// each one will hold the triangle index and a value (the square). The fragment +// shader will write the value to the specified index of the output buffer. + +// CHECK: 0 +// CHECK-NEXT: 1 +// CHECK-NEXT: 8 +// CHECK-NEXT: 27 + +//TEST_INPUT: ubuffer(data=[0 0 0 0], stride=4):out,name outputBuffer + +RWStructuredBuffer<float> outputBuffer; + +cbuffer Uniforms +{ + float4x4 modelViewProjection; +} + +// +// Task shader +// + +struct MeshPayload +{ + int exponent; +}; + +[outputtopology("triangle")] +[numthreads(1, 1, 1)] +void taskMain(in uint tig : SV_GroupIndex) +{ + MeshPayload p; + p.exponent = 3; + DispatchMesh(1,1,1,p); +} + + +// +// Mesh shader +// + +const static float2 positions[3] = { + float2(0.0, -0.5), + float2(0.5, 0.5), + float2(-0.5, 0.5) +}; + +const static float3 colors[3] = { + float3(1.0, 1.0, 0.0), + float3(0.0, 1.0, 1.0), + float3(1.0, 0.0, 1.0) +}; + +struct Vertex +{ + float4 pos : SV_Position; + float3 color : Color; + int index : Index; + int value : Value; +}; + +const static uint MAX_VERTS = 12; +const static uint MAX_PRIMS = 4; + +[outputtopology("triangle")] +[numthreads(12, 1, 1)] +void meshMain( + in uint tig : SV_GroupIndex, + in payload MeshPayload meshPayload, + out Vertices<Vertex, MAX_VERTS> verts, + out Indices<uint3, MAX_PRIMS> triangles) +{ + const uint numVertices = 12; + const uint numPrimitives = 4; + SetMeshOutputCounts(numVertices, numPrimitives); + + if(tig < numVertices) + { + const int tri = tig / 3; + verts[tig] = {float4(positions[tig % 3], 0, 1), colors[tig % 3], tri, int(pow(tri, meshPayload.exponent))}; + } + + if(tig < numPrimitives) + triangles[tig] = tig * 3 + uint3(0,1,2); +} + +// +// Fragment Shader +// + +struct Fragment +{ + float4 color : SV_Target; +}; + +Fragment fragmentMain(Vertex input) +{ + outputBuffer[input.index] = input.value; + + Fragment output; + output.color = float4(input.color, 1.0); + return output; +} |
