yuno 0.2.0

Multimedia UI layout and rendering framework powered by Skia.
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]
    }
}