1use crate::bitio::{ByteReader, ByteWriter, DecodeError};
27use crate::codec::ErrorBound;
28use crate::gpuwav::{
29 code_res, dequant, feats, for_lines, gamma, init_of, lift_consts, prior_table, rate_control,
30 read_priors, row_ctx, to_f32_bits, write_priors, BandInfo, CountSink, DecSink, Enc, GpuStats,
31 RansDec, RecSink, Shape, Sink, MINIT, NDL, NMODEL, NOMODEL, NTAP,
32};
33use crate::lmodel3::{code_learned_ad, feat_vec3, AdCfg, Adapt, Mix3, Net32};
34
35pub const MAGIC3: &[u8; 4] = b"TCG3";
37
38#[derive(Clone, Debug)]
40pub struct Gpu3Config {
41 pub bound: ErrorBound,
43 pub block: usize,
45 pub block2d: usize,
47 pub tile: usize,
49 pub resctx: bool,
51 pub rho: f64,
53 pub lanes: usize,
57 pub model: Model3,
59 pub compact: bool,
65 pub axis: bool,
67 pub adapt: Option<AdCfg>,
70}
71
72#[derive(Clone, Debug, Default)]
74pub enum Model3 {
75 #[default]
77 Static,
78 Pretrained(std::sync::Arc<crate::learned::Net>),
81 Overfit {
83 hidden: Vec<usize>,
85 per_epoch: usize,
87 epochs: usize,
89 },
90}
91
92impl Gpu3Config {
93 pub fn new(bound: ErrorBound) -> Self {
95 Self {
96 bound,
97 block: 32,
98 block2d: 128,
99 tile: 64,
100 resctx: true,
101 rho: 0.45,
102 lanes: 1,
103 model: Model3::Static,
104 compact: true,
105 axis: true,
106 adapt: Some(ad_default()),
107 }
108 }
109}
110
111pub fn key3(level: usize, mask: u8) -> usize {
113 let l = if mask == 0 { 15 } else { level.min(14) };
114 (l * 8 + mask as usize) * 8
115}
116
117const TAPQ: u32 = 4;
119
120fn lane_cells(cfg: &Gpu3Config, cb: [usize; 3]) -> usize {
122 if cfg.compact && cfg.lanes > 1 {
123 (cb.iter().product::<usize>() / (8 * cfg.lanes))
126 .max(1)
127 .next_power_of_two()
128 } else {
129 0
130 }
131}
132
133pub fn blocks_of(
135 sh: &Shape,
136 cb: [usize; 3],
137 lanes: usize,
138 lane_cells: usize,
139 axis: bool,
140) -> (Vec<BandInfo>, Vec<usize>) {
141 let mut v = Vec::new();
142 let mut band = Vec::new();
143 for (bi, b) in sh.bands.iter().enumerate() {
144 let pb = &sh.p.bands[bi];
145 for z in (b.start[0]..b.end[0]).step_by(cb[0]) {
146 for y in (b.start[1]..b.end[1]).step_by(cb[1]) {
147 for x in (b.start[2]..b.end[2]).step_by(cb[2]) {
148 let mut k = b.clone();
149 k.start = [z, y, x];
150 k.end = [
151 (z + cb[0]).min(b.end[0]),
152 (y + cb[1]).min(b.end[1]),
153 (x + cb[2]).min(b.end[2]),
154 ];
155 k.org = b.start;
156 k.ax = axis;
157 let base = key3(pb.level, pb.mask);
158 if lanes <= 1 {
159 k.raster = true;
160 k.npass = 1;
161 k.pkey = [base; 8];
162 } else {
163 k.raster = false;
164 k.npass = crate::gpuwav::npass_of(k.start, k.end);
165 k.pkey = std::array::from_fn(|p| base + p);
166 k.nl = k
167 .end
168 .iter()
169 .zip(&k.start)
170 .map(|(e, s)| e - s)
171 .product::<usize>()
172 .checked_div(lane_cells)
173 .map_or(lanes, |v| v.clamp(1, lanes));
174 }
175 v.push(k);
176 band.push(bi);
177 }
178 }
179 }
180 }
181 (v, band)
182}
183
184#[allow(clippy::too_many_arguments)]
186fn code_block<S: Sink>(
187 sh: &Shape,
188 b: &BandInfo,
189 q: &mut [i32],
190 mut rs: Option<&mut [i32]>,
191 preds: &[[i32; NTAP]],
192 m: &mut [u32],
193 lanes: usize,
194 net: Option<&Net32>,
195 adc: AdCfg,
196 s: &mut S,
197 mut ir: Option<&mut IrCtx>,
198) {
199 let [_, ny, nx] = sh.dims;
200 let mut prog = net.filter(|_| cpu_ir()).map(|n| n.program());
202 let mut ad = vec![Adapt::new(adc); lanes.max(1)];
203 for_lines(b, lanes.max(1), |p, lane, z, y| {
204 let w = &preds[b.pkey[p]];
205 let rc = row_ctx(sh, b, p, z, y);
206 for x in b.start[2]..b.end[2] {
207 let (f, pred) = feats(sh, b, &rc, q, rs.as_deref(), z, y, x, w);
208 let i = (z * ny + y) * nx + x;
209 let r = match (net, ir.as_deref_mut()) {
210 (None, Some(c)) => c.res.res_static(
212 &mut c.lanes[lane],
213 c.mt,
214 c.sw,
215 f.sig as u32,
216 f.e as u32,
217 b.class as u32,
218 f.sctx as u32,
219 ),
220 (Some(n), Some(c)) => {
221 let x = feat_vec3(&f, b.class);
222 let o = match c.mlp.as_mut() {
223 Some(p) => n.infer_ir(p, &x),
224 None => n.infer(&x),
225 };
226 c.lres
227 .res_learned(&mut c.lanes[lane], c.mt, c.sw, &o, &mut c.adt[lane])
228 }
229 (None, None) => {
230 code_res::<S, false>(s, lane, m, b.class, &f, q[i].wrapping_sub(pred))
231 }
232 (Some(n), None) => {
233 let x = feat_vec3(&f, b.class);
234 let o = match prog.as_mut() {
235 Some(p) => n.infer_ir(p, &x),
236 None => n.infer(&x),
237 };
238 let mx = Mix3::new(&o);
239 code_learned_ad(s, lane, &mx, q[i].wrapping_sub(pred), &mut ad[lane])
240 }
241 };
242 q[i] = r.wrapping_add(pred);
243 if let Some(rs) = rs.as_deref_mut() {
244 rs[i] = r;
245 }
246 }
247 });
248}
249
250pub fn ad_default() -> AdCfg {
252 static V: std::sync::OnceLock<AdCfg> = std::sync::OnceLock::new();
253 *V.get_or_init(|| {
254 let v: Vec<u32> = std::env::var("TC_AD")
255 .unwrap_or("10,14,15".into())
256 .split(',')
257 .map(|x| x.parse().unwrap())
258 .collect();
259 AdCfg {
260 wa: v[0].min(16),
261 lim: v[1].min(255),
262 mask: v[2] & 15,
263 }
264 })
265}
266
267const AD_OFF: AdCfg = AdCfg {
268 wa: 0,
269 lim: 0,
270 mask: 0,
271};
272
273fn ad_pack(a: AdCfg) -> u64 {
274 (a.wa | a.lim << 5 | a.mask << 13) as u64
275}
276
277fn ad_unpack(v: u64) -> AdCfg {
278 AdCfg {
279 wa: (v & 31).min(16) as u32,
280 lim: (v >> 5 & 255) as u32,
281 mask: (v >> 13 & 15) as u32,
282 }
283}
284
285pub(crate) struct IrCtx<'a> {
287 res: crate::irdec::CpuRes,
288 lres: crate::irdec::CpuRes,
289 mlp: Option<tang_expr::int::Program>,
290 lanes: Vec<crate::irdec::Lane>,
291 adt: Vec<[u32; crate::lmodel3::AC * crate::lmodel3::AB]>,
293 mt: &'a [u32],
294 sw: &'a [u32],
295}
296
297struct IrBase {
299 dec: std::sync::Arc<crate::shipdec::Decoder>,
300 mt: Vec<u32>,
301 off: [u32; 2],
302 sw: Vec<u32>,
303}
304
305impl IrBase {
306 fn new(ps: &Parsed3, bytes: &[u8]) -> Option<Self> {
307 let dec = ps
308 .dec
309 .clone()
310 .or_else(|| cpu_irres().then(builtin_decoder))?;
311 let (mt, off) = crate::irdec::cpu_mt(&ps.init);
312 Some(Self {
313 dec,
314 mt,
315 off,
316 sw: crate::irdec::stream_words(bytes),
317 })
318 }
319}
320
321fn builtin_decoder() -> std::sync::Arc<crate::shipdec::Decoder> {
322 static D: std::sync::OnceLock<std::sync::Arc<crate::shipdec::Decoder>> =
323 std::sync::OnceLock::new();
324 D.get_or_init(|| {
325 std::sync::Arc::new(
326 crate::shipdec::compile(&crate::shipdec::builtin_program(None, false)).unwrap(),
327 )
328 })
329 .clone()
330}
331
332fn cpu_irres() -> bool {
333 static V: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
334 *V.get_or_init(|| std::env::var("TC_CPU_IRRES").is_ok())
335}
336
337fn cpu_ir() -> bool {
338 static V: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
339 *V.get_or_init(|| std::env::var("TC_CPU_IR").is_ok())
340}
341
342fn block_dims(d3: [usize; 3], cfg_block: usize, block2d: usize) -> [usize; 3] {
343 match d3.iter().filter(|&&d| d > 1).count() {
344 3 => [cfg_block; 3],
345 2 => [1, block2d, block2d],
346 _ => [1, 1, block2d * block2d],
347 }
348}
349
350fn tile_dims(d3: [usize; 3], t: usize) -> [usize; 3] {
351 match d3.iter().filter(|&&d| d > 1).count() {
352 3 => [t; 3],
353 2 => [1, 4 * t, 4 * t],
354 _ => [1, 1, 64 * t * t],
355 }
356}
357
358fn grid(d3: [usize; 3], bd: [usize; 3]) -> Vec<([usize; 3], [usize; 3])> {
359 let mut v = Vec::new();
360 for z in (0..d3[0]).step_by(bd[0]) {
361 for y in (0..d3[1]).step_by(bd[1]) {
362 for x in (0..d3[2]).step_by(bd[2]) {
363 let o = [z, y, x];
364 v.push((o, [0, 1, 2].map(|a| bd[a].min(d3[a] - o[a]))));
365 }
366 }
367 }
368 v
369}
370
371fn choose_priors3(n: &[[u32; 2]]) -> Vec<Option<u8>> {
374 let t = prior_table();
375 n.iter()
376 .map(|&[n0, n1]| {
377 if n0 + n1 == 0 {
378 return None;
379 }
380 let cost = |p: u32| {
381 let p = p as f64 / 65536.0;
382 -(n1 as f64) * p.log2() - (n0 as f64) * (1.0 - p).log2()
383 };
384 let k =
385 (0..64u8).min_by(|&a, &b| cost(t[a as usize]).total_cmp(&cost(t[b as usize])))?;
386 if cost(32768) - cost(t[k as usize]) > 12.0 {
387 Some(k)
388 } else {
389 None
390 }
391 })
392 .collect()
393}
394
395fn fit3(sh: &Shape, blocks: &[BandInfo], q: &[i32], tq: u32) -> Vec<Option<[i32; NTAP]>> {
397 let nkey = crate::gpuwav::NKEY;
398 let mut g = vec![[[0.0f64; NTAP]; NTAP]; nkey];
399 let mut h = vec![[0.0f64; NTAP]; nkey];
400 let mut n = vec![0usize; nkey];
401 let mut obs: Vec<Vec<([i32; NTAP], i32)>> = vec![Vec::new(); nkey];
402 let zero = [0i32; NTAP];
403 let [_, ny, nx] = sh.dims;
404 for b in blocks {
405 for_lines(b, 1, |p, _, z, y| {
406 let k = b.pkey[p];
407 let rc = row_ctx(sh, b, p, z, y);
408 for x in b.start[2]..b.end[2] {
409 let (f, _) = feats(sh, b, &rc, q, None, z, y, x, &zero);
410 let v = q[(z * ny + y) * nx + x];
411 if v == 0 && f.taps.iter().all(|&t| t == 0) {
412 continue;
413 }
414 n[k] += 1;
415 for i in 0..NTAP {
416 h[k][i] += f.taps[i] as f64 * v as f64;
417 for j in 0..NTAP {
418 g[k][i][j] += f.taps[i] as f64 * f.taps[j] as f64;
419 }
420 }
421 if obs[k].len() < 200_000 {
422 obs[k].push((f.taps, v));
423 }
424 }
425 });
426 }
427 (0..nkey)
428 .map(|k| {
429 if n[k] < 64 {
430 return None;
431 }
432 let mut a = g[k];
433 let mut r = h[k];
434 for i in 0..NTAP {
435 a[i][i] += 1e-3 * (g[k][i][i] + 1.0);
436 }
437 for c in 0..NTAP {
438 let piv = a[c][c];
439 if piv.abs() < 1e-12 {
440 continue;
441 }
442 for rr in 0..NTAP {
443 if rr != c {
444 let f = a[rr][c] / piv;
445 for kk in 0..NTAP {
446 a[rr][kk] -= f * a[c][kk];
447 }
448 r[rr] -= f * r[c];
449 }
450 }
451 }
452 let mut w = [0i32; NTAP];
453 for i in 0..NTAP {
454 let wi = if a[i][i].abs() > 1e-12 {
455 r[i] / a[i][i]
456 } else {
457 0.0
458 };
459 w[i] = ((wi * 4096.0 / (1 << tq) as f64)
460 .round()
461 .clamp(-(32767 >> tq) as f64, (32767 >> tq) as f64)
462 as i32)
463 << tq;
464 }
465 let (mut c0, mut c1) = (0.0f64, 0.0f64);
466 for &(t, v) in &obs[k] {
467 let mut acc = 0i32;
468 for i in 0..NTAP {
469 acc = acc.wrapping_add(w[i].wrapping_mul(t[i]));
470 }
471 let pr = acc.wrapping_add(2048) >> 12;
472 c0 += (1.0 + v.unsigned_abs() as f64).log2();
473 c1 += (1.0 + v.wrapping_sub(pr).unsigned_abs() as f64).log2();
474 }
475 if c1 < 0.98 * c0 && c0 - c1 > 64.0 {
476 Some(w)
477 } else {
478 None
479 }
480 })
481 .collect()
482}
483
484fn used_keys3(blocks: &[BandInfo]) -> Vec<usize> {
485 let mut k: Vec<usize> = blocks
486 .iter()
487 .flat_map(|b| b.pkey[..b.npass].to_vec())
488 .collect();
489 k.sort_unstable();
490 k.dedup();
491 k
492}
493
494fn words_le(v: &[u16], w: &mut ByteWriter) {
495 for &x in v {
496 w.bytes(&x.to_le_bytes());
497 }
498}
499
500fn collect3(
503 sh: &Shape,
504 blocks: &[BandInfo],
505 q: &mut [i32],
506 resctx: bool,
507 preds: &[[i32; NTAP]],
508 lanes: usize,
509 max: usize,
510) -> Vec<crate::learned::Sample> {
511 let n: usize = q.len();
512 let stride = n.div_ceil(max.max(1)).max(1);
513 let mut rs = vec![0i32; n];
514 let mut out = Vec::new();
515 let [_, ny, nx] = sh.dims;
516 let mut k = 0usize;
517 for b in blocks {
518 for_lines(b, lanes.max(1), |p, _, z, y| {
519 let rc = row_ctx(sh, b, p, z, y);
520 for x in b.start[2]..b.end[2] {
521 let (f, pred) = feats(
522 sh,
523 b,
524 &rc,
525 q,
526 resctx.then_some(&rs[..]),
527 z,
528 y,
529 x,
530 &preds[b.pkey[p]],
531 );
532 let i = (z * ny + y) * nx + x;
533 let r = q[i].wrapping_sub(pred);
534 rs[i] = r;
535 if k.is_multiple_of(stride) {
536 out.push(crate::learned::Sample {
537 x: feat_vec3(&f, b.class),
538 r,
539 });
540 }
541 k += 1;
542 }
543 });
544 }
545 out
546}
547
548pub fn samples3(
551 x: &[f32],
552 dims: &[usize],
553 cfg: &Gpu3Config,
554 threads: usize,
555 max: usize,
556) -> Vec<crate::learned::Sample> {
557 let big = dims.iter().copied().max().unwrap_or(1).max(2) * 2;
558 let got = std::sync::Mutex::new(Vec::new());
559 rate_control(x, dims, big, cfg.bound, cfg.rho, threads, |enc, dg, _| {
560 let shapes = enc.shapes_at(dg);
561 let sh = &shapes[0];
562 let (qs, _) = enc.quantize(dg, cfg.rho);
563 let cb = block_dims(sh.dims, cfg.block, cfg.block2d);
564 let lc = lane_cells(cfg, cb);
565 let (blocks, _) = blocks_of(sh, cb, cfg.lanes, lc, cfg.axis);
566 let fitted = fit3(sh, &blocks, &qs[0], if lc > 0 { TAPQ } else { 0 });
567 let preds: Vec<[i32; NTAP]> = fitted.iter().map(|p| p.unwrap_or([0; NTAP])).collect();
568 let mut q = qs[0].clone();
569 *got.lock().unwrap() = collect3(sh, &blocks, &mut q, cfg.resctx, &preds, cfg.lanes, max);
570 (Vec::new(), GpuStats::default())
571 });
572 got.into_inner().unwrap()
573}
574
575pub fn encode3_f32(
577 x: &[f32],
578 dims: &[usize],
579 cfg: &Gpu3Config,
580 threads: usize,
581) -> (Vec<u8>, GpuStats) {
582 let big = dims.iter().copied().max().unwrap_or(1).max(2) * 2;
584 rate_control(x, dims, big, cfg.bound, cfg.rho, threads, |enc, dg, mx| {
585 encode_at3(enc, dims, cfg, dg, mx)
586 })
587}
588
589fn encode_at3(
590 enc: &Enc,
591 dims: &[usize],
592 cfg: &Gpu3Config,
593 dg: f64,
594 maxabs: Option<f64>,
595) -> (Vec<u8>, GpuStats) {
596 let shapes = enc.shapes_at(dg);
597 assert_eq!(shapes.len(), 1);
598 let sh = &shapes[0];
599 let d3 = sh.dims;
600 let (qs, dl) = enc.quantize(dg, cfg.rho);
601 let cb = block_dims(d3, cfg.block, cfg.block2d);
602 let lc = lane_cells(cfg, cb);
603 let (blocks, _) = blocks_of(sh, cb, cfg.lanes, lc, cfg.axis);
604 let fitted = if std::env::var("TC_NOPRED").is_ok() {
605 vec![None; crate::gpuwav::NKEY]
606 } else {
607 fit3(sh, &blocks, &qs[0], if lc > 0 { TAPQ } else { 0 })
608 };
609 let preds: Vec<[i32; NTAP]> = fitted.iter().map(|p| p.unwrap_or([0; NTAP])).collect();
610 let mut cs = enc.reconstruct(&shapes, &qs, &dl);
611 let scale = enc.scale();
612 let g = 2f64.powi(enc.e);
613 let corr = maxabs
614 .map(|b| ((2.0 * b / g).floor() as i64).clamp(0, 1 << 30) as i32)
615 .unwrap_or(0);
616 let td = tile_dims(d3, cfg.tile);
617 let tiles = grid(d3, td);
618 let n = enc.x.len();
619 let mut outl: Vec<Vec<(usize, i32)>> = vec![Vec::new(); tiles.len()];
621 let mut escs: Vec<Vec<(usize, u32)>> = vec![Vec::new(); tiles.len()];
622 if let Some(b) = maxabs {
623 let c = &mut cs[0];
624 for (ti, (o, td)) in tiles.iter().enumerate() {
625 for z in 0..td[0] {
626 for y in 0..td[1] {
627 for xx in 0..td[2] {
628 let li = (z * td[1] + y) * td[2] + xx;
629 let gi = ((o[0] + z) * d3[1] + o[1] + y) * d3[2] + o[2] + xx;
630 let xv = enc.x[gi];
631 let yv =
632 f32::from_bits(to_f32_bits(c[gi].wrapping_add(enc.mean_fix), scale))
633 as f64;
634 let r = xv as f64 - yv;
635 if r.abs() > b && corr > 0 {
636 let k = (r / g / corr as f64)
637 .round()
638 .clamp(-(1 << 20) as f64, (1 << 20) as f64)
639 as i32;
640 if k != 0 {
641 c[gi] = c[gi].wrapping_add(k.wrapping_mul(corr));
642 outl[ti].push((li, k));
643 }
644 }
645 let yv =
646 f32::from_bits(to_f32_bits(c[gi].wrapping_add(enc.mean_fix), scale))
647 as f64;
648 if (xv as f64 - yv).abs() > b {
649 escs[ti].push((li, xv.to_bits()));
650 }
651 }
652 }
653 }
654 }
655 }
656 let mut q = qs[0].clone();
659 let mut rs = vec![0i32; n];
660 let mut cnt = CountSink {
661 n: vec![[0; 2]; NMODEL],
662 };
663 let mut m0 = vec![MINIT; NMODEL];
664 for b in &blocks {
665 code_block(
666 sh,
667 b,
668 &mut q,
669 cfg.resctx.then_some(&mut rs[..]),
670 &preds,
671 &mut m0,
672 cfg.lanes,
673 None,
674 AD_OFF,
675 &mut cnt,
676 None,
677 );
678 }
679 let mut q2 = qs[0].clone();
681 let (net, net_bytes): (Option<Net32>, Vec<u8>) = match &cfg.model {
682 Model3::Static => (None, vec![0]),
683 Model3::Pretrained(n) => {
684 let mut v = vec![1];
685 v.extend(n.fingerprint().to_le_bytes());
686 (Some(Net32::new(n)), v)
687 }
688 Model3::Overfit {
689 hidden,
690 per_epoch,
691 epochs,
692 } => {
693 let smp = collect3(
694 sh, &blocks, &mut q2, cfg.resctx, &preds, cfg.lanes, 2_000_000,
695 );
696 let tc = crate::learned::TrainConfig {
697 hidden: hidden.clone(),
698 epochs: *epochs,
699 per_epoch: *per_epoch,
700 batch: 256,
701 lr: 4e-3,
702 apm: false,
703 seed: 1,
704 };
705 let n = crate::learned::train(&smp, &tc);
706 let mut v = vec![2];
707 let nb = n.to_bytes();
708 v.extend((nb.len() as u32).to_le_bytes());
709 v.extend(nb);
710 (Some(Net32::new(&n)), v)
711 }
712 };
713 let adc = if net.is_some() {
714 cfg.adapt.unwrap_or(AD_OFF)
715 } else {
716 AD_OFF
717 };
718 let priors = if net.is_some() {
719 vec![None; NMODEL]
720 } else {
721 choose_priors3(&cnt.n)
722 };
723 let mut init = init_of(&priors);
724 let mut bw: Vec<Vec<u8>> = Vec::with_capacity(blocks.len());
725 let dbg = std::env::var("TC_STATS").is_ok();
726 let (mut ideal, mut nlanes, mut wbytes) = (0f64, 0usize, 0usize);
727 for b in &blocks {
728 let nl = cfg.lanes.max(1);
729 let mut sink = RecSink {
730 syms: vec![Vec::new(); nl],
731 };
732 code_block(
733 sh,
734 b,
735 &mut q,
736 cfg.resctx.then_some(&mut rs[..]),
737 &preds,
738 &mut init,
739 nl,
740 net.as_ref(),
741 adc,
742 &mut sink,
743 None,
744 );
745 let lw: Vec<Vec<u16>> = sink
746 .syms
747 .iter()
748 .map(|s| crate::gpuwav::rans_encode(s))
749 .collect();
750 if dbg {
751 ideal += sink
752 .syms
753 .iter()
754 .flatten()
755 .map(|&(_, f)| 16.0 - (f as f64).log2())
756 .sum::<f64>();
757 nlanes += lw.iter().filter(|l| !l.is_empty()).count();
758 wbytes += 2 * lw.iter().map(|l| l.len()).sum::<usize>();
759 }
760 let mut w = ByteWriter::new();
761 if nl > 1 {
762 let used = if lc > 0 { b.nl } else { nl };
763 debug_assert!(lw[used..].iter().all(|l| l.is_empty()));
764 let nv = if lc > 0 { used - 1 } else { used };
765 let mut prev = 0i64;
766 for l in &lw[..nv] {
767 if lc > 0 {
768 w.svarint(l.len() as i64 - prev);
771 prev = l.len() as i64;
772 } else {
773 w.varint(l.len() as u64);
774 }
775 }
776 if w.buf.len() % 2 == 1 {
777 w.u8(0);
778 }
779 }
780 for l in &lw {
781 words_le(l, &mut w);
782 }
783 bw.push(w.buf);
784 }
785 let mut tp: Vec<Vec<u8>> = Vec::with_capacity(tiles.len());
787 for ti in 0..tiles.len() {
788 let mut sink = RecSink {
789 syms: vec![Vec::new()],
790 };
791 if maxabs.is_some() {
792 let mut om = vec![MINIT; NOMODEL];
793 gamma::<_, true>(&mut sink, 0, &mut om, 0, outl[ti].len() as u32);
794 let mut last: i64 = -1;
795 for &(i, k) in &outl[ti] {
796 gamma::<_, true>(&mut sink, 0, &mut om, 32, (i as i64 - last - 1) as u32);
797 last = i as i64;
798 sink.raw(0, (k < 0) as u32, 1);
799 gamma::<_, true>(&mut sink, 0, &mut om, 64, k.unsigned_abs() - 1);
800 }
801 }
802 let words = crate::gpuwav::rans_encode(&sink.syms[0]);
803 let mut w = ByteWriter::new();
804 w.varint(words.len() as u64);
805 w.varint(escs[ti].len() as u64);
806 let mut last = 0usize;
807 for (j, &(i, bits)) in escs[ti].iter().enumerate() {
808 w.varint(if j == 0 { i } else { i - last } as u64);
809 last = i;
810 w.bytes(&bits.to_le_bytes());
811 }
812 if w.buf.len() % 2 == 1 {
813 w.u8(0);
814 }
815 words_le(&words, &mut w);
816 tp.push(w.buf);
817 }
818 let mut w = ByteWriter::new();
820 w.bytes(MAGIC3);
821 w.varint(dims.len() as u64);
822 for &d in dims {
823 w.varint(d as u64);
824 }
825 for a in 0..3 {
826 w.varint(cb[a] as u64);
827 }
828 for a in 0..3 {
829 w.varint(td[a] as u64);
830 }
831 w.u8(cfg.resctx as u8);
832 let has_ad = adc.wa > 0;
833 if lc > 0 || cfg.axis || has_ad {
834 w.varint(
835 (cfg.lanes.max(1) | 1 << 9 | (cfg.axis as usize) << 10 | (has_ad as usize) << 11)
836 as u64,
837 );
838 w.u8(if lc > 0 {
839 lc.trailing_zeros() as u8 + 1
840 } else {
841 0
842 });
843 if has_ad {
844 w.varint(ad_pack(adc));
845 }
846 } else {
847 w.varint(cfg.lanes.max(1) as u64);
848 }
849 w.bytes(&net_bytes);
850 w.svarint(enc.e as i64);
851 w.svarint(enc.mean_fix as i64);
852 w.f64(dg);
853 w.bytes(&dl);
854 w.varint(corr as u64);
855 let uk = used_keys3(&blocks);
856 let pred_at = w.buf.len();
857 if lc > 0 {
858 for c in uk.chunks(8) {
860 w.u8(c
861 .iter()
862 .enumerate()
863 .map(|(i, &k)| (fitted[k].is_some() as u8) << i)
864 .sum());
865 }
866 for &k in &uk {
867 for &t in fitted[k].iter().flatten() {
868 w.svarint((t >> TAPQ) as i64);
869 }
870 }
871 } else {
872 for &k in &uk {
873 match fitted[k] {
874 Some(p) => {
875 w.u8(1);
876 for &t in &p {
877 w.svarint(t as i64);
878 }
879 }
880 None => w.u8(0),
881 }
882 }
883 }
884 let pred_bytes = w.buf.len() - pred_at;
885 write_priors(&mut w, &priors);
886 let hdr_fixed = w.buf.len();
887 for b in &bw {
888 w.varint(b.len() as u64);
889 }
890 for t in &tp {
891 w.varint(t.len() as u64);
892 }
893 if w.buf.len() % 2 == 1 {
894 w.u8(0);
895 }
896 let header_bytes = w.buf.len();
897 if dbg {
898 let bb: usize = bw.iter().map(|b| b.len()).sum();
899 eprintln!(
900 "STATS hdr_fixed {hdr_fixed} index {} blocks {} block_bytes {bb} ideal_bytes {:.0} pred_bytes {pred_bytes} nkeys {} nfit {} nonempty_lanes {nlanes} word_bytes {wbytes} tiles_bytes {}",
901 header_bytes - hdr_fixed,
902 blocks.len(),
903 ideal / 8.0,
904 uk.len(),
905 uk.iter().filter(|&&k| fitted[k].is_some()).count(),
906 tp.iter().map(|t| t.len()).sum::<usize>()
907 );
908 }
909 for b in &bw {
910 w.bytes(b);
911 }
912 for t in &tp {
913 w.bytes(t);
914 }
915 let c = &cs[0];
917 let mut se = 0.0;
918 let mut mx = 0.0f64;
919 let mut esc_at: Vec<(usize, u32)> = Vec::new();
920 for (ti, (o, td)) in tiles.iter().enumerate() {
921 for &(li, bits) in &escs[ti] {
922 let (z, y, xx) = (li / (td[1] * td[2]), (li / td[2]) % td[1], li % td[2]);
923 esc_at.push((((o[0] + z) * d3[1] + o[1] + y) * d3[2] + o[2] + xx, bits));
924 }
925 }
926 esc_at.sort_unstable();
927 let mut ei = esc_at.iter().peekable();
928 for gi in 0..n {
929 let mut yv = f32::from_bits(to_f32_bits(c[gi].wrapping_add(enc.mean_fix), scale));
930 if ei.peek().is_some_and(|e| e.0 == gi) {
931 yv = f32::from_bits(ei.next().unwrap().1);
932 }
933 let e = enc.x[gi] as f64 - yv as f64;
934 se += e * e;
935 mx = mx.max(e.abs());
936 }
937 let st = GpuStats {
938 bytes: w.buf.len(),
939 bits_per_value: 8.0 * w.buf.len() as f64 / n as f64,
940 header_bytes,
941 index_bytes: header_bytes - hdr_fixed,
942 outlier_bytes: tp.iter().map(|t| t.len()).sum(),
943 n_outliers: outl.iter().map(|v| v.len()).sum(),
944 n_escapes: esc_at.len(),
945 rmse: (se / n as f64).sqrt(),
946 max_abs: mx,
947 delta: dg * g,
948 };
949 (w.buf, st)
950}
951
952#[derive(Clone, Debug)]
956pub struct TileRef {
957 pub origin: [usize; 3],
959 pub dims: [usize; 3],
961 pub words: (usize, usize),
963 pub bytes: (usize, usize),
965 pub esc: Vec<(usize, u32)>,
967}
968
969#[derive(Clone, Debug)]
971pub struct Parsed3 {
972 pub dims: Vec<usize>,
974 pub d3: [usize; 3],
976 pub cb: [usize; 3],
978 pub resctx: bool,
980 pub e: i32,
982 pub mean_fix: i32,
984 pub dl: [u8; NDL],
986 pub corr: i32,
988 pub preds: Vec<[i32; NTAP]>,
990 pub init: Vec<u32>,
992 pub sh: Shape,
994 pub blocks: Vec<BandInfo>,
996 pub block_band: Vec<usize>,
998 pub block_words: Vec<(usize, usize)>,
1000 pub lanes: usize,
1002 pub block_lanes: Vec<Vec<(usize, usize)>>,
1004 pub tiles: Vec<TileRef>,
1006 pub net: Option<Net32>,
1008 pub ad: AdCfg,
1010 pub header_bytes: usize,
1012 pub dec: Option<std::sync::Arc<crate::shipdec::Decoder>>,
1014}
1015
1016impl Parsed3 {
1017 pub fn scale(&self) -> f32 {
1019 f32::from_bits(((self.e + 127) as u32) << 23)
1020 }
1021 pub fn level_groups(&self) -> Vec<(usize, usize)> {
1023 let mut v: Vec<(usize, usize)> = Vec::new();
1024 let mut cur = usize::MAX;
1025 for (i, &bi) in self.block_band.iter().enumerate() {
1026 let l = self.sh.p.bands[bi].level;
1027 if l != cur {
1028 v.push((i, i + 1));
1029 cur = l;
1030 } else {
1031 v.last_mut().unwrap().1 = i + 1;
1032 }
1033 }
1034 v
1035 }
1036}
1037
1038pub fn parse3(bytes: &[u8]) -> Result<Parsed3, DecodeError> {
1041 let (dec, inner) = crate::shipdec::open(bytes)?;
1042 let Some(dec) = dec else {
1043 return parse3_inner(bytes, false);
1044 };
1045 let base = bytes.len() - inner.len();
1046 let mut ps = parse3_inner(inner, dec.mlp.is_some())?;
1047 for w in ps.block_words.iter_mut() {
1048 *w = (w.0 + base, w.1 + base);
1049 }
1050 for lv in ps.block_lanes.iter_mut() {
1051 for w in lv.iter_mut() {
1052 *w = (w.0 + base / 2, w.1 + base / 2);
1053 }
1054 }
1055 for t in ps.tiles.iter_mut() {
1056 t.words = (t.words.0 + base / 2, t.words.1 + base / 2);
1057 t.bytes = (t.bytes.0 + base, t.bytes.1 + base);
1058 }
1059 ps.header_bytes += base;
1060 ps.dec = Some(dec);
1061 Ok(ps)
1062}
1063
1064fn parse3_inner(bytes: &[u8], ext_net: bool) -> Result<Parsed3, DecodeError> {
1067 let mut r = ByteReader::new(bytes);
1068 if r.take(4)? != MAGIC3 {
1069 return Err(DecodeError::Invalid("not a tc-gpu v3 stream"));
1070 }
1071 let nd = r.varint()? as usize;
1072 if nd == 0 || nd > 3 {
1073 return Err(DecodeError::Invalid("rank"));
1074 }
1075 let dims: Vec<usize> = (0..nd)
1076 .map(|_| r.varint().map(|v| v as usize))
1077 .collect::<Result<_, _>>()?;
1078 let d3 = crate::wavelet::as3(&dims);
1079 let mut cb = [0usize; 3];
1080 let mut td = [0usize; 3];
1081 for v in cb.iter_mut().chain(td.iter_mut()) {
1082 *v = r.varint()? as usize;
1083 if *v == 0 {
1084 return Err(DecodeError::Invalid("block"));
1085 }
1086 }
1087 let resctx = r.u8()? != 0;
1088 let lv = r.varint()? as usize;
1089 let (lanes, lane_cells, axis, ad) = if lv & 1 << 9 != 0 {
1090 let t = r.u8()?;
1091 let ad = if lv & 1 << 11 != 0 {
1092 ad_unpack(r.varint()?)
1093 } else {
1094 AD_OFF
1095 };
1096 (
1097 lv & 511,
1098 if t > 0 { 1usize << (t - 1).min(30) } else { 0 },
1099 lv & 1 << 10 != 0,
1100 ad,
1101 )
1102 } else {
1103 (lv, 0, false, AD_OFF)
1104 };
1105 if lanes == 0 || lanes > 256 {
1106 return Err(DecodeError::Invalid("lanes"));
1107 }
1108 let net = match r.u8()? {
1109 0 => None,
1110 1 => {
1111 let b = r.take(8)?;
1112 let fp = u64::from_le_bytes(b.try_into().unwrap());
1113 match crate::learned::lookup(fp) {
1114 Some(n) => Some(Net32::new(&n)),
1115 None if ext_net => Some(crate::shipdec::placeholder_net()),
1116 None => return Err(DecodeError::Invalid("pretrained model not registered")),
1117 }
1118 }
1119 2 => {
1120 let b = r.take(4)?;
1121 let n = u32::from_le_bytes(b.try_into().unwrap()) as usize;
1122 Some(Net32::new(&crate::learned::Net::from_bytes(r.take(n)?)?))
1123 }
1124 _ => return Err(DecodeError::Invalid("model tag")),
1125 };
1126 let e = r.svarint()? as i32;
1127 let mean_fix = r.svarint()? as i32;
1128 let delta_g = r.f64()?;
1129 let mut dl = [0u8; NDL];
1130 dl.copy_from_slice(r.take(NDL)?);
1131 let corr = r.varint()? as i32;
1132 let mut sh = Shape::new(d3);
1133 sh.set_steps(delta_g);
1134 let (blocks, block_band) = blocks_of(&sh, cb, lanes, lane_cells, axis);
1135 let mut preds = vec![[0i32; NTAP]; crate::gpuwav::NKEY];
1136 let uk = used_keys3(&blocks);
1137 let has: Vec<bool> = if lane_cells > 0 {
1138 let bits: Vec<u8> = (0..uk.len().div_ceil(8))
1139 .map(|_| r.u8())
1140 .collect::<Result<_, _>>()?;
1141 (0..uk.len())
1142 .map(|i| bits[i / 8] >> (i % 8) & 1 != 0)
1143 .collect()
1144 } else {
1145 Vec::new()
1146 };
1147 for (i, &k) in uk.iter().enumerate() {
1148 if if lane_cells > 0 { has[i] } else { r.u8()? != 0 } {
1149 for t in preds[k].iter_mut() {
1150 let v = r.svarint()?;
1151 *t = if lane_cells > 0 {
1152 (v.clamp(-32767 >> TAPQ, 32767 >> TAPQ) as i32) << TAPQ
1153 } else {
1154 v as i32
1155 };
1156 }
1157 }
1158 }
1159 let init = read_priors(&mut r)?;
1160 let tg = grid(d3, td);
1161 let bsz: Vec<usize> = (0..blocks.len())
1162 .map(|_| r.varint().map(|v| v as usize))
1163 .collect::<Result<_, _>>()?;
1164 let tsz: Vec<usize> = (0..tg.len())
1165 .map(|_| r.varint().map(|v| v as usize))
1166 .collect::<Result<_, _>>()?;
1167 let header_bytes = r.position().next_multiple_of(2);
1168 let mut off = header_bytes;
1169 let mut block_words = Vec::with_capacity(blocks.len());
1170 let mut block_lanes = Vec::with_capacity(blocks.len());
1171 for (bi, &n) in bsz.iter().enumerate() {
1172 let end = off + n;
1173 if end > bytes.len() || n % 2 == 1 {
1174 return Err(DecodeError::Truncated);
1175 }
1176 let mut lv = Vec::with_capacity(lanes);
1177 if lanes == 1 {
1178 lv.push((off / 2, end / 2));
1179 } else {
1180 let mut br = ByteReader::new(&bytes[off..end]);
1181 let used = if lane_cells > 0 { blocks[bi].nl } else { lanes };
1182 let nv = if lane_cells > 0 { used - 1 } else { used };
1183 let mut nw = Vec::with_capacity(nv);
1184 let mut prev = 0i64;
1185 for _ in 0..nv {
1186 let k = if lane_cells > 0 {
1187 prev + br.svarint()?
1188 } else {
1189 br.varint()? as i64
1190 };
1191 if k < 0 {
1192 return Err(DecodeError::Invalid("lane length"));
1193 }
1194 nw.push(k as usize);
1195 prev = k;
1196 }
1197 let mut w = (off + br.position().next_multiple_of(2)) / 2;
1198 for &k in &nw {
1199 lv.push((w, w + k));
1200 w += k;
1201 }
1202 if w * 2 > end {
1203 return Err(DecodeError::Truncated);
1204 }
1205 if nv < used {
1206 lv.push((w, end / 2));
1207 w = end / 2;
1208 }
1209 while lv.len() < lanes {
1210 lv.push((w, w));
1211 }
1212 }
1213 block_words.push((off, end));
1214 block_lanes.push(lv);
1215 off = end;
1216 }
1217 let mut tiles = Vec::with_capacity(tg.len());
1218 for (ti, (o, d)) in tg.iter().enumerate() {
1219 let end = off + tsz[ti];
1220 if end > bytes.len() {
1221 return Err(DecodeError::Truncated);
1222 }
1223 let mut br = ByteReader::new(&bytes[off..end]);
1224 let nw = br.varint()? as usize;
1225 let ne = br.varint()? as usize;
1226 let mut esc = Vec::with_capacity(ne);
1227 let mut last = 0;
1228 for i in 0..ne {
1229 let g = br.varint()? as usize;
1230 let idx = if i == 0 { g } else { last + g };
1231 last = idx;
1232 let b = br.take(4)?;
1233 esc.push((idx, u32::from_le_bytes([b[0], b[1], b[2], b[3]])));
1234 }
1235 let ws = (off + br.position().next_multiple_of(2)) / 2;
1236 if (ws + nw) * 2 > end {
1237 return Err(DecodeError::Truncated);
1238 }
1239 tiles.push(TileRef {
1240 origin: *o,
1241 dims: *d,
1242 words: (ws, ws + nw),
1243 bytes: (off, end),
1244 esc,
1245 });
1246 off = end;
1247 }
1248 Ok(Parsed3 {
1249 dims,
1250 d3,
1251 cb,
1252 resctx,
1253 e,
1254 mean_fix,
1255 dl,
1256 corr,
1257 preds,
1258 init,
1259 sh,
1260 blocks,
1261 block_band,
1262 block_words,
1263 lanes,
1264 block_lanes,
1265 tiles,
1266 header_bytes,
1267 net,
1268 ad,
1269 dec: None,
1270 })
1271}
1272
1273fn words(bytes: &[u8], a: usize, b: usize) -> Vec<u16> {
1276 (a..b)
1277 .map(|i| u16::from_le_bytes([bytes[2 * i], bytes[2 * i + 1]]))
1278 .collect()
1279}
1280
1281#[derive(Clone, Copy)]
1282struct Ptr(*mut i32);
1283unsafe impl Send for Ptr {}
1284unsafe impl Sync for Ptr {}
1285
1286impl Ptr {
1287 fn get(&self) -> *mut i32 {
1288 self.0
1289 }
1290}
1291
1292fn decode_block(
1293 ps: &Parsed3,
1294 bytes: &[u8],
1295 bi: usize,
1296 q: Ptr,
1297 rs: Ptr,
1298 n: usize,
1299 irb: Option<&IrBase>,
1300) -> Result<(), DecodeError> {
1301 if let Some(ib) = irb {
1302 let d = &ib.dec;
1303 let mut c = IrCtx {
1304 res: crate::irdec::CpuRes::new(&d.stat.0, &d.stat.1, false, [0, 0]),
1305 lres: if ps.ad.wa > 0 && ps.net.is_some() {
1306 crate::irdec::CpuRes::new_ad(&d.learned_ad.0, &d.learned_ad.1, ib.off, ps.ad)
1307 } else {
1308 crate::irdec::CpuRes::new(&d.learned.0, &d.learned.1, true, ib.off)
1309 },
1310 mlp: d.mlp_program(),
1311 lanes: ps.block_lanes[bi]
1312 .iter()
1313 .map(|&(a, b)| crate::irdec::Lane::new(&ib.sw, a as u32, b as u32))
1314 .collect(),
1315 adt: vec![crate::lmodel3::ad_init(); ps.lanes.max(1)],
1316 mt: &ib.mt,
1317 sw: &ib.sw,
1318 };
1319 let q = unsafe { std::slice::from_raw_parts_mut(q.get(), n) };
1320 let rs = unsafe { std::slice::from_raw_parts_mut(rs.get(), n) };
1321 let mut m = ps.init.clone();
1322 let mut sink = DecSink { lanes: Vec::new() };
1323 code_block(
1324 &ps.sh,
1325 &ps.blocks[bi],
1326 q,
1327 ps.resctx.then_some(rs),
1328 &ps.preds,
1329 &mut m,
1330 ps.lanes,
1331 ps.net.as_ref(),
1332 ps.ad,
1333 &mut sink,
1334 Some(&mut c),
1335 );
1336 if c.lanes.iter().any(|l| l.overrun()) {
1337 return Err(DecodeError::Truncated);
1338 }
1339 return Ok(());
1340 }
1341 let lw: Vec<Vec<u16>> = ps.block_lanes[bi]
1342 .iter()
1343 .map(|&(a, b)| words(bytes, a, b))
1344 .collect();
1345 let mut sink = DecSink {
1346 lanes: lw.iter().map(|w| RansDec::new(w)).collect(),
1347 };
1348 let mut m = ps.init.clone();
1349 let q = unsafe { std::slice::from_raw_parts_mut(q.get(), n) };
1352 let rs = unsafe { std::slice::from_raw_parts_mut(rs.get(), n) };
1353 code_block(
1354 &ps.sh,
1355 &ps.blocks[bi],
1356 q,
1357 ps.resctx.then_some(rs),
1358 &ps.preds,
1359 &mut m,
1360 ps.lanes,
1361 ps.net.as_ref(),
1362 ps.ad,
1363 &mut sink,
1364 None,
1365 );
1366 if sink.lanes.iter().any(|l| l.overrun()) {
1367 return Err(DecodeError::Truncated);
1368 }
1369 Ok(())
1370}
1371
1372fn run_par(
1373 items: &[usize],
1374 threads: usize,
1375 f: impl Fn(usize) -> Result<(), DecodeError> + Sync,
1376) -> Result<(), DecodeError> {
1377 use std::sync::atomic::{AtomicUsize, Ordering};
1378 use std::sync::Mutex;
1379 if threads <= 1 || items.len() <= 1 {
1380 for &i in items {
1381 f(i)?;
1382 }
1383 return Ok(());
1384 }
1385 let next = AtomicUsize::new(0);
1386 let err = Mutex::new(None);
1387 std::thread::scope(|s| {
1388 for _ in 0..threads.min(items.len()) {
1389 s.spawn(|| loop {
1390 let t = next.fetch_add(1, Ordering::Relaxed);
1391 if t >= items.len() {
1392 break;
1393 }
1394 if let Err(e) = f(items[t]) {
1395 *err.lock().unwrap() = Some(e);
1396 }
1397 });
1398 }
1399 });
1400 match err.into_inner().unwrap() {
1401 Some(e) => Err(e),
1402 None => Ok(()),
1403 }
1404}
1405
1406type Need = [Vec<(usize, usize)>; 3];
1408
1409fn inside(v: &[(usize, usize)], i: usize) -> bool {
1410 v.iter().any(|&(a, b)| i >= a && i < b)
1411}
1412
1413fn hits(v: &[(usize, usize)], a: usize, b: usize) -> bool {
1414 v.iter().any(|&(c, d)| c < b && a < d)
1415}
1416
1417fn needs(sh: &Shape, lo: [usize; 3], hi: [usize; 3]) -> (Vec<Need>, Vec<Need>) {
1420 let p = &sh.p;
1421 let mut samp: Vec<Need> = vec![[
1422 vec![(lo[0], hi[0])],
1423 vec![(lo[1], hi[1])],
1424 vec![(lo[2], hi[2])],
1425 ]];
1426 let mut coef: Vec<Need> = Vec::new();
1427 for l in 0..p.nlev() {
1428 let cur = samp[l].clone();
1429 let mut c: Need = [vec![], vec![], vec![]];
1430 let mut next: Need = [vec![], vec![], vec![]];
1431 for a in 0..3 {
1432 let n = p.lens[l][a];
1433 if !p.split[l][a] {
1434 c[a] = cur[a].clone();
1435 next[a] = cur[a].clone();
1436 continue;
1437 }
1438 let ns = n.div_ceil(2);
1439 let nd = n / 2;
1440 for &(x0, x1) in &cur[a] {
1441 let i0 = (x0 / 2).saturating_sub(3);
1442 let i1 = (x1.saturating_sub(1)) / 2 + 4;
1443 c[a].push((i0, i1.min(ns)));
1444 c[a].push((ns + i0.min(nd), ns + i1.min(nd)));
1445 next[a].push((i0, i1.min(ns)));
1446 }
1447 }
1448 coef.push(c);
1449 samp.push(next);
1450 }
1451 (samp, coef)
1452}
1453
1454fn inverse_window(sh: &Shape, x: &mut [i32], win: Option<(&[Need], &[Need])>, threads: usize) {
1457 let p = &sh.p;
1458 let k = lift_consts();
1459 let st = [p.dims[1] * p.dims[2], p.dims[2], 1];
1460 let n = x.len();
1461 let xp = Ptr(x.as_mut_ptr());
1462 for l in (0..p.nlev()).rev() {
1463 let mut done = [false; 3];
1464 for a in [2usize, 1, 0] {
1465 if !p.split[l][a] {
1466 continue;
1467 }
1468 let ext = p.lens[l];
1469 let o: Vec<usize> = (0..3).filter(|&b| b != a).collect();
1470 let sel = |b: usize, i: usize| match win {
1471 None => true,
1472 Some((s, c)) => {
1473 if done[b] {
1474 inside(&s[l][b], i)
1475 } else {
1476 inside(&c[l][b], i)
1477 }
1478 }
1479 };
1480 let (o0, o1) = (o[0], o[1]);
1481 let mut lines: Vec<usize> = Vec::new();
1482 for i in (0..ext[o0]).filter(|&i| sel(o0, i)) {
1483 for j in (0..ext[o1]).filter(|&j| sel(o1, j)) {
1484 lines.push(i * st[o0] + j * st[o1]);
1485 }
1486 }
1487 let chunks: Vec<usize> = (0..threads.max(1)).collect();
1488 let per = lines.len().div_ceil(threads.max(1));
1489 let _ = run_par(&chunks, threads, |c| {
1490 let x = unsafe { std::slice::from_raw_parts_mut(xp.get(), n) };
1491 let mut line = Vec::new();
1492 let mut tmp = Vec::new();
1493 for &off in lines.iter().skip(c * per).take(per) {
1494 line.clear();
1495 line.extend((0..ext[a]).map(|t| x[off + t * st[a]]));
1496 crate::gpuwav::inv97_line(&mut line, &mut tmp, &k);
1497 for (t, &v) in line.iter().enumerate() {
1498 x[off + t * st[a]] = v;
1499 }
1500 }
1501 Ok(())
1502 });
1503 done[a] = true;
1504 }
1505 }
1506}
1507
1508fn apply_tile(ps: &Parsed3, bytes: &[u8], t: &TileRef, c: &mut [i32]) -> Result<(), DecodeError> {
1509 if ps.corr == 0 {
1510 return Ok(());
1511 }
1512 let w = words(bytes, t.words.0, t.words.1);
1513 let mut sink = DecSink {
1514 lanes: vec![RansDec::new(&w)],
1515 };
1516 let mut om = vec![MINIT; NOMODEL];
1517 let n = gamma::<_, true>(&mut sink, 0, &mut om, 0, 0) as usize;
1518 let mut last: i64 = -1;
1519 let d3 = ps.d3;
1520 let ncell: usize = t.dims.iter().product();
1521 for _ in 0..n {
1522 let g = gamma::<_, true>(&mut sink, 0, &mut om, 32, 0) as i64;
1523 let li = (last + 1 + g) as usize;
1524 last = li as i64;
1525 let neg = sink.raw(0, 0, 1) == 1;
1526 let k = gamma::<_, true>(&mut sink, 0, &mut om, 64, 0).wrapping_add(1) as i32;
1527 let k = if neg { -k } else { k };
1528 if li < ncell {
1529 let (z, y, x) = (
1530 li / (t.dims[1] * t.dims[2]),
1531 (li / t.dims[2]) % t.dims[1],
1532 li % t.dims[2],
1533 );
1534 let gi = ((t.origin[0] + z) * d3[1] + t.origin[1] + y) * d3[2] + t.origin[2] + x;
1535 c[gi] = c[gi].wrapping_add(k.wrapping_mul(ps.corr));
1536 }
1537 }
1538 if sink.lanes[0].overrun() {
1539 return Err(DecodeError::Truncated);
1540 }
1541 Ok(())
1542}
1543
1544pub struct Decoded3 {
1546 pub bits: Vec<u32>,
1548 pub bytes_read: usize,
1550 pub blocks: usize,
1552}
1553
1554pub fn decode3_box(
1556 bytes: &[u8],
1557 lo: [usize; 3],
1558 hi: [usize; 3],
1559 threads: usize,
1560) -> Result<Decoded3, DecodeError> {
1561 let ps = parse3(bytes)?;
1562 decode3_box_parsed(&ps, bytes, lo, hi, threads)
1563}
1564
1565pub fn decode3_box_parsed(
1567 ps: &Parsed3,
1568 bytes: &[u8],
1569 lo: [usize; 3],
1570 hi: [usize; 3],
1571 threads: usize,
1572) -> Result<Decoded3, DecodeError> {
1573 let d3 = ps.d3;
1574 for a in 0..3 {
1575 if lo[a] >= hi[a] || hi[a] > d3[a] {
1576 return Err(DecodeError::Invalid("box"));
1577 }
1578 }
1579 let n: usize = d3.iter().product();
1580 let whole = lo == [0; 3] && hi == d3;
1581 let (samp, coef) = needs(&ps.sh, lo, hi);
1582 let nb = ps.blocks.len();
1584 let mut want = vec![whole; nb];
1585 if !whole {
1586 let p = &ps.sh.p;
1587 for (i, b) in ps.blocks.iter().enumerate() {
1588 let band = &p.bands[ps.block_band[i]];
1589 let need = if band.mask == 0 {
1590 &samp[p.nlev()]
1591 } else {
1592 &coef[band.level]
1593 };
1594 want[i] = (0..3).all(|a| hits(&need[a], b.start[a], b.end[a]));
1595 }
1596 for i in (0..nb).rev() {
1598 if !want[i] {
1599 continue;
1600 }
1601 let b = &ps.blocks[i];
1602 let Some(pi) = b.parent else { continue };
1603 let pb = &ps.sh.bands[pi];
1604 let mut plo = [0usize; 3];
1605 let mut phi = [0usize; 3];
1606 for a in 0..3 {
1607 plo[a] = (pb.start[a] + ((b.start[a] - b.org[a]) >> b.pshift[a]))
1608 .min(pb.end[a] - 1)
1609 .saturating_sub(1)
1610 .max(pb.start[a]);
1611 phi[a] = (pb.start[a] + ((b.end[a] - 1 - b.org[a]) >> b.pshift[a]))
1612 .min(pb.end[a] - 1)
1613 + 2;
1614 }
1615 for j in 0..i {
1616 if ps.block_band[j] == pi && !want[j] {
1617 let c = &ps.blocks[j];
1618 if (0..3).all(|a| c.start[a] < phi[a] && plo[a] < c.end[a]) {
1619 want[j] = true;
1620 }
1621 }
1622 }
1623 }
1624 }
1625 let mut q = vec![0i32; n];
1626 let mut rs = vec![0i32; n];
1627 let (qp, rp) = (Ptr(q.as_mut_ptr()), Ptr(rs.as_mut_ptr()));
1628 let mut bytes_read = ps.header_bytes;
1629 let mut nblk = 0;
1630 let irb = IrBase::new(ps, bytes);
1631 for (g0, g1) in ps.level_groups() {
1632 let items: Vec<usize> = (g0..g1).filter(|&i| want[i]).collect();
1633 for &i in &items {
1634 bytes_read += ps.block_words[i].1 - ps.block_words[i].0;
1635 }
1636 nblk += items.len();
1637 run_par(&items, threads, |i| {
1638 decode_block(ps, bytes, i, qp, rp, n, irb.as_ref())
1639 })?;
1640 }
1641 drop(rs);
1642 let [_, ny, nx] = d3;
1644 for (i, b) in ps.blocks.iter().enumerate() {
1645 if !want[i] {
1646 continue;
1647 }
1648 let band = &ps.sh.bands[ps.block_band[i]];
1649 for z in b.start[0]..b.end[0] {
1650 for y in b.start[1]..b.end[1] {
1651 for x in b.start[2]..b.end[2] {
1652 let j = (z * ny + y) * nx + x;
1653 q[j] = dequant(q[j], band, &ps.dl);
1654 }
1655 }
1656 }
1657 }
1658 inverse_window(
1659 &ps.sh,
1660 &mut q,
1661 if whole { None } else { Some((&samp, &coef)) },
1662 threads,
1663 );
1664 let scale = ps.scale();
1665 let bx = [0, 1, 2].map(|a| hi[a] - lo[a]);
1666 for t in &ps.tiles {
1667 if (0..3).all(|a| t.origin[a] < hi[a] && t.origin[a] + t.dims[a] > lo[a]) {
1668 bytes_read += t.bytes.1 - t.bytes.0;
1669 apply_tile(ps, bytes, t, &mut q)?;
1670 }
1671 }
1672 let mut out = vec![0u32; bx.iter().product()];
1673 for z in lo[0]..hi[0] {
1674 for y in lo[1]..hi[1] {
1675 let src = (z * ny + y) * nx;
1676 let dst = ((z - lo[0]) * bx[1] + (y - lo[1])) * bx[2];
1677 for x in lo[2]..hi[2] {
1678 out[dst + x - lo[2]] = to_f32_bits(q[src + x].wrapping_add(ps.mean_fix), scale);
1679 }
1680 }
1681 }
1682 for t in &ps.tiles {
1683 for &(li, bits) in &t.esc {
1684 let (z, y, x) = (
1685 li / (t.dims[1] * t.dims[2]),
1686 (li / t.dims[2]) % t.dims[1],
1687 li % t.dims[2],
1688 );
1689 let g = [t.origin[0] + z, t.origin[1] + y, t.origin[2] + x];
1690 if (0..3).all(|a| g[a] >= lo[a] && g[a] < hi[a]) {
1691 out[((g[0] - lo[0]) * bx[1] + g[1] - lo[1]) * bx[2] + g[2] - lo[2]] = bits;
1692 }
1693 }
1694 }
1695 Ok(Decoded3 {
1696 bits: out,
1697 bytes_read,
1698 blocks: nblk,
1699 })
1700}
1701
1702pub fn decode3_f32(bytes: &[u8], threads: usize) -> Result<(Vec<usize>, Vec<f32>), DecodeError> {
1704 let ps = parse3(bytes)?;
1705 let d = decode3_box_parsed(&ps, bytes, [0; 3], ps.d3, threads)?;
1706 Ok((
1707 ps.dims.clone(),
1708 d.bits.into_iter().map(f32::from_bits).collect(),
1709 ))
1710}
1711
1712#[cfg(test)]
1713mod tests {
1714 use super::*;
1715
1716 fn field(d: [usize; 3]) -> Vec<f32> {
1717 let mut v = Vec::new();
1718 for i in 0..d[0] {
1719 for j in 0..d[1] {
1720 for k in 0..d[2] {
1721 let (x, y, z) = (i as f64, j as f64, k as f64);
1722 v.push(
1723 ((0.3 * x).sin() + (0.11 * y * z / 8.0).cos() + 0.01 * x * y
1724 - ((k * 7 + j * 3) % 11) as f64 * 0.003
1725 + 3.0) as f32,
1726 );
1727 }
1728 }
1729 }
1730 v
1731 }
1732
1733 fn err(x: &[f32], y: &[f32]) -> (f64, f64) {
1734 let mut se = 0.0;
1735 let mut mx = 0.0f64;
1736 for (a, b) in x.iter().zip(y) {
1737 let e = *a as f64 - *b as f64;
1738 se += e * e;
1739 mx = mx.max(e.abs());
1740 }
1741 ((se / x.len() as f64).sqrt(), mx)
1742 }
1743
1744 #[test]
1745 fn round_trip_and_random_access() {
1746 let d = [24, 37, 45];
1747 let x = field(d);
1748 for bound in [
1749 ErrorBound::Psnr(60.0),
1750 ErrorBound::Psnr(95.0),
1751 ErrorBound::MaxAbs(1e-3),
1752 ErrorBound::MaxAbs(2e-5),
1753 ] {
1754 for (block, resctx, lanes) in
1755 [(8, true, 1), (16, false, 1), (64, true, 1), (16, true, 4)]
1756 {
1757 let cfg = Gpu3Config {
1758 block,
1759 resctx,
1760 lanes,
1761 tile: 16,
1762 ..Gpu3Config::new(bound)
1763 };
1764 let (bytes, st) = encode3_f32(&x, &d, &cfg, 2);
1765 let (_, y) = decode3_f32(&bytes, 1).unwrap();
1766 let (rmse, mx) = err(&x, &y);
1767 assert!(
1768 (rmse - st.rmse).abs() <= 1e-12 * rmse.max(1e-30),
1769 "{bound:?} {block}"
1770 );
1771 assert_eq!(mx, st.max_abs);
1772 if let ErrorBound::MaxAbs(b) = bound {
1773 assert!(mx <= b);
1774 }
1775 let (_, y4) = decode3_f32(&bytes, 4).unwrap();
1776 assert!(y.iter().zip(&y4).all(|(a, b)| a.to_bits() == b.to_bits()));
1777 for (lo, hi) in [
1778 ([3, 5, 7], [21, 29, 20]),
1779 ([0, 0, 0], [1, 1, 1]),
1780 ([23, 36, 44], [24, 37, 45]),
1781 ([10, 0, 30], [14, 37, 31]),
1782 ] {
1783 let sub = decode3_box(&bytes, lo, hi, 1).unwrap();
1784 let mut k = 0;
1785 for z in lo[0]..hi[0] {
1786 for yy in lo[1]..hi[1] {
1787 for xx in lo[2]..hi[2] {
1788 assert_eq!(
1789 sub.bits[k],
1790 y[(z * d[1] + yy) * d[2] + xx].to_bits(),
1791 "{bound:?} {block} {lo:?}"
1792 );
1793 k += 1;
1794 }
1795 }
1796 }
1797 }
1798 }
1799 }
1800 }
1801
1802 #[test]
1803 fn two_d() {
1804 let x2: Vec<f32> = (0..70 * 90)
1805 .map(|i| ((i % 90) as f32 * 0.07).sin() * ((i / 90) as f32 * 0.05).cos())
1806 .collect();
1807 let (b, st) = encode3_f32(
1808 &x2,
1809 &[70, 90],
1810 &Gpu3Config {
1811 block2d: 16,
1812 tile: 4,
1813 ..Gpu3Config::new(ErrorBound::Psnr(70.0))
1814 },
1815 1,
1816 );
1817 let (_, y) = decode3_f32(&b, 1).unwrap();
1818 assert!((err(&x2, &y).0 - st.rmse).abs() <= 1e-12 * st.rmse);
1819 let sub = decode3_box(&b, [0, 30, 40], [1, 50, 70], 1).unwrap();
1820 assert!(sub.bytes_read < b.len());
1821 for (k, (yy, xx)) in (30..50)
1822 .flat_map(|a| (40..70).map(move |c| (a, c)))
1823 .enumerate()
1824 {
1825 assert_eq!(sub.bits[k], y[yy * 90 + xx].to_bits());
1826 }
1827 }
1828}