BNSH (Binary NX SHader) is a shader file format used on the Nintendo Switch. It contains shader data.
File Format
The file format starts with the following header:
Offset |
Type |
Description
|
0x00 |
Char[8] |
File magic. Always BNSH\0\0\0\0 in ASCII, or 42 4E 53 4E 00 00 00 00.
|
0x08 |
UInt32 |
Version number.
|
0x0C |
UInt16 |
Byte-order-mark. FE FF for big endian, FF FE for little endian.
|
0x0E |
Byte |
Alignment shift. 1 << v, where v is this value is the alignment required by the file.
|
0x0F |
Byte |
Target address size. Size of a pointer in bits, thus 64.
|
0x10 |
UInt32 |
File name offset. Points directly to the string, and not to the length unlike all other strings.
|
0x14 |
UInt16 |
A flag which is only used on runtime. One bit sets wether the file is relocated.
|
0x16 |
UInt16 |
Offset to the first section.
|
0x18 |
UInt32 |
Relocation table offset.
|
0x1C |
UInt32 |
Size of the file in bytes.
|
0x20 |
Byte[64] |
Reserved.
|
Shader Container
The shader container is the root and stores some general information about the shaders.
Offset |
Type |
Description
|
0x00 |
Char[4] |
Section magic. Always grsc in ASCII.
|
0x04 |
UInt32 |
Next section offset.
|
0x08 |
UInt32 |
Size of this section in bytes.
|
0x0C |
Byte[4] |
Reserved.
|
0x10 |
UInt16 |
API target type.
|
0x12 |
UInt16 |
API target version.
|
0x14 |
Byte |
Target code type.
|
0x15 |
Byte[3] |
Reserved.
|
0x18 |
UInt32 |
Compiler version.
|
0x1C |
UInt32 |
Number of shader variations.
|
0x20 |
Int64 |
Shader variation array offset.
|
0x28 |
Int64 |
Shader memory pool offset.
|
0x30 |
UInt64 |
Low level compiler version.
|
0x38 |
Byte[40] |
Reserved.
|
Shader Variation
A shader variation contains a variation of a shader program. The binary program is used for binary files on the Nintendo Switch and the source program is used when testing PTCL files on a computer (which means it contains text shader data). The intermediate language program has an unknown usage. Each entry has the following structure:
Shader Program
The shader program structure specifies a shader program, which will be run on the GPU. It has the following structure:
Offset |
Type |
Description
|
0x00 |
Byte |
Flags. 0 = Separation, 1= ResShader.
|
0x01 |
Byte |
Code type.
ID |
Description
|
0x00 |
Binary
|
0x01 |
Intermediate language
|
0x02 |
Source
|
0x03 |
Source array
|
|
0x02 |
Byte |
Source format. Only GLSL (0) is supported.
|
0x03 |
Byte |
Reserved.
|
0x04 |
Int32 |
Binary format.
|
0x08 |
Int64 |
Vertex shader code offset.
|
0x10 |
Int64 |
Hull shader code offset.
|
0x18 |
Int64 |
Domain shader code offset.
|
0x20 |
Int64 |
Geometry shader code offset.
|
0x28 |
Int64 |
Fragment shader code offset.
|
0x30 |
Int64 |
Compute shader code offset.
|
0x38 |
Byte[40] |
Reserved.
|
0x60 |
UInt32 |
Object size. The maximum shader size in bytes to store shader object.
|
0x64 |
Byte[4] |
Reserved.
|
0x68 |
Int64 |
Object offset.
|
0x70 |
Int64 |
Parent shader variation offset.
|
0x78 |
Int64 |
Shader reflection offset.
|
0x80 |
Byte[32] |
Reserved.
|
Shader Code
Depending on the code type, a different structure can be stored. This one is stored for source:
Offset |
Type |
Description
|
0x00 |
Int64 |
Unknown.
|
0x08 |
Int64 |
Data 1 offset.
|
0x10 |
Int64 |
Data 2 offset.
|
0x18 |
UInt32 |
Data 2 size in bytes.
|
0x1C |
UInt32 |
Data 1 size in bytes.
|
0x20 |
Byte[32] |
Padding.
|
This one is stored for source array:
Offset |
Type |
Description
|
0x00 |
UInt16 |
Number of codes.
|
0x02 |
Byte[6] |
Reserved.
|
0x08 |
Int64 |
Code size array offset. Points to an array of UInt32s which stores the code size.
|
0x10 |
Int64 |
Code data table offset. Points to an array of Int64s which points to the code datas.
|
0x18 |
Byte[8] |
Reserved.
|
Shader Reflection
Shader Reflection Stage
Offset |
Type |
Description
|
0x00 |
Int64 |
Shader input dictionary offset.
|
0x08 |
Int64 |
Shader output dictionary offset.
|
0x10 |
Int64 |
Sampler dictionary offset.
|
0x18 |
Int64 |
Constant buffer dictionary offset.
|
0x20 |
Int64 |
Unordered access buffer dictionary offset.
|
0x28 |
Int32 |
Shader output offset into the array.
|
0x2C |
Int32 |
Sampler offset into the array.
|
0x30 |
Int32 |
Constant buffer offset into the array.
|
0x34 |
Int32 |
Unordered access buffer offset into the array.
|
0x38 |
Int64 |
Shader slot array offset.
|
0x40 |
UInt32 |
Compute work group size X. The size of the workgroup's X dimension for compute shaders.
|
0x44 |
UInt32 |
Compute work group size Y. The size of the workgroup's Y dimension for compute shaders.
|
0x48 |
UInt32 |
Compute work group size Z. The size of the workgroup's Z dimension for compute shaders.
|
0x4C |
Int32 |
Image offset into the array.
|
0x50 |
Int64 |
Image dictionary offset.
|
0x58 |
Byte[8] |
Reserved.
|
Memory Pool
Offset |
Type |
Description
|
0x00 |
UInt32 |
Memory pool property. Always 0x61.
|
0x04 |
UInt32 |
Size of the memory pool in bytes.
|
0x08 |
Int64 |
Offset to the memory pool. Points directly to the start of the data.
|
0x10 |
Byte[16] |
Reserved.
|
0x20 |
Int64 |
Memory pool offset. Points to an array of 0x140 empty bytes, with unknown use.
|
0x28 |
Byte[8] |
Reserved.
|
0x30 |
Int64 |
Current memory pool offset, set at runtime.
|
0x38 |
Byte[24] |
Reserved.
|
String Table
The string table is a table where all strings are stored. Each string has first the length written, which is a 16-bit integer, and then the string is stored as a null-terminated string. The string length does not include the null byte, and the 16-bit string length value is always aligned by 2. The string sorting algorithm is unknown.
Offset |
Type |
Description
|
0x00 |
Char[4] |
Section magic. Always _STR in ASCII.
|
0x04 |
UInt32 |
Next section offset.
|
0x08 |
UInt32 |
Size of this section in bytes.
|
0x0C |
Byte[4] |
Reserved.
|
0x10 |
Int32 |
Number of strings stored in the string table. The first string is always an empty string ("") and is not included in this count.
|
Dictionary
A dictionary (sometimes known as DICT) is a common structure used in many Nintendo formats such as BFRES and BNTX. It is used for fast name look-up, in order to find a specific array item by its name. It starts with the following structure:
Offset |
Type |
Description
|
0x00 |
Char[4] |
Section magic. Always _DIC in ASCII. Note that in BFRES this magic is set to 00 00 00 00, most likely due to an export error.
|
0x04 |
Int32 |
Number of entries. This does not include the root entry.
|
After, the entries are specified. The root entry follows first, then all other entries are stored. Each entry has the following structure:
Offset |
Type |
Description
|
0x00 |
Int32 |
Ref bit.
|
0x04 |
UInt16[2] |
Child node indices. First the left node, then the right node.
|
0x08 |
Int64 |
Key offset, which points to the key name this entry stores.
|
Relocation Table
Offset |
Type |
Description
|
0x00 |
Char[4] |
Section magic. Always _RLT in ASCII.
|
0x04 |
UInt32 |
Table offset. The offset where this table starts.
|
0x08 |
Int32 |
Number of sections.
|
0x0C |
Byte[4] |
Padding.
|
Offset |
Type |
Description
|
0x00 |
Int64 |
Section pointer, set on runtime.
|
0x08 |
UInt32 |
Section offset.
|
0x0C |
UInt32 |
Section size.
|
0x10 |
UInt32 |
Entry ID.
|
0x14 |
UInt32 |
Number of entries.
|
Offset |
Type |
Description
|
0x00 |
UInt32 |
Entry offset.
|
0x04 |
UInt16 |
Array count.
|
0x06 |
Byte |
Offset count.
|
0x07 |
Byte |
Padding size.
|
Version List
Version |
Found in
|
2.1.2
|
|
2.1.4
|
|
2.1.5
|
|
2.1.10
|
- Nintendo Switch System BIOS (6.0.0 – 6.2.0)
- Tetris 99
|
2.1.11
|
|
2.1.12
|
|
2.2.1
|
|
2.3.1
|
|
Tools
The following tools can handle BNSH files: