nx_gsplat_perf.nx source
↩ module page · 361 lines · 18613 B
1// nx_gsplat_perf.nx -- THE SPLAT RENDER BASELINE: a number for every performance claim to beat.
2//
3// WHY THIS ORGAN EXISTS. On 2026-08-23 the sovereign splat rasterizer's viewport stopped being a
4// compile-time 512x384 and became a parameter. Every performance claim made after that moment needs
5// a measured baseline, per stage, at the resolutions we actually intend to deliver. WITHOUT A
6// BASELINE AN IMPROVEMENT CLAIM IS UNFALSIFIABLE -- so this organ ships before any optimisation does.
7//
8// WHAT IT REPORTS, per viewport: total frame microseconds, plus the microseconds of each of the four
9// stages the renderer is COMPOSED FROM (project+sort, clear, blend, resolve), and the CONIC
10// EVALUATION count -- the deterministic cost unit gs_blend_rect already returns. Two renderers can be
11// compared in that currency without a stopwatch at all, which is what makes an optimisation provable
12// on a loaded box.
13//
14// THE BLEND FIGURE IS DERIVED (total - project - clear - resolve), never measured directly: measuring
15// it directly would require a second copy of the full-screen policy, and a second policy is a second
16// ruler. The subtraction is stated here so nobody reads it as an independent measurement.
17//
18// TIMING IS THE MINIMUM OF PF_ITERS RUNS. A minimum is the least contaminated estimator of the true
19// cost on a shared box -- the mean absorbs every interfering lane, and this box carries many. The
20// spread (max-min) is printed beside it so the reader can see how noisy the sample was rather than
21// trusting the minimum blindly.
22//
23// THE VIEWPORT LADDER IS NOT PICKED. Each rung is a resolution the estate already has a reason for:
24// the historic cap it just escaped, the derived gallery target read from the capture wire's own
25// recorded frame, and the 4K rung the beauty tier is aimed at.
26
27import "nx_syscalls.nx"
28import "nx_itrig.nx"
29import "nx_gsplat.nx"
30import "nx_gsplat_tile_lib.nx"
31import "nx_gate_verdict.nx"
32
33const PF_W64: i64 = 8
34const PF_ITERS: i64 = 3 // min-of-3; see header on why the minimum and not the mean
35
36// Scene: the SAME fixture shape nx_gsplat_res_gate already proves the renderer against, so the
37// baseline is taken on a scene the estate has already accepted rather than one invented here.
38const PF_CAMZ: i64 = 30
39const PF_RTAN: i64 = 250
40const PF_XSPAN: i64 = 10000
41const PF_YSPAN: i64 = 8000
42
43// The two scene densities: the proven 8x8 fixture, and a 32x32 that puts real pressure on the sort.
44const PF_GRID_A: i64 = 8
45const PF_GRID_B: i64 = 32
46
47// Viewport ladder, largest first so the one allocation covers every rung.
48const PF_NRES: i64 = 5
49const PF_W0: i64 = 3840
50const PF_H0: i64 = 2160
51const PF_W1: i64 = 1920
52const PF_H1: i64 = 1200
53const PF_W2: i64 = 1920
54const PF_H2: i64 = 1080
55const PF_W3: i64 = 1280
56const PF_H3: i64 = 720
57const PF_W4: i64 = 512
58const PF_H4: i64 = 384
59
60func pf_w_at(i: i64) -> i64 {
61 if i == 0 { return PF_W0 }
62 if i == 1 { return PF_W1 }
63 if i == 2 { return PF_W2 }
64 if i == 3 { return PF_W3 }
65 return PF_W4
66}
67func pf_h_at(i: i64) -> i64 {
68 if i == 0 { return PF_H0 }
69 if i == 1 { return PF_H1 }
70 if i == 2 { return PF_H2 }
71 if i == 3 { return PF_H3 }
72 return PF_H4
73}
74
75// Build a grid scene of grid*grid anisotropic gaussians spanning the model box.
76func pf_scene(gauss: *i64, grid: i64) -> i64 {
77 let ng: i64 = grid * grid
78 var i: i64 = 0
79 while i < ng {
80 let row: i64 = i / grid
81 let col: i64 = i - row * grid
82 let x: i64 = 0 - PF_XSPAN + col * (2 * PF_XSPAN / (grid - 1))
83 let y: i64 = 0 - PF_YSPAN + row * (2 * PF_YSPAN / (grid - 1))
84 gs_set_aniso(gauss, i, x, y, 0, 0, 0, 0 - gs_fxa(), PF_RTAN, 60 + i * 3, 200, 255 - i * 2, gs_fxa())
85 i = i + 1
86 }
87 return ng
88}
89
90// Framebuffer checksum: the CORRECTNESS ANCHOR. Any optimisation of the rasterizer must reproduce
91// this number exactly at every rung -- a faster renderer that changes a pixel is a broken renderer,
92// and this is the one line that can tell those two apart.
93// PF_SUM_RADIX: the positional weight that makes the hash order-sensitive -- two frames with the same
94// pixels in a different order must not collide. PF_SUM_MOD: a prime modulus, present ONLY to keep the
95// running value inside i64 so the hash is defined rather than overflow-dependent.
96// Parallel-section budgets. PF_WORKERS is the worker count nx_gsplat_tile_gate already proves
97// byte-identical and spread across (T9/T10/T11). The three tile edges are POINTS ON THE CURVE the
98// gate sweeps, reported rather than chosen -- this organ publishes what each costs at the delivery
99// viewport instead of naming a favourite. PF_TILE_BUDGET is a DECLARED ceiling on tile-list slots:
100// a splat straddling many tiles takes one slot per tile, so the total is scene-dependent and the lib
101// REFUSES rather than truncating -- gt_entries() prints what was actually used so the next caller
102// sizes it from a measurement.
103const PF_WORKERS: i64 = 4
104const PF_NEDGE: i64 = 3
105const PF_EDGE0: i64 = 32
106const PF_EDGE1: i64 = 64
107const PF_EDGE2: i64 = 128
108const PF_TILE_BUDGET: i64 = 4000000
109const PF_SUM_RADIX: i64 = 31
110const PF_SUM_MOD: i64 = 1000000007
111func pf_sum(fb: *i64, n: i64) -> i64 {
112 var h: i64 = 0
113 var i: i64 = 0
114 while i < n { h = (h * PF_SUM_RADIX + fb[i]) % PF_SUM_MOD; i = i + 1 }
115 return h
116}
117
118func pf_pad(v: i64, width: i64) -> i64 {
119 var d: i64 = 1
120 var n: i64 = v
121 while n >= 10 { n = n / 10; d = d + 1 }
122 while d < width { gv_puts(" " as *u8); d = d + 1 }
123 return 0
124}
125
126func main() -> i64 {
127 gv_puts("nx_gsplat_perf -- sovereign splat rasterizer baseline (min of 3, microseconds)\n\n" as *u8)
128
129 let maxpx: i64 = PF_W0 * PF_H0
130 let maxng: i64 = PF_GRID_B * PF_GRID_B
131 let st: i64 = gs_stride_aniso()
132
133 // ONE allocation at the largest rung, reused by every smaller one. Sized from the ladder's own
134 // maximum, never from a chosen ceiling.
135 let gauss: *i64 = sys_mmap(maxng * st * PF_W64) as *i64
136 let acc: *i64 = sys_mmap(maxpx * 3 * PF_W64) as *i64
137 let trans: *i64 = sys_mmap(maxpx * PF_W64) as *i64
138 let fb: *i64 = sys_mmap(maxpx * PF_W64) as *i64
139 let depth: *i64 = sys_mmap(maxng * PF_W64) as *i64
140 let sxb: *i64 = sys_mmap(maxng * PF_W64) as *i64
141 let syb: *i64 = sys_mmap(maxng * PF_W64) as *i64
142 let pa: *i64 = sys_mmap(maxng * PF_W64) as *i64
143 let pb: *i64 = sys_mmap(maxng * PF_W64) as *i64
144 let pc: *i64 = sys_mmap(maxng * PF_W64) as *i64
145 let pdet: *i64 = sys_mmap(maxng * PF_W64) as *i64
146 let order: *i64 = sys_mmap(maxng * PF_W64) as *i64
147 let count: *i64 = sys_mmap((gs_nb() + 2) * PF_W64) as *i64
148 let explut: *i64 = sys_mmap(gs_expn() * PF_W64) as *i64
149 gs_build_explut(explut)
150
151 gv_puts(" bytes/pixel = 40 (acc x3 + trans + fb, i64 each) -- the resource contract\n" as *u8)
152 gv_puts(" scene = anisotropic grid, camz " as *u8); gv_num(PF_CAMZ)
153 gv_puts(", rtan " as *u8); gv_num(PF_RTAN); gv_puts("\n\n" as *u8)
154
155 var s: i64 = 0
156 while s < 2 {
157 var grid: i64 = PF_GRID_A
158 if s == 1 { grid = PF_GRID_B }
159 let ng: i64 = pf_scene(gauss, grid)
160
161 gv_puts("=== scene: " as *u8); gv_num(ng); gv_puts(" gaussians ===\n" as *u8)
162 gv_puts(" viewport pixels total_us proj_us clear_us blend_us resolve_us spread_us evals fb_checksum\n" as *u8)
163
164 var r: i64 = 0
165 while r < PF_NRES {
166 let w: i64 = pf_w_at(r)
167 let h: i64 = pf_h_at(r)
168 let npx: i64 = w * h
169 let focal: i64 = gs_focal_for(h)
170 let hw: i64 = w / 2
171 let hh: i64 = h / 2
172
173 // --- total frame, min of PF_ITERS -------------------------------------------------
174 var best: i64 = 0
175 var worst: i64 = 0
176 var it: i64 = 0
177 while it < PF_ITERS {
178 let t0: i64 = sys_clock_now_us()
179 gs_render_aniso_at(gauss, ng, 0, PF_CAMZ, fb, acc, trans, depth, sxb, syb, pa, pb, pc, pdet, order, count, explut, 0, 0, 0, w, h, focal)
180 let t1: i64 = sys_clock_now_us()
181 let el: i64 = t1 - t0
182 if it == 0 { best = el; worst = el }
183 if el < best { best = el }
184 if el > worst { worst = el }
185 it = it + 1
186 }
187
188 // --- stage attribution: each exported stage timed on its own, min of PF_ITERS ------
189 var bproj: i64 = 0
190 var bclear: i64 = 0
191 var bres: i64 = 0
192 it = 0
193 while it < PF_ITERS {
194 let p0: i64 = sys_clock_now_us()
195 gs_project_sort_at(gauss, ng, 0, PF_CAMZ, depth, sxb, syb, pa, pb, pc, pdet, order, count, hw, hh, focal)
196 let p1: i64 = sys_clock_now_us()
197 gs_clear_at(acc, trans, npx)
198 let p2: i64 = sys_clock_now_us()
199 gs_resolve(fb, acc, trans, npx, 0, 0, 0)
200 let p3: i64 = sys_clock_now_us()
201 if it == 0 { bproj = p1 - p0; bclear = p2 - p1; bres = p3 - p2 }
202 if p1 - p0 < bproj { bproj = p1 - p0 }
203 if p2 - p1 < bclear { bclear = p2 - p1 }
204 if p3 - p2 < bres { bres = p3 - p2 }
205 it = it + 1
206 }
207 // DERIVED, not measured: see header.
208 var blend: i64 = best - bproj - bclear - bres
209 if blend < 0 { blend = 0 }
210
211 // --- conic evaluations: the deterministic cost unit, independent of the clock -------
212 // Re-run the full-screen policy's own blend accounting by summing what gs_blend_rect
213 // returns for each visible splat over the same rectangles the policy uses.
214 let vis: i64 = gs_project_sort_at(gauss, ng, 0, PF_CAMZ, depth, sxb, syb, pa, pb, pc, pdet, order, count, hw, hh, focal)
215 gs_clear_at(acc, trans, npx)
216 var evals: i64 = 0
217 var oi: i64 = 0
218 while oi < vis {
219 let g: i64 = order[oi]
220 let sx: i64 = sxb[g]
221 let sy: i64 = syb[g]
222 let ca: i64 = pa[g]
223 let cbv: i64 = pb[g]
224 let cc: i64 = pc[g]
225 let det: i64 = pdet[g]
226 let rx: i64 = gs_splat_rx(ca)
227 let ry: i64 = gs_splat_ry(cc)
228 var y0: i64 = sy - ry
229 if y0 < 0 { y0 = 0 }
230 var y1: i64 = sy + ry
231 if y1 >= h { y1 = h - 1 }
232 var x0: i64 = sx - rx
233 if x0 < 0 { x0 = 0 }
234 var x1: i64 = sx + rx
235 if x1 >= w { x1 = w - 1 }
236 evals = evals + gs_blend_rect(gauss, g, sx, sy, ca, cbv, cc, det, x0, x1, y0, y1, acc, trans, explut, w, ((count as i64) + (gs_nb()+1)*8) as *i64)
237 oi = oi + 1
238 }
239
240 // One clean canonical frame for the checksum: the stage-attribution pass above resolved
241 // against scratch it had already disturbed, so fb must be re-rendered before it is hashed.
242 gs_render_aniso_at(gauss, ng, 0, PF_CAMZ, fb, acc, trans, depth, sxb, syb, pa, pb, pc, pdet, order, count, explut, 0, 0, 0, w, h, focal)
243 let sum: i64 = pf_sum(fb, npx)
244
245 gv_puts(" " as *u8)
246 pf_pad(w, 5); gv_num(w); gv_puts("x" as *u8); gv_num(h)
247 if h < 1000 { gv_puts(" " as *u8) }
248 gv_puts(" " as *u8); pf_pad(npx, 9); gv_num(npx)
249 gv_puts(" " as *u8); pf_pad(best, 9); gv_num(best)
250 gv_puts(" " as *u8); pf_pad(bproj, 9); gv_num(bproj)
251 gv_puts(" " as *u8); pf_pad(bclear, 9); gv_num(bclear)
252 gv_puts(" " as *u8); pf_pad(blend, 10); gv_num(blend)
253 gv_puts(" " as *u8); pf_pad(bres, 10); gv_num(bres)
254 gv_puts(" " as *u8); pf_pad(worst - best, 13); gv_num(worst - best)
255 gv_puts(" " as *u8); pf_pad(evals, 11); gv_num(evals)
256 gv_puts(" " as *u8); pf_pad(sum, 15); gv_num(sum)
257 gv_puts("\n" as *u8)
258
259 r = r + 1
260 }
261 gv_puts("\n" as *u8)
262 s = s + 1
263 }
264
265 // ==== PARALLEL SECTION: the one speed-up that is ARITHMETIC rather than EMPIRICAL ============
266 // Everything above is a wall-clock measurement, and this box currently carries six build lanes --
267 // nx_membound reversed direction (0.935 then 1.464) between two runs of ONE binary, so a +-50%
268 // effect cannot be resolved here at all. Dividing the tiles among N forked workers is different in
269 // kind: every pixel belongs to exactly ONE tile, so the partition IS the synchronisation, no two
270 // workers touch the same acc/trans word, and the frame is byte-identical BY CONSTRUCTION. That
271 // property survives a noisy box when no timing does.
272 //
273 // The tile edge is NOT picked here. nx_gsplat_tile_gate sweeps 8/16/32/64/128/256 and proves every
274 // one byte-identical; this organ reports the CURVE at the delivery viewport so a caller chooses on
275 // a measurement rather than on a favourite number. gt_entries() is printed for the same reason:
276 // the next reader sizes the budget from what a scene actually used.
277 gv_puts("=== 4K PARALLEL: full-screen serial vs tiled workers (checksums must all match) ===\n" as *u8)
278 gv_puts(" tile_edge workers total_us entries evals fb_checksum\n" as *u8)
279
280 let pw: i64 = PF_W0
281 let ph: i64 = PF_H0
282 let ppx: i64 = pw * ph
283 let pfoc: i64 = gs_focal_for(ph)
284 let ng2: i64 = pf_scene(gauss, PF_GRID_B)
285
286 // acc/trans MUST be MAP_SHARED for the forked workers to composite into one frame -- a private
287 // mapping would give each child its own copy-on-write pixels and the parent would resolve an
288 // EMPTY buffer while every worker reported a full day's work.
289 let sacc: *i64 = sys_mmap_shared(ppx * 3 * PF_W64) as *i64
290 let stra: *i64 = sys_mmap_shared(ppx * PF_W64) as *i64
291 let sfb: *i64 = sys_mmap_shared(ppx * PF_W64) as *i64
292
293 // reference: the full-screen policy at 4K, the number the parallel path must reproduce and beat
294 let rt0: i64 = sys_clock_now_us()
295 gs_render_aniso_at(gauss, ng2, 0, PF_CAMZ, sfb, sacc, stra, depth, sxb, syb, pa, pb, pc, pdet, order, count, explut, 0, 0, 0, pw, ph, pfoc)
296 let rt1: i64 = sys_clock_now_us()
297 let refsum: i64 = pf_sum(sfb, ppx)
298 gv_puts(" full-screen serial " as *u8); pf_pad(rt1-rt0, 12); gv_num(rt1-rt0)
299 gv_puts(" - " as *u8); pf_pad(0, 10); gv_num(0)
300 gv_puts(" " as *u8); pf_pad(refsum, 15); gv_num(refsum); gv_puts("\n" as *u8)
301
302 var mismatches: i64 = 0
303 var ei: i64 = 0
304 while ei < PF_NEDGE {
305 var edge: i64 = PF_EDGE0
306 if ei == 1 { edge = PF_EDGE1 }
307 if ei == 2 { edge = PF_EDGE2 }
308 if gt_init_at(edge, PF_TILE_BUDGET, PF_WORKERS, pw, ph) == 0 {
309 var wi: i64 = 0
310 while wi < 2 {
311 var nw: i64 = 1
312 if wi == 1 { nw = PF_WORKERS }
313 let g0: i64 = sys_clock_now_us()
314 gt_render(gauss, ng2, 0, PF_CAMZ, sfb, sacc, stra, depth, sxb, syb, pa, pb, pc, pdet, order, count, explut, 0, 0, 0, nw)
315 let g1: i64 = sys_clock_now_us()
316 let gsum: i64 = pf_sum(sfb, ppx)
317 if gsum != refsum { mismatches = mismatches + 1 }
318 gv_puts(" " as *u8); pf_pad(edge, 10); gv_num(edge)
319 gv_puts(" " as *u8); pf_pad(nw, 8); gv_num(nw)
320 gv_puts(" " as *u8); pf_pad(g1-g0, 12); gv_num(g1-g0)
321 gv_puts(" " as *u8); pf_pad(gt_entries(), 9); gv_num(gt_entries())
322 gv_puts(" " as *u8); pf_pad(gt_evals(), 11); gv_num(gt_evals())
323 gv_puts(" " as *u8); pf_pad(gsum, 15); gv_num(gsum)
324 if gsum != refsum { gv_puts(" <== CHECKSUM MISMATCH" as *u8) }
325 gv_puts("\n" as *u8)
326 wi = wi + 1
327 }
328 // per-worker spread: a run that claimed N workers and idled N-1 of them is a serial run
329 // wearing a parallel label, and this is the line that tells them apart.
330 gv_puts(" per-worker evals:" as *u8)
331 var w2: i64 = 0
332 while w2 < PF_WORKERS { gv_puts(" " as *u8); gv_num(gt_worker_evals(w2)); w2 = w2 + 1 }
333 gv_puts("\n" as *u8)
334 } else { gv_puts(" tile init REFUSED at edge " as *u8); gv_num(edge); gv_puts(" -- budget or viewport rejected it BY NAME\n" as *u8) }
335 ei = ei + 1
336 }
337 gv_puts("\n checksum mismatches across every tiled configuration = " as *u8); gv_num(mismatches)
338 gv_puts(" (must be 0: a faster frame that moves a pixel is a broken frame)\n\n" as *u8)
339
340 gv_puts("NX-GSPLAT-PERF baseline recorded (blend_us is DERIVED by subtraction; evals is the\n" as *u8)
341 gv_puts("clock-free cost unit -- but note it counts PIXELS VISITED, not cost per pixel, so an\n" as *u8)
342 gv_puts("optimisation that makes each evaluation cheaper does NOT move it: the clock is the\n" as *u8)
343 gv_puts("instrument for that class, and the fb_checksum is what keeps the clock honest.)\n\n" as *u8)
344
345 // ---- BANKED NEGATIVE RESULT, 2026-08-23 -------------------------------------------------
346 // Forward differencing + bracketed quotient (SHARP-GS SIGGRAPH 2026 contribution iii) was
347 // implemented in gs_blend_rect and MEASURED against these rows, then REVERTED. It was exactly
348 // correct -- all ten fb_checksums reproduced, and nx_fwddiff_equiv_gate proves the arithmetic
349 // identity 8/8 over 4,759,650 swept pixels -- but it was NOT faster here: on the least noisy
350 // rows (the low-resolution dense scene, where the box's own load contributes least) blend went
351 // 25,712 -> 31,721 us at 512x384 and 79,066 -> 96,147 us at 1280x720, i.e. ~22-23% SLOWER.
352 // It won only where scanlines are long (sparse scene, high resolution). The mechanism is that
353 // trading six multiplies and one divide for two adds plus two compare-loops pays only when the
354 // walk amortises over a long run of pixels; a small splat re-pays the per-scanline setup on
355 // every row. A published speed-up on a GPU accelerator did not transfer to this CPU rasterizer,
356 // and the honest record of that is worth more than the rewrite would have been.
357 gv_puts("SHARP-GS forward differencing was implemented, measured on these rows and REVERTED:\n" as *u8)
358 gv_puts("byte-identical (10/10 checksums) but ~22-23 percent SLOWER on the low-noise dense rows.\n" as *u8)
359 gv_puts("The incumbent is restored and proven byte-identical by rebuild. See nx_fwddiff_equiv_gate.\n" as *u8)
360 return 0
361}