Skip to main content

Crate dxcontainer

Crate dxcontainer 

Source
Expand description

Reader for the DXBC container, the file format Direct3D shader programs are stored in: Shader Model 4 and 5 programs (SHDR, SHEX, signatures, RDEF) and Shader Model 6 programs (DXIL, PSV0, RDAT, …) alike. chunks reads the container’s part directory and checksum computes the digest the compiler stores in it. feature_flags reads the SFI0 part, the shader’s required features, with names for the bits (feature_name). serialize writes parts as a container with a correct digest, repair_digest fixes the digest of one edited in place, and replace_part swaps one part of a container for new bytes.

The layout: a header (DXBC, a 16-byte digest, version 1, the container’s size, the number of parts), the directory of the parts’ offsets right after it, then the parts one after another in the directory’s order, each its four-character kind, its length and its bytes, the last ending where the container does. Shader Model 6 parts are not padded to 4 bytes, so an offset need not be a multiple of 4. This holds for every fixture committed in dxbc-reader and dxil-reader (the tests read each to its exact end and compare checksum with the stored digest).

The reader reads to the exact end: a part anywhere else, a gap, a byte after the last part, a kind twice, a size other than the container’s or a version other than 1 is an Error naming the byte. The digest is not verified (it is not an authenticity check); checksum is for a caller that wants to compare it.

// A container with one empty `ISGN` part: header, one directory entry, the part.
let mut bytes = b"DXBC".to_vec();
bytes.extend_from_slice(&[0; 16]); // digest
for word in [1u32, 44, 1, 36] {
    bytes.extend_from_slice(&word.to_le_bytes()); // version, size, part count, the part's offset
}
bytes.extend_from_slice(b"ISGN");
bytes.extend_from_slice(&0u32.to_le_bytes()); // the part's length

let parts = dxcontainer::chunks(&bytes).expect("a well-formed container");
assert_eq!(&parts[0].kind, b"ISGN");
assert!(parts[0].data.is_empty());
assert!(dxcontainer::checksum(&bytes).is_some());

Structs§

Chunk
A part of a container: its four-character kind and its bytes.
Error
What is wrong with a container, and where (a byte offset in it).
FeatureFlags
A container’s shader feature flags: its SFI0 part (eight bytes, a little-endian u64) and the bytecode that says what the bits mean.
WriteError
A container that cannot be written: what is wrong with the parts it was asked to hold.

Enums§

Bytecode
Which bytecode a container’s program part holds. It decides what the bits of the container’s SFI0 part name: the two compilers share the first bits and then diverge.
ReplaceError
Why replace_part failed: the container it was given, or the container it would write.

Functions§

checksum
The digest a container stores at bytes 4 to 20: MD5’s block function over its bytes from 20 on, the last block padded as the compiler does (the bit count first, then the rest, 0x80, zeros, and at 60 the bit count over 4, or 1; a rest of 56 bytes or more padded in a block of its own first). None for fewer than 20 bytes.
chunks
The part directory of the container bytes, in the container’s order. See the module documentation for what is refused.
feature_flags
The shader feature flags of container: None for a container with no SFI0 part (Sekiro’s and Riders Republic’s DXBC containers have none; the part is there in all 69,728 DXIL containers of skate. and Elden Ring). Refuses a container chunks refuses, an SFI0 part of other than eight bytes, and an SFI0 part in a container whose bytecode is unknown (no program part, or both kinds): the bits mean nothing without it.
feature_name
The name of bit bit of the SFI0 shader feature flags of bytecode, None for a bit with no name here.
repair_digest
Rewrites the digest at bytes 4 to 20 of container to the one checksum computes over the rest of it: for a container whose bytes were edited in place. Refuses bytes that are not a container’s (fewer than 20, or not starting DXBC), or too long for the digest’s 32-bit bit count.
replace_part
container with the part of kind kind replaced by data (a part not in it is appended after the others), every other part kept in its place and as it was, and the digest repaired: the edit a shader patch makes. Refuses a container chunks refuses.
serialize
Writes parts as a container: the header, the directory of the parts’ offsets, then the parts in the order given, each its kind, its length and its bytes with nothing between them, and the digest checksum computes over the result. A part’s bytes are written exactly as given, so a part whose producer padded it (or did not) stays so, and serialize(&chunks(bytes)?) is bytes again whenever bytes stores the digest checksum computes, as the games’ shipped containers do. Refuses a kind twice (the container chunks reads has each kind once) and a size or count that does not fit the header’s 32 bits.