1
0
Fork 0
forked from wry/wry
wry/src/format.rs
2026-02-13 11:13:37 +01:00

584 lines
15 KiB
Rust

use {
crate::{
gfx_apis::gl::sys::{GL_BGRA_EXT, GL_RGBA, GL_RGBA8, GL_UNSIGNED_BYTE, GLenum, GLint},
pipewire::pw_pod::{
SPA_VIDEO_FORMAT_ABGR_210LE, SPA_VIDEO_FORMAT_ARGB_210LE, SPA_VIDEO_FORMAT_BGR,
SPA_VIDEO_FORMAT_BGR15, SPA_VIDEO_FORMAT_BGR16, SPA_VIDEO_FORMAT_BGRA,
SPA_VIDEO_FORMAT_BGRx, SPA_VIDEO_FORMAT_GRAY8, SPA_VIDEO_FORMAT_RGB,
SPA_VIDEO_FORMAT_RGB16, SPA_VIDEO_FORMAT_RGBA, SPA_VIDEO_FORMAT_RGBx,
SPA_VIDEO_FORMAT_UNKNOWN, SPA_VIDEO_FORMAT_xBGR_210LE, SPA_VIDEO_FORMAT_xRGB_210LE,
SpaVideoFormat,
},
},
ahash::AHashMap,
ash::vk,
jay_config::video::Format as ConfigFormat,
once_cell::sync::Lazy,
std::{
fmt,
fmt::{Debug, Write},
},
};
#[derive(Copy, Clone, Debug)]
pub struct FormatShmInfo {
pub gl_format: GLint,
pub gl_internal_format: GLenum,
pub gl_type: GLint,
}
#[derive(Copy, Clone, Debug)]
pub struct Format {
pub name: &'static str,
pub vk_format: vk::Format,
pub drm: u32,
pub wl_id: Option<u32>,
pub external_only_guess: bool,
pub has_alpha: bool,
pub pipewire: SpaVideoFormat,
pub opaque: Option<&'static Format>,
pub shm_info: Option<FormatShmInfo>,
pub config: ConfigFormat,
pub bpp: u32,
}
const fn default(config: ConfigFormat) -> Format {
Format {
name: "",
vk_format: vk::Format::UNDEFINED,
drm: 0,
wl_id: None,
external_only_guess: false,
has_alpha: false,
pipewire: SPA_VIDEO_FORMAT_UNKNOWN,
opaque: None,
shm_info: None,
config,
bpp: 4,
}
}
impl PartialEq for Format {
fn eq(&self, other: &Self) -> bool {
self.drm == other.drm
}
}
impl Eq for Format {}
static FORMATS_MAP: Lazy<AHashMap<u32, &'static Format>> = Lazy::new(|| {
let mut map = AHashMap::new();
for format in FORMATS {
assert!(map.insert(format.drm, format).is_none());
}
map
});
static PW_FORMATS_MAP: Lazy<AHashMap<SpaVideoFormat, &'static Format>> = Lazy::new(|| {
let mut map = AHashMap::new();
for format in FORMATS {
if format.pipewire != SPA_VIDEO_FORMAT_UNKNOWN {
assert!(map.insert(format.pipewire, format).is_none());
}
}
map
});
static FORMATS_REFS: Lazy<Vec<&'static Format>> = Lazy::new(|| FORMATS.iter().collect());
static FORMATS_NAMES: Lazy<AHashMap<&'static str, &'static Format>> = Lazy::new(|| {
let mut map = AHashMap::new();
for format in FORMATS {
assert!(map.insert(format.name, format).is_none());
}
map
});
static FORMATS_CONFIG: Lazy<AHashMap<ConfigFormat, &'static Format>> = Lazy::new(|| {
let mut map = AHashMap::new();
for format in FORMATS {
assert!(map.insert(format.config, format).is_none());
}
map
});
#[test]
fn formats_dont_panic() {
formats();
pw_formats();
named_formats();
config_formats();
}
pub fn formats() -> &'static AHashMap<u32, &'static Format> {
&FORMATS_MAP
}
pub fn pw_formats() -> &'static AHashMap<SpaVideoFormat, &'static Format> {
&PW_FORMATS_MAP
}
pub fn ref_formats() -> &'static [&'static Format] {
&FORMATS_REFS
}
pub fn named_formats() -> &'static AHashMap<&'static str, &'static Format> {
&FORMATS_NAMES
}
pub fn config_formats() -> &'static AHashMap<ConfigFormat, &'static Format> {
&FORMATS_CONFIG
}
const fn fourcc_code(a: char, b: char, c: char, d: char) -> u32 {
(a as u32) | ((b as u32) << 8) | ((c as u32) << 16) | ((d as u32) << 24)
}
#[expect(dead_code)]
pub fn debug(fourcc: u32) -> impl Debug {
fmt::from_fn(move |fmt| {
fmt.write_char(fourcc as u8 as char)?;
fmt.write_char((fourcc >> 8) as u8 as char)?;
fmt.write_char((fourcc >> 16) as u8 as char)?;
fmt.write_char((fourcc >> 24) as u8 as char)?;
Ok(())
})
}
const ARGB8888_ID: u32 = 0;
const ARGB8888_DRM: u32 = fourcc_code('A', 'R', '2', '4');
const XRGB8888_ID: u32 = 1;
const XRGB8888_DRM: u32 = fourcc_code('X', 'R', '2', '4');
pub fn map_wayland_format_id(id: u32) -> u32 {
match id {
ARGB8888_ID => ARGB8888_DRM,
XRGB8888_ID => XRGB8888_DRM,
_ => id,
}
}
pub static ARGB8888: &Format = &Format {
name: "argb8888",
shm_info: Some(FormatShmInfo {
gl_format: GL_BGRA_EXT,
gl_internal_format: GL_RGBA8,
gl_type: GL_UNSIGNED_BYTE,
}),
vk_format: vk::Format::B8G8R8A8_UNORM,
bpp: 4,
drm: ARGB8888_DRM,
wl_id: Some(ARGB8888_ID),
external_only_guess: false,
has_alpha: true,
pipewire: SPA_VIDEO_FORMAT_BGRA,
opaque: Some(XRGB8888),
config: ConfigFormat::ARGB8888,
};
pub static XRGB8888: &Format = &Format {
name: "xrgb8888",
shm_info: Some(FormatShmInfo {
gl_format: GL_BGRA_EXT,
gl_internal_format: GL_RGBA8,
gl_type: GL_UNSIGNED_BYTE,
}),
vk_format: vk::Format::B8G8R8A8_UNORM,
bpp: 4,
drm: XRGB8888_DRM,
wl_id: Some(XRGB8888_ID),
external_only_guess: false,
has_alpha: false,
pipewire: SPA_VIDEO_FORMAT_BGRx,
opaque: None,
config: ConfigFormat::XRGB8888,
};
static ABGR8888: &Format = &Format {
name: "abgr8888",
shm_info: Some(FormatShmInfo {
gl_format: GL_RGBA,
gl_internal_format: GL_RGBA8,
gl_type: GL_UNSIGNED_BYTE,
}),
vk_format: vk::Format::R8G8B8A8_UNORM,
bpp: 4,
drm: fourcc_code('A', 'B', '2', '4'),
wl_id: None,
external_only_guess: false,
has_alpha: true,
pipewire: SPA_VIDEO_FORMAT_RGBA,
opaque: Some(XBGR8888),
config: ConfigFormat::ABGR8888,
};
static XBGR8888: &Format = &Format {
name: "xbgr8888",
shm_info: Some(FormatShmInfo {
gl_format: GL_RGBA,
gl_internal_format: GL_RGBA8,
gl_type: GL_UNSIGNED_BYTE,
}),
vk_format: vk::Format::R8G8B8A8_UNORM,
bpp: 4,
drm: fourcc_code('X', 'B', '2', '4'),
wl_id: None,
external_only_guess: false,
has_alpha: false,
pipewire: SPA_VIDEO_FORMAT_RGBx,
opaque: None,
config: ConfigFormat::XBGR8888,
};
static R8: &Format = &Format {
name: "r8",
vk_format: vk::Format::R8_UNORM,
bpp: 1,
drm: fourcc_code('R', '8', ' ', ' '),
pipewire: SPA_VIDEO_FORMAT_GRAY8,
..default(ConfigFormat::R8)
};
static GR88: &Format = &Format {
name: "gr88",
vk_format: vk::Format::R8G8_UNORM,
bpp: 2,
drm: fourcc_code('G', 'R', '8', '8'),
..default(ConfigFormat::GR88)
};
static RGB888: &Format = &Format {
name: "rgb888",
vk_format: vk::Format::B8G8R8_UNORM,
bpp: 3,
drm: fourcc_code('R', 'G', '2', '4'),
pipewire: SPA_VIDEO_FORMAT_BGR,
..default(ConfigFormat::RGB888)
};
static BGR888: &Format = &Format {
name: "bgr888",
vk_format: vk::Format::R8G8B8_UNORM,
bpp: 3,
drm: fourcc_code('B', 'G', '2', '4'),
pipewire: SPA_VIDEO_FORMAT_RGB,
..default(ConfigFormat::BGR888)
};
static RGBA4444: &Format = &Format {
name: "rgba4444",
vk_format: vk::Format::R4G4B4A4_UNORM_PACK16,
bpp: 2,
drm: fourcc_code('R', 'A', '1', '2'),
has_alpha: true,
opaque: Some(RGBX4444),
..default(ConfigFormat::RGBA4444)
};
static RGBX4444: &Format = &Format {
name: "rgbx4444",
vk_format: vk::Format::R4G4B4A4_UNORM_PACK16,
bpp: 2,
drm: fourcc_code('R', 'X', '1', '2'),
..default(ConfigFormat::RGBX4444)
};
static BGRA4444: &Format = &Format {
name: "bgra4444",
vk_format: vk::Format::B4G4R4A4_UNORM_PACK16,
bpp: 2,
drm: fourcc_code('B', 'A', '1', '2'),
has_alpha: true,
opaque: Some(BGRX4444),
..default(ConfigFormat::BGRA4444)
};
static BGRX4444: &Format = &Format {
name: "bgrx4444",
vk_format: vk::Format::B4G4R4A4_UNORM_PACK16,
bpp: 2,
drm: fourcc_code('B', 'X', '1', '2'),
..default(ConfigFormat::BGRX4444)
};
static RGB565: &Format = &Format {
name: "rgb565",
vk_format: vk::Format::R5G6B5_UNORM_PACK16,
bpp: 2,
drm: fourcc_code('R', 'G', '1', '6'),
pipewire: SPA_VIDEO_FORMAT_BGR16,
..default(ConfigFormat::RGB565)
};
static BGR565: &Format = &Format {
name: "bgr565",
vk_format: vk::Format::B5G6R5_UNORM_PACK16,
bpp: 2,
drm: fourcc_code('B', 'G', '1', '6'),
pipewire: SPA_VIDEO_FORMAT_RGB16,
..default(ConfigFormat::BGR565)
};
static RGBA5551: &Format = &Format {
name: "rgba5551",
vk_format: vk::Format::R5G5B5A1_UNORM_PACK16,
bpp: 2,
drm: fourcc_code('R', 'A', '1', '5'),
has_alpha: true,
opaque: Some(RGBX5551),
..default(ConfigFormat::RGBA5551)
};
static RGBX5551: &Format = &Format {
name: "rgbx5551",
vk_format: vk::Format::R5G5B5A1_UNORM_PACK16,
bpp: 2,
drm: fourcc_code('R', 'X', '1', '5'),
..default(ConfigFormat::RGBX5551)
};
static BGRA5551: &Format = &Format {
name: "bgra5551",
vk_format: vk::Format::B5G5R5A1_UNORM_PACK16,
bpp: 2,
drm: fourcc_code('B', 'A', '1', '5'),
has_alpha: true,
opaque: Some(BGRX5551),
..default(ConfigFormat::BGRA5551)
};
static BGRX5551: &Format = &Format {
name: "bgrx5551",
vk_format: vk::Format::B5G5R5A1_UNORM_PACK16,
bpp: 2,
drm: fourcc_code('B', 'X', '1', '5'),
..default(ConfigFormat::BGRX5551)
};
static ARGB1555: &Format = &Format {
name: "argb1555",
vk_format: vk::Format::A1R5G5B5_UNORM_PACK16,
bpp: 2,
drm: fourcc_code('A', 'R', '1', '5'),
has_alpha: true,
opaque: Some(XRGB1555),
..default(ConfigFormat::ARGB1555)
};
static XRGB1555: &Format = &Format {
name: "xrgb1555",
vk_format: vk::Format::A1R5G5B5_UNORM_PACK16,
bpp: 2,
drm: fourcc_code('X', 'R', '1', '5'),
pipewire: SPA_VIDEO_FORMAT_BGR15,
..default(ConfigFormat::XRGB1555)
};
static ARGB2101010: &Format = &Format {
name: "argb2101010",
vk_format: vk::Format::A2R10G10B10_UNORM_PACK32,
bpp: 4,
drm: fourcc_code('A', 'R', '3', '0'),
has_alpha: true,
opaque: Some(XRGB2101010),
pipewire: SPA_VIDEO_FORMAT_ARGB_210LE,
..default(ConfigFormat::ARGB2101010)
};
static XRGB2101010: &Format = &Format {
name: "xrgb2101010",
vk_format: vk::Format::A2R10G10B10_UNORM_PACK32,
bpp: 4,
drm: fourcc_code('X', 'R', '3', '0'),
pipewire: SPA_VIDEO_FORMAT_xRGB_210LE,
..default(ConfigFormat::XRGB2101010)
};
static ABGR2101010: &Format = &Format {
name: "abgr2101010",
vk_format: vk::Format::A2B10G10R10_UNORM_PACK32,
bpp: 4,
drm: fourcc_code('A', 'B', '3', '0'),
has_alpha: true,
opaque: Some(XBGR2101010),
pipewire: SPA_VIDEO_FORMAT_ABGR_210LE,
..default(ConfigFormat::ABGR2101010)
};
static XBGR2101010: &Format = &Format {
name: "xbgr2101010",
vk_format: vk::Format::A2B10G10R10_UNORM_PACK32,
bpp: 4,
drm: fourcc_code('X', 'B', '3', '0'),
pipewire: SPA_VIDEO_FORMAT_xBGR_210LE,
..default(ConfigFormat::XBGR2101010)
};
static ABGR16161616: &Format = &Format {
name: "abgr16161616",
vk_format: vk::Format::R16G16B16A16_UNORM,
bpp: 8,
drm: fourcc_code('A', 'B', '4', '8'),
has_alpha: true,
opaque: Some(XBGR16161616),
..default(ConfigFormat::ABGR16161616)
};
static XBGR16161616: &Format = &Format {
name: "xbgr16161616",
vk_format: vk::Format::R16G16B16A16_UNORM,
bpp: 8,
drm: fourcc_code('X', 'B', '4', '8'),
..default(ConfigFormat::XBGR16161616)
};
pub static ABGR16161616F: &Format = &Format {
name: "abgr16161616f",
vk_format: vk::Format::R16G16B16A16_SFLOAT,
bpp: 8,
drm: fourcc_code('A', 'B', '4', 'H'),
has_alpha: true,
opaque: Some(XBGR16161616F),
..default(ConfigFormat::ABGR16161616F)
};
static XBGR16161616F: &Format = &Format {
name: "xbgr16161616f",
vk_format: vk::Format::R16G16B16A16_SFLOAT,
bpp: 8,
drm: fourcc_code('X', 'B', '4', 'H'),
..default(ConfigFormat::XBGR16161616F)
};
static BGR161616: &Format = &Format {
name: "bgr161616",
vk_format: vk::Format::R16G16B16_UNORM,
bpp: 6,
drm: fourcc_code('B', 'G', '4', '8'),
..default(ConfigFormat::BGR161616)
};
static R16F: &Format = &Format {
name: "r16f",
vk_format: vk::Format::R16_SFLOAT,
bpp: 2,
drm: fourcc_code('R', ' ', ' ', 'H'),
..default(ConfigFormat::R16F)
};
static GR1616F: &Format = &Format {
name: "gr1616f",
vk_format: vk::Format::R16G16_SFLOAT,
bpp: 4,
drm: fourcc_code('G', 'R', ' ', 'H'),
..default(ConfigFormat::GR1616F)
};
static BGR161616F: &Format = &Format {
name: "bgr161616f",
vk_format: vk::Format::R16G16B16_SFLOAT,
bpp: 6,
drm: fourcc_code('B', 'G', 'R', 'H'),
..default(ConfigFormat::BGR161616F)
};
static R32F: &Format = &Format {
name: "r32f",
vk_format: vk::Format::R32_SFLOAT,
bpp: 4,
drm: fourcc_code('R', ' ', ' ', 'F'),
..default(ConfigFormat::R32F)
};
static GR3232F: &Format = &Format {
name: "gr3232f",
vk_format: vk::Format::R32G32_SFLOAT,
bpp: 8,
drm: fourcc_code('G', 'R', ' ', 'F'),
..default(ConfigFormat::GR3232F)
};
static BGR323232F: &Format = &Format {
name: "bgr323232f",
vk_format: vk::Format::R32G32B32_SFLOAT,
bpp: 12,
drm: fourcc_code('B', 'G', 'R', 'F'),
..default(ConfigFormat::BGR323232F)
};
static ABGR32323232F: &Format = &Format {
name: "abgr32323232f",
vk_format: vk::Format::R32G32B32A32_SFLOAT,
bpp: 16,
drm: fourcc_code('A', 'B', '8', 'F'),
has_alpha: true,
..default(ConfigFormat::ABGR32323232F)
};
pub static FORMATS: &[Format] = &[
*ARGB8888,
*XRGB8888,
*ABGR8888,
*XBGR8888,
*R8,
*GR88,
*RGB888,
*BGR888,
#[cfg(target_endian = "little")]
*RGBA4444,
#[cfg(target_endian = "little")]
*RGBX4444,
#[cfg(target_endian = "little")]
*BGRA4444,
#[cfg(target_endian = "little")]
*BGRX4444,
#[cfg(target_endian = "little")]
*RGB565,
#[cfg(target_endian = "little")]
*BGR565,
#[cfg(target_endian = "little")]
*RGBA5551,
#[cfg(target_endian = "little")]
*RGBX5551,
#[cfg(target_endian = "little")]
*BGRA5551,
#[cfg(target_endian = "little")]
*BGRX5551,
#[cfg(target_endian = "little")]
*ARGB1555,
#[cfg(target_endian = "little")]
*XRGB1555,
#[cfg(target_endian = "little")]
*ARGB2101010,
#[cfg(target_endian = "little")]
*XRGB2101010,
#[cfg(target_endian = "little")]
*ABGR2101010,
#[cfg(target_endian = "little")]
*XBGR2101010,
#[cfg(target_endian = "little")]
*ABGR16161616,
#[cfg(target_endian = "little")]
*XBGR16161616,
#[cfg(target_endian = "little")]
*ABGR16161616F,
#[cfg(target_endian = "little")]
*XBGR16161616F,
#[cfg(target_endian = "little")]
*BGR161616,
#[cfg(target_endian = "little")]
*R16F,
#[cfg(target_endian = "little")]
*GR1616F,
#[cfg(target_endian = "little")]
*BGR161616F,
#[cfg(target_endian = "little")]
*R32F,
#[cfg(target_endian = "little")]
*GR3232F,
#[cfg(target_endian = "little")]
*BGR323232F,
#[cfg(target_endian = "little")]
*ABGR32323232F,
];