drm: expose supported plane formats

This commit is contained in:
Victor Brekenfeld 2021-04-09 15:17:10 +02:00
parent 52d581371c
commit 9d021d52a4
4 changed files with 100 additions and 14 deletions

View File

@ -17,8 +17,8 @@ cgmath = "0.18.0"
dbus = { version = "0.9.0", optional = true }
drm-fourcc = "^2.1.0"
drm = { version = "^0.4.0-alpha1", git = "https://github.com/drakulix/drm-rs", branch = "next", optional = true }
drm-ffi = { version = "^0.4.0-alpha1", git = "https://github.com/drakulix/drm-rs", branch = "next", optional = true }
gbm = { version = "^0.6.0", git = "https://github.com/drakulix/gbm.rs", branch = "develop", optional = true, default-features = false, features = ["drm-support"] }
image = { version = "0.23.0", optional = true, default-features = false }
input = { version = "0.5", default-features = false, optional = true }
lazy_static = "1"
libc = "0.2.70"
@ -47,7 +47,7 @@ pkg-config = { version = "0.3.17", optional = true }
[features]
default = ["backend_drm", "backend_gbm", "backend_libinput", "backend_udev", "backend_session_logind", "backend_winit", "renderer_gl", "xwayland", "wayland_frontend", "slog-stdlog"]
backend_winit = ["winit", "wayland-server/dlopen", "backend_egl", "wayland-egl", "renderer_gl", "use_system_lib"]
backend_drm = ["drm"]
backend_drm = ["drm", "drm-ffi"]
backend_gbm = ["gbm"]
backend_egl = ["gl_generator"]
backend_libinput = ["input"]

View File

@ -1,12 +1,14 @@
use std::rc::Rc;
use std::cell::RefCell;
use std::collections::HashSet;
use std::convert::TryFrom;
use std::sync::{Arc, atomic::AtomicBool};
use std::path::PathBuf;
use std::os::unix::io::{AsRawFd, RawFd};
use calloop::{generic::Generic, InsertError, LoopHandle, Source};
use drm::{Device as BasicDevice, ClientCapability};
use drm::control::{ResourceHandles, PlaneResourceHandles, Device as ControlDevice, Event, Mode, PlaneType, crtc, plane, connector};
use drm::{Device as BasicDevice, ClientCapability, DriverCapability};
use drm::control::{ResourceHandles, PlaneResourceHandles, Device as ControlDevice, Event, Mode, PlaneType, crtc, plane, connector, property};
use nix::libc::dev_t;
use nix::sys::stat::fstat;
@ -16,6 +18,7 @@ use atomic::AtomicDrmDevice;
use legacy::LegacyDrmDevice;
use super::surface::{DrmSurface, DrmSurfaceInternal, atomic::AtomicDrmSurface, legacy::LegacyDrmSurface};
use super::error::Error;
use crate::backend::allocator::{Fourcc, Format, Modifier};
pub struct DrmDevice<A: AsRawFd + 'static> {
pub(super) dev_id: dev_t,
@ -279,7 +282,7 @@ impl<A: AsRawFd + 'static> DrmDevice<A> {
DrmDeviceInternal::Legacy(dev) => dev.active.clone(),
};
let internal = Arc::new(if self.is_atomic() {
let internal = if self.is_atomic() {
let mapping = match &*self.internal {
DrmDeviceInternal::Atomic(dev) => dev.prop_mapping.clone(),
_ => unreachable!(),
@ -292,12 +295,88 @@ impl<A: AsRawFd + 'static> DrmDevice<A> {
}
DrmSurfaceInternal::Legacy(LegacyDrmSurface::new(self.internal.clone(), active, crtc, mode, connectors, self.logger.clone())?)
});
};
// get plane formats
let plane_info = self.get_plane(plane).map_err(|source| Error::Access {
errmsg: "Error loading plane info",
dev: self.dev_path(),
source,
})?;
let mut formats = HashSet::new();
for code in plane_info.formats().iter().flat_map(|x| Fourcc::try_from(*x).ok()) {
formats.insert(Format {
code,
modifier: Modifier::Invalid,
});
}
if let (Ok(1), &DrmSurfaceInternal::Atomic(ref surf)) = (self.get_driver_capability(DriverCapability::AddFB2Modifiers), &internal) {
let set = self.get_properties(plane).map_err(|source| Error::Access {
errmsg: "Failed to query properties",
dev: self.dev_path(),
source
})?;
if let Ok(prop) = surf.plane_prop_handle(plane, "IN_FORMATS") {
let prop_info = self.get_property(prop).map_err(|source| Error::Access {
errmsg: "Failed to query property",
dev: self.dev_path(),
source,
})?;
let (handles, raw_values) = set.as_props_and_values();
let raw_value = raw_values[handles.iter().enumerate().find_map(|(i, handle)| if *handle == prop { Some(i) } else { None }).unwrap()];
if let property::Value::Blob(blob) = prop_info.value_type().convert_value(raw_value) {
let data = self.get_property_blob(blob).map_err(|source| Error::Access {
errmsg: "Failed to query property blob data",
dev: self.dev_path(),
source,
})?;
// be careful here, we have no idea about the alignment inside the blob, so always copy using `read_unaligned`,
// although slice::from_raw_parts would be so much nicer to iterate and to read.
unsafe {
let fmt_mod_blob_ptr = data.as_ptr() as *const drm_ffi::drm_format_modifier_blob;
let fmt_mod_blob = &*fmt_mod_blob_ptr;
let formats_ptr: *const u32 = fmt_mod_blob_ptr.cast::<u8>().offset(fmt_mod_blob.formats_offset as isize) as *const _;
let modifiers_ptr: *const drm_ffi::drm_format_modifier = fmt_mod_blob_ptr.cast::<u8>().offset(fmt_mod_blob.modifiers_offset as isize) as *const _;
let formats_ptr = formats_ptr as *const u32;
let modifiers_ptr = modifiers_ptr as *const drm_ffi::drm_format_modifier;
for i in 0..fmt_mod_blob.count_modifiers {
let mod_info = modifiers_ptr.offset(i as isize).read_unaligned();
for j in 0..64 {
if mod_info.formats & (1u64 << j) != 0 {
let code = Fourcc::try_from(formats_ptr.offset((j + mod_info.offset) as isize).read_unaligned()).ok();
let modifier = Modifier::from(mod_info.modifier);
if let Some(code) = code {
formats.insert(Format {
code,
modifier,
});
}
}
}
}
}
}
}
} else if self.plane_type(plane)? == PlaneType::Cursor {
// Force a LINEAR layout for the cursor if the driver doesn't support modifiers
for format in formats.clone() {
formats.insert(Format {
code: format.code,
modifier: Modifier::Linear,
});
}
}
info!(self.logger, "Supported scan-out formats for plane ({:?}): {:#?}", plane, formats);
Ok(DrmSurface {
crtc,
plane,
internal,
internal: Arc::new(internal),
formats,
})
}
}

View File

@ -63,7 +63,7 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
let current_mode = crtc_info.mode().unwrap_or_else(|| unsafe { std::mem::zeroed() });
let current_blob = match crtc_info.mode() {
Some(mode) => fd
.create_property_blob(mode)
.create_property_blob(&mode)
.map_err(|source| Error::Access {
errmsg: "Failed to create Property Blob for mode",
dev: fd.dev_path(),
@ -73,7 +73,7 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
};
let blob = fd
.create_property_blob(mode)
.create_property_blob(&mode)
.map_err(|source| Error::Access {
errmsg: "Failed to create Property Blob for mode",
dev: fd.dev_path(),
@ -312,7 +312,7 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
// check if new config is supported
let new_blob = self.fd
.create_property_blob(mode)
.create_property_blob(&mode)
.map_err(|source| Error::Access {
errmsg: "Failed to create Property Blob for mode",
dev: self.fd.dev_path(),
@ -485,7 +485,7 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
Ok(())
}
fn conn_prop_handle(
pub(crate) fn conn_prop_handle(
&self,
handle: connector::Handle,
name: &'static str,
@ -503,7 +503,7 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
.map(|x| *x)
}
fn crtc_prop_handle(&self, handle: crtc::Handle, name: &'static str) -> Result<property::Handle, Error> {
pub(crate) fn crtc_prop_handle(&self, handle: crtc::Handle, name: &'static str) -> Result<property::Handle, Error> {
self
.prop_mapping
.1
@ -518,7 +518,7 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
}
#[allow(dead_code)]
fn fb_prop_handle(
pub(crate) fn fb_prop_handle(
&self,
handle: framebuffer::Handle,
name: &'static str,
@ -536,7 +536,7 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
.map(|x| *x)
}
fn plane_prop_handle(
pub(crate) fn plane_prop_handle(
&self,
handle: plane::Handle,
name: &'static str,

View File

@ -1,3 +1,4 @@
use std::collections::HashSet;
use std::os::unix::io::{AsRawFd, RawFd};
use std::sync::Arc;
@ -9,12 +10,14 @@ pub(super) mod legacy;
use super::error::Error;
use atomic::AtomicDrmSurface;
use legacy::LegacyDrmSurface;
use crate::backend::allocator::Format;
pub struct DrmSurface<A: AsRawFd + 'static>
{
pub(super) crtc: crtc::Handle,
pub(super) plane: plane::Handle,
pub(super) internal: Arc<DrmSurfaceInternal<A>>,
pub(super) formats: HashSet<Format>,
}
pub enum DrmSurfaceInternal<A: AsRawFd + 'static> {
@ -177,4 +180,8 @@ impl<A: AsRawFd + 'static> DrmSurface<A> {
DrmSurfaceInternal::Legacy(surf) => surf.page_flip(framebuffer)
}
}
pub fn supported_formats(&self) -> &HashSet<Format> {
&self.formats
}
}