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}