use control::{self, ResourceHandle, ResourceInfo};
use result::*;
use ffi;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, From, Into)]
pub struct Handle(control::RawHandle);
impl ResourceHandle for Handle {}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Info {
handle: Handle,
size: (u32, u32),
pitch: u32,
bpp: u8,
depth: u8,
}
impl control::property::LoadProperties for Handle {
const TYPE: u32 = ffi::DRM_MODE_OBJECT_FB;
}
impl ResourceInfo for Info {
type Handle = Handle;
fn load_from_device<T>(device: &T, handle: Self::Handle) -> Result<Self>
where
T: control::Device,
{
let framebuffer = {
let mut raw: ffi::drm_mode_fb_cmd = Default::default();
raw.fb_id = handle.into();
unsafe {
try!(ffi::ioctl_mode_getfb(device.as_raw_fd(), &mut raw));
}
Self {
handle: handle,
size: (raw.width, raw.height),
pitch: raw.pitch,
bpp: raw.bpp as u8,
depth: raw.depth as u8,
}
};
Ok(framebuffer)
}
fn handle(&self) -> Self::Handle {
self.handle
}
}
pub fn create<T, U>(device: &T, buffer: &U) -> Result<Info>
where
T: control::Device,
U: super::super::buffer::Buffer + ?Sized,
{
let framebuffer = {
let mut raw: ffi::drm_mode_fb_cmd2 = Default::default();
let (w, h) = buffer.size();
raw.width = w;
raw.height = h;
raw.pixel_format = buffer.format().as_raw();
raw.flags = 0; raw.handles[0] = buffer.handle().into();
raw.pitches[0] = buffer.pitch();
raw.offsets[0] = 0; raw.modifier[0];
match unsafe { ffi::ioctl_mode_addfb2(device.as_raw_fd(), &mut raw) } {
Ok(_) => try!(Info::load_from_device(device, Handle::from(raw.fb_id))),
Err(_) => {
let mut raw_old: ffi::drm_mode_fb_cmd = Default::default();
raw_old.width = w;
raw_old.height = h;
raw_old.pitch = buffer.pitch();
let depth = try!(
buffer
.format()
.depth()
.ok_or(Error::from_kind(ErrorKind::UnsupportedPixelFormat))
);
let bpp = try!(
buffer
.format()
.bpp()
.ok_or(Error::from_kind(ErrorKind::UnsupportedPixelFormat))
);
raw_old.bpp = bpp as u32;
raw_old.depth = depth as u32;
raw_old.handle = buffer.handle().into();
unsafe {
try!(ffi::ioctl_mode_addfb(device.as_raw_fd(), &mut raw_old));
}
Info {
handle: Handle::from(raw_old.fb_id),
size: (raw_old.width, raw_old.height),
pitch: raw_old.pitch,
depth: raw_old.depth as u8,
bpp: raw_old.bpp as u8,
}
}
}
};
Ok(framebuffer)
}
pub type ClipRect = ffi::drm_clip_rect;
pub fn mark_dirty<T>(device: &T, fb: Handle, clips: &[ClipRect]) -> Result<()>
where
T: control::Device,
{
let mut raw: ffi::drm_mode_fb_dirty_cmd = Default::default();
raw.fb_id = fb.into();
raw.num_clips = clips.len() as u32;
raw.clips_ptr = clips.as_ptr() as u64;
unsafe {
try!(ffi::ioctl_mode_dirtyfb(device.as_raw_fd(), &mut raw));
}
Ok(())
}
pub fn destroy<T>(device: &T, fb: Handle) -> Result<()>
where
T: control::Device,
{
unsafe {
try!(ffi::ioctl_mode_rmfb(
device.as_raw_fd(),
&mut fb.into() as *mut _
));
}
Ok(())
}