1mod upsampling;
3
4use alloc::boxed::Box;
5
6use image_texel::image::{Coord, ImageRef};
7use image_texel::layout::{
8 AlignedOffset, Decay, Layout as ImageLayout, MatrixBytes, PlaneOf, Raster, Relocate,
9 SliceLayout, StrideSpec, StridedBytes, Strides, TexelLayout,
10};
11
12use crate::color::{Color, ColorChannel, ColorChannelModel};
13use crate::shader::ChunkSpec;
14
15#[derive(Clone, Debug, PartialEq, Eq, Hash)]
20pub(crate) struct ByteLayout {
21 pub(crate) width: u32,
23 pub(crate) height: u32,
25 pub(crate) bytes_per_row: u32,
28}
29
30#[derive(Clone, Debug, PartialEq)]
32pub struct CanvasLayout {
33 pub(crate) bytes: ByteLayout,
37 pub(crate) texel: Texel,
40 pub(crate) offset: usize,
42 pub(crate) color: Option<Color>,
44 pub(crate) planes: Box<[Plane]>,
46}
47
48#[derive(Clone, Copy, Debug)]
50pub(crate) struct PlaneIdx(pub(crate) u8);
51
52#[derive(Clone, Debug, PartialEq, Hash)]
57pub(crate) struct Plane {
58 pub(crate) bytes_per_row: u32,
59 pub(crate) texel: Texel,
61}
62
63#[derive(Clone, Debug, PartialEq, Hash)]
65pub struct ChannelSpec {
66 pub channels: u8,
67 pub channel_stride: usize,
68 pub height: u32,
69 pub height_stride: usize,
70 pub width: u32,
71 pub width_stride: usize,
72}
73
74#[derive(Clone, PartialEq)]
76pub struct ChannelBytes {
77 pub(crate) inner: StridedBytes,
79 pub(crate) texel: Texel,
81 pub(crate) channel_stride: usize,
83 pub(crate) channels: u8,
86}
87
88#[derive(Clone, PartialEq)]
90pub struct ChannelLayout<T> {
91 pub(crate) channel: image_texel::Texel<T>,
92 pub(crate) inner: ChannelBytes,
93}
94
95#[derive(Clone, PartialEq)]
97pub struct PlaneBytes {
98 pub(crate) texel: Texel,
100 pub(crate) width: u32,
103 pub(crate) height: u32,
105 pub(crate) matrix: StridedBytes,
107}
108
109#[derive(Clone, PartialEq)]
114pub struct PlanarLayout<T> {
115 texel: Texel,
117 matrix: Strides<T>,
119}
120
121#[derive(Clone, Debug, PartialEq, Hash)]
130pub struct RowLayoutDescription {
131 pub width: u32,
132 pub height: u32,
133 pub row_stride: u64,
134 pub texel: Texel,
135}
136
137#[derive(Clone, Debug, PartialEq, Eq, Hash)]
139pub struct Texel {
140 pub block: Block,
142 pub bits: SampleBits,
144 pub parts: SampleParts,
146}
147
148#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
154#[non_exhaustive]
155#[repr(u8)]
156pub enum Block {
157 Pixel = 0,
159 Sub1x2 = 1,
161 Sub1x4 = 2,
163 Sub2x2 = 3,
165 Sub2x4 = 4,
167 Sub4x4 = 5,
169 Pack1x2,
171 Pack1x4,
173 Pack1x8,
175 Yuv422,
177 Yuy2,
179 Yuv411,
180 }
182
183#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
194pub struct SampleParts {
195 pub(crate) parts: [Option<ColorChannel>; 4],
196 pub(crate) color_index: u8,
199}
200
201macro_rules! sample_parts {
202 ( $($(#[$attr:meta])* $color:ident: $name:ident = $($ch:path),+;)* ) => {
203 $(sample_parts! { @$color: $(#[$attr])* $name = $($ch),* })*
204
205 impl SampleParts {
206 $(sample_parts! { @$color: $(#[$attr])* $name = $($ch),* })*
207 }
208 };
209 (@$color:ident: $(#[$attr:meta])* $name:ident = $ch0:path) => {
210 $(#[$attr])*
211 pub const $name: SampleParts = SampleParts {
212 parts: [Some($ch0), None, None, None],
213 color_index: (
214 $ch0.canonical_index_in_surely(ColorChannelModel::$color)
215 ),
216 };
217 };
218 (@$color:ident: $(#[$attr:meta])* $name:ident = $ch0:path,$ch1:path) => {
219 $(#[$attr])*
220 pub const $name: SampleParts = SampleParts {
221 parts: [Some($ch0), Some($ch1), None, None],
222 color_index: (
223 $ch0.canonical_index_in_surely(ColorChannelModel::$color)
224 | $ch1.canonical_index_in_surely(ColorChannelModel::$color) << 2
225 ),
226 };
227 };
228 (@$color:ident: $(#[$attr:meta])* $name:ident = $ch0:path,$ch1:path,$ch2:path) => {
229 $(#[$attr])*
230 pub const $name: SampleParts = SampleParts {
231 parts: [Some($ch0), Some($ch1), Some($ch2), None],
232 color_index: (
233 $ch0.canonical_index_in_surely(ColorChannelModel::$color)
234 | $ch1.canonical_index_in_surely(ColorChannelModel::$color) << 2
235 | $ch2.canonical_index_in_surely(ColorChannelModel::$color) << 4
236 ),
237 };
238 };
239 (@$color:ident: $(#[$attr:meta])* $name:ident = $ch0:path,$ch1:path,$ch2:path,$ch3:path) => {
240 $(#[$attr])*
241 pub const $name: SampleParts = SampleParts {
242 parts: [Some($ch0), Some($ch1), Some($ch2), Some($ch3)],
243 color_index: (
244 $ch0.canonical_index_in_surely(ColorChannelModel::$color)
245 | $ch1.canonical_index_in_surely(ColorChannelModel::$color) << 2
246 | $ch2.canonical_index_in_surely(ColorChannelModel::$color) << 4
247 | $ch3.canonical_index_in_surely(ColorChannelModel::$color) << 6
248 ),
249 };
250 };
251}
252
253#[allow(non_upper_case_globals)]
254#[allow(unused)]
257mod sample_parts {
258 type Cc = super::ColorChannel;
259 use super::ColorChannelModel;
260 use super::SampleParts;
261
262 sample_parts! {
263 Rgb: A = Cc::Alpha;
265 Rgb: R = Cc::R;
267 Rgb: G = Cc::G;
268 Rgb: B = Cc::B;
269 Yuv: Luma = Cc::Luma;
270 Yuv: LumaA = Cc::Luma,Cc::Alpha;
271 Rgb: Rgb = Cc::R,Cc::G,Cc::B;
272 Rgb: RgbA = Cc::R,Cc::G,Cc::B,Cc::Alpha;
273 Rgb: ARgb = Cc::Alpha,Cc::R,Cc::G,Cc::B;
274 Rgb: Bgr = Cc::B,Cc::G,Cc::R;
275 Rgb: BgrA = Cc::B,Cc::G,Cc::R,Cc::Alpha;
276 Rgb: ABgr = Cc::Alpha,Cc::B,Cc::G,Cc::R;
277 Yuv: Yuv = Cc::Luma,Cc::Cb,Cc::Cr;
278 Yuv: YuvA = Cc::Luma,Cc::Cb,Cc::Cr,Cc::Alpha;
279 Lab: Lab = Cc::L,Cc::LABa,Cc::LABb;
280 Lab: LabA = Cc::L,Cc::LABa,Cc::LABb,Cc::Alpha;
281 Lab: Lch = Cc::L,Cc::C,Cc::LABh;
282 Lab: LchA = Cc::L,Cc::C,Cc::LABh,Cc::Alpha;
283 }
284
285 }
294
295#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
302#[non_exhaustive]
303#[allow(non_camel_case_types)]
304#[repr(u8)]
305pub enum SampleBits {
306 Int8,
308 UInt8,
310 UInt1x8,
312 UInt2x4,
314 UInt332,
316 UInt233,
318 Int16,
320 UInt16,
322 UInt4x2,
324 UInt4x4,
326 UInt4x6,
328 UInt_444,
330 UInt444_,
332 UInt565,
334 UInt8x2,
336 UInt8x3,
338 UInt8x4,
340 UInt8x6,
342 Int8x2,
344 Int8x3,
346 Int8x4,
348 UInt16x2,
350 UInt16x3,
352 UInt16x4,
354 Int16x2,
356 Int16x3,
358 Int16x4,
360 UInt16x6,
362 UInt1010102,
364 UInt2101010,
366 UInt101010_,
368 UInt_101010,
370 Float16x4,
372 Float32,
374 Float32x2,
376 Float32x3,
378 Float32x4,
380 Float32x6,
382}
383
384#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
385pub(crate) enum BitEncoding {
386 UInt,
387 Int,
388 Float,
389}
390
391#[derive(Clone, Copy, Debug, PartialEq, Eq)]
393pub struct LayoutError {
394 inner: LayoutErrorInner,
395}
396
397#[derive(Clone, Copy, Debug, PartialEq, Eq)]
398enum LayoutErrorInner {
399 NoInfo,
400 NoPlanes,
401 NoModel,
402 TooManyPlanes(usize),
403 WidthError(core::num::TryFromIntError),
404 HeightError(core::num::TryFromIntError),
405 StrideError,
406 NoChannelIndex(ColorChannel),
407 ValidationError(u32),
408}
409
410impl Texel {
411 pub fn new_u8(parts: SampleParts) -> Self {
412 use SampleBits::*;
413 Self::pixel_from_bits(parts, [UInt8, UInt8x2, UInt8x3, UInt8x4])
414 }
415
416 pub fn new_i8(parts: SampleParts) -> Self {
417 use SampleBits::*;
418 Self::pixel_from_bits(parts, [Int8, Int8x2, Int8x3, Int8x4])
419 }
420
421 pub fn new_u16(parts: SampleParts) -> Self {
422 use SampleBits::*;
423 Self::pixel_from_bits(parts, [UInt16, UInt16x2, UInt16x3, UInt16x4])
424 }
425
426 pub fn new_i16(parts: SampleParts) -> Self {
427 use SampleBits::*;
428 Self::pixel_from_bits(parts, [Int16, Int16x2, Int16x3, Int16x4])
429 }
430
431 pub fn new_f32(parts: SampleParts) -> Self {
432 use SampleBits::*;
433 Self::pixel_from_bits(parts, [Float32, Float32x2, Float32x3, Float32x4])
434 }
435
436 fn pixel_from_bits(parts: SampleParts, bits: [SampleBits; 4]) -> Self {
437 Texel {
438 block: Block::Pixel,
439 bits: bits[(parts.num_components() - 1) as usize],
440 parts,
441 }
442 }
443
444 pub fn channel_texel(&self, channel: ColorChannel) -> Option<Texel> {
450 use sample_parts::*;
451 use Block::*;
452 use SampleBits::*;
453
454 #[allow(non_upper_case_globals)]
455 let parts = match self.parts {
456 Rgb => match channel {
457 ColorChannel::R => R,
458 ColorChannel::G => G,
459 ColorChannel::B => B,
460 _ => return None,
461 },
462 RgbA | BgrA | ABgr | ARgb => match channel {
463 ColorChannel::R => R,
464 ColorChannel::G => G,
465 ColorChannel::B => B,
466 ColorChannel::Alpha => A,
467 _ => return None,
468 },
469 _ => return None,
470 };
471
472 let bits = match self.bits {
473 UInt8 | UInt8x3 | UInt8x4 => UInt8,
474 Int8 | Int8x3 | Int8x4 => Int8,
475 UInt16 | UInt16x3 | UInt16x4 => UInt16,
476 Int16 | Int16x3 | Int16x4 => Int16,
477 _ => return None,
478 };
479
480 let block = match self.block {
481 Yuv422 | Yuy2 | Yuv411 => return None,
483 _ => self.block,
484 };
485
486 Some(Texel { bits, parts, block })
487 }
488}
489
490impl ColorChannel {
491 pub const fn in_model(self, model: ColorChannelModel) -> bool {
495 self.canonical_index_in(model).is_some()
496 }
497
498 const fn canonical_index_in(self, model: ColorChannelModel) -> Option<u8> {
500 use ColorChannel::*;
501 use ColorChannelModel::*;
502
503 Some(match (self, model) {
504 (R | X, Rgb) => 0,
505 (G | Y, Rgb) => 1,
506 (B | Z, Rgb) => 2,
507 (ColorChannel::Luma, Yuv) => 0,
508 (ColorChannel::Luma, ColorChannelModel::Luma) => 0,
509 (Cb, Yuv) => 1,
510 (Cr, Yuv) => 2,
511 (L, Lab) => 0,
512 (LABa | C, Lab) => 1,
513 (LABb | LABh, Lab) => 2,
514 (Alpha, Cmyk) => return None,
516 (Alpha, _) => 3,
518 _ => return None,
520 })
521 }
522
523 const fn canonical_index_in_surely(self, model: ColorChannelModel) -> u8 {
529 debug_assert!(
530 Self::canonical_index_in(self, model).is_some(),
531 "you had one job, to validate the channels for the model"
532 );
533
534 match Self::canonical_index_in(self, model) {
535 Some(idx) => idx,
536 None => 0,
537 }
538 }
539}
540
541impl SampleBits {
542 pub(crate) const MAX_COMPONENTS: usize = 8;
543
544 pub fn bytes(self) -> u16 {
546 use SampleBits::*;
547
548 #[allow(non_upper_case_globals)]
549 match self {
550 Int8 | UInt8 | UInt1x8 | UInt2x4 | UInt332 | UInt233 | UInt4x2 => 1,
551 Int8x2 | UInt8x2 | Int16 | UInt16 | UInt565 | UInt4x4 | UInt444_ | UInt_444 => 2,
552 Int8x3 | UInt8x3 | UInt4x6 => 3,
553 Int8x4 | UInt8x4 | Int16x2 | UInt16x2 | UInt1010102 | UInt2101010 | UInt101010_
554 | UInt_101010 | Float32 => 4,
555 UInt8x6 | Int16x3 | UInt16x3 => 6,
556 Int16x4 | UInt16x4 | Float16x4 | Float32x2 => 8,
557 UInt16x6 | Float32x3 => 12,
558 Float32x4 => 16,
559 Float32x6 => 24,
560 }
561 }
562
563 fn as_array(self) -> Option<(TexelLayout, u8)> {
564 use image_texel::AsTexel;
565 use SampleBits::*;
566
567 Some(match self {
568 UInt8 | UInt8x2 | UInt8x3 | UInt8x4 | UInt8x6 => {
569 (u8::texel().into(), self.bytes() as u8)
570 }
571 Int8 | Int8x2 | Int8x3 | Int8x4 => (i8::texel().into(), self.bytes() as u8),
572 UInt16 | UInt16x2 | UInt16x3 | UInt16x4 | UInt16x6 => {
573 (u16::texel().into(), self.bytes() as u8 / 2)
574 }
575 Int16 | Int16x2 | Int16x3 | Int16x4 => (i16::texel().into(), self.bytes() as u8 / 2),
576 Float32 | Float32x2 | Float32x3 | Float32x4 | Float32x6 => {
577 (u32::texel().into(), self.bytes() as u8 / 4)
578 }
579 _ => return None,
580 })
581 }
582
583 fn layout(self) -> TexelLayout {
584 use crate::shader::{GenericTexelAction, TexelKind};
585 struct ToLayout;
586
587 impl GenericTexelAction<TexelLayout> for ToLayout {
588 fn run<T>(self, texel: image_texel::Texel<T>) -> TexelLayout {
589 texel.into()
590 }
591 }
592
593 TexelKind::from(self).action(ToLayout)
594 }
595
596 pub(crate) fn bit_encoding(self) -> ([BitEncoding; Self::MAX_COMPONENTS], u8) {
597 const M: usize = SampleBits::MAX_COMPONENTS;
598 use SampleBits::*;
599
600 match self {
601 UInt8 | UInt8x2 | UInt8x3 | UInt8x4 | UInt8x6 => {
602 ([BitEncoding::UInt; M], self.bytes() as u8)
603 }
604 UInt1x8 => ([BitEncoding::UInt; M], 8),
605 UInt2x4 => ([BitEncoding::UInt; M], 4),
606 Int8 | Int8x2 | Int8x3 | Int8x4 => ([BitEncoding::Int; M], self.bytes() as u8),
607 UInt16 | UInt16x2 | UInt16x3 | UInt16x4 | UInt16x6 => {
608 ([BitEncoding::UInt; M], self.bytes() as u8 / 2)
609 }
610 Int16 | Int16x2 | Int16x3 | Int16x4 => ([BitEncoding::Int; M], self.bytes() as u8 / 2),
611 Float32 | Float32x2 | Float32x3 | Float32x4 | Float32x6 => {
612 ([BitEncoding::Float; M], self.bytes() as u8 / 4)
613 }
614 UInt332 | UInt233 | UInt565 => ([BitEncoding::UInt; M], 3),
615 UInt4x2 => ([BitEncoding::UInt; M], 2),
616 UInt4x4 => ([BitEncoding::UInt; M], 4),
617 UInt4x6 => ([BitEncoding::UInt; M], 6),
618 UInt_444 | SampleBits::UInt444_ => ([BitEncoding::UInt; M], 3),
619 UInt101010_ | UInt_101010 => ([BitEncoding::Float; M], 3),
620 UInt1010102 | UInt2101010 => ([BitEncoding::Float; M], 4),
621 Float16x4 => ([BitEncoding::Float; M], 4),
622 }
623 }
624}
625
626impl SampleParts {
627 pub fn new(parts: [Option<ColorChannel>; 4], model: ColorChannelModel) -> Option<Self> {
635 let color_index = Self::color_index(&parts, model)?;
636
637 Some(SampleParts { parts, color_index })
638 }
639
640 pub fn with_channel(&self, ch: ColorChannel) -> Option<Self> {
645 let pos = self.parts.iter().position(|part| *part == Some(ch))?;
646 let mut parts = [None; 4];
647 parts[0] = self.parts[pos];
648 let color_index = (self.color_index >> (2 * pos)) & 0x3;
649
650 Some(SampleParts { parts, color_index })
651 }
652
653 pub fn contains(&self, ch: ColorChannel) -> bool {
655 self.with_channel(ch).is_some()
656 }
657
658 pub fn color_channels(&self) -> [Option<ColorChannel>; 4] {
660 self.parts
661 }
662
663 fn color_index(parts: &[Option<ColorChannel>; 4], model: ColorChannelModel) -> Option<u8> {
664 let mut unused = [true; 4];
665 let mut color_index = [0; 4];
666 for (part, pos) in parts.into_iter().zip(&mut color_index) {
667 if let Some(p) = part {
668 let idx = p.canonical_index_in(model)?;
669 if !core::mem::take(&mut unused[idx as usize]) {
670 return None;
671 }
672 *pos = idx;
673 }
674 }
675
676 let color_index = color_index
677 .into_iter()
678 .enumerate()
679 .fold(0u8, |acc, (idx, pos)| acc | pos << (2 * idx));
680
681 Some(color_index)
682 }
683
684 pub fn with_yuv_422(
688 parts: [Option<ColorChannel>; 3],
689 model: ColorChannelModel,
690 ) -> Option<Self> {
691 let parts = [parts[0], parts[1], parts[2], None];
692 let color_index = Self::color_index(&parts, model)?;
695
696 Some(SampleParts { parts, color_index })
697 }
698
699 pub fn with_yuv_411(
703 parts: [Option<ColorChannel>; 3],
704 model: ColorChannelModel,
705 ) -> Option<Self> {
706 let parts = [parts[0], parts[1], parts[2], None];
708 let color_index = Self::color_index(&parts, model)?;
709
710 Some(SampleParts { parts, color_index })
711 }
712
713 pub fn num_components(self) -> u8 {
714 self.parts.iter().map(|ch| u8::from(ch.is_some())).sum()
715 }
716
717 pub fn has_alpha(self) -> bool {
718 self.parts
719 .iter()
720 .any(|c| matches!(c, Some(ColorChannel::Alpha)))
721 }
722
723 pub(crate) fn channels(&self) -> impl '_ + Iterator<Item = (Option<ColorChannel>, u8)> {
724 (0..4).map(|i| (self.parts[i], (self.color_index >> (2 * i)) & 0x3))
725 }
726}
727
728impl Block {
729 pub fn width(&self) -> u32 {
730 use Block::*;
731 match self {
732 Pixel => 1,
733 Pack1x2 | Sub1x2 | Sub2x2 | Yuv422 | Yuy2 => 2,
734 Pack1x4 | Sub1x4 | Sub2x4 | Sub4x4 | Yuv411 => 4,
735 Pack1x8 => 8,
736 }
737 }
738
739 pub fn height(&self) -> u32 {
740 use Block::*;
741 match self {
742 Pixel | Sub1x2 | Sub1x4 | Yuv422 | Yuy2 | Yuv411 => 1,
743 Pack1x2 | Pack1x4 | Pack1x8 => 1,
744 Sub2x2 | Sub2x4 => 2,
745 Sub4x4 => 3,
746 }
747 }
748
749 pub(crate) fn block_width(&self, pixels: u32) -> u32 {
750 let div = self.width();
751 pixels / div + if pixels % div == 0 { 0 } else { 1 }
752 }
753
754 pub(crate) fn block_height(&self, pixels: u32) -> u32 {
755 let div = self.height();
756 pixels / div + if pixels % div == 0 { 0 } else { 1 }
757 }
758}
759
760impl CanvasLayout {
761 pub fn with_plane(bytes: PlaneBytes) -> Self {
763 CanvasLayout::from(&bytes)
764 }
765
766 pub fn with_planes(layers: &[PlaneBytes], texel: Texel) -> Result<Self, LayoutError> {
768 if layers.len() == 0 {
769 return Err(LayoutError::NO_PLANES);
770 }
771
772 if layers.len() > 1 {
773 return Err(LayoutError::bad_planes(layers.len()));
775 }
776
777 let spec = layers[0].matrix.spec();
778 let width: u32 = spec.width.try_into().map_err(LayoutError::width_error)?;
779 let min_height_stride = spec.width_stride as u32 * width;
780 let height_stride = spec
781 .height_stride
782 .try_into()
783 .map_err(LayoutError::height_error)?;
784
785 if min_height_stride > height_stride {
786 return Err(LayoutError::bad_planes(0));
788 }
789
790 Self::validate(CanvasLayout {
791 bytes: ByteLayout {
792 width: layers[0].width,
793 height: layers[0].height,
794 bytes_per_row: height_stride,
795 },
796 planes: Box::default(),
797 offset: 0,
798 texel,
799 color: None,
800 })
801 }
802
803 pub fn with_row_layout(rows: &RowLayoutDescription) -> Result<Self, LayoutError> {
805 let bytes_per_texel = rows.texel.bits.bytes();
806 let bytes_per_row = usize::try_from(rows.row_stride).map_err(LayoutError::width_error)?;
807
808 let stride = StrideSpec {
809 offset: 0,
810 width: rows.texel.block.block_width(rows.width) as usize,
811 height: rows.texel.block.block_height(rows.height) as usize,
812 element: rows.texel.bits.layout(),
813 height_stride: bytes_per_row,
814 width_stride: bytes_per_texel.into(),
815 };
816
817 let bytes = PlaneBytes {
818 texel: rows.texel.clone(),
819 width: rows.width,
820 height: rows.height,
821 matrix: StridedBytes::new(stride).map_err(LayoutError::stride_error)?,
822 };
823
824 Self::with_planes(&[bytes], rows.texel.clone())
825 }
826
827 pub fn with_texel(texel: &Texel, width: u32, height: u32) -> Result<Self, LayoutError> {
831 let texel_stride = u64::from(texel.bits.bytes());
832 let width_sub = texel.block.block_width(width);
833
834 Self::with_row_layout(&RowLayoutDescription {
835 width,
836 height,
837 row_stride: u64::from(width_sub) * texel_stride,
839 texel: texel.clone(),
840 })
841 }
842
843 pub fn texel(&self) -> &Texel {
848 &self.texel
849 }
850
851 pub fn color(&self) -> Option<&Color> {
853 self.color.as_ref()
854 }
855
856 pub fn texel_index(&self, x: u32, y: u32) -> u64 {
858 let bytes_per_texel = self.texel.bits.bytes();
859 let byte_index = u64::from(x) * u64::from(self.bytes.bytes_per_row)
860 + u64::from(y) * u64::from(bytes_per_texel);
861 byte_index / u64::from(bytes_per_texel)
862 }
863
864 pub fn as_row_layout(&self) -> RowLayoutDescription {
871 RowLayoutDescription {
872 width: self.bytes.width,
873 height: self.bytes.height,
874 texel: self.texel.clone(),
875 row_stride: u64::from(self.bytes.bytes_per_row),
876 }
877 }
878
879 pub fn width(&self) -> u32 {
881 self.bytes.width
882 }
883
884 pub fn height(&self) -> u32 {
886 self.bytes.height
887 }
888
889 pub fn u64_len(&self) -> u64 {
891 u64::from(self.bytes.bytes_per_row) * u64::from(self.bytes.height)
893 }
894
895 pub fn byte_len(&self) -> usize {
897 (self.bytes.bytes_per_row as usize) * (self.bytes.height as usize)
899 }
900
901 pub fn set_color(&mut self, color: Color) -> Result<(), LayoutError> {
903 let model = color.model().ok_or(LayoutError::NO_MODEL)?;
904
905 for (channel, idx) in self.texel.parts.channels() {
906 if let Some(channel) = channel {
907 let other_idx = match channel.canonical_index_in(model) {
908 Some(idx) => idx,
909 None => return Err(LayoutError::no_index(channel)),
910 };
911
912 if other_idx != idx {
913 return Err(LayoutError::NO_INFO);
914 }
915 }
916 }
917
918 self.color = Some(color);
919 Ok(())
920 }
921
922 pub(crate) fn plane(&self, idx: u8) -> Option<PlaneBytes> {
923 if !self.planes.is_empty() {
924 return None;
926 }
927
928 if idx != 0 {
929 return None;
930 }
931
932 let matrix = StridedBytes::with_row_major(
933 MatrixBytes::from_width_height(
934 self.texel.bits.layout(),
935 self.texel.block.block_width(self.bytes.width) as usize,
936 self.texel.block.block_height(self.bytes.height) as usize,
937 )
938 .unwrap(),
939 );
940
941 Some(PlaneBytes {
942 texel: self.texel.clone(),
943 width: self.bytes.width,
944 height: self.bytes.height,
945 matrix,
946 })
947 }
948
949 pub(crate) fn num_planes(&self) -> u8 {
950 if self.planes.is_empty() {
951 1
952 } else {
953 self.planes.len() as u8
954 }
955 }
956
957 pub fn as_plane(&self) -> Option<PlaneBytes> {
958 if !self.planes.is_empty() {
960 return None;
961 }
962
963 self.plane(0)
964 }
965
966 fn validate(this: Self) -> Result<Self, LayoutError> {
968 let mut start = this.offset;
969 for plane in 0..this.num_planes() {
972 let plane = this.plane(plane).ok_or(LayoutError::validation(line!()))?;
974 let spec = plane.matrix.spec();
975
976 let offset = plane.matrix.spec().offset;
977 let texel_offset = plane
978 .offset_in_texels()
979 .checked_mul(spec.element.size())
980 .ok_or(LayoutError::validation(line!()))?;
981
982 if texel_offset != offset {
984 return Err(LayoutError::validation(line!()));
985 }
986
987 if texel_offset % 256 != 0 {
990 return Err(LayoutError::validation(line!()));
991 }
992
993 let plane_end = offset
994 .checked_add(plane.matrix.byte_len())
995 .ok_or(LayoutError::validation(line!()))?;
996
997 let texel_layout = plane.texel.bits.layout();
998 if !spec.element.superset_of(texel_layout) {
999 return Err(LayoutError::validation(line!()));
1000 }
1001
1002 if start > offset {
1003 return Err(LayoutError::validation(line!()));
1004 }
1005
1006 start = plane_end;
1007 }
1008
1009 let lines = usize::try_from(this.bytes.width).map_err(LayoutError::width_error)?;
1010 let height = usize::try_from(this.bytes.height).map_err(LayoutError::height_error)?;
1011 let ok = height
1012 .checked_mul(lines)
1013 .map_or(false, |len| len < isize::MAX as usize);
1014
1015 if ok {
1016 Ok(this)
1017 } else {
1018 Err(LayoutError::validation(line!()))
1019 }
1020 }
1021}
1022
1023impl PlaneBytes {
1024 pub fn texel(&self) -> &Texel {
1026 &self.texel
1027 }
1028
1029 pub(crate) fn sub_offset(&mut self, offset: usize) {
1030 let mut spec = self.matrix.spec();
1031 assert!(offset % spec.element.size() == 0);
1032 assert!(offset % 256 == 0);
1033
1034 spec.offset = spec.offset.saturating_sub(offset);
1035 self.matrix = StridedBytes::new(spec).unwrap();
1036 }
1037
1038 pub(crate) fn as_channel_bytes(&self) -> Option<ChannelBytes> {
1039 let (channel_layout, channels) = self.texel.bits.as_array()?;
1040 Some(ChannelBytes {
1041 channel_stride: channel_layout.size(),
1042 channels,
1043 inner: self.matrix.clone(),
1044 texel: self.texel.clone(),
1045 })
1046 }
1047
1048 pub(crate) fn is_compatible<T>(&self, texel: image_texel::Texel<T>) -> Option<PlanarLayout<T>> {
1049 use image_texel::layout::TryMend;
1050 Some(PlanarLayout {
1051 texel: self.texel.clone(),
1052 matrix: texel.try_mend(&self.matrix).ok()?,
1053 })
1054 }
1055
1056 pub(crate) fn offset_in_texels(&self) -> usize {
1057 self.matrix.spec().offset / self.matrix.spec().element.size()
1058 }
1059
1060 pub(crate) fn fill_texel_indices_impl(
1061 &self,
1062 idx: &mut [usize],
1063 iter: &[[u32; 2]],
1064 chunk: ChunkSpec,
1065 ) {
1066 debug_assert_eq!(idx.len(), iter.len());
1067
1068 if self.texel.bits.bytes() == 0 {
1069 unreachable!("No texel with zero bytes");
1070 }
1071
1072 if self.matrix.spec().height_stride % usize::from(self.texel.bits.bytes()) == 0 {
1073 let pitch = self.matrix.spec().height_stride / usize::from(self.texel.bits.bytes());
1074 return Self::fill_indices_constant_size(idx, iter, pitch, chunk);
1075 }
1076
1077 for (&[x, y], idx) in iter.iter().zip(idx) {
1083 *idx = self.texel_index(x, y) as usize;
1084 }
1085 }
1086
1087 fn texel_index(&self, x: u32, y: u32) -> u64 {
1093 let bytes_per_texel = self.texel.bits.bytes();
1094 let byte_index = u64::from(x) * (self.matrix.spec().height_stride as u64)
1095 + u64::from(y) * u64::from(bytes_per_texel);
1096 byte_index / u64::from(bytes_per_texel)
1097 }
1098
1099 fn fill_indices_constant_size(
1100 idx: &mut [usize],
1101 iter: &[[u32; 2]],
1102 pitch: usize,
1103 spec: ChunkSpec,
1104 ) {
1105 debug_assert_eq!(iter.len(), idx.len());
1106
1107 let mut index_chunks = idx.chunks_mut(spec.chunk_size);
1108 let mut iter = iter.chunks(spec.chunk_size);
1109
1110 for _ in &mut spec.chunks[..] {
1111 let (idx, iter) = match (index_chunks.next(), iter.next()) {
1112 (Some(idx), Some(iter)) => (idx, iter),
1113 _ => break,
1114 };
1115
1116 for (&[x, y], idx) in iter.iter().zip(&mut idx[..]) {
1117 let texindex = (x as usize) * pitch + (y as usize);
1118 *idx = texindex as usize;
1119 }
1120 }
1121
1122 if spec.should_defer_texel_ops {
1123 for (idx, chunk_spec) in idx.chunks_mut(spec.chunk_size).zip(spec.chunks) {
1124 let mut contig = true;
1125 for wnd in idx.windows(2) {
1126 if wnd[1].saturating_sub(wnd[0]) != 1 {
1127 contig = false;
1128 }
1129 }
1130
1131 let contiguous_start = idx[0];
1132 if contig {
1133 *chunk_spec = [contiguous_start, idx.len()];
1134 }
1135 }
1136 }
1137 }
1138}
1139
1140impl<T> PlanarLayout<T> {
1141 pub fn texel(&self) -> &Texel {
1143 &self.texel
1144 }
1145
1146 pub(crate) fn offset_in_texels(&self) -> usize {
1147 self.matrix.spec().offset / self.matrix.spec().element.size()
1148 }
1149}
1150
1151impl ChannelBytes {
1152 pub fn spec(&self) -> ChannelSpec {
1153 let StrideSpec {
1154 width,
1155 width_stride,
1156 height,
1157 height_stride,
1158 ..
1159 } = self.inner.spec();
1160
1161 ChannelSpec {
1162 channels: self.channels,
1163 channel_stride: self.channel_stride,
1164 height: height as u32,
1165 height_stride,
1166 width: width as u32,
1167 width_stride,
1168 }
1169 }
1170
1171 pub(crate) fn is_compatible<T>(
1172 &self,
1173 texel: image_texel::Texel<T>,
1174 ) -> Option<ChannelLayout<T>> {
1175 if self.channel_stride == texel.size() {
1176 Some(ChannelLayout {
1177 channel: texel,
1178 inner: self.clone(),
1179 })
1180 } else {
1181 None
1182 }
1183 }
1184}
1185
1186impl<T> ChannelLayout<T> {
1187 pub fn texel(&self) -> &Texel {
1189 &self.inner.texel
1190 }
1191
1192 pub fn spec(&self) -> ChannelSpec {
1193 self.inner.spec()
1194 }
1195
1196 fn from_planar_assume_u8<const N: usize>(from: PlanarLayout<[T; N]>) -> Self {
1197 let channel = from.matrix.texel().array_element();
1198 let inner = StridedBytes::decay(from.matrix);
1199 ChannelLayout {
1200 channel,
1201 inner: ChannelBytes {
1202 texel: from.texel,
1203 channels: N as u8,
1204 channel_stride: channel.size(),
1205 inner,
1206 },
1207 }
1208 }
1209}
1210
1211impl PlaneOf<CanvasLayout> for PlaneIdx {
1212 type Plane = PlaneBytes;
1213
1214 fn get_plane(self, layout: &CanvasLayout) -> Option<Self::Plane> {
1215 layout.plane(self.0)
1216 }
1217}
1218
1219impl LayoutError {
1220 const NO_INFO: Self = LayoutError {
1221 inner: LayoutErrorInner::NoInfo,
1222 };
1223
1224 const NO_PLANES: Self = LayoutError {
1225 inner: LayoutErrorInner::NoPlanes,
1226 };
1227
1228 const NO_MODEL: Self = LayoutError {
1229 inner: LayoutErrorInner::NoModel,
1230 };
1231
1232 fn validation(num: u32) -> Self {
1233 LayoutError {
1234 inner: LayoutErrorInner::ValidationError(num),
1235 }
1236 }
1237
1238 fn bad_planes(num: usize) -> Self {
1239 LayoutError {
1240 inner: LayoutErrorInner::TooManyPlanes(num),
1241 }
1242 }
1243
1244 fn width_error(err: core::num::TryFromIntError) -> Self {
1245 LayoutError {
1246 inner: LayoutErrorInner::WidthError(err),
1247 }
1248 }
1249
1250 fn height_error(err: core::num::TryFromIntError) -> Self {
1251 LayoutError {
1252 inner: LayoutErrorInner::HeightError(err),
1253 }
1254 }
1255
1256 fn stride_error(_: image_texel::layout::BadStrideError) -> Self {
1257 LayoutError {
1258 inner: LayoutErrorInner::StrideError,
1259 }
1260 }
1261
1262 fn no_index(ch: ColorChannel) -> Self {
1263 LayoutError {
1264 inner: LayoutErrorInner::NoChannelIndex(ch),
1265 }
1266 }
1267}
1268
1269impl ImageLayout for CanvasLayout {
1270 fn byte_len(&self) -> usize {
1271 CanvasLayout::byte_len(self)
1272 }
1273}
1274
1275impl Decay<PlaneBytes> for CanvasLayout {
1276 fn decay(from: PlaneBytes) -> Self {
1277 CanvasLayout::from(&from)
1278 }
1279}
1280
1281impl ImageLayout for PlaneBytes {
1282 fn byte_len(&self) -> usize {
1283 self.matrix.byte_len()
1284 }
1285}
1286
1287impl<T> ImageLayout for PlanarLayout<T> {
1288 fn byte_len(&self) -> usize {
1289 self.matrix.byte_len()
1290 }
1291}
1292
1293impl<T> SliceLayout for PlanarLayout<T> {
1294 type Sample = T;
1295
1296 fn sample(&self) -> image_texel::Texel<Self::Sample> {
1297 self.matrix.texel()
1298 }
1299}
1300
1301impl<T> Raster<T> for PlanarLayout<T> {
1302 fn dimensions(&self) -> Coord {
1303 let StrideSpec { width, height, .. } = self.matrix.spec();
1304 debug_assert!(u32::try_from(width).is_ok(), "Invalid dimension: {}", width);
1307 debug_assert!(
1308 u32::try_from(height).is_ok(),
1309 "Invalid dimension: {}",
1310 height
1311 );
1312 Coord(width as u32, height as u32)
1313 }
1314
1315 fn get(from: ImageRef<&Self>, at: Coord) -> Option<T> {
1317 let (x, y) = at.xy();
1318 let layout = from.layout();
1319 let matrix = &layout.matrix;
1320 let texel = matrix.texel();
1321 let StrideSpec { width_stride, .. } = matrix.spec();
1323
1324 debug_assert!(
1325 width_stride % texel.size() == 0,
1326 "Invalid stride: {} not valid for {:?}",
1327 width_stride,
1328 texel
1329 );
1330
1331 let idx = y as usize * (width_stride / texel.size()) + x as usize;
1332 let slice = from.as_texels(texel);
1333 let value = slice.get(layout.offset_in_texels()..)?.get(idx)?;
1334 Some(texel.copy_val(value))
1335 }
1336}
1337
1338impl<T> Decay<PlanarLayout<T>> for PlaneBytes {
1339 fn decay(from: PlanarLayout<T>) -> Self {
1340 let spec = from.matrix.spec();
1341 PlaneBytes {
1343 texel: from.texel,
1344 width: spec.width as u32,
1345 height: spec.height as u32,
1346 matrix: StridedBytes::decay(from.matrix),
1347 }
1348 }
1349}
1350
1351impl ImageLayout for ChannelBytes {
1352 fn byte_len(&self) -> usize {
1353 self.inner.byte_len()
1354 }
1355}
1356
1357impl<T> ImageLayout for ChannelLayout<T> {
1358 fn byte_len(&self) -> usize {
1359 self.inner.byte_len()
1360 }
1361}
1362
1363impl<T> SliceLayout for ChannelLayout<T> {
1364 type Sample = T;
1365
1366 fn sample(&self) -> image_texel::Texel<Self::Sample> {
1367 self.channel
1368 }
1369}
1370
1371impl<T> Decay<PlanarLayout<[T; 1]>> for ChannelLayout<T> {
1372 fn decay(from: PlanarLayout<[T; 1]>) -> Self {
1373 ChannelLayout::from_planar_assume_u8(from)
1374 }
1375}
1376
1377impl<T> Decay<PlanarLayout<[T; 2]>> for ChannelLayout<T> {
1378 fn decay(from: PlanarLayout<[T; 2]>) -> Self {
1379 ChannelLayout::from_planar_assume_u8(from)
1380 }
1381}
1382
1383impl<T> Decay<PlanarLayout<[T; 3]>> for ChannelLayout<T> {
1384 fn decay(from: PlanarLayout<[T; 3]>) -> Self {
1385 ChannelLayout::from_planar_assume_u8(from)
1386 }
1387}
1388
1389impl<T> Decay<PlanarLayout<[T; 4]>> for ChannelLayout<T> {
1390 fn decay(from: PlanarLayout<[T; 4]>) -> Self {
1391 ChannelLayout::from_planar_assume_u8(from)
1392 }
1393}
1394
1395impl<T> Decay<ChannelLayout<T>> for ChannelBytes {
1396 fn decay(from: ChannelLayout<T>) -> Self {
1397 from.inner
1398 }
1399}
1400
1401impl From<&'_ PlaneBytes> for CanvasLayout {
1402 fn from(plane: &PlaneBytes) -> Self {
1403 let StrideSpec {
1404 width: _,
1405 height: _,
1406 width_stride: _,
1407 height_stride,
1408 element: _,
1409 offset,
1410 } = plane.matrix.spec();
1411
1412 CanvasLayout {
1413 bytes: ByteLayout {
1414 width: plane.width,
1415 height: plane.height,
1416 bytes_per_row: height_stride as u32,
1417 },
1418 texel: plane.texel.clone(),
1419 offset,
1420 color: None,
1421 planes: Box::default(),
1422 }
1423 }
1424}
1425
1426impl Relocate for PlaneBytes {
1427 fn byte_offset(&self) -> usize {
1428 self.matrix.spec().offset
1429 }
1430
1431 fn relocate(&mut self, offset: AlignedOffset) {
1432 let mut spec = self.matrix.spec();
1433 spec.offset = offset.get();
1434 self.matrix = match StridedBytes::new(spec) {
1435 Err(_) => panic!("Relocated offset out-of-bounds"),
1436 Ok(m) => m,
1437 };
1438 }
1439}