Overview#
Yotsuba Shader is the shader authoring layer for your engine, framework or content tool. Your team writes shaders in C# using types, structures and attributes. The compiler interprets their interfaces and stages, lowers them to a shared intermediate representation, and generates output for the selected backend.
The central idea is simple: the syntax you write with does not determine the output target. HLSL, GLSL, MSL, SPIR-V and WGSL provide equivalent authoring vocabularies. Choose the one your team knows best, then select SPIR-V or another backend when compiling.
C# with familiar attributes
↓
semantic analysis and validation
↓
Yotsuba IR
↓
SPIR-V · future backendsThe three layers#
Yotsuba Shader is organised around three ideas that map to separate projects:
- Language (
YotsubaShader.Language): the attributes and native types you write against. See Shader stages. - Intermediate representation (
YotsubaShader.IR): a backend-neutral model of functions, storage and interface slots. See Compilation process. - Compiler (
YotsubaShader.Roslyn,YotsubaShader.Compiler.SpirV): discovery, analysis and SPIR-V emission. See Compilation pipeline.
A shader in one glance#
using Microsoft.Xna.Framework;
using YotsubaShader.Language;
using YotsubaShader.HlslSyntax;
public class BasicColorShader
{
public struct VS_Input
{
[POSITION]
public Vector2 Position;
[COLOR]
public Vector4 Color;
}
public struct VS_Output
{
[SV_Position]
public Vector4 Position;
[COLOR]
public Vector4 Color;
}
[ShaderStage(Stage.Vertex)]
public VS_Output VS(VS_Input input)
{
VS_Output output = new VS_Output();
output.Position = new Vector4(
input.Position.X,
input.Position.Y,
0.0f,
1.0f
);
output.Color = input.Color;
return output;
}
[ShaderStage(Stage.Fragment)]
[return: SV_Target(0)]
public Vector4 FS(VS_Output input)
{
return input.Color;
}
}
The example uses HLSL semantics: [POSITION] and [COLOR], plus the built-in [SV_Position]. Numbered [Location(n)] attributes belong to the separate SPIR-V syntax namespace.
Why attributes?#
Attributes make the interface explicit: inputs, outputs, resources, locations, bindings and stages are all declared, never inferred from naming conventions. That is what lets the compiler validate a shader before any GPU is involved.
