1#![allow(dead_code)]
13
14pub(crate) mod common;
15pub(crate) mod decoder32;
16pub(crate) mod decoder64;
17pub(crate) mod encoder;
18pub(crate) mod simd;
19pub(crate) mod tables;
20
21pub(crate) use encoder::EncodeResult;
23
24#[derive(Debug, Clone, Default)]
26pub struct CodedCbHeader {
27 pub pass_length: [u32; 2],
29 pub num_passes: u32,
31 pub k_max: u32,
33 pub missing_msbs: u32,
35}
36
37pub(crate) fn init_block_encoder_tables() -> bool {
45 let _ = common::encoder_tables();
46 true
47}
48
49pub(crate) fn init_block_decoder_tables() -> bool {
52 let _ = common::decoder_tables();
53 true
54}
55
56pub(crate) type EncodeCodeblock32Fn = fn(
62 buf: &[u32],
63 missing_msbs: u32,
64 num_passes: u32,
65 width: u32,
66 height: u32,
67 stride: u32,
68) -> crate::error::Result<EncodeResult>;
69
70pub(crate) type EncodeCodeblock64Fn = fn(
72 buf: &[u64],
73 missing_msbs: u32,
74 num_passes: u32,
75 width: u32,
76 height: u32,
77 stride: u32,
78) -> crate::error::Result<EncodeResult>;
79
80pub(crate) type DecodeCodeblock32Fn = fn(
82 coded_data: &mut [u8],
83 decoded_data: &mut [u32],
84 missing_msbs: u32,
85 num_passes: u32,
86 lengths1: u32,
87 lengths2: u32,
88 width: u32,
89 height: u32,
90 stride: u32,
91 stripe_causal: bool,
92) -> crate::error::Result<bool>;
93
94pub(crate) type DecodeCodeblock64Fn = fn(
96 coded_data: &mut [u8],
97 decoded_data: &mut [u64],
98 missing_msbs: u32,
99 num_passes: u32,
100 lengths1: u32,
101 lengths2: u32,
102 width: u32,
103 height: u32,
104 stride: u32,
105 stripe_causal: bool,
106) -> crate::error::Result<bool>;
107
108#[inline]
114pub(crate) fn get_encode_codeblock32() -> EncodeCodeblock32Fn {
115 encoder::encode_codeblock32
116}
117
118#[inline]
120pub(crate) fn get_encode_codeblock64() -> EncodeCodeblock64Fn {
121 encoder::encode_codeblock64
122}
123
124#[inline]
126pub(crate) fn get_decode_codeblock32() -> DecodeCodeblock32Fn {
127 decoder32::decode_codeblock32
128}
129
130#[inline]
132pub(crate) fn get_decode_codeblock64() -> DecodeCodeblock64Fn {
133 decoder64::decode_codeblock64
134}
135
136#[cfg(test)]
141mod tests {
142 use super::*;
143
144 fn make_mag32(mu_p: u32, p: u32) -> u32 {
154 if mu_p == 0 {
155 return 0;
156 }
157 (2 * mu_p + 1) << (p - 1)
158 }
159
160 fn make_mag64(mu_p: u64, p: u32) -> u64 {
162 if mu_p == 0 {
163 return 0;
164 }
165 (2 * mu_p + 1) << (p - 1)
166 }
167
168 fn roundtrip32(samples: &[u32], width: u32, height: u32, missing_msbs: u32) {
170 let stride = width;
171 assert_eq!(samples.len(), (stride * height) as usize);
172
173 let enc_result =
174 encoder::encode_codeblock32(samples, missing_msbs, 1, width, height, stride)
175 .expect("encode failed");
176
177 let dec_h = height.max(2).next_multiple_of(2);
180 let mut decoded = vec![0u32; (stride * dec_h) as usize];
181
182 if enc_result.length >= 2 {
186 let mut coded = enc_result.data.clone();
187 coded.resize(coded.len() + 64, 0);
190
191 decoder32::decode_codeblock32(
192 &mut coded,
193 &mut decoded,
194 missing_msbs,
195 1,
196 enc_result.length,
197 0,
198 width,
199 height,
200 stride,
201 false,
202 )
203 .expect("decode failed");
204 }
205
206 for y in 0..height as usize {
207 for x in 0..width as usize {
208 let idx = y * stride as usize + x;
209 assert_eq!(
210 decoded[idx], samples[idx],
211 "mismatch at ({x}, {y}): got 0x{:08X}, expected 0x{:08X}",
212 decoded[idx], samples[idx],
213 );
214 }
215 }
216 }
217
218 fn roundtrip64(samples: &[u64], width: u32, height: u32, missing_msbs: u32) {
220 let stride = width;
221 assert_eq!(samples.len(), (stride * height) as usize);
222
223 let enc_result =
224 encoder::encode_codeblock64(samples, missing_msbs, 1, width, height, stride)
225 .expect("encode failed");
226
227 let dec_h = height.max(2).next_multiple_of(2);
228 let mut decoded = vec![0u64; (stride * dec_h) as usize];
229
230 if enc_result.length >= 2 {
231 let mut coded = enc_result.data.clone();
232 coded.resize(coded.len() + 64, 0);
233
234 decoder64::decode_codeblock64(
235 &mut coded,
236 &mut decoded,
237 missing_msbs,
238 1,
239 enc_result.length,
240 0,
241 width,
242 height,
243 stride,
244 false,
245 )
246 .expect("decode failed");
247 }
248
249 for y in 0..height as usize {
250 for x in 0..width as usize {
251 let idx = y * stride as usize + x;
252 assert_eq!(
253 decoded[idx], samples[idx],
254 "mismatch at ({x}, {y}): got 0x{:016X}, expected 0x{:016X}",
255 decoded[idx], samples[idx],
256 );
257 }
258 }
259 }
260
261 #[test]
266 fn roundtrip_zeros_4x4() {
267 roundtrip32(&[0u32; 16], 4, 4, 0);
268 }
269
270 #[test]
271 fn roundtrip_zeros_8x8() {
272 roundtrip32(&vec![0u32; 64], 8, 8, 0);
273 }
274
275 #[test]
276 fn roundtrip_16x16_zeros() {
277 roundtrip32(&vec![0u32; 256], 16, 16, 0);
278 }
279
280 #[test]
281 fn roundtrip_32x32_zeros() {
282 roundtrip32(&vec![0u32; 1024], 32, 32, 0);
283 }
284
285 #[test]
286 fn roundtrip_64x64_zeros() {
287 let samples = vec![0u32; 4096];
291 let enc_result =
292 encoder::encode_codeblock32(&samples, 0, 1, 64, 64, 64).expect("encode failed");
293 assert!(enc_result.length > 0);
294 }
295
296 #[test]
297 fn roundtrip_64x64_nonzero() {
298 let p = 1u32;
299 let msbs = 29u32;
300 let n = 64 * 64;
301 let samples: Vec<u32> = (0..n).map(|i| make_mag32((i as u32 % 10) + 1, p)).collect();
302 roundtrip32(&samples, 64, 64, msbs);
303 }
304
305 #[test]
310 fn roundtrip_single_sample() {
311 let mag = make_mag32(1, 1); roundtrip32(&[mag], 1, 1, 29);
314 }
315
316 #[test]
321 fn roundtrip_uniform_4x4() {
322 let mag = make_mag32(3, 1); let mag_arr = [mag; 16];
325 roundtrip32(&mag_arr, 4, 4, 29);
326 }
327
328 #[test]
333 fn roundtrip_simple_4x4() {
334 let p = 1u32;
336 let msbs = 29u32;
337 let samples: Vec<u32> = (1..=16).map(|k| make_mag32(k, p)).collect();
338 roundtrip32(&samples, 4, 4, msbs);
339 }
340
341 #[test]
346 fn roundtrip_8x8_pattern() {
347 let p = 2u32;
349 let msbs = 28u32;
350 let a = make_mag32(1, p); let b = make_mag32(3, p); let mut samples = vec![0u32; 64];
353 for y in 0..8u32 {
354 for x in 0..8u32 {
355 samples[(y * 8 + x) as usize] = if (x + y) % 2 == 0 { a } else { b };
356 }
357 }
358 roundtrip32(&samples, 8, 8, msbs);
359 }
360
361 #[test]
366 fn roundtrip_signed_4x4() {
367 let p = 1u32;
369 let msbs = 29u32;
370 let samples: Vec<u32> = (1..=16)
371 .map(|k| {
372 let mag = make_mag32(k, p);
373 if k % 3 == 0 {
374 mag | 0x80000000
375 } else {
376 mag
377 }
378 })
379 .collect();
380 roundtrip32(&samples, 4, 4, msbs);
381 }
382
383 #[test]
388 fn roundtrip_sparse_8x8() {
389 let p = 1u32;
391 let msbs = 29u32;
392 let mut samples = vec![0u32; 64];
393 samples[0] = make_mag32(1, p);
395 samples[7] = make_mag32(2, p);
396 samples[9] = make_mag32(4, p) | 0x80000000; samples[35] = make_mag32(3, p);
398 samples[63] = make_mag32(5, p);
399 roundtrip32(&samples, 8, 8, msbs);
400 }
401
402 #[test]
403 fn roundtrip_centered_gradient_33x33_kmax8() {
404 use super::decoder32;
405 use super::encoder;
406
407 let width = 33u32;
408 let height = 33u32;
409 let kmax = 8u32;
410 let shift = 31 - kmax;
411 let missing_msbs = kmax - 1;
412 let mut samples = Vec::with_capacity((width * height) as usize);
413 let mut expected = Vec::with_capacity((width * height) as usize);
414 for y in 0..height {
415 for x in 0..width {
416 let pixel = ((3 * x + 7 * y) & 0xFF) as i32;
417 let centered = pixel - 128;
418 expected.push(centered);
419 let sign = if centered < 0 { 0x8000_0000 } else { 0 };
420 let mag = centered.unsigned_abs() << shift;
421 samples.push(sign | mag);
422 }
423 }
424
425 let enc_result =
426 encoder::encode_codeblock32(&samples, missing_msbs, 1, width, height, width)
427 .expect("encode failed");
428 let mut coded = enc_result.data.clone();
429 coded.resize(coded.len() + 64, 0);
430 let dec_h = height.max(2).next_multiple_of(2);
431 let mut decoded = vec![0u32; (width * dec_h) as usize];
432 decoder32::decode_codeblock32(
433 &mut coded,
434 &mut decoded,
435 missing_msbs,
436 1,
437 enc_result.length,
438 0,
439 width,
440 height,
441 width,
442 false,
443 )
444 .expect("decode failed");
445
446 for y in 0..height as usize {
447 for x in 0..width as usize {
448 let v = decoded[y * width as usize + x];
449 let mag = ((v & 0x7FFF_FFFF) >> shift) as i32;
450 let got = if (v >> 31) != 0 { -mag } else { mag };
451 assert_eq!(
452 got,
453 expected[y * width as usize + x],
454 "mismatch at ({x}, {y})"
455 );
456 }
457 }
458 }
459
460 #[test]
465 fn roundtrip_4x4_64bit() {
466 let p = 1u32;
468 let msbs = 61u32;
469 let samples: Vec<u64> = (1..=16).map(|k| make_mag64(k as u64, p)).collect();
470 roundtrip64(&samples, 4, 4, msbs);
471 }
472
473 #[test]
474 fn roundtrip_zeros_64bit_8x8() {
475 roundtrip64(&vec![0u64; 64], 8, 8, 0);
476 }
477
478 #[test]
479 fn roundtrip_signed_64bit_4x4() {
480 let p = 1u32;
481 let msbs = 61u32;
482 let samples: Vec<u64> = (1..=16)
483 .map(|k| {
484 let mag = make_mag64(k as u64, p);
485 if k % 2 == 0 {
486 mag | (1u64 << 63)
487 } else {
488 mag
489 }
490 })
491 .collect();
492 roundtrip64(&samples, 4, 4, msbs);
493 }
494
495 #[test]
500 fn roundtrip_various_block_sizes() {
501 let p = 1u32;
502 let msbs = 29u32;
503 for &(w, h) in &[(4u32, 4), (4, 8), (8, 4), (8, 8), (16, 16)] {
504 let n = (w * h) as usize;
505 let samples: Vec<u32> = (0..n)
506 .map(|i| {
507 let mu = (i as u32 % 15) + 1; make_mag32(mu, p)
509 })
510 .collect();
511 roundtrip32(&samples, w, h, msbs);
512 }
513 }
514
515 #[test]
520 fn roundtrip_16x16_nonzero() {
521 let p = 2u32;
522 let msbs = 28u32;
523 let n = 16 * 16;
524 let samples: Vec<u32> = (0..n)
525 .map(|i| {
526 let mu = (i as u32 % 7) + 1;
527 let mag = make_mag32(mu, p);
528 if i % 5 == 0 {
529 mag | 0x80000000
530 } else {
531 mag
532 }
533 })
534 .collect();
535 roundtrip32(&samples, 16, 16, msbs);
536 }
537}