use super::backends::{
Class, Constraint, Description, Extent, Flags, Handle, HandlePayload, Layout, MemoryType, Usage,
};
use super::types::{Access, Error, Mapping, Result, Size};
use super::utils;
use std::os::fd::{BorrowedFd, OwnedFd};
pub struct Resource {
layout: Layout,
dmabuf: Option<OwnedFd>,
}
impl Resource {
pub fn new(layout: Layout) -> Self {
Self {
layout,
dmabuf: None,
}
}
fn size(&self) -> Size {
self.layout.size
}
pub fn bind_memory(&mut self, dmabuf: OwnedFd) {
self.dmabuf = Some(dmabuf);
}
fn dmabuf(&self) -> &OwnedFd {
self.dmabuf.as_ref().unwrap()
}
}
fn get_resource(handle: &Handle) -> &Resource {
match handle.payload {
HandlePayload::DmaBuf(ref res) => res,
_ => unreachable!(),
}
}
fn get_resource_mut(handle: &mut Handle) -> &mut Resource {
match handle.payload {
HandlePayload::DmaBuf(ref mut res) => res,
_ => unreachable!(),
}
}
pub fn classify(desc: Description, usage: Usage) -> Result<Class> {
if !desc.is_buffer() && !desc.modifier.is_linear() {
return Error::unsupported();
}
let unsupported_flags = Flags::PROTECTED;
if desc.flags.intersects(unsupported_flags) {
return Error::unsupported();
}
let mut class = Class::new(desc)
.usage(usage)
.max_extent(Extent::max(desc.is_buffer()));
if desc.is_buffer() {
class = class.modifiers(vec![desc.modifier]);
}
Ok(class)
}
pub fn with_constraint(class: &Class, extent: Extent, con: Option<Constraint>) -> Result<Handle> {
let layout = Layout::packed(class, extent, con)?;
let handle = Handle::from(Resource::new(layout));
Ok(handle)
}
pub fn with_layout(
class: &Class,
extent: Extent,
layout: Layout,
_dmabuf: Option<BorrowedFd>,
) -> Result<Handle> {
let packed = Layout::packed(class, extent, None)?;
if layout.size < packed.size
|| layout.modifier != packed.modifier
|| layout.plane_count != packed.plane_count
{
return Error::user();
}
let handle = Handle::from(Resource::new(layout));
Ok(handle)
}
pub fn layout(handle: &Handle) -> Layout {
get_resource(handle).layout.clone()
}
pub fn memory_types(_handle: &Handle) -> Vec<MemoryType> {
vec![MemoryType::MAPPABLE]
}
pub fn bind_memory<T>(
handle: &mut Handle,
mt: MemoryType,
dmabuf: Option<OwnedFd>,
alloc: T,
) -> Result<()>
where
T: FnOnce(Size) -> Result<OwnedFd>,
{
let res = get_resource_mut(handle);
if !MemoryType::MAPPABLE.contains(mt) {
return Error::user();
}
if res.dmabuf.is_some() {
return if dmabuf.is_some() {
Error::user()
} else {
Ok(())
};
}
let dmabuf = if let Some(dmabuf) = dmabuf {
let size = utils::seek_end(&dmabuf)?;
if res.size() > size {
return Error::user();
}
dmabuf
} else {
alloc(res.size())?
};
res.bind_memory(dmabuf);
Ok(())
}
pub fn export_dma_buf(handle: &Handle, name: Option<&str>) -> Result<OwnedFd> {
let dmabuf = get_resource(handle).dmabuf();
if let Some(name) = name {
let _ = utils::dma_buf_set_name(dmabuf, name);
}
let dmabuf = dmabuf.try_clone().map_err(Error::from)?;
Ok(dmabuf)
}
pub fn map(handle: &Handle) -> Result<Mapping> {
let dmabuf = get_resource(handle).dmabuf();
let len = utils::seek_end(dmabuf)?;
let mapping = utils::mmap(dmabuf, len, Access::ReadWrite)?;
Ok(mapping)
}
pub fn unmap(_handle: &Handle, mapping: Mapping) {
let _ = utils::munmap(mapping);
}
pub fn flush(handle: &Handle) {
let dmabuf = get_resource(handle).dmabuf();
let _ = utils::dma_buf_sync(dmabuf, Access::ReadWrite, false);
}
pub fn invalidate(handle: &Handle) {
let dmabuf = get_resource(handle).dmabuf();
let _ = utils::dma_buf_sync(dmabuf, Access::ReadWrite, true);
}