The build task writes one reflection file per shader; the source generator reads it without loading
the compiler. The model is OneShader.Reflection.ShaderReflection; ReflectionFormat.Write and
TryRead implement this format. Version 1.
Rules
- UTF-8, no byte-order mark,
\nline ends, one record per line, ending with a newline. - First line:
oneshader-reflection 1. A reader must reject other versions. Additive changes (new records or new attributes) keep version 1; readers ignore unknown records and attributes. - A record is
keyword key=value key=value .... Values are bare tokens (no spaces) or double-quoted strings with\\,\",\n,\r,\tand\uXXXXescapes. Numbers are invariant-culture decimals; all counts, sizes, strides, offsets, locations and workgroup sizes are unsigned. Enum values use the member names of the C# enums. Lists are comma-separated; an empty list is-. - Nesting is by indentation: two spaces per level.
- Order is the model's order (declaration order). Equal models give identical bytes.
Records
source name="Shaders/Sprite.hlsl" targets list=SpirV,Wgsl resource name="Frame" kind=ConstantBuffer count=1 stages=Vertex,Pixel rtype=ConstantBuffer hlsl="" slot target=SpirV set=0 binding=0 layout type kind=Struct scalar=Bool rows=0 cols=0 name="Frame" size=128 align=16 length=0 stride=0 mstride=0 packing=ColumnMajor member name="ViewProjection" offset=0 type kind=Matrix ... mstride=16 packing=ColumnMajor member name="Weights" offset=80 type kind=Array ... length=3 stride=16 element type kind=Scalar scalar=Float ... entry name="VSMain" stage=Vertex workgroup=0,0,0 stride=32 input name="Position" semantic="POSITION" index=0 location=0 builtin=None scalar=Float components=2 format=Float32x2 offset=0 interp=Default output name="Position" semantic="SV_Position" index=0 location=- builtin=Position scalar=Float components=4 format=None offset=0 interp=Default uses name="Frame"
resource: an optionalformatattribute holds the[[vk::image_format]]name of a read-write texture;kindisResourceKind;stagesa list ofVertex,Pixel,Compute(-for none);rtypeisResourceTypeKind;hlslthe type as written. Childslotrecords give one slot per target (targetisSpirV,MslorWgsl; Metal uses the argument index asbindingand 0 asset).countis the array size (1 for a single resource); an array occupies oneslot. Alayoutchild holds atypetree.counter(child ofresource, append and consume buffers only):target,set,bindingof the hidden counter buffer, one record per target likeslot. Readers that do not know it ignore it.push: a push-constant block (not aresource):name,stages, alayoutchild with atypetree, andslotchildren for the targets that deliver it as a bound buffer:Msl(bindingis the[[buffer(n)]]index,set0) andWgsl(setis the bind group,bindingthe binding). SPIR-V has no slot. Anentrynames the block it reads with apushuse name=...child.features(child ofentry, written only when non-zero):bits, theDeviceFeaturesflags the entry point needs for 16-bit and 64-bit types (1 Float16, 2 Int16, 4 Float64, 8 Int64, 16 StorageBuffer16, 32 UniformBuffer16, 64 PushConstant16, 128 InputOutput16, 256 Int64Atomics).spec: a specialization constant:name,id(theconstant_id),scalar(Bool,Int,UIntorFloat) anddefault(the 32-bit pattern, as a number). Childslotrecords (target,index,name) give the SPIR-VSpecId, the Metal function-constant index and variable, and the WGSL@idand override name per target. Written only for files that have constants; it follows thepushrecords. Anentrylists the constants it reads withspecuse name=...children.type:kindisScalar,Vector,Matrix,ArrayorStruct.rowsis the vector component count or matrix rows;colsmatrix columns;size,alignin bytes;length/stridefor arrays (length 0 = unsized);mstride/packingfor matrices (the stride is between stored columns forColumnMajor, rows forRowMajor). AnArrayhas oneelementchild holding atype; aStructhasmemberchildren (name,offset) each holding onetype.entry:workgroupisx,y,z(zeros unless compute);stridethe interleaved vertex size (vertex stage only).input/outputare stage variables;location=-means built-in;formatis aVertexFormatname for vertex inputs andNoneelsewhere.useslists resource names the entry point touches.
Layouts are the single buffer layout shared by all targets (see BufferLayout).