use control::{self, ResourceHandle, ResourceInfo};
use result::*;
use ffi;
#[derive(Handle, Clone, Copy, PartialEq, Eq, Hash)]
#[HandleType = "framebuffer"]
#[HandleTrait = "ResourceHandle"]
#[HandleRaw = "control::RawHandle"]
pub struct Handle(control::RawHandle);
#[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.as_raw();
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 {
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().as_raw();
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(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().as_raw();
unsafe {
try!(ffi::ioctl_mode_addfb(device.as_raw_fd(), &mut raw_old));
}
Info {
handle: Handle::from_raw(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.as_raw();
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.as_raw() as *mut _));
}
Ok(())
}