use anyhow::{Context, Result};
use drm::{
buffer::{DrmFourcc, DrmModifier, Handle as GemHandle, PlanarBuffer},
control::{Device as ControlDevice, FbCmd2Flags, framebuffer::Handle as FramebufferHandle},
};
use gbm::BufferObject;
use crate::multimedia::video::Nv12DmaBufFrame;
use log::info;
use std::sync::Arc;
#[derive(Debug)]
pub struct Framebuffer<D: ControlDevice + ?Sized> {
device: Arc<D>,
pub id: FramebufferHandle,
#[allow(unused)]
pub width: i32,
#[allow(unused)]
pub height: i32,
}
impl<D: ControlDevice + ?Sized> Framebuffer<D> {
pub fn create<T>(device: Arc<D>, bo: &BufferObject<T>) -> Result<Self>
where
T: 'static,
{
let bo_modifier = bo.modifier();
let flags = if bo_modifier != DrmModifier::Invalid {
FbCmd2Flags::MODIFIERS
} else {
FbCmd2Flags::empty()
};
let id = device
.add_planar_framebuffer(bo, flags)
.context("Adding DRM framebuffer")?;
Ok(Self {
device,
id,
width: bo.width() as i32,
height: bo.height() as i32,
})
}
#[allow(unused)]
pub fn from_nv12_with_handle(
device: Arc<D>,
frame: &Nv12DmaBufFrame,
gem_handle: GemHandle,
) -> Result<Self> {
let planar = Nv12ImportedBuffer {
width: frame.width as u32,
height: frame.height as u32,
handle: gem_handle,
pitch_y: frame.pitch_y,
pitch_uv: frame.pitch_uv,
offset_y: frame.offset_y,
offset_uv: frame.offset_uv,
modifier: frame.format_modifier,
};
let id = device
.add_planar_framebuffer(&planar, FbCmd2Flags::MODIFIERS)
.context("DRM AddFB2 Fail")?;
Ok(Self {
device,
id,
width: frame.width,
height: frame.height,
})
}
#[allow(unused)]
pub fn id(&self) -> FramebufferHandle {
self.id
}
}
impl<D: ControlDevice + ?Sized> Drop for Framebuffer<D> {
fn drop(&mut self) {
info!("Dropping Framebuffer");
let _ = self.device.destroy_framebuffer(self.id);
}
}
#[derive(Debug, Clone, Copy)]
struct Nv12ImportedBuffer {
width: u32,
height: u32,
handle: GemHandle,
pitch_y: u32,
pitch_uv: u32,
offset_y: u32,
offset_uv: u32,
modifier: u64,
}
impl PlanarBuffer for Nv12ImportedBuffer {
fn size(&self) -> (u32, u32) {
(self.width, self.height)
}
fn format(&self) -> DrmFourcc {
DrmFourcc::Nv12
}
fn modifier(&self) -> Option<DrmModifier> {
Some(self.modifier.into())
}
fn pitches(&self) -> [u32; 4] {
[self.pitch_y, self.pitch_uv, 0, 0]
}
fn handles(&self) -> [Option<GemHandle>; 4] {
[Some(self.handle), Some(self.handle), None, None]
}
fn offsets(&self) -> [u32; 4] {
[self.offset_y, self.offset_uv, 0, 0]
}
}