drm: allow to test if scanning out a buffer would succeed
This commit is contained in:
parent
d042609dbd
commit
0180bb6ef5
|
@ -23,14 +23,14 @@ pub struct State {
|
||||||
|
|
||||||
pub struct AtomicDrmSurface<A: AsRawFd + 'static> {
|
pub struct AtomicDrmSurface<A: AsRawFd + 'static> {
|
||||||
pub(super) fd: Arc<DrmDeviceInternal<A>>,
|
pub(super) fd: Arc<DrmDeviceInternal<A>>,
|
||||||
active: Arc<AtomicBool>,
|
pub(super) active: Arc<AtomicBool>,
|
||||||
crtc: crtc::Handle,
|
crtc: crtc::Handle,
|
||||||
plane: plane::Handle,
|
plane: plane::Handle,
|
||||||
prop_mapping: Mapping,
|
prop_mapping: Mapping,
|
||||||
state: RwLock<State>,
|
state: RwLock<State>,
|
||||||
pending: RwLock<State>,
|
pending: RwLock<State>,
|
||||||
test_buffer: Mutex<Option<(DumbBuffer, framebuffer::Handle)>>,
|
test_buffer: Mutex<Option<(DumbBuffer, framebuffer::Handle)>>,
|
||||||
logger: ::slog::Logger,
|
pub(super) logger: ::slog::Logger,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
|
impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
|
||||||
|
@ -485,6 +485,37 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn test_buffer(&self, fb: framebuffer::Handle, mode: &Mode) -> Result<bool, Error> {
|
||||||
|
if !self.active.load(Ordering::SeqCst) {
|
||||||
|
return Err(Error::DeviceInactive);
|
||||||
|
}
|
||||||
|
|
||||||
|
let blob = self.fd
|
||||||
|
.create_property_blob(&mode)
|
||||||
|
.map_err(|source| Error::Access {
|
||||||
|
errmsg: "Failed to create Property Blob for mode",
|
||||||
|
dev: self.fd.dev_path(),
|
||||||
|
source,
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let req = self.build_request(
|
||||||
|
&mut [].iter(),
|
||||||
|
&mut [].iter(),
|
||||||
|
self.plane,
|
||||||
|
Some(fb),
|
||||||
|
Some(*mode),
|
||||||
|
Some(blob)
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let result = self.fd.atomic_commit(&[AtomicCommitFlags::AllowModeset, AtomicCommitFlags::TestOnly], req).is_ok();
|
||||||
|
|
||||||
|
if let Err(err) = self.fd.destroy_framebuffer(fb) {
|
||||||
|
debug!(self.logger, "Failed to destroy framebuffer({:?}): {}", fb, err);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn conn_prop_handle(
|
pub(crate) fn conn_prop_handle(
|
||||||
&self,
|
&self,
|
||||||
handle: connector::Handle,
|
handle: connector::Handle,
|
||||||
|
|
|
@ -21,11 +21,11 @@ pub struct State {
|
||||||
|
|
||||||
pub struct LegacyDrmSurface<A: AsRawFd + 'static> {
|
pub struct LegacyDrmSurface<A: AsRawFd + 'static> {
|
||||||
pub(super) fd: Arc<DrmDeviceInternal<A>>,
|
pub(super) fd: Arc<DrmDeviceInternal<A>>,
|
||||||
active: Arc<AtomicBool>,
|
pub(super) active: Arc<AtomicBool>,
|
||||||
crtc: crtc::Handle,
|
crtc: crtc::Handle,
|
||||||
state: RwLock<State>,
|
state: RwLock<State>,
|
||||||
pending: RwLock<State>,
|
pending: RwLock<State>,
|
||||||
logger: ::slog::Logger,
|
pub(super) logger: ::slog::Logger,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<A: AsRawFd + 'static> LegacyDrmSurface<A> {
|
impl<A: AsRawFd + 'static> LegacyDrmSurface<A> {
|
||||||
|
@ -312,6 +312,21 @@ impl<A: AsRawFd + 'static> LegacyDrmSurface<A> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn test_buffer(&self, fb: framebuffer::Handle, mode: &Mode) -> Result<bool, Error> {
|
||||||
|
if !self.active.load(Ordering::SeqCst) {
|
||||||
|
return Err(Error::DeviceInactive);
|
||||||
|
}
|
||||||
|
|
||||||
|
debug!(self.logger, "Setting screen for buffer *testing*");
|
||||||
|
Ok(self.fd.set_crtc(
|
||||||
|
self.crtc,
|
||||||
|
Some(fb),
|
||||||
|
(0, 0),
|
||||||
|
&[],
|
||||||
|
Some(*mode),
|
||||||
|
).is_ok())
|
||||||
|
}
|
||||||
|
|
||||||
// we use this function to verify, if a certain connector/mode combination
|
// we use this function to verify, if a certain connector/mode combination
|
||||||
// is valid on our crtc. We do this with the most basic information we have:
|
// is valid on our crtc. We do this with the most basic information we have:
|
||||||
// - is there a matching encoder
|
// - is there a matching encoder
|
||||||
|
|
|
@ -7,10 +7,10 @@ use drm::control::{Device as ControlDevice, Mode, crtc, connector, framebuffer,
|
||||||
|
|
||||||
pub(super) mod atomic;
|
pub(super) mod atomic;
|
||||||
pub(super) mod legacy;
|
pub(super) mod legacy;
|
||||||
use super::error::Error;
|
use super::{error::Error, device::DevPath};
|
||||||
use atomic::AtomicDrmSurface;
|
use atomic::AtomicDrmSurface;
|
||||||
use legacy::LegacyDrmSurface;
|
use legacy::LegacyDrmSurface;
|
||||||
use crate::backend::allocator::Format;
|
use crate::backend::allocator::{Format, Fourcc, Modifier};
|
||||||
|
|
||||||
pub struct DrmSurface<A: AsRawFd + 'static>
|
pub struct DrmSurface<A: AsRawFd + 'static>
|
||||||
{
|
{
|
||||||
|
@ -184,4 +184,65 @@ impl<A: AsRawFd + 'static> DrmSurface<A> {
|
||||||
pub fn supported_formats(&self) -> &HashSet<Format> {
|
pub fn supported_formats(&self) -> &HashSet<Format> {
|
||||||
&self.formats
|
&self.formats
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn test_buffer<B>(&self, buffer: &B, bpp: u32, modifier: Option<[Modifier; 4]>, mode: &Mode, allow_screen_change: bool) -> Result<Option<framebuffer::Handle>, Error>
|
||||||
|
where
|
||||||
|
B: drm::buffer::Buffer + drm::buffer::PlanarBuffer
|
||||||
|
{
|
||||||
|
use std::sync::atomic::Ordering;
|
||||||
|
|
||||||
|
let (active, logger) = match &*self.internal {
|
||||||
|
DrmSurfaceInternal::Atomic(surf) => (surf.active.load(Ordering::SeqCst), surf.logger.clone()),
|
||||||
|
DrmSurfaceInternal::Legacy(surf) => (surf.active.load(Ordering::SeqCst), surf.logger.clone()),
|
||||||
|
};
|
||||||
|
|
||||||
|
if !active {
|
||||||
|
return Err(Error::DeviceInactive);
|
||||||
|
}
|
||||||
|
|
||||||
|
let fb = match
|
||||||
|
if let Some(mods) = modifier {
|
||||||
|
self.add_planar_framebuffer(buffer, unsafe {
|
||||||
|
std::mem::transmute::<&[Modifier; 4], &[Option<Modifier>; 4]>(&mods)
|
||||||
|
}, drm_ffi::DRM_MODE_FB_MODIFIERS)
|
||||||
|
} else {
|
||||||
|
self.add_planar_framebuffer(buffer, &[None, None, None, None], 0)
|
||||||
|
}
|
||||||
|
{
|
||||||
|
Ok(fb) => fb,
|
||||||
|
Err(_) => {
|
||||||
|
// We only support this as a fallback of last resort for ARGB8888 visuals,
|
||||||
|
// like xf86-video-modesetting does.
|
||||||
|
if drm::buffer::Buffer::format(buffer) != Fourcc::Argb8888
|
||||||
|
|| buffer.handles()[1].is_some() {
|
||||||
|
return Ok(false);
|
||||||
|
}
|
||||||
|
debug!(logger, "Failed to add framebuffer, trying legacy method");
|
||||||
|
self.add_framebuffer(buffer, bpp, 32).map_err(|source| Error::Access {
|
||||||
|
errmsg: "Failed to add framebuffer",
|
||||||
|
dev: self.dev_path(),
|
||||||
|
source,
|
||||||
|
})?
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let result = match &*self.internal {
|
||||||
|
DrmSurfaceInternal::Atomic(surf) => surf.test_buffer(fb, mode),
|
||||||
|
DrmSurfaceInternal::Legacy(surf) => if allow_screen_change {
|
||||||
|
surf.test_buffer(fb, mode)
|
||||||
|
} else { Ok(false) } // There is no test-commiting with the legacy interface
|
||||||
|
};
|
||||||
|
|
||||||
|
if !result.unwrap_or(false) {
|
||||||
|
if let Err(err) = self.destroy_framebuffer(fb) {
|
||||||
|
debug!(logger, "Failed to destroy framebuffer({:?}): {}", fb, err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result.map(|x| if x {
|
||||||
|
Some(fb)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue