use core::fmt;
pub mod vendor {
pub const NONE: u8 = 0x00;
pub const INTEL: u8 = 0x01;
pub const AMD: u8 = 0x02;
pub const NVIDIA: u8 = 0x03;
pub const SAMSUNG: u8 = 0x04;
pub const QCOM: u8 = 0x05;
pub const VIVANTE: u8 = 0x06;
pub const BROADCOM: u8 = 0x07;
pub const ARM: u8 = 0x08;
pub const ALLWINNER: u8 = 0x09;
pub const AMLOGIC: u8 = 0x0a;
pub const VS: u8 = 0x0b;
}
#[must_use]
pub const fn mod_code(vendor: u8, body: u64) -> u64 {
((vendor as u64) << 56) | (body & 0x00ff_ffff_ffff_ffff)
}
pub const ARM_16X16_BLOCK_U_INTERLEAVED: Modifier =
Modifier(mod_code(vendor::ARM, (arm_type::MISC << 52) | 1));
pub mod arm_type {
pub const AFBC: u64 = 0x0;
pub const MISC: u64 = 0x1;
pub const AFRC: u64 = 0x2;
}
pub mod afbc_block {
pub const SIZE_16X16: u64 = 1;
pub const SIZE_32X8: u64 = 2;
pub const SIZE_64X4: u64 = 3;
pub const SIZE_32X8_64X4: u64 = 4;
}
pub mod afbc_flag {
pub const YTR: u64 = 1 << 4;
pub const SPLIT: u64 = 1 << 5;
pub const SPARSE: u64 = 1 << 6;
pub const CBR: u64 = 1 << 7;
pub const TILED: u64 = 1 << 8;
pub const SC: u64 = 1 << 9;
pub const DB: u64 = 1 << 10;
pub const BCH: u64 = 1 << 11;
pub const USM: u64 = 1 << 12;
}
pub mod broadcom {
pub const VC4_T_TILED: u64 = 1;
pub const SAND32: u64 = 2;
pub const SAND64: u64 = 3;
pub const SAND128: u64 = 4;
pub const SAND256: u64 = 5;
pub const UIF: u64 = 6;
}
const AMD_DCC_SHIFT: u64 = 13;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[allow(
clippy::exhaustive_structs,
reason = "a value defined by its fields; there is nothing to add to it"
)]
pub struct Modifier(pub u64);
impl Default for Modifier {
fn default() -> Self {
Self::LINEAR
}
}
impl Modifier {
pub const LINEAR: Self = Self(0);
pub const INVALID: Self = Self(mod_code(vendor::NONE, (1 << 56) - 1));
#[must_use]
pub const fn vendor(self) -> u8 {
(self.0 >> 56) as u8
}
#[must_use]
pub const fn body(self) -> u64 {
self.0 & 0x00ff_ffff_ffff_ffff
}
#[must_use]
pub const fn is_linear(self) -> bool {
self.0 == Self::LINEAR.0
}
#[must_use]
pub const fn is_invalid(self) -> bool {
self.0 == Self::INVALID.0
}
#[must_use]
const fn amd_has_dcc(self) -> bool {
self.vendor() == vendor::AMD && ((self.0 >> AMD_DCC_SHIFT) & 0x1) != 0
}
}
impl From<u64> for Modifier {
fn from(value: u64) -> Self {
Self(value)
}
}
impl From<Modifier> for u64 {
fn from(value: Modifier) -> Self {
value.0
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[allow(
clippy::exhaustive_enums,
reason = "drmkit-planes scores it with an exhaustive match, so a new class fails to compile until it is scored"
)]
pub enum BandwidthClass {
Linear,
Tiling,
Compression,
}
#[must_use]
pub const fn classify(m: Modifier) -> BandwidthClass {
if m.is_linear() || m.is_invalid() {
return BandwidthClass::Linear;
}
match m.vendor() {
vendor::ARM => {
if m.0 == ARM_16X16_BLOCK_U_INTERLEAVED.0 {
return BandwidthClass::Tiling;
}
let ty = (m.0 >> 52) & 0xf;
if ty == arm_type::AFBC || ty == arm_type::AFRC {
BandwidthClass::Compression
} else {
BandwidthClass::Tiling
}
}
vendor::AMD => {
if m.amd_has_dcc() {
BandwidthClass::Compression
} else {
BandwidthClass::Tiling
}
}
vendor::QCOM => BandwidthClass::Compression,
vendor::NVIDIA => {
if ((m.0 >> 23) & 0x7) != 0 {
BandwidthClass::Compression
} else {
BandwidthClass::Tiling
}
}
vendor::VS => {
if m.body() == 0 {
return BandwidthClass::Linear;
}
if ((m.0 >> 54) & 0x3) == 0x1 {
BandwidthClass::Compression
} else {
BandwidthClass::Tiling
}
}
_ => BandwidthClass::Tiling,
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
#[allow(
clippy::exhaustive_enums,
reason = "a closed set: there is no further variant to add"
)]
pub enum Rotation {
#[default]
Rotate0,
Rotate90,
Rotate180,
Rotate270,
}
impl Rotation {
#[must_use]
pub const fn transposes(self) -> bool {
matches!(self, Self::Rotate90 | Self::Rotate270)
}
}
#[must_use]
pub const fn rotation_compatible(m: Modifier, r: Rotation) -> bool {
if !r.transposes() {
return true; }
if m.is_linear() {
return false; }
!m.amd_has_dcc()
}
impl fmt::Display for Modifier {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(&crate::describe(*self))
}
}