metal: use IN_FORMATS plane property
This commit is contained in:
parent
d022d96fbf
commit
e0ed29038e
9 changed files with 183 additions and 87 deletions
|
|
@ -28,7 +28,7 @@ use {
|
||||||
DRM_MODE_ATOMIC_NONBLOCK, DRM_MODE_PAGE_FLIP_EVENT,
|
DRM_MODE_ATOMIC_NONBLOCK, DRM_MODE_PAGE_FLIP_EVENT,
|
||||||
},
|
},
|
||||||
gbm::{GbmDevice, GBM_BO_USE_LINEAR, GBM_BO_USE_RENDERING, GBM_BO_USE_SCANOUT},
|
gbm::{GbmDevice, GBM_BO_USE_LINEAR, GBM_BO_USE_RENDERING, GBM_BO_USE_SCANOUT},
|
||||||
ModifiedFormat, INVALID_MODIFIER,
|
Modifier,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
ahash::{AHashMap, AHashSet},
|
ahash::{AHashMap, AHashSet},
|
||||||
|
|
@ -505,6 +505,12 @@ pub enum PlaneType {
|
||||||
Cursor,
|
Cursor,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct PlaneFormat {
|
||||||
|
_format: &'static Format,
|
||||||
|
modifiers: Vec<Modifier>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct MetalPlane {
|
pub struct MetalPlane {
|
||||||
pub id: DrmPlane,
|
pub id: DrmPlane,
|
||||||
|
|
@ -513,7 +519,7 @@ pub struct MetalPlane {
|
||||||
pub ty: PlaneType,
|
pub ty: PlaneType,
|
||||||
|
|
||||||
pub possible_crtcs: u32,
|
pub possible_crtcs: u32,
|
||||||
pub formats: AHashMap<u32, &'static Format>,
|
pub formats: AHashMap<u32, PlaneFormat>,
|
||||||
|
|
||||||
pub assigned: Cell<bool>,
|
pub assigned: Cell<bool>,
|
||||||
|
|
||||||
|
|
@ -755,19 +761,36 @@ fn create_crtc(
|
||||||
|
|
||||||
fn create_plane(plane: DrmPlane, master: &Rc<DrmMaster>) -> Result<MetalPlane, DrmError> {
|
fn create_plane(plane: DrmPlane, master: &Rc<DrmMaster>) -> Result<MetalPlane, DrmError> {
|
||||||
let info = master.get_plane_info(plane)?;
|
let info = master.get_plane_info(plane)?;
|
||||||
|
let props = collect_properties(master, plane)?;
|
||||||
let mut formats = AHashMap::new();
|
let mut formats = AHashMap::new();
|
||||||
for format in info.format_types {
|
if let Some((_, v)) = props.props.get(b"IN_FORMATS".as_bstr()) {
|
||||||
if let Some(f) = crate::format::formats().get(&format) {
|
for format in master.get_in_formats(*v as _)? {
|
||||||
formats.insert(format, *f);
|
if format.modifiers.is_empty() {
|
||||||
} else {
|
continue;
|
||||||
// log::warn!(
|
}
|
||||||
// "{:?} supports unknown format '{:?}'",
|
if let Some(f) = crate::format::formats().get(&format.format) {
|
||||||
// plane,
|
formats.insert(
|
||||||
// crate::format::debug(format)
|
format.format,
|
||||||
// );
|
PlaneFormat {
|
||||||
|
_format: f,
|
||||||
|
modifiers: format.modifiers,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for format in info.format_types {
|
||||||
|
if let Some(f) = crate::format::formats().get(&format) {
|
||||||
|
formats.insert(
|
||||||
|
format,
|
||||||
|
PlaneFormat {
|
||||||
|
_format: f,
|
||||||
|
modifiers: vec![],
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let props = collect_properties(master, plane)?;
|
|
||||||
let ty = match props.props.get(b"type".as_bstr()) {
|
let ty = match props.props.get(b"type".as_bstr()) {
|
||||||
Some((def, val)) => match &def.ty {
|
Some((def, val)) => match &def.ty {
|
||||||
DrmPropertyType::Enum { values, .. } => 'ty: {
|
DrmPropertyType::Enum { values, .. } => 'ty: {
|
||||||
|
|
@ -1569,30 +1592,33 @@ impl MetalBackend {
|
||||||
fn create_scanout_buffers(
|
fn create_scanout_buffers(
|
||||||
&self,
|
&self,
|
||||||
dev: &Rc<MetalDrmDevice>,
|
dev: &Rc<MetalDrmDevice>,
|
||||||
format: &ModifiedFormat,
|
format: &Format,
|
||||||
|
modifiers: &[Modifier],
|
||||||
width: i32,
|
width: i32,
|
||||||
height: i32,
|
height: i32,
|
||||||
ctx: &MetalRenderContext,
|
ctx: &MetalRenderContext,
|
||||||
cursor: bool,
|
cursor: bool,
|
||||||
) -> Result<[RenderBuffer; 2], MetalError> {
|
) -> Result<[RenderBuffer; 2], MetalError> {
|
||||||
let create = || self.create_scanout_buffer(dev, format, width, height, ctx, cursor);
|
let create =
|
||||||
|
|| self.create_scanout_buffer(dev, format, modifiers, width, height, ctx, cursor);
|
||||||
Ok([create()?, create()?])
|
Ok([create()?, create()?])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_scanout_buffer(
|
fn create_scanout_buffer(
|
||||||
&self,
|
&self,
|
||||||
dev: &Rc<MetalDrmDevice>,
|
dev: &Rc<MetalDrmDevice>,
|
||||||
format: &ModifiedFormat,
|
format: &Format,
|
||||||
|
modifiers: &[Modifier],
|
||||||
width: i32,
|
width: i32,
|
||||||
height: i32,
|
height: i32,
|
||||||
render_ctx: &MetalRenderContext,
|
render_ctx: &MetalRenderContext,
|
||||||
cursor: bool,
|
cursor: bool,
|
||||||
) -> Result<RenderBuffer, MetalError> {
|
) -> Result<RenderBuffer, MetalError> {
|
||||||
let mut usage = GBM_BO_USE_RENDERING | GBM_BO_USE_SCANOUT;
|
let mut usage = GBM_BO_USE_RENDERING | GBM_BO_USE_SCANOUT;
|
||||||
if cursor {
|
if cursor && modifiers.is_empty() {
|
||||||
usage |= GBM_BO_USE_LINEAR;
|
usage |= GBM_BO_USE_LINEAR;
|
||||||
};
|
};
|
||||||
let dev_bo = dev.gbm.create_bo(width, height, format, usage);
|
let dev_bo = dev.gbm.create_bo(width, height, format, modifiers, usage);
|
||||||
let dev_bo = match dev_bo {
|
let dev_bo = match dev_bo {
|
||||||
Ok(b) => b,
|
Ok(b) => b,
|
||||||
Err(e) => return Err(MetalError::ScanoutBuffer(e)),
|
Err(e) => return Err(MetalError::ScanoutBuffer(e)),
|
||||||
|
|
@ -1619,7 +1645,10 @@ impl MetalBackend {
|
||||||
} else {
|
} else {
|
||||||
// Create a _bridge_ BO in the render device
|
// Create a _bridge_ BO in the render device
|
||||||
usage = GBM_BO_USE_RENDERING | GBM_BO_USE_LINEAR;
|
usage = GBM_BO_USE_RENDERING | GBM_BO_USE_LINEAR;
|
||||||
let render_bo = render_ctx.gfx.gbm().create_bo(width, height, format, usage);
|
let render_bo = render_ctx
|
||||||
|
.gfx
|
||||||
|
.gbm()
|
||||||
|
.create_bo(width, height, format, &[], usage);
|
||||||
let render_bo = match render_bo {
|
let render_bo = match render_bo {
|
||||||
Ok(b) => b,
|
Ok(b) => b,
|
||||||
Err(e) => return Err(MetalError::ScanoutBuffer(e)),
|
Err(e) => return Err(MetalError::ScanoutBuffer(e)),
|
||||||
|
|
@ -1716,46 +1745,45 @@ impl MetalBackend {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let primary_plane = 'primary_plane: {
|
let (primary_plane, primary_modifiers) = 'primary_plane: {
|
||||||
for plane in crtc.possible_planes.values() {
|
for plane in crtc.possible_planes.values() {
|
||||||
if plane.ty == PlaneType::Primary
|
if plane.ty == PlaneType::Primary && !plane.assigned.get() {
|
||||||
&& !plane.assigned.get()
|
if let Some(format) = plane.formats.get(&XRGB8888.drm) {
|
||||||
&& plane.formats.contains_key(&XRGB8888.drm)
|
break 'primary_plane (plane.clone(), &format.modifiers);
|
||||||
{
|
}
|
||||||
break 'primary_plane plane.clone();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Err(MetalError::NoPrimaryPlaneForConnector);
|
return Err(MetalError::NoPrimaryPlaneForConnector);
|
||||||
};
|
};
|
||||||
let buffers = Rc::new(self.create_scanout_buffers(
|
let buffers = Rc::new(self.create_scanout_buffers(
|
||||||
&connector.dev,
|
&connector.dev,
|
||||||
&ModifiedFormat {
|
XRGB8888,
|
||||||
format: XRGB8888,
|
primary_modifiers,
|
||||||
modifier: INVALID_MODIFIER,
|
|
||||||
},
|
|
||||||
mode.hdisplay as _,
|
mode.hdisplay as _,
|
||||||
mode.vdisplay as _,
|
mode.vdisplay as _,
|
||||||
ctx,
|
ctx,
|
||||||
false,
|
false,
|
||||||
)?);
|
)?);
|
||||||
let mut cursor_plane = None;
|
let mut cursor_plane = None;
|
||||||
|
let mut cursor_modifiers = &[][..];
|
||||||
for plane in crtc.possible_planes.values() {
|
for plane in crtc.possible_planes.values() {
|
||||||
if plane.ty == PlaneType::Cursor
|
if plane.ty == PlaneType::Cursor
|
||||||
&& !plane.assigned.get()
|
&& !plane.assigned.get()
|
||||||
&& plane.formats.contains_key(&ARGB8888.drm)
|
&& plane.formats.contains_key(&ARGB8888.drm)
|
||||||
{
|
{
|
||||||
cursor_plane = Some(plane.clone());
|
if let Some(format) = plane.formats.get(&ARGB8888.drm) {
|
||||||
break;
|
cursor_plane = Some(plane.clone());
|
||||||
|
cursor_modifiers = &format.modifiers[..];
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let mut cursor_buffers = None;
|
let mut cursor_buffers = None;
|
||||||
if cursor_plane.is_some() {
|
if cursor_plane.is_some() {
|
||||||
let res = self.create_scanout_buffers(
|
let res = self.create_scanout_buffers(
|
||||||
&connector.dev,
|
&connector.dev,
|
||||||
&ModifiedFormat {
|
ARGB8888,
|
||||||
format: ARGB8888,
|
cursor_modifiers,
|
||||||
modifier: INVALID_MODIFIER,
|
|
||||||
},
|
|
||||||
connector.dev.cursor_width as _,
|
connector.dev.cursor_width as _,
|
||||||
connector.dev.cursor_height as _,
|
connector.dev.cursor_height as _,
|
||||||
ctx,
|
ctx,
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,6 @@ use {
|
||||||
video::{
|
video::{
|
||||||
drm::{ConnectorType, Drm, DrmError, DrmVersion},
|
drm::{ConnectorType, Drm, DrmError, DrmVersion},
|
||||||
gbm::{GbmDevice, GbmError, GBM_BO_USE_RENDERING},
|
gbm::{GbmDevice, GbmError, GBM_BO_USE_RENDERING},
|
||||||
ModifiedFormat, INVALID_MODIFIER,
|
|
||||||
},
|
},
|
||||||
wire_xcon::{
|
wire_xcon::{
|
||||||
ChangeProperty, ChangeWindowAttributes, ConfigureNotify, CreateCursor, CreatePixmap,
|
ChangeProperty, ChangeWindowAttributes, ConfigureNotify, CreateCursor, CreatePixmap,
|
||||||
|
|
@ -376,15 +375,11 @@ impl XBackend {
|
||||||
width: i32,
|
width: i32,
|
||||||
height: i32,
|
height: i32,
|
||||||
) -> Result<[XImage; 2], XBackendError> {
|
) -> Result<[XImage; 2], XBackendError> {
|
||||||
let format = ModifiedFormat {
|
|
||||||
format: XRGB8888,
|
|
||||||
modifier: INVALID_MODIFIER,
|
|
||||||
};
|
|
||||||
let mut images = [None, None];
|
let mut images = [None, None];
|
||||||
for image in &mut images {
|
for image in &mut images {
|
||||||
let bo = self
|
let bo = self
|
||||||
.gbm
|
.gbm
|
||||||
.create_bo(width, height, &format, GBM_BO_USE_RENDERING)?;
|
.create_bo(width, height, XRGB8888, &[], GBM_BO_USE_RENDERING)?;
|
||||||
let dma = bo.dmabuf();
|
let dma = bo.dmabuf();
|
||||||
assert!(dma.planes.len() == 1);
|
assert!(dma.planes.len() == 1);
|
||||||
let plane = dma.planes.first().unwrap();
|
let plane = dma.planes.first().unwrap();
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,6 @@ use {
|
||||||
video::{
|
video::{
|
||||||
dmabuf::DmaBuf,
|
dmabuf::DmaBuf,
|
||||||
gbm::{GbmError, GBM_BO_USE_LINEAR, GBM_BO_USE_RENDERING},
|
gbm::{GbmError, GBM_BO_USE_LINEAR, GBM_BO_USE_RENDERING},
|
||||||
ModifiedFormat, INVALID_MODIFIER,
|
|
||||||
},
|
},
|
||||||
wire::{jay_screencast::*, JayScreencastId},
|
wire::{jay_screencast::*, JayScreencastId},
|
||||||
},
|
},
|
||||||
|
|
@ -199,17 +198,13 @@ impl JayScreencast {
|
||||||
let mode = output.global.mode.get();
|
let mode = output.global.mode.get();
|
||||||
let num = 3;
|
let num = 3;
|
||||||
for _ in 0..num {
|
for _ in 0..num {
|
||||||
let format = ModifiedFormat {
|
|
||||||
format: XRGB8888,
|
|
||||||
modifier: INVALID_MODIFIER,
|
|
||||||
};
|
|
||||||
let mut flags = GBM_BO_USE_RENDERING;
|
let mut flags = GBM_BO_USE_RENDERING;
|
||||||
if self.linear.get() {
|
if self.linear.get() {
|
||||||
flags |= GBM_BO_USE_LINEAR;
|
flags |= GBM_BO_USE_LINEAR;
|
||||||
}
|
}
|
||||||
let buffer = ctx
|
let buffer = ctx
|
||||||
.gbm()
|
.gbm()
|
||||||
.create_bo(mode.width, mode.height, &format, flags)?;
|
.create_bo(mode.width, mode.height, XRGB8888, &[], flags)?;
|
||||||
let fb = ctx.clone().dmabuf_img(buffer.dmabuf())?.to_framebuffer()?;
|
let fb = ctx.clone().dmabuf_img(buffer.dmabuf())?.to_framebuffer()?;
|
||||||
buffers.push(ScreencastBuffer {
|
buffers.push(ScreencastBuffer {
|
||||||
dmabuf: buffer.dmabuf().clone(),
|
dmabuf: buffer.dmabuf().clone(),
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ use {
|
||||||
asyncevent::AsyncEvent, clonecell::CloneCell, copyhashmap::CopyHashMap,
|
asyncevent::AsyncEvent, clonecell::CloneCell, copyhashmap::CopyHashMap,
|
||||||
errorfmt::ErrorFmt, rc_eq::rc_eq,
|
errorfmt::ErrorFmt, rc_eq::rc_eq,
|
||||||
},
|
},
|
||||||
video::{gbm::GBM_BO_USE_RENDERING, ModifiedFormat, INVALID_MODIFIER},
|
video::gbm::GBM_BO_USE_RENDERING,
|
||||||
wire::{
|
wire::{
|
||||||
wp_fractional_scale_v1::PreferredScale, zwlr_layer_surface_v1::Configure,
|
wp_fractional_scale_v1::PreferredScale, zwlr_layer_surface_v1::Configure,
|
||||||
ZwpLinuxBufferParamsV1Id,
|
ZwpLinuxBufferParamsV1Id,
|
||||||
|
|
@ -694,21 +694,18 @@ impl WindowData {
|
||||||
let width = (self.width.get() as f64 * self.scale.get().to_f64()).round() as i32;
|
let width = (self.width.get() as f64 * self.scale.get().to_f64()).round() as i32;
|
||||||
let height = (self.height.get() as f64 * self.scale.get().to_f64()).round() as i32;
|
let height = (self.height.get() as f64 * self.scale.get().to_f64()).round() as i32;
|
||||||
for _ in 0..NUM_BUFFERS {
|
for _ in 0..NUM_BUFFERS {
|
||||||
let format = ModifiedFormat {
|
let bo =
|
||||||
format: ARGB8888,
|
match ctx
|
||||||
modifier: INVALID_MODIFIER,
|
.ctx
|
||||||
};
|
.gbm()
|
||||||
let bo = match ctx
|
.create_bo(width, height, ARGB8888, &[], GBM_BO_USE_RENDERING)
|
||||||
.ctx
|
{
|
||||||
.gbm()
|
Ok(b) => b,
|
||||||
.create_bo(width, height, &format, GBM_BO_USE_RENDERING)
|
Err(e) => {
|
||||||
{
|
log::error!("Could not allocate dmabuf: {}", ErrorFmt(e));
|
||||||
Ok(b) => b,
|
return;
|
||||||
Err(e) => {
|
}
|
||||||
log::error!("Could not allocate dmabuf: {}", ErrorFmt(e));
|
};
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let img = match ctx.ctx.clone().dmabuf_img(bo.dmabuf()) {
|
let img = match ctx.ctx.clone().dmabuf_img(bo.dmabuf()) {
|
||||||
Ok(b) => b,
|
Ok(b) => b,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@ use {
|
||||||
video::{
|
video::{
|
||||||
drm::DrmError,
|
drm::DrmError,
|
||||||
gbm::{GbmBo, GbmError, GBM_BO_USE_LINEAR, GBM_BO_USE_RENDERING},
|
gbm::{GbmBo, GbmError, GBM_BO_USE_LINEAR, GBM_BO_USE_RENDERING},
|
||||||
ModifiedFormat, INVALID_MODIFIER,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
std::{ops::Deref, rc::Rc},
|
std::{ops::Deref, rc::Rc},
|
||||||
|
|
@ -43,15 +42,12 @@ pub fn take_screenshot(state: &State) -> Result<Screenshot, ScreenshooterError>
|
||||||
if extents.is_empty() {
|
if extents.is_empty() {
|
||||||
return Err(ScreenshooterError::EmptyDisplay);
|
return Err(ScreenshooterError::EmptyDisplay);
|
||||||
}
|
}
|
||||||
let format = ModifiedFormat {
|
|
||||||
format: XRGB8888,
|
|
||||||
modifier: INVALID_MODIFIER,
|
|
||||||
};
|
|
||||||
let gbm = ctx.gbm();
|
let gbm = ctx.gbm();
|
||||||
let bo = gbm.create_bo(
|
let bo = gbm.create_bo(
|
||||||
extents.width(),
|
extents.width(),
|
||||||
extents.height(),
|
extents.height(),
|
||||||
&format,
|
XRGB8888,
|
||||||
|
&[],
|
||||||
GBM_BO_USE_RENDERING | GBM_BO_USE_LINEAR,
|
GBM_BO_USE_RENDERING | GBM_BO_USE_LINEAR,
|
||||||
)?;
|
)?;
|
||||||
let fb = ctx.clone().dmabuf_fb(bo.dmabuf())?;
|
let fb = ctx.clone().dmabuf_fb(bo.dmabuf())?;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
use crate::format::Format;
|
|
||||||
|
|
||||||
pub mod dmabuf;
|
pub mod dmabuf;
|
||||||
pub mod drm;
|
pub mod drm;
|
||||||
pub mod gbm;
|
pub mod gbm;
|
||||||
|
|
@ -9,9 +7,3 @@ pub type Modifier = u64;
|
||||||
pub const INVALID_MODIFIER: Modifier = 0x00ff_ffff_ffff_ffff;
|
pub const INVALID_MODIFIER: Modifier = 0x00ff_ffff_ffff_ffff;
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub const LINEAR_MODIFIER: Modifier = 0;
|
pub const LINEAR_MODIFIER: Modifier = 0;
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
|
||||||
pub struct ModifiedFormat {
|
|
||||||
pub format: &'static Format,
|
|
||||||
pub modifier: Modifier,
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -35,8 +35,11 @@ use crate::{
|
||||||
utils::{buf::Buf, errorfmt::ErrorFmt, stack::Stack, syncqueue::SyncQueue, vec_ext::VecExt},
|
utils::{buf::Buf, errorfmt::ErrorFmt, stack::Stack, syncqueue::SyncQueue, vec_ext::VecExt},
|
||||||
video::{
|
video::{
|
||||||
dmabuf::DmaBuf,
|
dmabuf::DmaBuf,
|
||||||
drm::sys::{get_version, DRM_CAP_CURSOR_HEIGHT, DRM_CAP_CURSOR_WIDTH},
|
drm::sys::{
|
||||||
INVALID_MODIFIER,
|
drm_format_modifier, drm_format_modifier_blob, get_version, DRM_CAP_CURSOR_HEIGHT,
|
||||||
|
DRM_CAP_CURSOR_WIDTH, FORMAT_BLOB_CURRENT,
|
||||||
|
},
|
||||||
|
Modifier, INVALID_MODIFIER,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
pub use sys::{
|
pub use sys::{
|
||||||
|
|
@ -106,6 +109,8 @@ pub enum DrmError {
|
||||||
InvalidRead,
|
InvalidRead,
|
||||||
#[error("Could not determine the drm version")]
|
#[error("Could not determine the drm version")]
|
||||||
Version(#[source] OsError),
|
Version(#[source] OsError),
|
||||||
|
#[error("Format of IN_FORMATS property is invalid")]
|
||||||
|
InFormats,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_node_name(fd: c::c_int) -> Result<Ustring, DrmError> {
|
fn render_node_name(fd: c::c_int) -> Result<Ustring, DrmError> {
|
||||||
|
|
@ -174,6 +179,11 @@ impl Drm {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct InFormat {
|
||||||
|
pub format: u32,
|
||||||
|
pub modifiers: Vec<Modifier>,
|
||||||
|
}
|
||||||
|
|
||||||
pub struct DrmMaster {
|
pub struct DrmMaster {
|
||||||
drm: Drm,
|
drm: Drm,
|
||||||
u32_bufs: Stack<Vec<u32>>,
|
u32_bufs: Stack<Vec<u32>>,
|
||||||
|
|
@ -373,6 +383,64 @@ impl DrmMaster {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_in_formats(&self, property: u32) -> Result<Vec<InFormat>, DrmError> {
|
||||||
|
let blob = self.getblob_vec::<u8>(DrmBlob(property))?;
|
||||||
|
let header: drm_format_modifier_blob = match uapi::pod_read_init(blob.as_bytes()) {
|
||||||
|
Ok(h) => h,
|
||||||
|
Err(_) => {
|
||||||
|
log::error!("Header of IN_FORMATS blob doesn't fit in the blob");
|
||||||
|
return Err(DrmError::InFormats);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if header.version != FORMAT_BLOB_CURRENT {
|
||||||
|
log::error!(
|
||||||
|
"Header of IN_FORMATS has an invalid version: {}",
|
||||||
|
header.version
|
||||||
|
);
|
||||||
|
return Err(DrmError::InFormats);
|
||||||
|
}
|
||||||
|
let formats_start = header.formats_offset as usize;
|
||||||
|
let formats_end = formats_start
|
||||||
|
.wrapping_add((header.count_formats as usize).wrapping_mul(mem::size_of::<u32>()));
|
||||||
|
let modifiers_start = header.modifiers_offset as usize;
|
||||||
|
let modifiers_end = modifiers_start.wrapping_add(
|
||||||
|
(header.count_modifiers as usize).wrapping_mul(mem::size_of::<drm_format_modifier>()),
|
||||||
|
);
|
||||||
|
if blob.len() < formats_end || formats_end < formats_start {
|
||||||
|
log::error!("Formats of IN_FORMATS blob don't fit in the blob");
|
||||||
|
return Err(DrmError::InFormats);
|
||||||
|
}
|
||||||
|
if blob.len() < modifiers_end || modifiers_end < modifiers_start {
|
||||||
|
log::error!("Formats of IN_FORMATS blob don't fit in the blob");
|
||||||
|
return Err(DrmError::InFormats);
|
||||||
|
}
|
||||||
|
let mut formats: Vec<_> = uapi::pod_iter::<u32, _>(&blob[formats_start..formats_end])
|
||||||
|
.unwrap()
|
||||||
|
.map(|f| InFormat {
|
||||||
|
format: f,
|
||||||
|
modifiers: vec![],
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
let modifiers =
|
||||||
|
uapi::pod_iter::<drm_format_modifier, _>(&blob[modifiers_start..modifiers_end])
|
||||||
|
.unwrap();
|
||||||
|
for modifier in modifiers {
|
||||||
|
let offset = modifier.offset as usize;
|
||||||
|
let mut indices = modifier.formats;
|
||||||
|
while indices != 0 {
|
||||||
|
let idx = indices.trailing_zeros();
|
||||||
|
indices &= !(1 << idx);
|
||||||
|
let idx = idx as usize + offset;
|
||||||
|
if idx >= formats.len() {
|
||||||
|
log::error!("Modifier offset is out of bounds");
|
||||||
|
return Err(DrmError::InFormats);
|
||||||
|
}
|
||||||
|
formats[idx].modifiers.push(modifier.modifier);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(formats)
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(clippy::await_holding_refcell_ref)]
|
#[allow(clippy::await_holding_refcell_ref)]
|
||||||
pub async fn event(&self) -> Result<Option<DrmEvent>, DrmError> {
|
pub async fn event(&self) -> Result<Option<DrmEvent>, DrmError> {
|
||||||
if self.events.is_empty() {
|
if self.events.is_empty() {
|
||||||
|
|
|
||||||
|
|
@ -1132,3 +1132,27 @@ pub fn get_version(fd: c::c_int) -> Result<DrmVersion, OsError> {
|
||||||
desc: desc.into(),
|
desc: desc.into(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const FORMAT_BLOB_CURRENT: u32 = 1;
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct drm_format_modifier_blob {
|
||||||
|
pub version: u32,
|
||||||
|
pub flags: u32,
|
||||||
|
pub count_formats: u32,
|
||||||
|
pub formats_offset: u32,
|
||||||
|
pub count_modifiers: u32,
|
||||||
|
pub modifiers_offset: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl Pod for drm_format_modifier_blob {}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct drm_format_modifier {
|
||||||
|
pub formats: u64,
|
||||||
|
pub offset: u32,
|
||||||
|
pub pad: u32,
|
||||||
|
pub modifier: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl Pod for drm_format_modifier {}
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,12 @@
|
||||||
|
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
format::formats,
|
format::{formats, Format},
|
||||||
utils::oserror::OsError,
|
utils::oserror::OsError,
|
||||||
video::{
|
video::{
|
||||||
dmabuf::{DmaBuf, DmaBufPlane, PlaneVec},
|
dmabuf::{DmaBuf, DmaBufPlane, PlaneVec},
|
||||||
drm::{Drm, DrmError},
|
drm::{Drm, DrmError},
|
||||||
ModifiedFormat, INVALID_MODIFIER,
|
Modifier,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
std::{
|
std::{
|
||||||
|
|
@ -27,7 +27,7 @@ pub enum GbmError {
|
||||||
#[error("Cloud not create a gbm device")]
|
#[error("Cloud not create a gbm device")]
|
||||||
CreateDevice,
|
CreateDevice,
|
||||||
#[error("Cloud not create a gbm buffer")]
|
#[error("Cloud not create a gbm buffer")]
|
||||||
CreateBo,
|
CreateBo(#[source] OsError),
|
||||||
#[error("gbm buffer has an unknown format")]
|
#[error("gbm buffer has an unknown format")]
|
||||||
UnknownFormat,
|
UnknownFormat,
|
||||||
#[error("Could not retrieve a drm-buf fd")]
|
#[error("Could not retrieve a drm-buf fd")]
|
||||||
|
|
@ -199,26 +199,27 @@ impl GbmDevice {
|
||||||
&self,
|
&self,
|
||||||
width: i32,
|
width: i32,
|
||||||
height: i32,
|
height: i32,
|
||||||
format: &ModifiedFormat,
|
format: &Format,
|
||||||
|
modifiers: &[Modifier],
|
||||||
usage: u32,
|
usage: u32,
|
||||||
) -> Result<GbmBo, GbmError> {
|
) -> Result<GbmBo, GbmError> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let (modifiers, n_modifiers) = if format.modifier == INVALID_MODIFIER {
|
let (modifiers, n_modifiers) = if modifiers.is_empty() {
|
||||||
(ptr::null(), 0)
|
(ptr::null(), 0)
|
||||||
} else {
|
} else {
|
||||||
(&format.modifier as _, 1)
|
(modifiers.as_ptr() as _, modifiers.len() as _)
|
||||||
};
|
};
|
||||||
let bo = gbm_bo_create_with_modifiers2(
|
let bo = gbm_bo_create_with_modifiers2(
|
||||||
self.dev,
|
self.dev,
|
||||||
width as _,
|
width as _,
|
||||||
height as _,
|
height as _,
|
||||||
format.format.drm,
|
format.drm,
|
||||||
modifiers,
|
modifiers,
|
||||||
n_modifiers,
|
n_modifiers,
|
||||||
usage,
|
usage,
|
||||||
);
|
);
|
||||||
if bo.is_null() {
|
if bo.is_null() {
|
||||||
return Err(GbmError::CreateBo);
|
return Err(GbmError::CreateBo(OsError::default()));
|
||||||
}
|
}
|
||||||
let bo = BoHolder { bo };
|
let bo = BoHolder { bo };
|
||||||
let dma = export_bo(bo.bo)?;
|
let dma = export_bo(bo.bo)?;
|
||||||
|
|
@ -250,7 +251,7 @@ impl GbmDevice {
|
||||||
usage,
|
usage,
|
||||||
);
|
);
|
||||||
if bo.is_null() {
|
if bo.is_null() {
|
||||||
return Err(GbmError::CreateBo);
|
return Err(GbmError::CreateBo(OsError::default()));
|
||||||
}
|
}
|
||||||
let bo = BoHolder { bo };
|
let bo = BoHolder { bo };
|
||||||
Ok(GbmBo {
|
Ok(GbmBo {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue