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 }
|
dbus = { version = "0.9.0", optional = true }
|
||||||
drm-fourcc = "^2.1.0"
|
drm-fourcc = "^2.1.0"
|
||||||
drm = { version = "^0.4.0-alpha1", git = "https://github.com/drakulix/drm-rs", branch = "next", optional = true }
|
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"] }
|
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 }
|
input = { version = "0.5", default-features = false, optional = true }
|
||||||
lazy_static = "1"
|
lazy_static = "1"
|
||||||
libc = "0.2.70"
|
libc = "0.2.70"
|
||||||
|
@ -47,7 +47,7 @@ pkg-config = { version = "0.3.17", optional = true }
|
||||||
[features]
|
[features]
|
||||||
default = ["backend_drm", "backend_gbm", "backend_libinput", "backend_udev", "backend_session_logind", "backend_winit", "renderer_gl", "xwayland", "wayland_frontend", "slog-stdlog"]
|
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_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_gbm = ["gbm"]
|
||||||
backend_egl = ["gl_generator"]
|
backend_egl = ["gl_generator"]
|
||||||
backend_libinput = ["input"]
|
backend_libinput = ["input"]
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
|
use std::collections::HashSet;
|
||||||
|
use std::convert::TryFrom;
|
||||||
use std::sync::{Arc, atomic::AtomicBool};
|
use std::sync::{Arc, atomic::AtomicBool};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::os::unix::io::{AsRawFd, RawFd};
|
use std::os::unix::io::{AsRawFd, RawFd};
|
||||||
|
|
||||||
use calloop::{generic::Generic, InsertError, LoopHandle, Source};
|
use calloop::{generic::Generic, InsertError, LoopHandle, Source};
|
||||||
use drm::{Device as BasicDevice, ClientCapability};
|
use drm::{Device as BasicDevice, ClientCapability, DriverCapability};
|
||||||
use drm::control::{ResourceHandles, PlaneResourceHandles, Device as ControlDevice, Event, Mode, PlaneType, crtc, plane, connector};
|
use drm::control::{ResourceHandles, PlaneResourceHandles, Device as ControlDevice, Event, Mode, PlaneType, crtc, plane, connector, property};
|
||||||
use nix::libc::dev_t;
|
use nix::libc::dev_t;
|
||||||
use nix::sys::stat::fstat;
|
use nix::sys::stat::fstat;
|
||||||
|
|
||||||
|
@ -16,6 +18,7 @@ use atomic::AtomicDrmDevice;
|
||||||
use legacy::LegacyDrmDevice;
|
use legacy::LegacyDrmDevice;
|
||||||
use super::surface::{DrmSurface, DrmSurfaceInternal, atomic::AtomicDrmSurface, legacy::LegacyDrmSurface};
|
use super::surface::{DrmSurface, DrmSurfaceInternal, atomic::AtomicDrmSurface, legacy::LegacyDrmSurface};
|
||||||
use super::error::Error;
|
use super::error::Error;
|
||||||
|
use crate::backend::allocator::{Fourcc, Format, Modifier};
|
||||||
|
|
||||||
pub struct DrmDevice<A: AsRawFd + 'static> {
|
pub struct DrmDevice<A: AsRawFd + 'static> {
|
||||||
pub(super) dev_id: dev_t,
|
pub(super) dev_id: dev_t,
|
||||||
|
@ -279,7 +282,7 @@ impl<A: AsRawFd + 'static> DrmDevice<A> {
|
||||||
DrmDeviceInternal::Legacy(dev) => dev.active.clone(),
|
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 {
|
let mapping = match &*self.internal {
|
||||||
DrmDeviceInternal::Atomic(dev) => dev.prop_mapping.clone(),
|
DrmDeviceInternal::Atomic(dev) => dev.prop_mapping.clone(),
|
||||||
_ => unreachable!(),
|
_ => 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())?)
|
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 {
|
Ok(DrmSurface {
|
||||||
crtc,
|
crtc,
|
||||||
plane,
|
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_mode = crtc_info.mode().unwrap_or_else(|| unsafe { std::mem::zeroed() });
|
||||||
let current_blob = match crtc_info.mode() {
|
let current_blob = match crtc_info.mode() {
|
||||||
Some(mode) => fd
|
Some(mode) => fd
|
||||||
.create_property_blob(mode)
|
.create_property_blob(&mode)
|
||||||
.map_err(|source| Error::Access {
|
.map_err(|source| Error::Access {
|
||||||
errmsg: "Failed to create Property Blob for mode",
|
errmsg: "Failed to create Property Blob for mode",
|
||||||
dev: fd.dev_path(),
|
dev: fd.dev_path(),
|
||||||
|
@ -73,7 +73,7 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
|
||||||
};
|
};
|
||||||
|
|
||||||
let blob = fd
|
let blob = fd
|
||||||
.create_property_blob(mode)
|
.create_property_blob(&mode)
|
||||||
.map_err(|source| Error::Access {
|
.map_err(|source| Error::Access {
|
||||||
errmsg: "Failed to create Property Blob for mode",
|
errmsg: "Failed to create Property Blob for mode",
|
||||||
dev: fd.dev_path(),
|
dev: fd.dev_path(),
|
||||||
|
@ -312,7 +312,7 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
|
||||||
|
|
||||||
// check if new config is supported
|
// check if new config is supported
|
||||||
let new_blob = self.fd
|
let new_blob = self.fd
|
||||||
.create_property_blob(mode)
|
.create_property_blob(&mode)
|
||||||
.map_err(|source| Error::Access {
|
.map_err(|source| Error::Access {
|
||||||
errmsg: "Failed to create Property Blob for mode",
|
errmsg: "Failed to create Property Blob for mode",
|
||||||
dev: self.fd.dev_path(),
|
dev: self.fd.dev_path(),
|
||||||
|
@ -485,7 +485,7 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn conn_prop_handle(
|
pub(crate) fn conn_prop_handle(
|
||||||
&self,
|
&self,
|
||||||
handle: connector::Handle,
|
handle: connector::Handle,
|
||||||
name: &'static str,
|
name: &'static str,
|
||||||
|
@ -503,7 +503,7 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
|
||||||
.map(|x| *x)
|
.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
|
self
|
||||||
.prop_mapping
|
.prop_mapping
|
||||||
.1
|
.1
|
||||||
|
@ -518,7 +518,7 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
fn fb_prop_handle(
|
pub(crate) fn fb_prop_handle(
|
||||||
&self,
|
&self,
|
||||||
handle: framebuffer::Handle,
|
handle: framebuffer::Handle,
|
||||||
name: &'static str,
|
name: &'static str,
|
||||||
|
@ -536,7 +536,7 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
|
||||||
.map(|x| *x)
|
.map(|x| *x)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn plane_prop_handle(
|
pub(crate) fn plane_prop_handle(
|
||||||
&self,
|
&self,
|
||||||
handle: plane::Handle,
|
handle: plane::Handle,
|
||||||
name: &'static str,
|
name: &'static str,
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
use std::collections::HashSet;
|
||||||
use std::os::unix::io::{AsRawFd, RawFd};
|
use std::os::unix::io::{AsRawFd, RawFd};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
@ -9,12 +10,14 @@ pub(super) mod legacy;
|
||||||
use super::error::Error;
|
use super::error::Error;
|
||||||
use atomic::AtomicDrmSurface;
|
use atomic::AtomicDrmSurface;
|
||||||
use legacy::LegacyDrmSurface;
|
use legacy::LegacyDrmSurface;
|
||||||
|
use crate::backend::allocator::Format;
|
||||||
|
|
||||||
pub struct DrmSurface<A: AsRawFd + 'static>
|
pub struct DrmSurface<A: AsRawFd + 'static>
|
||||||
{
|
{
|
||||||
pub(super) crtc: crtc::Handle,
|
pub(super) crtc: crtc::Handle,
|
||||||
pub(super) plane: plane::Handle,
|
pub(super) plane: plane::Handle,
|
||||||
pub(super) internal: Arc<DrmSurfaceInternal<A>>,
|
pub(super) internal: Arc<DrmSurfaceInternal<A>>,
|
||||||
|
pub(super) formats: HashSet<Format>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum DrmSurfaceInternal<A: AsRawFd + 'static> {
|
pub enum DrmSurfaceInternal<A: AsRawFd + 'static> {
|
||||||
|
@ -177,4 +180,8 @@ impl<A: AsRawFd + 'static> DrmSurface<A> {
|
||||||
DrmSurfaceInternal::Legacy(surf) => surf.page_flip(framebuffer)
|
DrmSurfaceInternal::Legacy(surf) => surf.page_flip(framebuffer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn supported_formats(&self) -> &HashSet<Format> {
|
||||||
|
&self.formats
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue