summaryrefslogtreecommitdiffstats
path: root/tests/pipeline
diff options
context:
space:
mode:
authorEllie Hermaszewska <ellieh@nvidia.com>2022-11-16 09:49:06 +0800
committerGitHub <noreply@github.com>2022-11-16 09:49:06 +0800
commit1643471da0d6239177d11b0301c26d1adf95c0fb (patch)
tree9b8fddf92a5f817541e055a2657f9b0a00f90069 /tests/pipeline
parent4917d71100aafcc38a81cd99d2a44a4cb3a89a0c (diff)
Mesh shader support (#2464)
* Add gdb generated files to .gitignore * Switch to c++17 TODO: Ellie update coding style doc * WIP mesh shaders * Add MeshOutputType and mesh output decorations * Lift array type layout creation out of _createTypeLayout in preparation for sharing it elsewhere * Initial pass at GLSL legalization for mesh shaders * Create output types for builtin mesh outputs This should be rendered as an out paramter block * Handle writes to member fields in mesh shader output * Per primitive output from mesh shaders * Add mesh shader tests * Redeclare mesh output builtins * Remove unused instruction * Emit explicit mesh output max max size * Add unimplemented warning for array members in mesh output * Implement mesh output splitting for GLSL in terms of getSubscriptVal * Allow HLSL syntax for mesh output modifiers * Improve error messages for mesh output * Add test for HLSL style mesh output syntax * Emit explicit mesh output indices max size * HLSL generation support for mesh shaders * Better errors for mesh shader misuse * Neaten comments * Regenerate vs2019 project files * Fix build on vs2019 * Retreat on c++17 Will make the change in a separate PR * slang-glslang binary dep 11.10.0 -> 11.12.0-32 * Fixes for msvc compiler * Update msvc project
Diffstat (limited to 'tests/pipeline')
-rw-r--r--tests/pipeline/rasterization/mesh/component-write.slang49
-rw-r--r--tests/pipeline/rasterization/mesh/component-write.slang.glsl39
-rw-r--r--tests/pipeline/rasterization/mesh/hello.slang49
-rw-r--r--tests/pipeline/rasterization/mesh/hello.slang.glsl46
-rw-r--r--tests/pipeline/rasterization/mesh/hello.slang.hlsl36
-rw-r--r--tests/pipeline/rasterization/mesh/hlsl-syntax.slang54
-rw-r--r--tests/pipeline/rasterization/mesh/hlsl-syntax.slang.glsl51
-rw-r--r--tests/pipeline/rasterization/mesh/nested-component-write.slang51
-rw-r--r--tests/pipeline/rasterization/mesh/nested-component-write.slang.glsl37
-rw-r--r--tests/pipeline/rasterization/mesh/passing-outputs.slang114
-rw-r--r--tests/pipeline/rasterization/mesh/passing-outputs.slang.glsl172
-rw-r--r--tests/pipeline/rasterization/mesh/primitive-output.slang57
-rw-r--r--tests/pipeline/rasterization/mesh/primitive-output.slang.glsl66
-rw-r--r--tests/pipeline/rasterization/mesh/swizzled-store.slang32
-rw-r--r--tests/pipeline/rasterization/mesh/swizzled-store.slang.glsl35
15 files changed, 888 insertions, 0 deletions
diff --git a/tests/pipeline/rasterization/mesh/component-write.slang b/tests/pipeline/rasterization/mesh/component-write.slang
new file mode 100644
index 000000000..a34f6ee31
--- /dev/null
+++ b/tests/pipeline/rasterization/mesh/component-write.slang
@@ -0,0 +1,49 @@
+// component-write.slang
+
+// This tests that writing to individual components of the output struct works
+
+//TEST:CROSS_COMPILE:-target spirv -profile glsl_450+spirv_1_4 -entry main -stage mesh
+
+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;
+};
+
+const static uint MAX_VERTS = 3;
+const static uint MAX_PRIMS = 1;
+
+[outputtopology("triangle")]
+[numthreads(3, 1, 1)]
+void main(
+ in uint tig : SV_GroupIndex,
+ out Vertices<Vertex, MAX_VERTS> verts,
+ out Indices<uint3, MAX_PRIMS> triangles
+ )
+{
+ const uint numVertices = 3;
+ const uint numPrimitives = 1;
+ SetMeshOutputCounts(numVertices, numPrimitives);
+
+ if(tig < numVertices) {
+ verts[tig].pos = float4(positions[tig], 0, 1);
+ verts[tig].color = colors[tig];
+ }
+
+ if(tig < numPrimitives) {
+ triangles[tig] = uint3(0,1,2);
+ }
+}
+
diff --git a/tests/pipeline/rasterization/mesh/component-write.slang.glsl b/tests/pipeline/rasterization/mesh/component-write.slang.glsl
new file mode 100644
index 000000000..5234fb62f
--- /dev/null
+++ b/tests/pipeline/rasterization/mesh/component-write.slang.glsl
@@ -0,0 +1,39 @@
+#version 450
+#extension GL_EXT_mesh_shader : require
+layout(row_major) uniform;
+layout(row_major) buffer;
+const vec3 colors_0[3] = { vec3(1.00000000000000000000, 1.00000000000000000000, 0.00000000000000000000), vec3(0.00000000000000000000, 1.00000000000000000000, 1.00000000000000000000), vec3(1.00000000000000000000, 0.00000000000000000000, 1.00000000000000000000) };
+const vec2 positions_0[3] = { vec2(0.00000000000000000000, -0.50000000000000000000), vec2(0.50000000000000000000, 0.50000000000000000000), vec2(-0.50000000000000000000, 0.50000000000000000000) };
+layout(location = 0)
+out vec3 _S1[3];
+
+out gl_MeshPerVertexEXT
+{
+ vec4 gl_Position;
+} gl_MeshVerticesEXT[3];
+
+layout(local_size_x = 3, local_size_y = 1, local_size_z = 1) in;
+layout(max_vertices = 3) out;
+layout(max_primitives = 1) out;
+layout(triangles) out;
+void main()
+{
+ SetMeshOutputsEXT(3U, 1U);
+ if(gl_LocalInvocationIndex < 3U)
+ {
+ gl_MeshVerticesEXT[gl_LocalInvocationIndex].gl_Position = vec4(positions_0[gl_LocalInvocationIndex], 0.00000000000000000000, 1.00000000000000000000);
+ _S1[gl_LocalInvocationIndex] = colors_0[gl_LocalInvocationIndex];
+ }
+ else
+ {
+ }
+ if(gl_LocalInvocationIndex < 1U)
+ {
+ gl_PrimitiveTriangleIndicesEXT[gl_LocalInvocationIndex] = uvec3(0U, 1U, 2U);
+ }
+ else
+ {
+ }
+ return;
+}
+
diff --git a/tests/pipeline/rasterization/mesh/hello.slang b/tests/pipeline/rasterization/mesh/hello.slang
new file mode 100644
index 000000000..5eea900d3
--- /dev/null
+++ b/tests/pipeline/rasterization/mesh/hello.slang
@@ -0,0 +1,49 @@
+// hello.slang
+
+// Test that a simple mesh shader compiles
+
+//TEST:CROSS_COMPILE:-target spirv-assembly -entry main -stage mesh -profile glsl_450+spirv_1_4
+//TEST:CROSS_COMPILE:-target dxil-assembly -entry main -stage mesh -profile sm_6_6
+
+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;
+};
+
+const static uint MAX_VERTS = 3;
+const static uint MAX_PRIMS = 1;
+
+[outputtopology("triangle")]
+[numthreads(3, 1, 1)]
+void main(
+ in uint tig : SV_GroupIndex,
+ out Vertices<Vertex, MAX_VERTS> verts,
+ out Indices<uint3, MAX_PRIMS> triangles
+ )
+{
+ const uint numVertices = 3;
+ const uint numPrimitives = 1;
+ SetMeshOutputCounts(numVertices, numPrimitives);
+
+ if(tig < numVertices) {
+ verts[tig] = {float4(positions[tig], 0, 1), colors[tig]};
+ }
+
+ if(tig < numPrimitives) {
+ triangles[tig] = uint3(0,1,2);
+ }
+}
+
diff --git a/tests/pipeline/rasterization/mesh/hello.slang.glsl b/tests/pipeline/rasterization/mesh/hello.slang.glsl
new file mode 100644
index 000000000..66630012b
--- /dev/null
+++ b/tests/pipeline/rasterization/mesh/hello.slang.glsl
@@ -0,0 +1,46 @@
+#version 450
+#extension GL_EXT_mesh_shader : require
+layout(row_major) uniform;
+layout(row_major) buffer;
+const vec3 colors_0[3] = { vec3(1.00000000000000000000, 1.00000000000000000000, 0.00000000000000000000), vec3(0.00000000000000000000, 1.00000000000000000000, 1.00000000000000000000), vec3(1.00000000000000000000, 0.00000000000000000000, 1.00000000000000000000) };
+const vec2 positions_0[3] = { vec2(0.00000000000000000000, -0.50000000000000000000), vec2(0.50000000000000000000, 0.50000000000000000000), vec2(-0.50000000000000000000, 0.50000000000000000000) };
+layout(location = 0)
+out vec3 _S1[3];
+
+out gl_MeshPerVertexEXT
+{
+ vec4 gl_Position;
+} gl_MeshVerticesEXT[3];
+
+struct Vertex_0
+{
+ vec4 pos_0;
+ vec3 color_0;
+};
+
+layout(local_size_x = 3, local_size_y = 1, local_size_z = 1) in;
+layout(max_vertices = 3) out;
+layout(max_primitives = 1) out;
+layout(triangles) out;
+void main()
+{
+ SetMeshOutputsEXT(3U, 1U);
+ if(gl_LocalInvocationIndex < 3U)
+ {
+ Vertex_0 _S2 = { vec4(positions_0[gl_LocalInvocationIndex], 0.00000000000000000000, 1.00000000000000000000), colors_0[gl_LocalInvocationIndex] };
+ gl_MeshVerticesEXT[gl_LocalInvocationIndex].gl_Position = _S2.pos_0;
+ _S1[gl_LocalInvocationIndex] = _S2.color_0;
+ }
+ else
+ {
+ }
+ if(gl_LocalInvocationIndex < 1U)
+ {
+ gl_PrimitiveTriangleIndicesEXT[gl_LocalInvocationIndex] = uvec3(0U, 1U, 2U);
+ }
+ else
+ {
+ }
+ return;
+}
+
diff --git a/tests/pipeline/rasterization/mesh/hello.slang.hlsl b/tests/pipeline/rasterization/mesh/hello.slang.hlsl
new file mode 100644
index 000000000..ea41895b1
--- /dev/null
+++ b/tests/pipeline/rasterization/mesh/hello.slang.hlsl
@@ -0,0 +1,36 @@
+#pragma pack_matrix(column_major)
+#ifdef SLANG_HLSL_ENABLE_NVAPI
+#include "nvHLSLExtns.h"
+#endif
+
+static const float3 colors_0[int(3)] = { float3(1.00000000000000000000, 1.00000000000000000000, 0.00000000000000000000), float3(0.00000000000000000000, 1.00000000000000000000, 1.00000000000000000000), float3(1.00000000000000000000, 0.00000000000000000000, 1.00000000000000000000) };
+static const float2 positions_0[int(3)] = { float2(0.00000000000000000000, -0.50000000000000000000), float2(0.50000000000000000000, 0.50000000000000000000), float2(-0.50000000000000000000, 0.50000000000000000000) };
+struct Vertex_0
+{
+ float4 pos_0 : SV_Position;
+ float3 color_0 : Color;
+};
+
+[numthreads(3, 1, 1)]
+[outputtopology("triangle")]
+void main(uint tig_0 : SV_GROUPINDEX, vertices out Vertex_0 verts_0[int(3)], indices out uint3 triangles_0[int(1)])
+{
+ SetMeshOutputCounts(3U, 1U);
+ if(tig_0 < 3U)
+ {
+ Vertex_0 _S1 = { float4(positions_0[tig_0], 0.00000000000000000000, 1.00000000000000000000), colors_0[tig_0] };
+ verts_0[tig_0] = _S1;
+ }
+ else
+ {
+ }
+ if(tig_0 < 1U)
+ {
+ triangles_0[tig_0] = uint3(0U, 1U, 2U);
+ }
+ else
+ {
+ }
+ return;
+}
+
diff --git a/tests/pipeline/rasterization/mesh/hlsl-syntax.slang b/tests/pipeline/rasterization/mesh/hlsl-syntax.slang
new file mode 100644
index 000000000..a0b397ca2
--- /dev/null
+++ b/tests/pipeline/rasterization/mesh/hlsl-syntax.slang
@@ -0,0 +1,54 @@
+// hlsl-syntax.slang
+
+// Test that we can ingest hlsl mesh output syntax
+
+//TEST:CROSS_COMPILE:-target spirv -profile glsl_450+spirv_1_4 -entry main -stage mesh
+
+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;
+};
+
+const static uint MAX_VERTS = 3;
+const static uint MAX_PRIMS = 1;
+
+// Test that we can convert the HLSL Syntax to the typed syntax
+void foo(uint tig, out Vertices<Vertex, MAX_VERTS> verts)
+{
+ if(tig < 3) {
+ verts[tig] = {float4(positions[tig], 0, 1), colors[tig]};
+ }
+}
+
+[outputtopology("triangle")]
+[numthreads(3, 1, 1)]
+void main(
+ in uint tig : SV_GroupIndex,
+ out vertices Vertex verts[MAX_VERTS],
+ out indices uint3 triangles[MAX_PRIMS]
+ )
+{
+ const uint numVertices = 3;
+ const uint numPrimitives = 1;
+ SetMeshOutputCounts(numVertices, numPrimitives);
+
+ foo(tig, verts);
+
+ if(tig < numPrimitives) {
+ triangles[tig] = uint3(0,1,2);
+ }
+}
+
diff --git a/tests/pipeline/rasterization/mesh/hlsl-syntax.slang.glsl b/tests/pipeline/rasterization/mesh/hlsl-syntax.slang.glsl
new file mode 100644
index 000000000..4a6b8f86f
--- /dev/null
+++ b/tests/pipeline/rasterization/mesh/hlsl-syntax.slang.glsl
@@ -0,0 +1,51 @@
+#version 450
+#extension GL_EXT_mesh_shader : require
+layout(row_major) uniform;
+layout(row_major) buffer;
+const vec3 colors_0[3] = { vec3(1.00000000000000000000, 1.00000000000000000000, 0.00000000000000000000), vec3(0.00000000000000000000, 1.00000000000000000000, 1.00000000000000000000), vec3(1.00000000000000000000, 0.00000000000000000000, 1.00000000000000000000) };
+const vec2 positions_0[3] = { vec2(0.00000000000000000000, -0.50000000000000000000), vec2(0.50000000000000000000, 0.50000000000000000000), vec2(-0.50000000000000000000, 0.50000000000000000000) };
+layout(location = 0)
+out vec3 _S1[3];
+
+out gl_MeshPerVertexEXT
+{
+ vec4 gl_Position;
+} gl_MeshVerticesEXT[3];
+
+struct Vertex_0
+{
+ vec4 pos_0;
+ vec3 color_0;
+};
+
+void foo_0(uint _S2)
+{
+ if(_S2 < 3U)
+ {
+ Vertex_0 _S3 = { vec4(positions_0[_S2], 0.00000000000000000000, 1.00000000000000000000), colors_0[_S2] };
+ gl_MeshVerticesEXT[_S2].gl_Position = _S3.pos_0;
+ _S1[_S2] = _S3.color_0;
+ }
+ else
+ {
+ }
+ return;
+}
+
+layout(local_size_x = 3, local_size_y = 1, local_size_z = 1) in;
+layout(max_vertices = 3) out;
+layout(max_primitives = 1) out;
+layout(triangles) out;
+void main()
+{
+ SetMeshOutputsEXT(3U, 1U);
+ foo_0(gl_LocalInvocationIndex);
+ if(gl_LocalInvocationIndex < 1U)
+ {
+ gl_PrimitiveTriangleIndicesEXT[gl_LocalInvocationIndex] = uvec3(0U, 1U, 2U);
+ }
+ else
+ {
+ }
+ return;
+}
diff --git a/tests/pipeline/rasterization/mesh/nested-component-write.slang b/tests/pipeline/rasterization/mesh/nested-component-write.slang
new file mode 100644
index 000000000..68bb6dfb9
--- /dev/null
+++ b/tests/pipeline/rasterization/mesh/nested-component-write.slang
@@ -0,0 +1,51 @@
+// nested-component-write.slang
+
+// This tests that writing to individual components nested structs works for
+// mesh shader outputs.
+
+//TEST:CROSS_COMPILE:-target spirv -profile glsl_450+spirv_1_4 -entry main -stage mesh
+
+struct Foo
+{
+ float4 pos : SV_Position;
+ Bar bar;
+};
+
+struct Bar
+{
+ Baz baz : Color;
+};
+
+struct Baz
+{
+ float3 color;
+};
+
+struct Vertex
+{
+ Foo foo;
+};
+
+const static uint MAX_VERTS = 3;
+const static uint MAX_PRIMS = 1;
+
+[outputtopology("triangle")]
+[numthreads(3, 1, 1)]
+void main(
+ in uint tig : SV_GroupIndex,
+ out Vertices<Vertex, MAX_VERTS> verts,
+ out Indices<uint3, MAX_PRIMS> triangles
+ )
+{
+ SetMeshOutputCounts(3, 1);
+
+ if(tig < 3) {
+ verts[tig].foo.pos = float4(0, 0, 0, 1);
+ verts[tig].foo.bar.baz.color = float3(1, 2, 3);
+ }
+
+ if(tig < 1) {
+ triangles[tig] = uint3(0,1,2);
+ }
+}
+
diff --git a/tests/pipeline/rasterization/mesh/nested-component-write.slang.glsl b/tests/pipeline/rasterization/mesh/nested-component-write.slang.glsl
new file mode 100644
index 000000000..4c70955a1
--- /dev/null
+++ b/tests/pipeline/rasterization/mesh/nested-component-write.slang.glsl
@@ -0,0 +1,37 @@
+#version 450
+#extension GL_EXT_mesh_shader : require
+layout(row_major) uniform;
+layout(row_major) buffer;
+layout(location = 0)
+out vec3 _S1[3];
+
+out gl_MeshPerVertexEXT
+{
+ vec4 gl_Position;
+} gl_MeshVerticesEXT[3];
+
+layout(local_size_x = 3, local_size_y = 1, local_size_z = 1) in;
+layout(max_vertices = 3) out;
+layout(max_primitives = 1) out;
+layout(triangles) out;
+void main()
+{
+ SetMeshOutputsEXT(3U, 1U);
+ if(gl_LocalInvocationIndex < 3U)
+ {
+ gl_MeshVerticesEXT[gl_LocalInvocationIndex].gl_Position = vec4(0.00000000000000000000, 0.00000000000000000000, 0.00000000000000000000, 1.00000000000000000000);
+ _S1[gl_LocalInvocationIndex] = vec3(1.00000000000000000000, 2.00000000000000000000, 3.00000000000000000000);
+ }
+ else
+ {
+ }
+ if(gl_LocalInvocationIndex < 1U)
+ {
+ gl_PrimitiveTriangleIndicesEXT[gl_LocalInvocationIndex] = uvec3(0U, 1U, 2U);
+ }
+ else
+ {
+ }
+ return;
+}
+
diff --git a/tests/pipeline/rasterization/mesh/passing-outputs.slang b/tests/pipeline/rasterization/mesh/passing-outputs.slang
new file mode 100644
index 000000000..321c1179e
--- /dev/null
+++ b/tests/pipeline/rasterization/mesh/passing-outputs.slang
@@ -0,0 +1,114 @@
+// component-write.slang
+
+// This tests that writing to individual components of the output struct works
+
+//TEST:CROSS_COMPILE:-target spirv-assembly -entry main -stage mesh -profile glsl_450+spirv_1_4
+
+// DXC is stricter than we are about passing references to individual mesh shader outputs
+// We could get around this by doing what we do for GLSL, i.e. use a temporary
+// variable to pass as the out parameter, and then copy that into the array
+// after the function call.
+//TEST_DISABLED:CROSS_COMPILE:-target dxil-assembly -entry main -stage mesh -profile sm_6_6
+
+const static uint MAX_VERTS = 3;
+const static uint MAX_PRIMS = 1;
+
+struct Texes
+{
+ float2 tex1;
+ float4 tex2;
+}
+
+struct Vertex
+{
+ float4 pos : SV_Position;
+ float3 col : Color;
+ Texes ts : Coord;
+};
+
+void everything<let N : uint>(out Vertices<Vertex, N> vs)
+{
+ vs[0] = {float4(0), float3(1)};
+}
+
+void just_one(out Vertex v)
+{
+ v = {float4(0), float3(1)};
+}
+
+void just_two(out Vertex v, out Vertex w)
+{
+ v = {float4(0), float3(1)};
+ w = v;
+}
+
+void part_of_one(out float4 p)
+{
+ p = float4(1,2,3,4);
+}
+
+void write_struct(out Texes t)
+{
+ t.tex1 = float2(0);
+ t.tex2 = float4(1);
+}
+
+// Split out the things to test to avoid main becoming an unreadable jumble
+void a<let N : uint>(out Vertices<Vertex, N> vs)
+{
+ // Test passing a reference to the entire array
+ everything(vs);
+}
+
+void b<let N : uint>(out Vertices<Vertex, N> vs)
+{
+ // test passing two references to the same element
+ just_two(vs[0], vs[0]);
+}
+
+void c<let N : uint>(out Vertices<Vertex, N> vs, uint tig)
+{
+ // Test passing a reference to an element
+ just_one(vs[tig]);
+}
+
+void d<let N : uint>(out Vertices<Vertex, N> vs, uint tig)
+{
+ // Test passing references to different elements (to check that the operand
+ // rewriting doesn't mess the order)
+ just_two(vs[tig], vs[0]);
+}
+
+void e<let N : uint>(out Vertices<Vertex, N> vs, uint tig)
+{
+ // Test passing a scalar member and a struct member and a struct member's member
+ part_of_one(vs[tig].pos);
+ write_struct(vs[tig].ts);
+ part_of_one(vs[tig].ts.tex2);
+}
+
+[outputtopology("triangle")]
+[numthreads(3, 1, 1)]
+void main(
+ in uint tig : SV_GroupIndex,
+ out Vertices<Vertex, MAX_VERTS> verts,
+ out Indices<uint3, MAX_PRIMS> triangles
+ )
+{
+ const uint numVertices = 3;
+ const uint numPrimitives = 1;
+ SetMeshOutputCounts(numVertices, numPrimitives);
+
+ if(tig < numVertices) {
+ a(verts);
+ b(verts);
+ c(verts, tig);
+ d(verts, tig);
+ e(verts, tig);
+ }
+
+ if(tig < numPrimitives) {
+ triangles[tig] = uint3(0,1,2);
+ }
+}
+
diff --git a/tests/pipeline/rasterization/mesh/passing-outputs.slang.glsl b/tests/pipeline/rasterization/mesh/passing-outputs.slang.glsl
new file mode 100644
index 000000000..cfd7675ab
--- /dev/null
+++ b/tests/pipeline/rasterization/mesh/passing-outputs.slang.glsl
@@ -0,0 +1,172 @@
+#version 450
+#extension GL_EXT_mesh_shader : require
+layout(row_major) uniform;
+layout(row_major) buffer;
+struct Texes_0
+{
+ vec2 tex1_0;
+ vec4 tex2_0;
+};
+
+struct Vertex_0
+{
+ vec4 pos_0;
+ vec3 col_0;
+ Texes_0 ts_0;
+};
+
+void just_two_0(out Vertex_0 v_0, out Vertex_0 w_0)
+{
+ Texes_0 _S1 = { vec2(0.00000000000000000000, 0.00000000000000000000), vec4(0.00000000000000000000, 0.00000000000000000000, 0.00000000000000000000, 0.00000000000000000000) };
+ Vertex_0 _S2 = { vec4(0), vec3(1), _S1 };
+ v_0 = _S2;
+ w_0 = v_0;
+ return;
+}
+
+void just_one_0(out Vertex_0 v_1)
+{
+ Texes_0 _S3 = { vec2(0.00000000000000000000, 0.00000000000000000000), vec4(0.00000000000000000000, 0.00000000000000000000, 0.00000000000000000000, 0.00000000000000000000) };
+ Vertex_0 _S4 = { vec4(0), vec3(1), _S3 };
+ v_1 = _S4;
+ return;
+}
+
+void part_of_one_0(out vec4 p_0)
+{
+ p_0 = vec4(1.00000000000000000000, 2.00000000000000000000, 3.00000000000000000000, 4.00000000000000000000);
+ return;
+}
+
+void write_struct_0(out Texes_0 t_0)
+{
+ t_0.tex1_0 = vec2(0);
+ t_0.tex2_0 = vec4(1);
+ return;
+}
+
+layout(location = 0)
+out vec3 _S5[3];
+
+layout(location = 1)
+out vec2 _S6[3];
+
+layout(location = 2)
+out vec4 _S7[3];
+
+out gl_MeshPerVertexEXT
+{
+ vec4 gl_Position;
+} gl_MeshVerticesEXT[3];
+
+void everything_0()
+{
+ Texes_0 _S8 = { vec2(0.00000000000000000000, 0.00000000000000000000), vec4(0.00000000000000000000, 0.00000000000000000000, 0.00000000000000000000, 0.00000000000000000000) };
+ Vertex_0 _S9 = { vec4(0), vec3(1), _S8 };
+ gl_MeshVerticesEXT[0U].gl_Position = _S9.pos_0;
+ _S5[0U] = _S9.col_0;
+ Texes_0 _S10 = _S9.ts_0;
+ _S6[0U] = _S10.tex1_0;
+ _S7[0U] = _S10.tex2_0;
+ return;
+}
+
+void a_0()
+{
+ everything_0();
+ return;
+}
+
+void b_0()
+{
+ Vertex_0 _S11;
+ Vertex_0 _S12;
+ just_two_0(_S12, _S11);
+ Vertex_0 _S13 = _S12;
+ gl_MeshVerticesEXT[0U].gl_Position = _S13.pos_0;
+ _S5[0U] = _S13.col_0;
+ Texes_0 _S14 = _S13.ts_0;
+ _S6[0U] = _S14.tex1_0;
+ _S7[0U] = _S14.tex2_0;
+ Vertex_0 _S15 = _S11;
+ gl_MeshVerticesEXT[0U].gl_Position = _S15.pos_0;
+ _S5[0U] = _S15.col_0;
+ Texes_0 _S16 = _S15.ts_0;
+ _S6[0U] = _S16.tex1_0;
+ _S7[0U] = _S16.tex2_0;
+ return;
+}
+
+void c_0(uint _S17)
+{
+ Vertex_0 _S18;
+ just_one_0(_S18);
+ Vertex_0 _S19 = _S18;
+ gl_MeshVerticesEXT[_S17].gl_Position = _S19.pos_0;
+ _S5[_S17] = _S19.col_0;
+ Texes_0 _S20 = _S19.ts_0;
+ _S6[_S17] = _S20.tex1_0;
+ _S7[_S17] = _S20.tex2_0;
+ return;
+}
+
+void d_0(uint _S21)
+{
+ Vertex_0 _S22;
+ Vertex_0 _S23;
+ just_two_0(_S23, _S22);
+ Vertex_0 _S24 = _S23;
+ gl_MeshVerticesEXT[_S21].gl_Position = _S24.pos_0;
+ _S5[_S21] = _S24.col_0;
+ Texes_0 _S25 = _S24.ts_0;
+ _S6[_S21] = _S25.tex1_0;
+ _S7[_S21] = _S25.tex2_0;
+ Vertex_0 _S26 = _S22;
+ gl_MeshVerticesEXT[0U].gl_Position = _S26.pos_0;
+ _S5[0U] = _S26.col_0;
+ Texes_0 _S27 = _S26.ts_0;
+ _S6[0U] = _S27.tex1_0;
+ _S7[0U] = _S27.tex2_0;
+ return;
+}
+
+void e_0(uint _S28)
+{
+ part_of_one_0(gl_MeshVerticesEXT[_S28].gl_Position);
+ Texes_0 _S29;
+ write_struct_0(_S29);
+ Texes_0 _S30 = _S29;
+ _S6[_S28] = _S30.tex1_0;
+ _S7[_S28] = _S30.tex2_0;
+ part_of_one_0(_S7[_S28]);
+ return;
+}
+
+layout(local_size_x = 3, local_size_y = 1, local_size_z = 1) in;
+layout(max_vertices = 3) out;
+layout(max_primitives = 1) out;
+layout(triangles) out;
+void main()
+{
+ SetMeshOutputsEXT(3U, 1U);
+ if(gl_LocalInvocationIndex < 3U)
+ {
+ a_0();
+ b_0();
+ c_0(gl_LocalInvocationIndex);
+ d_0(gl_LocalInvocationIndex);
+ e_0(gl_LocalInvocationIndex);
+ }
+ else
+ {
+ }
+ if(gl_LocalInvocationIndex < 1U)
+ {
+ gl_PrimitiveTriangleIndicesEXT[gl_LocalInvocationIndex] = uvec3(0U, 1U, 2U);
+ }
+ else
+ {
+ }
+ return;
+}
+
diff --git a/tests/pipeline/rasterization/mesh/primitive-output.slang b/tests/pipeline/rasterization/mesh/primitive-output.slang
new file mode 100644
index 000000000..fdbcf6912
--- /dev/null
+++ b/tests/pipeline/rasterization/mesh/primitive-output.slang
@@ -0,0 +1,57 @@
+// hello.slang
+
+// Test that a simple mesh shader compiles
+
+//TEST:CROSS_COMPILE:-target spirv -profile glsl_450+spirv_1_4 -entry main -stage mesh
+
+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;
+};
+
+struct Prim
+{
+ float3 triangleNormal : Normal;
+ uint id : SV_PrimitiveID;
+ bool cull : SV_CullPrimitive;
+};
+
+const static uint MAX_VERTS = 3;
+const static uint MAX_PRIMS = 1;
+
+[outputtopology("triangle")]
+[numthreads(3, 1, 1)]
+void main(
+ in uint tig : SV_GroupIndex,
+ out Indices<uint3, MAX_PRIMS> triangles,
+ out Vertices<Vertex, MAX_VERTS> verts,
+ out Primitives<Prim, MAX_PRIMS> primitives
+ )
+{
+ const uint numVertices = 3;
+ const uint numPrimitives = 1;
+ SetMeshOutputCounts(numVertices, numPrimitives);
+
+ if(tig < numVertices) {
+ verts[tig] = {float4(positions[tig], 0, 1), colors[tig]};
+ }
+
+ if(tig < numPrimitives) {
+ triangles[tig] = uint3(0,1,2);
+ primitives[tig] = {float3(0,0,1), tig, false};
+ }
+}
+
diff --git a/tests/pipeline/rasterization/mesh/primitive-output.slang.glsl b/tests/pipeline/rasterization/mesh/primitive-output.slang.glsl
new file mode 100644
index 000000000..b7b4f1d62
--- /dev/null
+++ b/tests/pipeline/rasterization/mesh/primitive-output.slang.glsl
@@ -0,0 +1,66 @@
+#version 450
+#extension GL_EXT_mesh_shader : require
+layout(row_major) uniform;
+layout(row_major) buffer;
+const vec3 colors_0[3] = { vec3(1.00000000000000000000, 1.00000000000000000000, 0.00000000000000000000), vec3(0.00000000000000000000, 1.00000000000000000000, 1.00000000000000000000), vec3(1.00000000000000000000, 0.00000000000000000000, 1.00000000000000000000) };
+const vec2 positions_0[3] = { vec2(0.00000000000000000000, -0.50000000000000000000), vec2(0.50000000000000000000, 0.50000000000000000000), vec2(-0.50000000000000000000, 0.50000000000000000000) };
+layout(location = 0)
+out vec3 _S1[3];
+
+out gl_MeshPerVertexEXT
+{
+ vec4 gl_Position;
+} gl_MeshVerticesEXT[3];
+
+perprimitiveEXT layout(location = 1)
+out vec3 _S2[1];
+
+perprimitiveEXT out gl_MeshPerPrimitiveEXT
+{
+ int gl_PrimitiveID;
+ bool gl_CullPrimitiveEXT;
+} gl_MeshPrimitivesEXT[1];
+
+struct Vertex_0
+{
+ vec4 pos_0;
+ vec3 color_0;
+};
+
+struct Prim_0
+{
+ vec3 triangleNormal_0;
+ uint id_0;
+ bool cull_0;
+};
+
+layout(local_size_x = 3, local_size_y = 1, local_size_z = 1) in;
+layout(max_vertices = 3) out;
+layout(max_primitives = 1) out;
+layout(triangles) out;
+void main()
+{
+ SetMeshOutputsEXT(3U, 1U);
+ if(gl_LocalInvocationIndex < 3U)
+ {
+ Vertex_0 _S3 = { vec4(positions_0[gl_LocalInvocationIndex], 0.00000000000000000000, 1.00000000000000000000), colors_0[gl_LocalInvocationIndex] };
+ gl_MeshVerticesEXT[gl_LocalInvocationIndex].gl_Position = _S3.pos_0;
+ _S1[gl_LocalInvocationIndex] = _S3.color_0;
+ }
+ else
+ {
+ }
+ if(gl_LocalInvocationIndex < 1U)
+ {
+ gl_PrimitiveTriangleIndicesEXT[gl_LocalInvocationIndex] = uvec3(0U, 1U, 2U);
+ Prim_0 _S4 = { vec3(0.00000000000000000000, 0.00000000000000000000, 1.00000000000000000000), gl_LocalInvocationIndex, false };
+ _S2[gl_LocalInvocationIndex] = _S4.triangleNormal_0;
+ gl_MeshPrimitivesEXT[gl_LocalInvocationIndex].gl_PrimitiveID = int(_S4.id_0);
+ gl_MeshPrimitivesEXT[gl_LocalInvocationIndex].gl_CullPrimitiveEXT = _S4.cull_0;
+ }
+ else
+ {
+ }
+ return;
+}
+
diff --git a/tests/pipeline/rasterization/mesh/swizzled-store.slang b/tests/pipeline/rasterization/mesh/swizzled-store.slang
new file mode 100644
index 000000000..f85f9ed62
--- /dev/null
+++ b/tests/pipeline/rasterization/mesh/swizzled-store.slang
@@ -0,0 +1,32 @@
+// component-write.slang
+
+// This tests that writing to individual components of the output struct works
+
+//TEST:CROSS_COMPILE:-target spirv -profile glsl_450+spirv_1_4 -entry main -stage mesh
+
+const static uint MAX_VERTS = 3;
+const static uint MAX_PRIMS = 1;
+
+[outputtopology("triangle")]
+[numthreads(3, 1, 1)]
+void main(
+ in uint tig : SV_GroupIndex,
+ out Vertices<float4, MAX_VERTS> verts : SV_Position,
+ out Indices<uint3, MAX_PRIMS> triangles
+ )
+{
+ const uint numVertices = 3;
+ const uint numPrimitives = 1;
+ SetMeshOutputCounts(numVertices, numPrimitives);
+
+ if(tig < numVertices) {
+ verts[tig].wz = float2(1, 0);
+ verts[tig].x = 0;
+ verts[tig].y = 0;
+ }
+
+ if(tig < numPrimitives) {
+ triangles[tig] = uint3(0,1,2);
+ }
+}
+
diff --git a/tests/pipeline/rasterization/mesh/swizzled-store.slang.glsl b/tests/pipeline/rasterization/mesh/swizzled-store.slang.glsl
new file mode 100644
index 000000000..b2467901e
--- /dev/null
+++ b/tests/pipeline/rasterization/mesh/swizzled-store.slang.glsl
@@ -0,0 +1,35 @@
+#version 450
+#extension GL_EXT_mesh_shader : require
+layout(row_major) uniform;
+layout(row_major) buffer;
+out gl_MeshPerVertexEXT
+{
+ vec4 gl_Position;
+} gl_MeshVerticesEXT[3];
+
+layout(local_size_x = 3, local_size_y = 1, local_size_z = 1) in;
+layout(max_vertices = 3) out;
+layout(max_primitives = 1) out;
+layout(triangles) out;
+void main()
+{
+ SetMeshOutputsEXT(3U, 1U);
+ if(gl_LocalInvocationIndex < 3U)
+ {
+ gl_MeshVerticesEXT[gl_LocalInvocationIndex].gl_Position.wz = vec2(1.00000000000000000000, 0.00000000000000000000);
+ gl_MeshVerticesEXT[gl_LocalInvocationIndex].gl_Position.x = 0.00000000000000000000;
+ gl_MeshVerticesEXT[gl_LocalInvocationIndex].gl_Position.y = 0.00000000000000000000;
+ }
+ else
+ {
+ }
+ if(gl_LocalInvocationIndex < 1U)
+ {
+ gl_PrimitiveTriangleIndicesEXT[gl_LocalInvocationIndex] = uvec3(0U, 1U, 2U);
+ }
+ else
+ {
+ }
+ return;
+}
+