use drm_ffi as ffi;
use drm_ffi::result::SystemError;
use drm_fourcc::{DrmFourcc, DrmModifier, UnrecognizedFourcc};
use bytemuck::allocation::TransparentWrapperAlloc;
pub mod atomic;
pub mod connector;
pub mod crtc;
pub mod dumbbuffer;
pub mod encoder;
pub mod framebuffer;
pub mod plane;
pub mod property;
use self::dumbbuffer::*;
use buffer;
use super::util::*;
use std::convert::TryFrom;
use std::mem;
use std::num::NonZeroUsize;
use std::ops::RangeBounds;
use std::os::unix::io::{AsRawFd, RawFd};
use std::time::Duration;
use core::num::NonZeroU32;
pub type RawResourceHandle = NonZeroU32;
pub trait ResourceHandle:
From<RawResourceHandle> + Into<RawResourceHandle> + Into<u32> + Copy + Sized
{
const FFI_TYPE: u32;
}
pub fn from_u32<T: From<RawResourceHandle>>(raw: u32) -> Option<T> {
RawResourceHandle::new(raw).map(T::from)
}
pub trait Device: super::Device {
fn resource_handles(&self) -> Result<ResourceHandles, SystemError> {
let mut fbs = Vec::new();
let mut crtcs = Vec::new();
let mut connectors = Vec::new();
let mut encoders = Vec::new();
let ffi_res = ffi::mode::get_resources(
self.as_fd().as_raw_fd(),
Some(&mut fbs),
Some(&mut crtcs),
Some(&mut connectors),
Some(&mut encoders),
)?;
let res = unsafe {
ResourceHandles {
fbs: transmute_vec_from_u32(fbs),
crtcs: transmute_vec_from_u32(crtcs),
connectors: transmute_vec_from_u32(connectors),
encoders: transmute_vec_from_u32(encoders),
width: (ffi_res.min_width, ffi_res.max_width),
height: (ffi_res.min_height, ffi_res.max_height),
}
};
Ok(res)
}
fn plane_handles(&self) -> Result<Vec<plane::Handle>, SystemError> {
let mut planes = Vec::new();
let _ = ffi::mode::get_plane_resources(self.as_fd().as_raw_fd(), Some(&mut planes))?;
Ok(unsafe { transmute_vec_from_u32(planes) })
}
fn get_connector(
&self,
handle: connector::Handle,
force_probe: bool,
) -> Result<connector::Info, SystemError> {
let mut encoders = Vec::new();
let mut modes = Vec::new();
let ffi_info = ffi::mode::get_connector(
self.as_fd().as_raw_fd(),
handle.into(),
None,
None,
Some(&mut modes),
Some(&mut encoders),
force_probe,
)?;
let connector = connector::Info {
handle,
interface: connector::Interface::from(ffi_info.connector_type),
interface_id: ffi_info.connector_type_id,
connection: connector::State::from(ffi_info.connection),
size: match (ffi_info.mm_width, ffi_info.mm_height) {
(0, 0) => None,
(x, y) => Some((x, y)),
},
modes: Mode::wrap_vec(modes),
encoders: unsafe { transmute_vec_from_u32(encoders) },
curr_enc: unsafe { mem::transmute(ffi_info.encoder_id) },
};
Ok(connector)
}
fn get_encoder(&self, handle: encoder::Handle) -> Result<encoder::Info, SystemError> {
let info = ffi::mode::get_encoder(self.as_fd().as_raw_fd(), handle.into())?;
let enc = encoder::Info {
handle,
enc_type: encoder::Kind::from(info.encoder_type),
crtc: from_u32(info.crtc_id),
pos_crtcs: info.possible_crtcs,
pos_clones: info.possible_clones,
};
Ok(enc)
}
fn get_crtc(&self, handle: crtc::Handle) -> Result<crtc::Info, SystemError> {
let info = ffi::mode::get_crtc(self.as_fd().as_raw_fd(), handle.into())?;
let crtc = crtc::Info {
handle,
position: (info.x, info.y),
mode: match info.mode_valid {
0 => None,
_ => Some(Mode::from(info.mode)),
},
fb: from_u32(info.fb_id),
gamma_length: info.gamma_size,
};
Ok(crtc)
}
fn set_crtc(
&self,
handle: crtc::Handle,
framebuffer: Option<framebuffer::Handle>,
pos: (u32, u32),
conns: &[connector::Handle],
mode: Option<Mode>,
) -> Result<(), SystemError> {
let _info = ffi::mode::set_crtc(
self.as_fd().as_raw_fd(),
handle.into(),
framebuffer.map(Into::into).unwrap_or(0),
pos.0,
pos.1,
unsafe { &*(conns as *const _ as *const [u32]) },
mode.map(|m| m.into()),
)?;
Ok(())
}
fn get_framebuffer(
&self,
handle: framebuffer::Handle,
) -> Result<framebuffer::Info, SystemError> {
let info = ffi::mode::get_framebuffer(self.as_fd().as_raw_fd(), handle.into())?;
let fb = framebuffer::Info {
handle,
size: (info.width, info.height),
pitch: info.pitch,
bpp: info.bpp,
depth: info.depth,
buffer: from_u32(info.handle),
};
Ok(fb)
}
fn get_planar_framebuffer(
&self,
handle: framebuffer::Handle,
) -> Result<framebuffer::PlanarInfo, SystemError> {
let info = ffi::mode::get_framebuffer2(self.as_fd().as_raw_fd(), handle.into())?;
let pixel_format = match DrmFourcc::try_from(info.pixel_format) {
Ok(pixel_format) => pixel_format,
Err(UnrecognizedFourcc(_)) => return Err(SystemError::UnknownFourcc),
};
let fb = framebuffer::PlanarInfo {
handle,
size: (info.width, info.height),
pixel_format,
flags: info.flags,
buffers: bytemuck::cast(info.handles),
pitches: info.pitches,
offsets: info.offsets,
modifier: info.modifier.map(DrmModifier::from),
};
Ok(fb)
}
fn add_framebuffer<B>(
&self,
buffer: &B,
depth: u32,
bpp: u32,
) -> Result<framebuffer::Handle, SystemError>
where
B: buffer::Buffer + ?Sized,
{
let (w, h) = buffer.size();
let info = ffi::mode::add_fb(
self.as_fd().as_raw_fd(),
w,
h,
buffer.pitch(),
bpp,
depth,
buffer.handle().into(),
)?;
Ok(from_u32(info.fb_id).unwrap())
}
fn add_planar_framebuffer<B>(
&self,
planar_buffer: &B,
modifiers: &[Option<DrmModifier>; 4],
flags: u32,
) -> Result<framebuffer::Handle, SystemError>
where
B: buffer::PlanarBuffer + ?Sized,
{
let (w, h) = planar_buffer.size();
let opt_handles = planar_buffer.handles();
let handles = bytemuck::cast(opt_handles);
let mods = [
modifiers[0].map(Into::<u64>::into).unwrap_or(0),
modifiers[1].map(Into::<u64>::into).unwrap_or(0),
modifiers[2].map(Into::<u64>::into).unwrap_or(0),
modifiers[3].map(Into::<u64>::into).unwrap_or(0),
];
let info = ffi::mode::add_fb2(
self.as_fd().as_raw_fd(),
w,
h,
planar_buffer.format() as u32,
&handles,
&planar_buffer.pitches(),
&planar_buffer.offsets(),
&mods,
flags,
)?;
Ok(from_u32(info.fb_id).unwrap())
}
fn dirty_framebuffer(
&self,
handle: framebuffer::Handle,
clips: &[ClipRect],
) -> Result<(), SystemError> {
ffi::mode::dirty_fb(self.as_fd().as_raw_fd(), handle.into(), clips)?;
Ok(())
}
fn destroy_framebuffer(&self, handle: framebuffer::Handle) -> Result<(), SystemError> {
ffi::mode::rm_fb(self.as_fd().as_raw_fd(), handle.into())
}
fn get_plane(&self, handle: plane::Handle) -> Result<plane::Info, SystemError> {
let mut formats = Vec::new();
let info =
ffi::mode::get_plane(self.as_fd().as_raw_fd(), handle.into(), Some(&mut formats))?;
let plane = plane::Info {
handle,
crtc: from_u32(info.crtc_id),
fb: from_u32(info.fb_id),
pos_crtcs: info.possible_crtcs,
formats: unsafe { transmute_vec_from_u32(formats) },
};
Ok(plane)
}
fn set_plane(
&self,
handle: plane::Handle,
crtc: crtc::Handle,
framebuffer: Option<framebuffer::Handle>,
flags: u32,
crtc_rect: (i32, i32, u32, u32),
src_rect: (u32, u32, u32, u32),
) -> Result<(), SystemError> {
let _info = ffi::mode::set_plane(
self.as_fd().as_raw_fd(),
handle.into(),
crtc.into(),
framebuffer.map(Into::into).unwrap_or(0),
flags,
crtc_rect.0,
crtc_rect.1,
crtc_rect.2,
crtc_rect.3,
src_rect.0,
src_rect.1,
src_rect.2,
src_rect.3,
)?;
Ok(())
}
fn get_property(&self, handle: property::Handle) -> Result<property::Info, SystemError> {
let mut values = Vec::new();
let mut enums = Vec::new();
let info = ffi::mode::get_property(
self.as_fd().as_raw_fd(),
handle.into(),
Some(&mut values),
Some(&mut enums),
)?;
let flags = ModePropFlags::from_bits_truncate(info.flags);
let val_type = {
use self::property::ValueType;
if flags.contains(ModePropFlags::RANGE) {
let min = values[0];
let max = values[1];
match (min, max) {
(0, 1) => ValueType::Boolean,
(min, max) => ValueType::UnsignedRange(min, max),
}
} else if flags.contains(ModePropFlags::SIGNED_RANGE) {
let min = values[0];
let max = values[1];
ValueType::SignedRange(min as i64, max as i64)
} else if flags.contains(ModePropFlags::ENUM) {
let enum_values = self::property::EnumValues {
values,
enums: property::EnumValue::wrap_vec(enums),
};
ValueType::Enum(enum_values)
} else if flags.contains(ModePropFlags::BLOB) {
ValueType::Blob
} else if flags.contains(ModePropFlags::BITMASK) {
ValueType::Bitmask
} else if flags.contains(ModePropFlags::OBJECT) {
match values[0] as u32 {
ffi::DRM_MODE_OBJECT_CRTC => ValueType::CRTC,
ffi::DRM_MODE_OBJECT_CONNECTOR => ValueType::Connector,
ffi::DRM_MODE_OBJECT_ENCODER => ValueType::Encoder,
ffi::DRM_MODE_OBJECT_FB => ValueType::Framebuffer,
ffi::DRM_MODE_OBJECT_PLANE => ValueType::Plane,
ffi::DRM_MODE_OBJECT_PROPERTY => ValueType::Property,
ffi::DRM_MODE_OBJECT_BLOB => ValueType::Blob,
ffi::DRM_MODE_OBJECT_ANY => ValueType::Object,
_ => ValueType::Unknown,
}
} else {
ValueType::Unknown
}
};
let property = property::Info {
handle,
val_type,
mutable: !flags.contains(ModePropFlags::IMMUTABLE),
atomic: flags.contains(ModePropFlags::ATOMIC),
info,
};
Ok(property)
}
fn set_property<T: ResourceHandle>(
&self,
handle: T,
prop: property::Handle,
value: property::RawValue,
) -> Result<(), SystemError> {
ffi::mode::set_property(
self.as_fd().as_raw_fd(),
prop.into(),
handle.into(),
T::FFI_TYPE,
value,
)?;
Ok(())
}
fn create_property_blob<T>(&self, data: &T) -> Result<property::Value<'static>, SystemError> {
let data = unsafe {
std::slice::from_raw_parts_mut(data as *const _ as *mut u8, mem::size_of::<T>())
};
let blob = ffi::mode::create_property_blob(self.as_fd().as_raw_fd(), data)?;
Ok(property::Value::Blob(blob.blob_id.into()))
}
fn get_property_blob(&self, blob: u64) -> Result<Vec<u8>, SystemError> {
let mut data = Vec::new();
let _ =
ffi::mode::get_property_blob(self.as_fd().as_raw_fd(), blob as u32, Some(&mut data))?;
Ok(data)
}
fn destroy_property_blob(&self, blob: u64) -> Result<(), SystemError> {
ffi::mode::destroy_property_blob(self.as_fd().as_raw_fd(), blob as u32)?;
Ok(())
}
fn get_modes(&self, handle: connector::Handle) -> Result<Vec<Mode>, SystemError> {
let mut modes = Vec::new();
let _ffi_info = ffi::mode::get_connector(
self.as_fd().as_raw_fd(),
handle.into(),
None,
None,
Some(&mut modes),
None,
false,
)?;
Ok(Mode::wrap_vec(modes))
}
fn get_properties<T: ResourceHandle>(
&self,
handle: T,
) -> Result<PropertyValueSet, SystemError> {
let mut prop_ids = Vec::new();
let mut prop_vals = Vec::new();
ffi::mode::get_properties(
self.as_fd().as_raw_fd(),
handle.into(),
T::FFI_TYPE,
Some(&mut prop_ids),
Some(&mut prop_vals),
)?;
let prop_val_set = PropertyValueSet {
prop_ids: unsafe { transmute_vec_from_u32(prop_ids) },
prop_vals,
};
Ok(prop_val_set)
}
fn get_gamma(
&self,
crtc: crtc::Handle,
red: &mut [u16],
green: &mut [u16],
blue: &mut [u16],
) -> Result<(), SystemError> {
let crtc_info = self.get_crtc(crtc)?;
if crtc_info.gamma_length as usize > red.len()
|| crtc_info.gamma_length as usize > green.len()
|| crtc_info.gamma_length as usize > blue.len()
{
return Err(SystemError::InvalidArgument);
}
ffi::mode::get_gamma(
self.as_fd().as_raw_fd(),
crtc.into(),
crtc_info.gamma_length as usize,
red,
green,
blue,
)?;
Ok(())
}
fn set_gamma(
&self,
crtc: crtc::Handle,
red: &[u16],
green: &[u16],
blue: &[u16],
) -> Result<(), SystemError> {
let crtc_info = self.get_crtc(crtc)?;
if crtc_info.gamma_length as usize > red.len()
|| crtc_info.gamma_length as usize > green.len()
|| crtc_info.gamma_length as usize > blue.len()
{
return Err(SystemError::InvalidArgument);
}
ffi::mode::set_gamma(
self.as_fd().as_raw_fd(),
crtc.into(),
crtc_info.gamma_length as usize,
red,
green,
blue,
)?;
Ok(())
}
fn open_buffer(&self, name: buffer::Name) -> Result<buffer::Handle, SystemError> {
let info = drm_ffi::gem::open(self.as_fd().as_raw_fd(), name.into())?;
Ok(from_u32(info.handle).unwrap())
}
fn close_buffer(&self, handle: buffer::Handle) -> Result<(), SystemError> {
let _info = drm_ffi::gem::close(self.as_fd().as_raw_fd(), handle.into())?;
Ok(())
}
fn create_dumb_buffer(
&self,
size: (u32, u32),
format: buffer::DrmFourcc,
bpp: u32,
) -> Result<DumbBuffer, SystemError> {
let info =
drm_ffi::mode::dumbbuffer::create(self.as_fd().as_raw_fd(), size.0, size.1, bpp, 0)?;
let dumb = DumbBuffer {
size: (info.width, info.height),
length: info.size as usize,
format,
pitch: info.pitch,
handle: from_u32(info.handle).unwrap(),
};
Ok(dumb)
}
fn map_dumb_buffer<'a>(
&self,
buffer: &'a mut DumbBuffer,
) -> Result<DumbMapping<'a>, SystemError> {
let info =
drm_ffi::mode::dumbbuffer::map(self.as_fd().as_raw_fd(), buffer.handle.into(), 0, 0)?;
let map = {
use nix::sys::mman;
let prot = mman::ProtFlags::PROT_READ | mman::ProtFlags::PROT_WRITE;
let flags = mman::MapFlags::MAP_SHARED;
let length = NonZeroUsize::new(buffer.length).ok_or(SystemError::InvalidArgument)?;
let fd = self.as_fd().as_raw_fd();
let offset = info.offset as _;
unsafe { mman::mmap(None, length, prot, flags, fd, offset)? }
};
let mapping = DumbMapping {
_phantom: ::std::marker::PhantomData,
map: unsafe { ::std::slice::from_raw_parts_mut(map as *mut _, buffer.length) },
};
Ok(mapping)
}
fn destroy_dumb_buffer(&self, buffer: DumbBuffer) -> Result<(), SystemError> {
let _info =
drm_ffi::mode::dumbbuffer::destroy(self.as_fd().as_raw_fd(), buffer.handle.into())?;
Ok(())
}
#[deprecated(note = "Usage of deprecated ioctl set_cursor: use a cursor plane instead")]
#[allow(deprecated)]
fn set_cursor<B>(&self, crtc: crtc::Handle, buffer: Option<&B>) -> Result<(), SystemError>
where
B: buffer::Buffer + ?Sized,
{
let (id, w, h) = buffer
.map(|buf| {
let (w, h) = buf.size();
(buf.handle().into(), w, h)
})
.unwrap_or((0, 0, 0));
drm_ffi::mode::set_cursor(self.as_fd().as_raw_fd(), crtc.into(), id, w, h)?;
Ok(())
}
#[deprecated(note = "Usage of deprecated ioctl set_cursor2: use a cursor plane instead")]
#[allow(deprecated)]
fn set_cursor2<B>(
&self,
crtc: crtc::Handle,
buffer: Option<&B>,
hotspot: (i32, i32),
) -> Result<(), SystemError>
where
B: buffer::Buffer + ?Sized,
{
let (id, w, h) = buffer
.map(|buf| {
let (w, h) = buf.size();
(buf.handle().into(), w, h)
})
.unwrap_or((0, 0, 0));
drm_ffi::mode::set_cursor2(
self.as_fd().as_raw_fd(),
crtc.into(),
id,
w,
h,
hotspot.0,
hotspot.1,
)?;
Ok(())
}
#[deprecated(note = "Usage of deprecated ioctl move_cursor: use a cursor plane instead")]
#[allow(deprecated)]
fn move_cursor(&self, crtc: crtc::Handle, pos: (i32, i32)) -> Result<(), SystemError> {
drm_ffi::mode::move_cursor(self.as_fd().as_raw_fd(), crtc.into(), pos.0, pos.1)?;
Ok(())
}
fn atomic_commit(
&self,
flags: AtomicCommitFlags,
mut req: atomic::AtomicModeReq,
) -> Result<(), SystemError> {
drm_ffi::mode::atomic_commit(
self.as_fd().as_raw_fd(),
flags.bits(),
unsafe { &mut *(&mut *req.objects as *mut _ as *mut [u32]) },
&mut req.count_props_per_object,
unsafe { &mut *(&mut *req.props as *mut _ as *mut [u32]) },
&mut req.values,
)
}
fn prime_fd_to_buffer(&self, fd: RawFd) -> Result<buffer::Handle, SystemError> {
let info = ffi::gem::fd_to_handle(self.as_fd().as_raw_fd(), fd)?;
Ok(from_u32(info.handle).unwrap())
}
fn buffer_to_prime_fd(&self, handle: buffer::Handle, flags: u32) -> Result<RawFd, SystemError> {
let info = ffi::gem::handle_to_fd(self.as_fd().as_raw_fd(), handle.into(), flags)?;
Ok(info.fd)
}
fn page_flip(
&self,
handle: crtc::Handle,
framebuffer: framebuffer::Handle,
flags: PageFlipFlags,
target_sequence: Option<PageFlipTarget>,
) -> Result<(), SystemError> {
let mut flags = flags.bits();
let sequence = match target_sequence {
Some(PageFlipTarget::Absolute(n)) => {
flags |= ffi::drm_sys::DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE;
n
}
Some(PageFlipTarget::Relative(n)) => {
flags |= ffi::drm_sys::DRM_MODE_PAGE_FLIP_TARGET_RELATIVE;
n
}
None => 0,
};
ffi::mode::page_flip(
self.as_fd().as_raw_fd(),
handle.into(),
framebuffer.into(),
flags,
sequence,
)?;
Ok(())
}
fn receive_events(&self) -> Result<Events, SystemError>
where
Self: Sized,
{
let mut event_buf: [u8; 1024] = [0; 1024];
let amount = ::nix::unistd::read(self.as_fd().as_raw_fd(), &mut event_buf)?;
Ok(Events {
event_buf,
amount,
i: 0,
})
}
}
bitflags::bitflags! {
pub struct PageFlipFlags : u32 {
const EVENT = ffi::drm_sys::DRM_MODE_PAGE_FLIP_EVENT;
const ASYNC = ffi::drm_sys::DRM_MODE_PAGE_FLIP_ASYNC;
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum PageFlipTarget {
Absolute(u32),
Relative(u32),
}
pub struct Events {
event_buf: [u8; 1024],
amount: usize,
i: usize,
}
pub enum Event {
Vblank(VblankEvent),
PageFlip(PageFlipEvent),
Unknown(Vec<u8>),
}
pub struct VblankEvent {
pub frame: u32,
pub time: Duration,
pub crtc: crtc::Handle,
pub user_data: usize,
}
pub struct PageFlipEvent {
pub frame: u32,
pub duration: Duration,
pub crtc: crtc::Handle,
}
impl Iterator for Events {
type Item = Event;
fn next(&mut self) -> Option<Event> {
if self.amount > 0 && self.i < self.amount {
let event = unsafe { &*(self.event_buf.as_ptr().add(self.i) as *const ffi::drm_event) };
self.i += event.length as usize;
match event.type_ {
ffi::DRM_EVENT_VBLANK => {
let vblank_event =
unsafe { &*(event as *const _ as *const ffi::drm_event_vblank) };
Some(Event::Vblank(VblankEvent {
frame: vblank_event.sequence,
time: Duration::new(
vblank_event.tv_sec as u64,
vblank_event.tv_usec * 1000,
),
#[allow(clippy::unnecessary_cast)]
crtc: from_u32(vblank_event.crtc_id as u32).unwrap(),
user_data: vblank_event.user_data as usize,
}))
}
ffi::DRM_EVENT_FLIP_COMPLETE => {
let vblank_event =
unsafe { &*(event as *const _ as *const ffi::drm_event_vblank) };
Some(Event::PageFlip(PageFlipEvent {
frame: vblank_event.sequence,
duration: Duration::new(
vblank_event.tv_sec as u64,
vblank_event.tv_usec * 1000,
),
crtc: from_u32(if vblank_event.crtc_id != 0 {
vblank_event.crtc_id
} else {
vblank_event.user_data as u32
})
.unwrap(),
}))
}
_ => Some(Event::Unknown(
self.event_buf[self.i - (event.length as usize)..self.i].to_vec(),
)),
}
} else {
None
}
}
}
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct ResourceHandles {
pub fbs: Vec<framebuffer::Handle>,
pub crtcs: Vec<crtc::Handle>,
pub connectors: Vec<connector::Handle>,
pub encoders: Vec<encoder::Handle>,
width: (u32, u32),
height: (u32, u32),
}
impl ResourceHandles {
pub fn connectors(&self) -> &[connector::Handle] {
&self.connectors
}
pub fn encoders(&self) -> &[encoder::Handle] {
&self.encoders
}
pub fn crtcs(&self) -> &[crtc::Handle] {
&self.crtcs
}
pub fn framebuffers(&self) -> &[framebuffer::Handle] {
&self.fbs
}
pub fn supported_fb_width(&self) -> impl RangeBounds<u32> {
self.width.0..=self.width.1
}
pub fn supported_fb_height(&self) -> impl RangeBounds<u32> {
self.height.0..=self.height.1
}
pub fn filter_crtcs(&self, filter: CrtcListFilter) -> Vec<crtc::Handle> {
self.crtcs
.iter()
.enumerate()
.filter(|&(n, _)| (1 << n) & filter.0 != 0)
.map(|(_, &e)| e)
.collect()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct CrtcListFilter(u32);
#[repr(transparent)]
#[derive(Copy, Clone, Hash, PartialEq, Eq, bytemuck::TransparentWrapper)]
pub struct Mode {
mode: ffi::drm_mode_modeinfo,
}
impl Mode {
pub fn name(&self) -> &std::ffi::CStr {
unsafe { std::ffi::CStr::from_ptr(&self.mode.name[0] as _) }
}
pub fn clock(&self) -> u32 {
self.mode.clock
}
pub fn size(&self) -> (u16, u16) {
(self.mode.hdisplay, self.mode.vdisplay)
}
pub fn hsync(&self) -> (u16, u16, u16) {
(self.mode.hsync_start, self.mode.hsync_end, self.mode.htotal)
}
pub fn vsync(&self) -> (u16, u16, u16) {
(self.mode.vsync_start, self.mode.vsync_end, self.mode.vtotal)
}
pub fn hskew(&self) -> u16 {
self.mode.hskew
}
pub fn vscan(&self) -> u16 {
self.mode.vscan
}
pub fn vrefresh(&self) -> u32 {
self.mode.vrefresh
}
pub fn mode_type(&self) -> ModeTypeFlags {
ModeTypeFlags::from_bits_truncate(self.mode.type_)
}
pub fn flags(&self) -> ModeFlags {
ModeFlags::from_bits_truncate(self.mode.flags)
}
}
impl From<ffi::drm_mode_modeinfo> for Mode {
fn from(raw: ffi::drm_mode_modeinfo) -> Mode {
Mode { mode: raw }
}
}
impl From<Mode> for ffi::drm_mode_modeinfo {
fn from(mode: Mode) -> Self {
mode.mode
}
}
impl std::fmt::Debug for Mode {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
f.debug_struct("Mode")
.field("name", &self.name())
.field("clock", &self.clock())
.field("size", &self.size())
.field("hsync", &self.hsync())
.field("vsync", &self.vsync())
.field("hskew", &self.hskew())
.field("vscan", &self.vscan())
.field("vrefresh", &self.vrefresh())
.field("mode_type", &self.mode_type())
.finish()
}
}
bitflags::bitflags! {
pub struct ModeTypeFlags : u32 {
#[deprecated]
const BUILTIN = ffi::DRM_MODE_TYPE_BUILTIN;
#[deprecated]
const CLOCK_C = ffi::DRM_MODE_TYPE_CLOCK_C;
#[deprecated]
const CRTC_C = ffi::DRM_MODE_TYPE_CRTC_C;
const PREFERRED = ffi::DRM_MODE_TYPE_PREFERRED;
#[deprecated]
const DEFAULT = ffi::DRM_MODE_TYPE_DEFAULT;
const USERDEF = ffi::DRM_MODE_TYPE_USERDEF;
const DRIVER = ffi::DRM_MODE_TYPE_DRIVER;
const ALL = ffi::DRM_MODE_TYPE_ALL;
}
}
bitflags::bitflags! {
pub struct ModeFlags: u32 {
const PHSYNC = ffi::DRM_MODE_FLAG_PHSYNC;
const NHSYNC = ffi::DRM_MODE_FLAG_NHSYNC;
const PVSYNC = ffi::DRM_MODE_FLAG_PVSYNC;
const NVSYNC = ffi::DRM_MODE_FLAG_NVSYNC;
const INTERLACE = ffi::DRM_MODE_FLAG_INTERLACE;
const DBLSCAN = ffi::DRM_MODE_FLAG_DBLSCAN;
const CSYNC = ffi::DRM_MODE_FLAG_CSYNC;
const PCSYNC = ffi::DRM_MODE_FLAG_PCSYNC;
const NCSYNC = ffi::DRM_MODE_FLAG_NCSYNC;
const HSKEW = ffi::DRM_MODE_FLAG_HSKEW;
#[deprecated]
const BCAST = ffi::DRM_MODE_FLAG_BCAST;
#[deprecated]
const PIXMUX = ffi::DRM_MODE_FLAG_PIXMUX;
const DBLCLK = ffi::DRM_MODE_FLAG_DBLCLK;
const CLKDIV2 = ffi::DRM_MODE_FLAG_CLKDIV2;
const _3D_FRAME_PACKING = ffi::DRM_MODE_FLAG_3D_FRAME_PACKING;
const _3D_FIELD_ALTERNATIVE = ffi::DRM_MODE_FLAG_3D_FIELD_ALTERNATIVE;
const _3D_LINE_ALTERNATIVE = ffi::DRM_MODE_FLAG_3D_LINE_ALTERNATIVE;
const _3D_SIDE_BY_SIDE_FULL = ffi::DRM_MODE_FLAG_3D_SIDE_BY_SIDE_FULL;
const _3D_L_DEPTH = ffi::DRM_MODE_FLAG_3D_L_DEPTH;
const _3D_L_DEPTH_GFX_GFX_DEPTH = ffi::DRM_MODE_FLAG_3D_L_DEPTH_GFX_GFX_DEPTH;
const _3D_TOP_AND_BOTTOM = ffi::DRM_MODE_FLAG_3D_TOP_AND_BOTTOM;
const _3D_SIDE_BY_SIDE_HALF = ffi::DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF;
}
}
#[repr(u32)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum PlaneType {
Overlay = ffi::DRM_PLANE_TYPE_OVERLAY,
Primary = ffi::DRM_PLANE_TYPE_PRIMARY,
Cursor = ffi::DRM_PLANE_TYPE_CURSOR,
}
#[derive(Debug, Clone)]
pub struct PropertyValueSet {
prop_ids: Vec<property::Handle>,
prop_vals: Vec<property::RawValue>,
}
impl PropertyValueSet {
pub fn as_props_and_values(&self) -> (&[property::Handle], &[property::RawValue]) {
(&self.prop_ids, &self.prop_vals)
}
}
pub type ClipRect = ffi::drm_sys::drm_clip_rect;
bitflags::bitflags! {
pub struct AtomicCommitFlags : u32 {
const PAGE_FLIP_EVENT = ffi::drm_sys::DRM_MODE_PAGE_FLIP_EVENT;
const PAGE_FLIP_ASYNC = ffi::drm_sys::DRM_MODE_PAGE_FLIP_ASYNC;
const TEST_ONLY = ffi::drm_sys::DRM_MODE_ATOMIC_TEST_ONLY;
const NONBLOCK = ffi::drm_sys::DRM_MODE_ATOMIC_NONBLOCK;
const ALLOW_MODESET = ffi::drm_sys::DRM_MODE_ATOMIC_ALLOW_MODESET;
}
}
bitflags::bitflags! {
pub struct ModePropFlags : u32 {
#[deprecated]
const PENDING = ffi::DRM_MODE_PROP_PENDING;
const LEGACY_TYPE = ffi::DRM_MODE_PROP_LEGACY_TYPE;
const RANGE = ffi::DRM_MODE_PROP_RANGE;
const IMMUTABLE = ffi::DRM_MODE_PROP_IMMUTABLE;
const ENUM = ffi::DRM_MODE_PROP_ENUM;
const BLOB = ffi::DRM_MODE_PROP_BLOB;
const BITMASK = ffi::DRM_MODE_PROP_BITMASK;
const EXTENDED_TYPE = ffi::DRM_MODE_PROP_EXTENDED_TYPE;
const OBJECT = ffi::DRM_MODE_PROP_OBJECT;
const SIGNED_RANGE = ffi::DRM_MODE_PROP_SIGNED_RANGE;
const ATOMIC = ffi::DRM_MODE_PROP_ATOMIC;
}
}