nx_dxbc.nx source
↩ module page · 86 lines · 4621 B
1// nx_dxbc.nx -- D1 of the D3D-game ladder: a real DXBC (DirectX ByteCode) container + shader-token DECODER. A Windows
2// D3D9-11 game ships COMPILED shaders as DXBC blobs; running them starts with PARSING them. This decodes:
3// CONTAINER: "DXBC" magic, 16B checksum, u32 1, u32 total_size, u32 chunk_count, u32[chunk_count] offsets,
4// then chunks each = FourCC tag + u32 byte-size + payload. (little-endian, the real on-disk layout.)
5// SHADER CHUNK (SHEX/SHDR): u32 version (program-type in high nibble: 0=pixel 1=vertex ...) + u32 dword-length,
6// then a stream of instruction tokens: token = [opcode 0:10][length 24:30]; length = dwords incl the
7// token, so the next instruction is at +length. We classify the opcode (dcl_*, mov, add, mul, mad,
8// dp3/dp4, sample, ret) and count instructions -- the basis D2 lowers to our ISA / SPIR-V.
9// Pure integer, bounds-checked (defensive at the boundary: this is untrusted external input). license_tier: ORIGINAL
10import "nx_syscalls.nx"
11const K_MAGIC_100000: i64 = 100000
12const K_MAGIC_2047: i64 = 2047
13
14func dx_u32(b: *u8, o: i64) -> i64 {
15 return (b[o] as i64) | ((b[o+1] as i64) << 8) | ((b[o+2] as i64) << 16) | ((b[o+3] as i64) << 24)
16}
17func dx_fourcc(a: i64, b: i64, c: i64, d: i64) -> i64 { return a | (b<<8) | (c<<16) | (d<<24) }
18
19// verify the DXBC magic ("DXBC"). returns 1/0.
20func dxbc_is(b: *u8, n: i64) -> i64 {
21 if n < 32 { return 0 }
22 if (b[0] as i64) != 68 { return 0 } // D
23 if (b[1] as i64) != 88 { return 0 } // X
24 if (b[2] as i64) != 66 { return 0 } // B
25 if (b[3] as i64) != 67 { return 0 } // C
26 return 1
27}
28func dxbc_total_size(b: *u8) -> i64 { return dx_u32(b, 24) }
29func dxbc_chunk_count(b: *u8) -> i64 { return dx_u32(b, 28) }
30// offset of chunk i (the u32 offset table starts at byte 32)
31func dxbc_chunk_off(b: *u8, i: i64) -> i64 { return dx_u32(b, 32 + i*4) }
32func dxbc_chunk_tag(b: *u8, off: i64) -> i64 { return dx_u32(b, off) }
33func dxbc_chunk_size(b: *u8, off: i64) -> i64 { return dx_u32(b, off + 4) }
34
35// find a chunk by FourCC tag -> its payload offset (after the 8B tag+size header), or -1.
36func dxbc_find(b: *u8, n: i64, tag: i64) -> i64 {
37 let nc: i64 = dxbc_chunk_count(b)
38 var i: i64 = 0
39 while i < nc {
40 let off: i64 = dxbc_chunk_off(b, i)
41 if off + 8 <= n {
42 if dxbc_chunk_tag(b, off) == tag { return off + 8 }
43 }
44 i = i + 1
45 }
46 return 0 - 1
47}
48
49// program type from a shader chunk's version dword (high nibble of the high 16 bits): SM4/5 encode it in bits 16..19.
50func dxbc_program_type(ver: i64) -> i64 { return (ver >> 16) & 15 }
51
52// decode a shader chunk payload: [0]=version [1]=dword-length, then instruction tokens.
53// counts instructions + declarations; classify counters passed in cnt[8]:
54// cnt[0]=total-instrs cnt[1]=dcl cnt[2]=mov cnt[3]=arith(add/mul/mad) cnt[4]=dot(dp2/3/4) cnt[5]=sample cnt[6]=ret cnt[7]=other
55func dxbc_decode_shader(b: *u8, payoff: i64, n: i64, cnt: *i64) -> i64 {
56 var k: i64 = 0
57 while k < 8 { cnt[k] = 0; k = k + 1 }
58 let dwlen: i64 = dx_u32(b, payoff + 4) // length in dwords of the token stream incl header
59 var p: i64 = payoff + 8 // first instruction token (after version + length dwords)
60 let endp: i64 = payoff + dwlen * 4
61 var guard: i64 = 0
62 while p + 4 <= endp {
63 if p + 4 > n { return cnt[0] } // bounds: never read past the blob
64 if guard > K_MAGIC_100000 { return cnt[0] }
65 guard = guard + 1
66 let tok: i64 = dx_u32(b, p)
67 let opcode: i64 = tok & K_MAGIC_2047 // opcode = bits 0..10
68 var ilen: i64 = (tok >> 24) & 127 // instruction length in dwords (bits 24..30)
69 if ilen == 0 { ilen = 1 } // defensive: never advance 0 (would loop forever)
70 cnt[0] = cnt[0] + 1
71 // D3D10/11 SM4/5 opcode numbers (subset): 0=add 1=and 14=dp2 15=dp3 16=dp4 54=mov 56=mul 50=mad
72 // 69=sample 62=ret ; declarations are opcodes >=88 (dcl_*)
73 if opcode == 54 { cnt[2] = cnt[2] + 1 }
74 if opcode == 0 { cnt[3] = cnt[3] + 1 }
75 if opcode == 56 { cnt[3] = cnt[3] + 1 }
76 if opcode == 50 { cnt[3] = cnt[3] + 1 }
77 if opcode == 14 { cnt[4] = cnt[4] + 1 }
78 if opcode == 15 { cnt[4] = cnt[4] + 1 }
79 if opcode == 16 { cnt[4] = cnt[4] + 1 }
80 if opcode == 69 { cnt[5] = cnt[5] + 1 }
81 if opcode == 62 { cnt[6] = cnt[6] + 1 }
82 if opcode >= 88 { cnt[1] = cnt[1] + 1 }
83 p = p + ilen * 4
84 }
85 return cnt[0]
86}