code wiki / (root) / nx_dxbc.nx

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}