From 09854a4596019ddb3bb315b8836b5c88e718cdc7 Mon Sep 17 00:00:00 2001 From: Ellie Hermaszewska Date: Tue, 12 Sep 2023 11:13:11 +0800 Subject: 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 --- tests/pipeline/rasterization/mesh/simple.slang | 86 ++++++++++++++++ .../rasterization/mesh/task-groupshared.slang | 109 +++++++++++++++++++++ .../pipeline/rasterization/mesh/task-simple.slang | 106 ++++++++++++++++++++ 3 files changed, 301 insertions(+) create mode 100644 tests/pipeline/rasterization/mesh/simple.slang create mode 100644 tests/pipeline/rasterization/mesh/task-groupshared.slang create mode 100644 tests/pipeline/rasterization/mesh/task-simple.slang (limited to 'tests/pipeline') 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 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 verts, + out Indices 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 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 verts, + out Indices 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 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 verts, + out Indices 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; +} -- cgit v1.2.3