One shader. Five ways to write it.
The five syntax projects declare C# attributes inspired by HLSL, GLSL, MSL, SPIR-V, and WGSL. Their concepts are intended to share an output path; the complete compiler pipeline is still in development. WGSL authoring attributes exist, while WGSL output is planned for 2027.
using YotsubaShader.Language;
using YotsubaShader.HlslSyntax;
using YotsubaShader.HlslSyntax.Resources;
public struct VertexOutput
{
[SV_Position]
public Vector4 Position;
}
public class Triangle
{
[register(RegisterPrefix.u, 0)]
public RWStructuredBuffer<float> Output;
[ShaderStage(Stage.Vertex)]
public VertexOutput Vertex([SV_VertexID] uint id)
{
VertexOutput output = new VertexOutput();
output.Position = new Vector4(0, 0, 0, 1);
return output;
}
[ShaderStage(Stage.Fragment)]
[return: SV_Target(0)]
public Vector4 Fragment(VertexOutput input)
{
return new Vector4(1, 0.4f, 0.7f, 1);
}
[ShaderStage(Stage.Compute)]
[numthreads(8, 8, 1)]
public void Compute([SV_DispatchThreadID] UInt3 id)
{
}
}
using YotsubaShader.Language;
using YotsubaShader.GlslSyntax;
using YotsubaShader.GlslSyntax.Resources;
public struct VertexOutput
{
[gl_Position]
public Vector4 Position;
}
public class Triangle
{
[buffer, layout(0, 0)]
public float[] Output;
[ShaderStage(Stage.Vertex)]
public VertexOutput Vertex([gl_VertexIndex] uint id)
{
VertexOutput output = new VertexOutput();
output.Position = new Vector4(0, 0, 0, 1);
return output;
}
[ShaderStage(Stage.Fragment)]
public Vector4 Fragment(VertexOutput input)
{
return new Vector4(1, 0.4f, 0.7f, 1);
}
[ShaderStage(Stage.Compute)]
[layout_local_size(8, 8, 1)]
public void Compute([gl_GlobalInvocationID] UInt3 id)
{
}
}
using YotsubaShader.Language;
using YotsubaShader.MslSyntax;
using YotsubaShader.MslSyntax.Resources;
public struct VertexOutput
{
[position]
public Vector4 Position;
}
public class Triangle
{
[device, buffer(0)]
public float[] Output;
[ShaderStage(Stage.Vertex)]
public VertexOutput Vertex([vertex_id] uint id)
{
VertexOutput output = new VertexOutput();
output.Position = new Vector4(0, 0, 0, 1);
return output;
}
[ShaderStage(Stage.Fragment)]
public Vector4 Fragment(VertexOutput input)
{
return new Vector4(1, 0.4f, 0.7f, 1);
}
// Workgroup size is set by the host
[ShaderStage(Stage.Compute)]
public void Compute([thread_position_in_grid] UInt3 id)
{
}
}
using YotsubaShader.Language;
using YotsubaShader.SpirvSyntax;
using YotsubaShader.SpirvSyntax.Resources;
public struct VertexOutput
{
[BuiltIn_Position]
public Vector4 Position;
}
public class Triangle
{
[StorageBuffer, DescriptorSet(0), @Binding(0)]
public float[] Output;
[ShaderStage(Stage.Vertex)]
public VertexOutput Vertex([BuiltIn_VertexIndex] uint id)
{
VertexOutput output = new VertexOutput();
output.Position = new Vector4(0, 0, 0, 1);
return output;
}
[ShaderStage(Stage.Fragment)]
public Vector4 Fragment(VertexOutput input)
{
return new Vector4(1, 0.4f, 0.7f, 1);
}
// Workgroup size is set by the host
[ShaderStage(Stage.Compute)]
public void Compute([BuiltIn_GlobalInvocationId] UInt3 id)
{
}
}
using YotsubaShader.Language;
using YotsubaShader.WgslSyntax;
using YotsubaShader.WgslSyntax.Resources;
public struct VertexOutput
{
[@builtin_position]
public Vector4 Position;
}
public class Triangle
{
[storage(storage_use.read_write), @group(0), @binding(0)]
public float[] Output;
[ShaderStage(Stage.Vertex)]
public VertexOutput Vertex([@builtin_vertex_index] uint id)
{
VertexOutput output = new VertexOutput();
output.Position = new Vector4(0, 0, 0, 1);
return output;
}
[ShaderStage(Stage.Fragment)]
public Vector4 Fragment(VertexOutput input)
{
return new Vector4(1, 0.4f, 0.7f, 1);
}
[ShaderStage(Stage.Compute)]
[@workgroup_size(8, 8, 1)]
public void Compute([@builtin_global_invocation_id] UInt3 id)
{
}
}
Choose your vocabulary
HLSL syntax
Teams coming from Direct3D and HLSL. 31 attributes.
Learn more
GLSL syntax
Teams coming from OpenGL and Vulkan GLSL. 35 attributes.
Learn more
MSL syntax
Teams coming from the Metal Shading Language. 32 attributes.
Learn more
SPIR-V syntax
Teams that think in SPIR-V and Vulkan descriptors. 34 attributes.
Learn more
WGSL syntax
Teams coming from WebGPU and WGSL. 24 attributes.
Learn more
Side-by-side reference
Every built-in value in all five syntaxes in one table.
Learn more
The same concept, five spellings
using YotsubaShader.Language;
using YotsubaShader.HlslSyntax;
public struct VertexOutput
{
// Clip-space position (vertex output)
[SV_Position]
public Vector4 Position;
}
public class BuiltIns
{
[ShaderStage(Stage.Vertex)]
public VertexOutput Vertex(
// Vertex index
[SV_VertexID] uint vertex,
// Instance index
[SV_InstanceID] uint instance)
{
VertexOutput output = new VertexOutput();
output.Position = new Vector4(vertex, instance, 0, 1);
return output;
}
[ShaderStage(Stage.Fragment)]
public Vector4 Fragment(
// Fragment coordinate
[SV_Position] Vector4 coord)
{
return new Vector4(coord.X, coord.Y, 0, 1);
}
[ShaderStage(Stage.Compute)]
// Workgroup size (method attribute)
[numthreads(8, 8, 1)]
public void Compute(
// Global invocation id
[SV_DispatchThreadID] uint id)
{
uint index = id;
}
}
using YotsubaShader.Language;
using YotsubaShader.GlslSyntax;
public struct VertexOutput
{
// Clip-space position (vertex output)
[gl_Position]
public Vector4 Position;
}
public class BuiltIns
{
[ShaderStage(Stage.Vertex)]
public VertexOutput Vertex(
// Vertex index
[gl_VertexIndex] uint vertex,
// Instance index
[gl_InstanceIndex] uint instance)
{
VertexOutput output = new VertexOutput();
output.Position = new Vector4(vertex, instance, 0, 1);
return output;
}
[ShaderStage(Stage.Fragment)]
public Vector4 Fragment(
// Fragment coordinate
[gl_FragCoord] Vector4 coord)
{
return new Vector4(coord.X, coord.Y, 0, 1);
}
[ShaderStage(Stage.Compute)]
// Workgroup size (method attribute)
[layout_local_size(8, 8, 1)]
public void Compute(
// Global invocation id
[gl_GlobalInvocationID] uint id)
{
uint index = id;
}
}
using YotsubaShader.Language;
using YotsubaShader.MslSyntax;
public struct VertexOutput
{
// Clip-space position (vertex output)
[position]
public Vector4 Position;
}
public class BuiltIns
{
[ShaderStage(Stage.Vertex)]
public VertexOutput Vertex(
// Vertex index
[vertex_id] uint vertex,
// Instance index
[instance_id] uint instance)
{
VertexOutput output = new VertexOutput();
output.Position = new Vector4(vertex, instance, 0, 1);
return output;
}
[ShaderStage(Stage.Fragment)]
public Vector4 Fragment(
// Fragment coordinate
[position] Vector4 coord)
{
return new Vector4(coord.X, coord.Y, 0, 1);
}
[ShaderStage(Stage.Compute)]
// No method attribute: the workgroup size is a built-in value
public void Compute(
// Global invocation id
[thread_position_in_grid] uint id)
{
uint index = id;
}
}
using YotsubaShader.Language;
using YotsubaShader.SpirvSyntax;
public struct VertexOutput
{
// Clip-space position (vertex output)
[BuiltIn_Position]
public Vector4 Position;
}
public class BuiltIns
{
[ShaderStage(Stage.Vertex)]
public VertexOutput Vertex(
// Vertex index
[BuiltIn_VertexIndex] uint vertex,
// Instance index
[BuiltIn_InstanceIndex] uint instance)
{
VertexOutput output = new VertexOutput();
output.Position = new Vector4(vertex, instance, 0, 1);
return output;
}
[ShaderStage(Stage.Fragment)]
public Vector4 Fragment(
// Fragment coordinate
[BuiltIn_FragCoord] Vector4 coord)
{
return new Vector4(coord.X, coord.Y, 0, 1);
}
[ShaderStage(Stage.Compute)]
// No method attribute: the workgroup size is a built-in value
public void Compute(
// Global invocation id
[BuiltIn_GlobalInvocationId] uint id)
{
uint index = id;
}
}
using YotsubaShader.Language;
using YotsubaShader.WgslSyntax;
public struct VertexOutput
{
// Clip-space position (vertex output)
[@builtin_position]
public Vector4 Position;
}
public class BuiltIns
{
[ShaderStage(Stage.Vertex)]
public VertexOutput Vertex(
// Vertex index
[@builtin_vertex_index] uint vertex,
// Instance index
[@builtin_instance_index] uint instance)
{
VertexOutput output = new VertexOutput();
output.Position = new Vector4(vertex, instance, 0, 1);
return output;
}
[ShaderStage(Stage.Fragment)]
public Vector4 Fragment(
// Fragment coordinate
[@builtin_position] Vector4 coord)
{
return new Vector4(coord.X, coord.Y, 0, 1);
}
[ShaderStage(Stage.Compute)]
// Workgroup size (method attribute)
[@workgroup_size(8, 8, 1)]
public void Compute(
// Global invocation id
[@builtin_global_invocation_id] uint id)
{
uint index = id;
}
}
