#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ColorModel {
Yuv,
Rgb,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Subsampling {
C400,
C411,
C420,
C422,
C444,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PlaneLayout {
Packed,
SemiPlanar,
Planar,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RgbOrder {
Rgb,
Bgr,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ChromaOrder {
CbCr,
CrCb,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SampleDepth {
Bits8,
Bits10,
Bits12,
Bits16,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SampleContainer {
U8,
U16,
U32Packed,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Alpha {
None,
Straight,
Premultiplied,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct SurfaceFormat {
model: ColorModel,
subsampling: Subsampling,
layout: PlaneLayout,
rgb_order: RgbOrder,
chroma_order: ChromaOrder,
depth: SampleDepth,
container: SampleContainer,
alpha: Alpha,
}
impl SurfaceFormat {
const fn rgb(
order: RgbOrder,
depth: SampleDepth,
container: SampleContainer,
alpha: Alpha,
) -> Self {
Self {
model: ColorModel::Rgb,
subsampling: Subsampling::C444,
layout: PlaneLayout::Packed,
rgb_order: order,
chroma_order: ChromaOrder::CbCr,
depth,
container,
alpha,
}
}
const fn yuv(
subsampling: Subsampling,
layout: PlaneLayout,
order: ChromaOrder,
depth: SampleDepth,
container: SampleContainer,
) -> Self {
Self {
model: ColorModel::Yuv,
subsampling,
layout,
rgb_order: RgbOrder::Rgb,
chroma_order: order,
depth,
container,
alpha: Alpha::None,
}
}
pub const fn model(&self) -> ColorModel {
self.model
}
pub const fn subsampling(&self) -> Subsampling {
self.subsampling
}
pub const fn layout(&self) -> PlaneLayout {
self.layout
}
pub const fn rgb_order(&self) -> RgbOrder {
self.rgb_order
}
pub const fn chroma_order(&self) -> ChromaOrder {
self.chroma_order
}
pub const fn depth(&self) -> SampleDepth {
self.depth
}
pub const fn container(&self) -> SampleContainer {
self.container
}
pub const fn alpha(&self) -> Alpha {
self.alpha
}
pub const fn is_yuv(&self) -> bool {
matches!(self.model, ColorModel::Yuv)
}
pub const fn plane_count(&self) -> usize {
match self.subsampling {
Subsampling::C400 => 1,
_ => match self.layout {
PlaneLayout::Packed => 1,
PlaneLayout::SemiPlanar => 2,
PlaneLayout::Planar => 3,
},
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SurfaceFormatKind {
Bgra8(SurfaceFormat),
Rgba8(SurfaceFormat),
Nv12(SurfaceFormat),
Nv21(SurfaceFormat),
I420(SurfaceFormat),
Yv12(SurfaceFormat),
Nv16(SurfaceFormat),
Nv61(SurfaceFormat),
Yu16(SurfaceFormat),
Yv16(SurfaceFormat),
Nv24(SurfaceFormat),
Yuv444(SurfaceFormat),
Mono8(SurfaceFormat),
P010(SurfaceFormat),
P012(SurfaceFormat),
P016(SurfaceFormat),
I010(SurfaceFormat),
I012(SurfaceFormat),
I016(SurfaceFormat),
P210(SurfaceFormat),
P212(SurfaceFormat),
P216(SurfaceFormat),
P410(SurfaceFormat),
P412(SurfaceFormat),
P416(SurfaceFormat),
Q410(SurfaceFormat),
Q416(SurfaceFormat),
}
impl SurfaceFormatKind {
pub const fn bgra8() -> Self {
Self::Bgra8(SurfaceFormat::rgb(
RgbOrder::Bgr,
SampleDepth::Bits8,
SampleContainer::U8,
Alpha::Straight,
))
}
pub const fn rgba8() -> Self {
Self::Rgba8(SurfaceFormat::rgb(
RgbOrder::Rgb,
SampleDepth::Bits8,
SampleContainer::U8,
Alpha::Straight,
))
}
pub const fn nv12() -> Self {
Self::Nv12(SurfaceFormat::yuv(
Subsampling::C420,
PlaneLayout::SemiPlanar,
ChromaOrder::CbCr,
SampleDepth::Bits8,
SampleContainer::U8,
))
}
pub const fn nv21() -> Self {
Self::Nv21(SurfaceFormat::yuv(
Subsampling::C420,
PlaneLayout::SemiPlanar,
ChromaOrder::CrCb,
SampleDepth::Bits8,
SampleContainer::U8,
))
}
pub const fn i420() -> Self {
Self::I420(SurfaceFormat::yuv(
Subsampling::C420,
PlaneLayout::Planar,
ChromaOrder::CbCr,
SampleDepth::Bits8,
SampleContainer::U8,
))
}
pub const fn yv12() -> Self {
Self::Yv12(SurfaceFormat::yuv(
Subsampling::C420,
PlaneLayout::Planar,
ChromaOrder::CrCb,
SampleDepth::Bits8,
SampleContainer::U8,
))
}
pub const fn nv16() -> Self {
Self::Nv16(SurfaceFormat::yuv(
Subsampling::C422,
PlaneLayout::SemiPlanar,
ChromaOrder::CbCr,
SampleDepth::Bits8,
SampleContainer::U8,
))
}
pub const fn nv61() -> Self {
Self::Nv61(SurfaceFormat::yuv(
Subsampling::C422,
PlaneLayout::SemiPlanar,
ChromaOrder::CrCb,
SampleDepth::Bits8,
SampleContainer::U8,
))
}
pub const fn yu16() -> Self {
Self::Yu16(SurfaceFormat::yuv(
Subsampling::C422,
PlaneLayout::Planar,
ChromaOrder::CbCr,
SampleDepth::Bits8,
SampleContainer::U8,
))
}
pub const fn yv16() -> Self {
Self::Yv16(SurfaceFormat::yuv(
Subsampling::C422,
PlaneLayout::Planar,
ChromaOrder::CrCb,
SampleDepth::Bits8,
SampleContainer::U8,
))
}
pub const fn nv24() -> Self {
Self::Nv24(SurfaceFormat::yuv(
Subsampling::C444,
PlaneLayout::SemiPlanar,
ChromaOrder::CbCr,
SampleDepth::Bits8,
SampleContainer::U8,
))
}
pub const fn yuv444() -> Self {
Self::Yuv444(SurfaceFormat::yuv(
Subsampling::C444,
PlaneLayout::Planar,
ChromaOrder::CbCr,
SampleDepth::Bits8,
SampleContainer::U8,
))
}
pub const fn mono8() -> Self {
Self::Mono8(SurfaceFormat::yuv(
Subsampling::C400,
PlaneLayout::Planar,
ChromaOrder::CbCr,
SampleDepth::Bits8,
SampleContainer::U8,
))
}
pub const fn p010() -> Self {
Self::P010(SurfaceFormat::yuv(
Subsampling::C420,
PlaneLayout::SemiPlanar,
ChromaOrder::CbCr,
SampleDepth::Bits10,
SampleContainer::U16,
))
}
pub const fn p012() -> Self {
Self::P012(SurfaceFormat::yuv(
Subsampling::C420,
PlaneLayout::SemiPlanar,
ChromaOrder::CbCr,
SampleDepth::Bits12,
SampleContainer::U16,
))
}
pub const fn p016() -> Self {
Self::P016(SurfaceFormat::yuv(
Subsampling::C420,
PlaneLayout::SemiPlanar,
ChromaOrder::CbCr,
SampleDepth::Bits16,
SampleContainer::U16,
))
}
pub const fn i010() -> Self {
Self::I010(SurfaceFormat::yuv(
Subsampling::C420,
PlaneLayout::Planar,
ChromaOrder::CbCr,
SampleDepth::Bits10,
SampleContainer::U16,
))
}
pub const fn i012() -> Self {
Self::I012(SurfaceFormat::yuv(
Subsampling::C420,
PlaneLayout::Planar,
ChromaOrder::CbCr,
SampleDepth::Bits12,
SampleContainer::U16,
))
}
pub const fn i016() -> Self {
Self::I016(SurfaceFormat::yuv(
Subsampling::C420,
PlaneLayout::Planar,
ChromaOrder::CbCr,
SampleDepth::Bits16,
SampleContainer::U16,
))
}
pub const fn p210() -> Self {
Self::P210(SurfaceFormat::yuv(
Subsampling::C422,
PlaneLayout::SemiPlanar,
ChromaOrder::CbCr,
SampleDepth::Bits10,
SampleContainer::U16,
))
}
pub const fn p212() -> Self {
Self::P212(SurfaceFormat::yuv(
Subsampling::C422,
PlaneLayout::SemiPlanar,
ChromaOrder::CbCr,
SampleDepth::Bits12,
SampleContainer::U16,
))
}
pub const fn p216() -> Self {
Self::P216(SurfaceFormat::yuv(
Subsampling::C422,
PlaneLayout::SemiPlanar,
ChromaOrder::CbCr,
SampleDepth::Bits16,
SampleContainer::U16,
))
}
pub const fn p410() -> Self {
Self::P410(SurfaceFormat::yuv(
Subsampling::C444,
PlaneLayout::SemiPlanar,
ChromaOrder::CbCr,
SampleDepth::Bits10,
SampleContainer::U16,
))
}
pub const fn p412() -> Self {
Self::P412(SurfaceFormat::yuv(
Subsampling::C444,
PlaneLayout::SemiPlanar,
ChromaOrder::CbCr,
SampleDepth::Bits12,
SampleContainer::U16,
))
}
pub const fn p416() -> Self {
Self::P416(SurfaceFormat::yuv(
Subsampling::C444,
PlaneLayout::SemiPlanar,
ChromaOrder::CbCr,
SampleDepth::Bits16,
SampleContainer::U16,
))
}
pub const fn q410() -> Self {
Self::Q410(SurfaceFormat::yuv(
Subsampling::C444,
PlaneLayout::Planar,
ChromaOrder::CbCr,
SampleDepth::Bits10,
SampleContainer::U16,
))
}
pub const fn q416() -> Self {
Self::Q416(SurfaceFormat::yuv(
Subsampling::C444,
PlaneLayout::Planar,
ChromaOrder::CbCr,
SampleDepth::Bits16,
SampleContainer::U16,
))
}
pub const fn dimensions(self) -> SurfaceFormat {
match self {
Self::Bgra8(format) | Self::Rgba8(format) => format,
Self::Nv12(format)
| Self::Nv21(format)
| Self::I420(format)
| Self::Yv12(format)
| Self::Nv16(format)
| Self::Nv61(format)
| Self::Yu16(format)
| Self::Yv16(format)
| Self::Nv24(format)
| Self::Yuv444(format)
| Self::Mono8(format) => format,
Self::P010(format)
| Self::P012(format)
| Self::P016(format)
| Self::I010(format)
| Self::I012(format)
| Self::I016(format)
| Self::P210(format)
| Self::P212(format)
| Self::P216(format)
| Self::P410(format)
| Self::P412(format)
| Self::P416(format)
| Self::Q410(format)
| Self::Q416(format) => format,
}
}
pub const fn is_yuv(self) -> bool {
self.dimensions().is_yuv()
}
pub const fn plane_count(self) -> usize {
self.dimensions().plane_count()
}
}
impl std::fmt::Display for SurfaceFormatKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(match self {
Self::Bgra8(_) => "BGRA8",
Self::Rgba8(_) => "RGBA8",
Self::Nv12(_) => "NV12",
Self::Nv21(_) => "NV21",
Self::I420(_) => "I420",
Self::Yv12(_) => "YV12",
Self::Nv16(_) => "NV16",
Self::Nv61(_) => "NV61",
Self::Yu16(_) => "YU16",
Self::Yv16(_) => "YV16",
Self::Nv24(_) => "NV24",
Self::Yuv444(_) => "YUV444",
Self::Mono8(_) => "MONO8",
Self::P010(_) => "P010",
Self::P012(_) => "P012",
Self::P016(_) => "P016",
Self::I010(_) => "I010",
Self::I012(_) => "I012",
Self::I016(_) => "I016",
Self::P210(_) => "P210",
Self::P212(_) => "P212",
Self::P216(_) => "P216",
Self::P410(_) => "P410",
Self::P412(_) => "P412",
Self::P416(_) => "P416",
Self::Q410(_) => "Q410",
Self::Q416(_) => "Q416",
})
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct DmaBufFormatCapability {
pub format: SurfaceFormatKind,
pub modifiers: Vec<u64>,
}
impl DmaBufFormatCapability {
pub fn supports(&self, modifier: u64) -> bool {
self.modifiers.contains(&modifier)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct DmaBufCapabilities {
formats: Vec<DmaBufFormatCapability>,
}
impl DmaBufCapabilities {
pub fn new(formats: Vec<DmaBufFormatCapability>) -> Self {
Self { formats }
}
pub fn formats(&self) -> &[DmaBufFormatCapability] {
&self.formats
}
pub fn format(&self, format: &SurfaceFormatKind) -> Option<&DmaBufFormatCapability> {
self.formats.iter().find(|entry| entry.format == *format)
}
pub fn modifiers(&self, format: &SurfaceFormatKind) -> Option<&[u64]> {
self.format(format).map(|entry| entry.modifiers.as_slice())
}
pub fn supports(&self, format: &SurfaceFormatKind, modifier: u64) -> bool {
self.format(format)
.is_some_and(|entry| entry.supports(modifier))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn a_packed_rgb_format_is_one_plane_and_not_yuv() {
let format = SurfaceFormatKind::bgra8().dimensions();
assert_eq!(format.model(), ColorModel::Rgb);
assert_eq!(format.rgb_order(), RgbOrder::Bgr);
assert_eq!(format.plane_count(), 1);
assert!(!format.is_yuv());
}
#[test]
fn a_semi_planar_yuv_format_is_two_planes() {
let format = SurfaceFormatKind::nv12().dimensions();
assert!(format.is_yuv());
assert_eq!(format.subsampling(), Subsampling::C420);
assert_eq!(format.layout(), PlaneLayout::SemiPlanar);
assert_eq!(format.plane_count(), 2);
assert_eq!(format.depth(), SampleDepth::Bits8);
assert_eq!(SurfaceFormatKind::nv12().plane_count(), 2);
}
#[test]
fn a_planar_yuv_format_is_three_planes_bar_mono() {
assert_eq!(SurfaceFormatKind::i420().plane_count(), 3);
assert_eq!(SurfaceFormatKind::q416().plane_count(), 3);
assert_eq!(SurfaceFormatKind::mono8().plane_count(), 1);
}
#[test]
fn a_sixteen_bit_container_carries_ten_bits_in_its_high_bits() {
let format = SurfaceFormatKind::p010().dimensions();
assert_eq!(format.depth(), SampleDepth::Bits10);
assert_eq!(format.container(), SampleContainer::U16);
}
#[test]
fn the_chroma_orders_differ_only_in_which_component_comes_first() {
let cb_cr = SurfaceFormatKind::nv12().dimensions();
let cr_cb = SurfaceFormatKind::nv21().dimensions();
assert_eq!(cb_cr.chroma_order(), ChromaOrder::CbCr);
assert_eq!(cr_cb.chroma_order(), ChromaOrder::CrCb);
assert_ne!(cb_cr, cr_cb);
assert_eq!(cb_cr.subsampling(), cr_cb.subsampling());
assert_eq!(cb_cr.plane_count(), cr_cb.plane_count());
}
#[test]
fn a_kind_displays_as_its_conventional_name() {
assert_eq!(SurfaceFormatKind::nv12().to_string(), "NV12");
assert_eq!(SurfaceFormatKind::p010().to_string(), "P010");
assert_eq!(SurfaceFormatKind::bgra8().to_string(), "BGRA8");
}
#[test]
fn kinds_compare_by_their_shape() {
assert_eq!(SurfaceFormatKind::nv12(), SurfaceFormatKind::nv12());
assert_ne!(SurfaceFormatKind::nv12(), SurfaceFormatKind::nv21());
assert_ne!(SurfaceFormatKind::nv12(), SurfaceFormatKind::i420());
}
}