code wiki / (root) / nx_dxbc_exec.nx

nx_dxbc_exec.nx source

↩ module page · 163 lines · 7058 B

1// nx_dxbc_exec.nx -- D2 of the D3D-game ladder: DECODE OPERANDS + EXECUTE a real DXBC shader. A minimal SM5 2// interpreter over 4-component float32 registers (input v[], output o[], temp r[]) using REAL hardware float32 3// (nx_f32_hw mulss/addss = the same IEEE-754 ops D3D uses -> bit-matching semantics). Operand token layout decoded 4// from Microsoft fxc's actual output (confirmed): [0:1]=ncomp [2:3]=selmode [4:11]=swizzle/mask [12:19]=optype 5// (0=temp 1=input 2=output 4=immediate32) [20:21]=index-dim. Subset: mov + mad (enough to execute + GRADE a real 6// fxc arithmetic shader vs its known output). Extended operand tokens + full opcode coverage = D2b. license_tier: ORIGINAL 7import "nx_syscalls.nx" 8import "nx_dxbc.nx" 9import "nx_f32_hw.nx" 10const K_MAGIC_100000: i64 = 100000 11const K_MAGIC_2047: i64 = 2047 12 13// decode the operand token at byte offset `off` into out[0..9]; returns dwords consumed. 14// out: [0]=optype [1]=ncomp [2]=selmode [3]=swiz/mask [4]=indexdim [5..8]=imm floats [9]=register index 15func op_decode(b: *u8, off: i64, out: *i64) -> i64 { 16 let otok: i64 = dx_u32(b, off) 17 out[0] = (otok >> 12) & 255 // optype 18 out[1] = otok & 3 // ncomp 19 out[2] = (otok >> 2) & 3 // selmode 20 out[3] = (otok >> 4) & 255 // swizzle(2b x4) or mask(4b) 21 out[4] = (otok >> 20) & 3 // index dimension 22 out[9] = 0 23 var consumed: i64 = 1 24 if out[0] == 4 { // immediate32 25 var nimm: i64 = 1 26 if out[1] == 2 { nimm = 4 } // 4-component 27 var i: i64 = 0 28 while i < nimm { out[5+i] = dx_u32(b, off + consumed*4); consumed = consumed + 1; i = i + 1 } 29 } 30 if out[0] != 4 { // register: immediate index rep (our subset) 31 if out[4] >= 1 { out[9] = dx_u32(b, off + consumed*4); consumed = consumed + 1 } 32 } 33 return consumed 34} 35 36// pointer to a register's 4-component slot in the reg block (v[0..15] | o[0..15] | r[0..15], 4 f32 each) 37func sh_regbase(regs: *i64, optype: i64, idx: i64) -> *i64 { 38 var slot: i64 = 0 39 if optype == 1 { slot = idx*4 } // input v 40 if optype == 2 { slot = 64 + idx*4 } // output o 41 if optype == 0 { slot = 128 + idx*4 } // temp r 42 let p: *i64 = (regs as i64 + slot*8) as *i64 43 return p 44} 45 46// read a source operand -> 4 float32 values into dst[0..3] (apply swizzle for registers; immediates as-is) 47func sh_read_src(regs: *i64, opd: *i64, dst: *i64) -> i64 { 48 if opd[0] == 4 { 49 dst[0] = opd[5]; dst[1] = opd[6]; dst[2] = opd[7]; dst[3] = opd[8] 50 return 0 51 } 52 let base: *i64 = sh_regbase(regs, opd[0], opd[9]) 53 if opd[2] == 1 { // swizzle mode 54 let sw: i64 = opd[3] 55 dst[0] = base[sw & 3] 56 dst[1] = base[(sw >> 2) & 3] 57 dst[2] = base[(sw >> 4) & 3] 58 dst[3] = base[(sw >> 6) & 3] 59 return 0 60 } 61 dst[0] = base[0]; dst[1] = base[1]; dst[2] = base[2]; dst[3] = base[3] // identity (mask/select) 62 return 0 63} 64 65// write a dest operand (mask mode: low 4 bits select components) 66func sh_write_dest(regs: *i64, opd: *i64, src: *i64) -> i64 { 67 let base: *i64 = sh_regbase(regs, opd[0], opd[9]) 68 let mask: i64 = opd[3] 69 if (mask & 1) != 0 { base[0] = src[0] } 70 if (mask & 2) != 0 { base[1] = src[1] } 71 if (mask & 4) != 0 { base[2] = src[2] } 72 if (mask & 8) != 0 { base[3] = src[3] } 73 return 0 74} 75 76// DLL-safe variant: identical to sh_execute but takes CALLER-PROVIDED scratch (>=76 i64) instead of sys_mmap, so it runs 77// inside a Windows DLL (no Linux syscall). scratch layout: dst[0..15] a0[16..31] a1[32..47] a2[48..63] s0[64..67] s1[68..71] s2[72..75]. 78func sh_execute_scratch(b: *u8, payoff: i64, n: i64, regs: *i64, scratch: *i64) -> i64 { 79 let dwlen: i64 = dx_u32(b, payoff + 4) 80 let endp: i64 = payoff + dwlen*4 81 let dst: *i64 = scratch 82 let a0: *i64 = (scratch as i64 + 16*8) as *i64 83 let a1: *i64 = (scratch as i64 + 32*8) as *i64 84 let a2: *i64 = (scratch as i64 + 48*8) as *i64 85 let s0: *i64 = (scratch as i64 + 64*8) as *i64 86 let s1: *i64 = (scratch as i64 + 68*8) as *i64 87 let s2: *i64 = (scratch as i64 + 72*8) as *i64 88 var p: i64 = payoff + 8 89 var guard: i64 = 0 90 while p + 4 <= endp { 91 if p + 4 > n { return 0 } 92 if guard > K_MAGIC_100000 { return 0 } 93 guard = guard + 1 94 let itok: i64 = dx_u32(b, p) 95 let opcode: i64 = itok & K_MAGIC_2047 96 var ilen: i64 = (itok >> 24) & 127 97 if ilen == 0 { ilen = 1 } 98 if opcode == 54 { 99 let cd: i64 = op_decode(b, p + 4, dst) 100 op_decode(b, p + 4 + cd*4, a0) 101 sh_read_src(regs, a0, s0) 102 sh_write_dest(regs, dst, s0) 103 } 104 if opcode == 50 { 105 let cd: i64 = op_decode(b, p + 4, dst) 106 let c0: i64 = op_decode(b, p + 4 + cd*4, a0) 107 let c1: i64 = op_decode(b, p + 4 + (cd+c0)*4, a1) 108 op_decode(b, p + 4 + (cd+c0+c1)*4, a2) 109 sh_read_src(regs, a0, s0) 110 sh_read_src(regs, a1, s1) 111 sh_read_src(regs, a2, s2) 112 var c: i64 = 0 113 while c < 4 { s0[c] = f32_add(f32_mul(s0[c], s1[c]), s2[c]); c = c + 1 } 114 sh_write_dest(regs, dst, s0) 115 } 116 p = p + ilen*4 117 } 118 return 0 119} 120 121// execute the shader token stream over regs. handles mov + mad; skips declarations + ret. 122func sh_execute(b: *u8, payoff: i64, n: i64, regs: *i64) -> i64 { 123 let dwlen: i64 = dx_u32(b, payoff + 4) 124 let endp: i64 = payoff + dwlen*4 125 let dst: *i64 = sys_mmap(16*8) as *i64 126 let a0: *i64 = sys_mmap(16*8) as *i64 127 let a1: *i64 = sys_mmap(16*8) as *i64 128 let a2: *i64 = sys_mmap(16*8) as *i64 129 let s0: *i64 = sys_mmap(4*8) as *i64 130 let s1: *i64 = sys_mmap(4*8) as *i64 131 let s2: *i64 = sys_mmap(4*8) as *i64 132 var p: i64 = payoff + 8 133 var guard: i64 = 0 134 while p + 4 <= endp { 135 if p + 4 > n { return 0 } 136 if guard > K_MAGIC_100000 { return 0 } 137 guard = guard + 1 138 let itok: i64 = dx_u32(b, p) 139 let opcode: i64 = itok & K_MAGIC_2047 140 var ilen: i64 = (itok >> 24) & 127 141 if ilen == 0 { ilen = 1 } 142 if opcode == 54 { // mov dest, src0 143 let cd: i64 = op_decode(b, p + 4, dst) 144 op_decode(b, p + 4 + cd*4, a0) 145 sh_read_src(regs, a0, s0) 146 sh_write_dest(regs, dst, s0) 147 } 148 if opcode == 50 { // mad dest, src0, src1, src2 : dst = s0*s1 + s2 149 let cd: i64 = op_decode(b, p + 4, dst) 150 let c0: i64 = op_decode(b, p + 4 + cd*4, a0) 151 let c1: i64 = op_decode(b, p + 4 + (cd+c0)*4, a1) 152 op_decode(b, p + 4 + (cd+c0+c1)*4, a2) 153 sh_read_src(regs, a0, s0) 154 sh_read_src(regs, a1, s1) 155 sh_read_src(regs, a2, s2) 156 var c: i64 = 0 157 while c < 4 { s0[c] = f32_add(f32_mul(s0[c], s1[c]), s2[c]); c = c + 1 } 158 sh_write_dest(regs, dst, s0) 159 } 160 p = p + ilen*4 161 } 162 return 0 163}