Compiled Shader Format - LibVega/VSL GitHub Wiki
This page documents the binary format of the compiled shaders that are output by the vslc
tool.
The output shader files (by default ending in .vbc
for "Vega ByteCode") are binary files that act as a combination of reflection data and compiled SPIR-V bytecode that can be directly fed into Vulkan. The overall structure of the file is reflection information at the beginning, with raw SPIR-V bytecode at the end. This is split into three sections: Header, Reflection, Bytecode.
Unless otherwise noted, the shader stages appear in the following order in the file: vert
, tesc
, tese
, geom
, frag
.
The compiled shader files will be in native endian format, but since the tool currently only compiles for x86_64, the files will be little endian.
Header
The header is fixed-size, and contains the information required to parse and understand the rest of the file.
Offset | Type | Value | Description |
---|---|---|---|
0 | u8[3] |
Magic Number | The ascii characters "VBC" identifying the file type |
3 | u8 |
Version | The file format version, currently always 1 |
4 | u8 |
Shader Type | The pipeline type of the shader, currently always 1 for graphics |
5 | u16[5] |
Bytecode Sizes | The number of 4-byte instructions in each stage, zero denotes that the stage was not present in the shader |
15 | u16[5] |
Binding Table Sizes | The size of the binding tables for the binding types, in the order: samplers, images, buffers, rotexels, rwtexels. |
Total header size: 25 bytes
Reflection
Next is the reflection data, which is split into a series of variable-size sections describing the external interface to the shader. This section starts immediately after the end of the header.
Vertex Inputs
This section describes the vertex attributes that the shader requires as input. It begins with a u32
, which gives the number of vertex attributes present. It is immediately followed by a tightly packed list of vertex attribute descriptions, which takes the following format:
Offset | Type | Value | Description |
---|---|---|---|
0 | u8 |
Location | The binding location as an attribute index |
1 | u8 |
Base Type | The binding base type, as described in Reflection Info |
2 | u8[2] |
Type Dimensions | The dimensions of the type, as described in Reflection Info |
4 | u8 |
Array Size | The array size, if the attribute is an array, otherwise 1 |
5 | u8[3] |
Padding | Currently unused padding values, which are reserved |
Fragment Outputs
This section describes the fragment output variables that will write to renderer attachments. Its layout is identical to the Vertex Inputs section, including the format of the descriptions. For the descriptions, the location gives the attachment index of the output variable, and the output variables will never be arrays or matrices (dim[1] == 1 always).
Bindings
The next section describes the binding variables present in the shader. Each binding is bound to a specific index in the range [0, 32), and is accessed through a binding lookup table to allow the bind-once paradigm used by Vega. Similar to the vertex/fragment sections, this section starts with a u32
giving the number of bindings present, and is then followed by tightly-packed binding descriptions. All binding descriptions are 8 bytes, but have different internal layouts depending on the specific binding type (acting like a union of sorts).
Buffer Types - Including ROBuffer
and RWBuffer
Offset | Type | Value | Description |
---|---|---|---|
0 | u8 |
Slot | The binding slot of the binding (in [0, 32)) |
1 | u8 |
Base Type | The base type of the binding, as described in Reflection Info |
2 | u16 |
Stage Mask | The mask of stages in which this binding is accessed |
4 | u16 |
Buffer Size | The size of the buffer element type, in bytes |
6 | u8[2] |
Padding | Unused but reserved padding space |
Texel Types - Including Sampler
, Image
, ROTexels
, and RWTexels
Offset | Type | Value | Description |
---|---|---|---|
0 | u8 |
Slot | The binding slot of the binding (in [0, 32)) |
1 | u8 |
Base Type | The base type of the binding, as described in Reflection Info |
2 | u16 |
Stage Mask | The mask of stages in which this binding is accessed |
4 | u8 |
Texel Rank | The rank of the texel type |
5 | u8 |
Texel Type | The base type of the texel format |
6 | u8 |
Texel Size | The size of each texel component, in bytes |
7 | u8 |
Texel Components | The number of components in each texel, will be one of 1 , 2 , or 4 |
A description of the image rank values and texel types can be found in Reflection Info.
Uniform Data
Each shader can have exactly 0 or 1 uniform value, which is read-only structured data pulled from a buffer and made accessible in high-speed memory for the shader invocation. This section contains information on the shader uniform, if present, in the following format:
Offset | Type | Value | Description |
---|---|---|---|
0 | u16 |
Uniform Size | The size of the uniform type, in bytes, or zero if there is no uniform |
2 | u16 |
Stage Mask | The mask of shader stages that access the uniform data |
4 | u32 |
Member Count | The number of named members in the struct type used in the uniform |
8 | * |
Member Info | A tightly packed array of member descriptions |
If there are member descriptions present, they take the following format:
Offset | Type | Value | Description |
---|---|---|---|
0 | u8 |
Name Length | The length of the member name, in bytes (characters) |
1 | u8[*] |
Name | The name of the member, of length "Name Length" |
L | u16 |
Offset | The offset of the member, in bytes, into the uniform type |
L+2 | u8 |
Base Type | The base type of the member |
L+3 | u8[2] |
Dimensions | The dimensions of the numeric type |
L+5 | u8 |
Array Size | The size of the member array, or 1 if the member is not an array |
Note: If the shader does not utilize uniforms, then the only field of this section will be the first u16
"Uniform Size", which will be zero.
Subpass Inputs
The final reflection section describes the subpass input attachments used by the shader. It starts with a u32
giving the number of subpass inputs (not to exceed 4). If there are subpass inputs, this count is immediately followed by a tightly packed array of input descriptions, which take the format:
Offset | Type | Value | Description |
---|---|---|---|
0 | u8 |
Texel Type | The base type of the texel components |
1 | u8 |
Texel Comp. Count | The number of components in each texel - always one of 1 , 2 , or 4 |
2 | u8[2] |
Padding | Unused but reserved padding space |
The subpass inputs do not provide an attachment index, since all subpass inputs must be specified in order, and are contiguous starting from 0
.
Bytecode
The final section is a raw dump of SPIR-V bytecode from each stage that is present in the shader. The length of each bytecode dump is given by the associated section in the header.
Note that the actual bytecode length in bytes will be 4 * length
, since the header lengths are given as a count of instructions, and all SPIR-V instructions are 4 bytes in length.