drm: expose supported plane formats
This commit is contained in:
parent
52d581371c
commit
9d021d52a4
|
@ -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"]
|
||||
|
|
|
@ -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,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue