1mod dispatch;
25
26use dispatch::dispatch;
27
28#[derive(Debug, Copy, Clone)]
36pub struct Surface<'a> {
37 pub data: &'a [u8],
39 pub width: u32,
41 pub height: u32,
43}
44
45impl<'a> Surface<'a> {
46 pub fn new(data: &'a [u8], width: u32, height: u32) -> Self {
57 assert!(width > 0 && height > 0, "width and height must be non-zero");
58 assert!(
59 width.is_multiple_of(4),
60 "width {width} must be a multiple of 4"
61 );
62 assert!(
63 height.is_multiple_of(4),
64 "height {height} must be a multiple of 4"
65 );
66 let required = (width as usize)
67 .checked_mul(height as usize)
68 .and_then(|wh| wh.checked_mul(4))
69 .expect("width * height * 4 overflows usize");
70 assert!(
71 data.len() >= required,
72 "data length {} is less than width * height * 4 ({required})",
73 data.len()
74 );
75 Self {
76 data,
77 width,
78 height,
79 }
80 }
81
82 fn blocks(&self) -> u32 {
83 (self.width / 4) * (self.height / 4)
84 }
85}
86
87#[must_use]
92pub fn output_size_64bpb(width: u32, height: u32) -> usize {
93 let block_count = (width.div_ceil(4) * height.div_ceil(4)) as usize;
94 block_count * 8
95}
96
97#[must_use]
100pub fn output_size_128bpb(width: u32, height: u32) -> usize {
101 let block_count = (width.div_ceil(4) * height.div_ceil(4)) as usize;
102 block_count * 16
103}
104
105pub mod etc1 {
112 use super::*;
113
114 #[must_use]
115 pub fn compress_blocks(surface: &Surface) -> Vec<u8> {
116 let size = output_size_64bpb(surface.width, surface.height);
117 let mut output = vec![0u8; size];
118 compress_blocks_into(surface, &mut output);
119 output
120 }
121
122 pub fn compress_blocks_into(surface: &Surface, output: &mut [u8]) {
123 assert_eq!(
124 output.len(),
125 output_size_64bpb(surface.width, surface.height)
126 );
127 unsafe {
128 (dispatch().compress_etc1_rgb)(
129 surface.data.as_ptr().cast(),
130 output.as_mut_ptr().cast(),
131 surface.blocks(),
132 surface.width as usize,
133 );
134 }
135 }
136
137 #[must_use]
138 pub fn compress_blocks_dither(surface: &Surface) -> Vec<u8> {
139 let size = output_size_64bpb(surface.width, surface.height);
140 let mut output = vec![0u8; size];
141 compress_blocks_dither_into(surface, &mut output);
142 output
143 }
144
145 pub fn compress_blocks_dither_into(surface: &Surface, output: &mut [u8]) {
146 assert_eq!(
147 output.len(),
148 output_size_64bpb(surface.width, surface.height)
149 );
150 unsafe {
151 (dispatch().compress_etc1_rgb_dither)(
152 surface.data.as_ptr().cast(),
153 output.as_mut_ptr().cast(),
154 surface.blocks(),
155 surface.width as usize,
156 );
157 }
158 }
159}
160
161pub mod etc2_rgb {
167 use super::*;
168
169 #[must_use]
170 pub fn compress_blocks(surface: &Surface, use_heuristics: bool) -> Vec<u8> {
171 let size = output_size_64bpb(surface.width, surface.height);
172 let mut output = vec![0u8; size];
173 compress_blocks_into(surface, use_heuristics, &mut output);
174 output
175 }
176
177 pub fn compress_blocks_into(surface: &Surface, use_heuristics: bool, output: &mut [u8]) {
178 assert_eq!(
179 output.len(),
180 output_size_64bpb(surface.width, surface.height)
181 );
182 unsafe {
183 (dispatch().compress_etc2_rgb)(
184 surface.data.as_ptr().cast(),
185 output.as_mut_ptr().cast(),
186 surface.blocks(),
187 surface.width as usize,
188 use_heuristics,
189 );
190 }
191 }
192}
193
194pub mod etc2_rgba {
200 use super::*;
201
202 #[must_use]
203 pub fn compress_blocks(surface: &Surface, use_heuristics: bool) -> Vec<u8> {
204 let size = output_size_128bpb(surface.width, surface.height);
205 let mut output = vec![0u8; size];
206 compress_blocks_into(surface, use_heuristics, &mut output);
207 output
208 }
209
210 pub fn compress_blocks_into(surface: &Surface, use_heuristics: bool, output: &mut [u8]) {
211 assert_eq!(
212 output.len(),
213 output_size_128bpb(surface.width, surface.height)
214 );
215 unsafe {
216 (dispatch().compress_etc2_rgba)(
217 surface.data.as_ptr().cast(),
218 output.as_mut_ptr().cast(),
219 surface.blocks(),
220 surface.width as usize,
221 use_heuristics,
222 );
223 }
224 }
225}
226
227pub mod eac_r {
233 use super::*;
234
235 #[must_use]
236 pub fn compress_blocks(surface: &Surface) -> Vec<u8> {
237 let size = output_size_64bpb(surface.width, surface.height);
238 let mut output = vec![0u8; size];
239 compress_blocks_into(surface, &mut output);
240 output
241 }
242
243 pub fn compress_blocks_into(surface: &Surface, output: &mut [u8]) {
244 assert_eq!(
245 output.len(),
246 output_size_64bpb(surface.width, surface.height)
247 );
248 unsafe {
249 (dispatch().compress_eac_r)(
250 surface.data.as_ptr().cast(),
251 output.as_mut_ptr().cast(),
252 surface.blocks(),
253 surface.width as usize,
254 );
255 }
256 }
257}
258
259pub mod eac_rg {
265 use super::*;
266
267 #[must_use]
268 pub fn compress_blocks(surface: &Surface) -> Vec<u8> {
269 let size = output_size_128bpb(surface.width, surface.height);
270 let mut output = vec![0u8; size];
271 compress_blocks_into(surface, &mut output);
272 output
273 }
274
275 pub fn compress_blocks_into(surface: &Surface, output: &mut [u8]) {
276 assert_eq!(
277 output.len(),
278 output_size_128bpb(surface.width, surface.height)
279 );
280 unsafe {
281 (dispatch().compress_eac_rg)(
282 surface.data.as_ptr().cast(),
283 output.as_mut_ptr().cast(),
284 surface.blocks(),
285 surface.width as usize,
286 );
287 }
288 }
289}
290
291pub mod bc1 {
297 use super::*;
298
299 #[must_use]
300 pub fn compress_blocks(surface: &Surface) -> Vec<u8> {
301 let size = output_size_64bpb(surface.width, surface.height);
302 let mut output = vec![0u8; size];
303 compress_blocks_into(surface, &mut output);
304 output
305 }
306
307 pub fn compress_blocks_into(surface: &Surface, output: &mut [u8]) {
308 assert_eq!(
309 output.len(),
310 output_size_64bpb(surface.width, surface.height)
311 );
312 unsafe {
313 (dispatch().compress_bc1)(
314 surface.data.as_ptr().cast(),
315 output.as_mut_ptr().cast(),
316 surface.blocks(),
317 surface.width as usize,
318 );
319 }
320 }
321
322 #[must_use]
323 pub fn compress_blocks_dither(surface: &Surface) -> Vec<u8> {
324 let size = output_size_64bpb(surface.width, surface.height);
325 let mut output = vec![0u8; size];
326 compress_blocks_dither_into(surface, &mut output);
327 output
328 }
329
330 pub fn compress_blocks_dither_into(surface: &Surface, output: &mut [u8]) {
331 assert_eq!(
332 output.len(),
333 output_size_64bpb(surface.width, surface.height)
334 );
335 unsafe {
336 (dispatch().compress_bc1_dither)(
337 surface.data.as_ptr().cast(),
338 output.as_mut_ptr().cast(),
339 surface.blocks(),
340 surface.width as usize,
341 );
342 }
343 }
344}
345
346pub mod bc3 {
352 use super::*;
353
354 #[must_use]
355 pub fn compress_blocks(surface: &Surface) -> Vec<u8> {
356 let size = output_size_128bpb(surface.width, surface.height);
357 let mut output = vec![0u8; size];
358 compress_blocks_into(surface, &mut output);
359 output
360 }
361
362 pub fn compress_blocks_into(surface: &Surface, output: &mut [u8]) {
363 assert_eq!(
364 output.len(),
365 output_size_128bpb(surface.width, surface.height)
366 );
367 unsafe {
368 (dispatch().compress_bc3)(
369 surface.data.as_ptr().cast(),
370 output.as_mut_ptr().cast(),
371 surface.blocks(),
372 surface.width as usize,
373 );
374 }
375 }
376}
377
378pub mod bc4 {
384 use super::*;
385
386 #[must_use]
387 pub fn compress_blocks(surface: &Surface) -> Vec<u8> {
388 let size = output_size_64bpb(surface.width, surface.height);
389 let mut output = vec![0u8; size];
390 compress_blocks_into(surface, &mut output);
391 output
392 }
393
394 pub fn compress_blocks_into(surface: &Surface, output: &mut [u8]) {
395 assert_eq!(
396 output.len(),
397 output_size_64bpb(surface.width, surface.height)
398 );
399 unsafe {
400 (dispatch().compress_bc4)(
401 surface.data.as_ptr().cast(),
402 output.as_mut_ptr().cast(),
403 surface.blocks(),
404 surface.width as usize,
405 );
406 }
407 }
408}
409
410pub mod bc5 {
416 use super::*;
417
418 #[must_use]
419 pub fn compress_blocks(surface: &Surface) -> Vec<u8> {
420 let size = output_size_128bpb(surface.width, surface.height);
421 let mut output = vec![0u8; size];
422 compress_blocks_into(surface, &mut output);
423 output
424 }
425
426 pub fn compress_blocks_into(surface: &Surface, output: &mut [u8]) {
427 assert_eq!(
428 output.len(),
429 output_size_128bpb(surface.width, surface.height)
430 );
431 unsafe {
432 (dispatch().compress_bc5)(
433 surface.data.as_ptr().cast(),
434 output.as_mut_ptr().cast(),
435 surface.blocks(),
436 surface.width as usize,
437 );
438 }
439 }
440}
441
442pub mod decode {
449 use super::*;
450
451 fn output_pixel_size(width: u32, height: u32) -> usize {
452 (width as usize) * (height as usize) * 4
453 }
454
455 #[must_use]
459 pub fn decode_rgb(data: &[u8], width: u32, height: u32) -> Vec<u8> {
460 let size = output_pixel_size(width, height);
461 let mut output = vec![0u8; size];
462 decode_rgb_into(data, width, height, &mut output);
463 output
464 }
465
466 pub fn decode_rgb_into(data: &[u8], width: u32, height: u32, output: &mut [u8]) {
467 assert_eq!(output.len(), output_pixel_size(width, height));
468 assert!(data.len() >= output_size_64bpb(width, height));
469 unsafe {
470 (dispatch().decode_rgb)(
471 data.as_ptr().cast(),
472 output.as_mut_ptr().cast(),
473 width as i32,
474 height as i32,
475 );
476 }
477 }
478
479 #[must_use]
481 pub fn decode_rgba(data: &[u8], width: u32, height: u32) -> Vec<u8> {
482 let size = output_pixel_size(width, height);
483 let mut output = vec![0u8; size];
484 decode_rgba_into(data, width, height, &mut output);
485 output
486 }
487
488 pub fn decode_rgba_into(data: &[u8], width: u32, height: u32, output: &mut [u8]) {
489 assert_eq!(output.len(), output_pixel_size(width, height));
490 assert!(data.len() >= output_size_128bpb(width, height));
491 unsafe {
492 (dispatch().decode_rgba)(
493 data.as_ptr().cast(),
494 output.as_mut_ptr().cast(),
495 width as i32,
496 height as i32,
497 );
498 }
499 }
500
501 #[must_use]
503 pub fn decode_r(data: &[u8], width: u32, height: u32, is_signed: bool) -> Vec<u8> {
504 let size = output_pixel_size(width, height);
505 let mut output = vec![0u8; size];
506 decode_r_into(data, width, height, is_signed, &mut output);
507 output
508 }
509
510 pub fn decode_r_into(data: &[u8], width: u32, height: u32, is_signed: bool, output: &mut [u8]) {
511 assert_eq!(output.len(), output_pixel_size(width, height));
512 assert!(data.len() >= output_size_64bpb(width, height));
513 unsafe {
514 (dispatch().decode_r)(
515 data.as_ptr().cast(),
516 output.as_mut_ptr().cast(),
517 width as i32,
518 height as i32,
519 is_signed,
520 );
521 }
522 }
523
524 #[must_use]
526 pub fn decode_rg(data: &[u8], width: u32, height: u32, is_signed: bool) -> Vec<u8> {
527 let size = output_pixel_size(width, height);
528 let mut output = vec![0u8; size];
529 decode_rg_into(data, width, height, is_signed, &mut output);
530 output
531 }
532
533 pub fn decode_rg_into(
534 data: &[u8],
535 width: u32,
536 height: u32,
537 is_signed: bool,
538 output: &mut [u8],
539 ) {
540 assert_eq!(output.len(), output_pixel_size(width, height));
541 assert!(data.len() >= output_size_128bpb(width, height));
542 unsafe {
543 (dispatch().decode_rg)(
544 data.as_ptr().cast(),
545 output.as_mut_ptr().cast(),
546 width as i32,
547 height as i32,
548 is_signed,
549 );
550 }
551 }
552
553 #[must_use]
557 pub fn decode_bc1(data: &[u8], width: u32, height: u32) -> Vec<u8> {
558 let size = output_pixel_size(width, height);
559 let mut output = vec![0u8; size];
560 decode_bc1_into(data, width, height, &mut output);
561 output
562 }
563
564 pub fn decode_bc1_into(data: &[u8], width: u32, height: u32, output: &mut [u8]) {
565 assert_eq!(output.len(), output_pixel_size(width, height));
566 assert!(data.len() >= output_size_64bpb(width, height));
567 unsafe {
568 (dispatch().decode_bc1)(
569 data.as_ptr().cast(),
570 output.as_mut_ptr().cast(),
571 width as i32,
572 height as i32,
573 );
574 }
575 }
576
577 #[must_use]
579 pub fn decode_bc3(data: &[u8], width: u32, height: u32) -> Vec<u8> {
580 let size = output_pixel_size(width, height);
581 let mut output = vec![0u8; size];
582 decode_bc3_into(data, width, height, &mut output);
583 output
584 }
585
586 pub fn decode_bc3_into(data: &[u8], width: u32, height: u32, output: &mut [u8]) {
587 assert_eq!(output.len(), output_pixel_size(width, height));
588 assert!(data.len() >= output_size_128bpb(width, height));
589 unsafe {
590 (dispatch().decode_bc3)(
591 data.as_ptr().cast(),
592 output.as_mut_ptr().cast(),
593 width as i32,
594 height as i32,
595 );
596 }
597 }
598
599 #[must_use]
601 pub fn decode_bc4(data: &[u8], width: u32, height: u32) -> Vec<u8> {
602 let size = output_pixel_size(width, height);
603 let mut output = vec![0u8; size];
604 decode_bc4_into(data, width, height, &mut output);
605 output
606 }
607
608 pub fn decode_bc4_into(data: &[u8], width: u32, height: u32, output: &mut [u8]) {
609 assert_eq!(output.len(), output_pixel_size(width, height));
610 assert!(data.len() >= output_size_64bpb(width, height));
611 unsafe {
612 (dispatch().decode_bc4)(
613 data.as_ptr().cast(),
614 output.as_mut_ptr().cast(),
615 width as i32,
616 height as i32,
617 );
618 }
619 }
620
621 #[must_use]
623 pub fn decode_bc5(data: &[u8], width: u32, height: u32) -> Vec<u8> {
624 let size = output_pixel_size(width, height);
625 let mut output = vec![0u8; size];
626 decode_bc5_into(data, width, height, &mut output);
627 output
628 }
629
630 pub fn decode_bc5_into(data: &[u8], width: u32, height: u32, output: &mut [u8]) {
631 assert_eq!(output.len(), output_pixel_size(width, height));
632 assert!(data.len() >= output_size_128bpb(width, height));
633 unsafe {
634 (dispatch().decode_bc5)(
635 data.as_ptr().cast(),
636 output.as_mut_ptr().cast(),
637 width as i32,
638 height as i32,
639 );
640 }
641 }
642
643 #[must_use]
645 pub fn decode_bc7(data: &[u8], width: u32, height: u32) -> Vec<u8> {
646 let size = output_pixel_size(width, height);
647 let mut output = vec![0u8; size];
648 decode_bc7_into(data, width, height, &mut output);
649 output
650 }
651
652 pub fn decode_bc7_into(data: &[u8], width: u32, height: u32, output: &mut [u8]) {
653 assert_eq!(output.len(), output_pixel_size(width, height));
654 assert!(data.len() >= output_size_128bpb(width, height));
655 unsafe {
656 (dispatch().decode_bc7)(
657 data.as_ptr().cast(),
658 output.as_mut_ptr().cast(),
659 width as i32,
660 height as i32,
661 );
662 }
663 }
664}