drm: Require all surfaces to always have a mode set
This commit is contained in:
parent
b6087bf2d2
commit
d6fa2e96cf
|
@ -319,7 +319,7 @@ impl<S: SessionNotifier, Data: 'static> UdevHandlerImpl<S, Data> {
|
||||||
for crtc in res_handles.filter_crtcs(encoder_info.possible_crtcs()) {
|
for crtc in res_handles.filter_crtcs(encoder_info.possible_crtcs()) {
|
||||||
if let Entry::Vacant(entry) = backends.entry(crtc) {
|
if let Entry::Vacant(entry) = backends.entry(crtc) {
|
||||||
let renderer = GliumDrawer::init(
|
let renderer = GliumDrawer::init(
|
||||||
device.create_surface(crtc).unwrap(),
|
device.create_surface(crtc, connector_info.modes()[0], &[connector_info.handle()]).unwrap(),
|
||||||
egl_buffer_reader.clone(),
|
egl_buffer_reader.clone(),
|
||||||
logger.clone(),
|
logger.clone(),
|
||||||
);
|
);
|
||||||
|
|
|
@ -96,9 +96,7 @@ fn main() {
|
||||||
let mode = connector_info.modes()[0]; // Use first mode (usually highest resoltion, but in reality you should filter and sort and check and match with other connectors, if you use more then one.)
|
let mode = connector_info.modes()[0]; // Use first mode (usually highest resoltion, but in reality you should filter and sort and check and match with other connectors, if you use more then one.)
|
||||||
|
|
||||||
// Initialize the hardware backend
|
// Initialize the hardware backend
|
||||||
let surface = Rc::new(device.create_surface(crtc).unwrap());
|
let surface = Rc::new(device.create_surface(crtc, mode, &[connector_info.handle()]).unwrap());
|
||||||
surface.set_connectors(&[connector_info.handle()]).unwrap();
|
|
||||||
surface.use_mode(Some(mode)).unwrap();
|
|
||||||
|
|
||||||
for conn in surface.current_connectors().into_iter() {
|
for conn in surface.current_connectors().into_iter() {
|
||||||
if conn != connector_info.handle() {
|
if conn != connector_info.handle() {
|
||||||
|
|
|
@ -78,10 +78,8 @@ fn main() {
|
||||||
let mode = connector_info.modes()[0]; // Use first mode (usually highest resoltion, but in reality you should filter and sort and check and match with other connectors, if you use more then one.)
|
let mode = connector_info.modes()[0]; // Use first mode (usually highest resoltion, but in reality you should filter and sort and check and match with other connectors, if you use more then one.)
|
||||||
|
|
||||||
// Initialize the hardware backend
|
// Initialize the hardware backend
|
||||||
let surface = Rc::new(device.create_surface(crtc).unwrap());
|
let surface = Rc::new(device.create_surface(crtc, mode, &[connector_info.handle()]).unwrap());
|
||||||
|
|
||||||
surface.use_mode(Some(mode)).unwrap();
|
|
||||||
surface.set_connectors(&[connector_info.handle()]).unwrap();
|
|
||||||
/*
|
/*
|
||||||
* Lets create buffers and framebuffers.
|
* Lets create buffers and framebuffers.
|
||||||
* We use drm-rs DumbBuffers, because they always work and require little to no setup.
|
* We use drm-rs DumbBuffers, because they always work and require little to no setup.
|
||||||
|
|
|
@ -19,7 +19,7 @@ use std::sync::{
|
||||||
|
|
||||||
use drm::control::{atomic::AtomicModeReq, AtomicCommitFlags, Device as ControlDevice, Event};
|
use drm::control::{atomic::AtomicModeReq, AtomicCommitFlags, Device as ControlDevice, Event};
|
||||||
use drm::control::{
|
use drm::control::{
|
||||||
connector, crtc, encoder, framebuffer, plane, property, PropertyValueSet, ResourceHandle, ResourceHandles,
|
connector, crtc, encoder, framebuffer, plane, property, Mode, PropertyValueSet, ResourceHandle, ResourceHandles,
|
||||||
};
|
};
|
||||||
use drm::SystemError as DrmError;
|
use drm::SystemError as DrmError;
|
||||||
use drm::{ClientCapability, Device as BasicDevice};
|
use drm::{ClientCapability, Device as BasicDevice};
|
||||||
|
@ -339,7 +339,7 @@ impl<A: AsRawFd + 'static> Device for AtomicDrmDevice<A> {
|
||||||
let _ = self.handler.take();
|
let _ = self.handler.take();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_surface(&mut self, crtc: crtc::Handle) -> Result<AtomicDrmSurface<A>, Error> {
|
fn create_surface(&mut self, crtc: crtc::Handle, mode: Mode, connectors: &[connector::Handle]) -> Result<AtomicDrmSurface<A>, Error> {
|
||||||
if self.backends.borrow().contains_key(&crtc) {
|
if self.backends.borrow().contains_key(&crtc) {
|
||||||
return Err(Error::CrtcAlreadyInUse(crtc));
|
return Err(Error::CrtcAlreadyInUse(crtc));
|
||||||
}
|
}
|
||||||
|
@ -348,9 +348,15 @@ impl<A: AsRawFd + 'static> Device for AtomicDrmDevice<A> {
|
||||||
return Err(Error::DeviceInactive);
|
return Err(Error::DeviceInactive);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if connectors.is_empty() {
|
||||||
|
return Err(Error::SurfaceWithoutConnectors(crtc));
|
||||||
|
}
|
||||||
|
|
||||||
let backend = Rc::new(AtomicDrmSurfaceInternal::new(
|
let backend = Rc::new(AtomicDrmSurfaceInternal::new(
|
||||||
self.dev.clone(),
|
self.dev.clone(),
|
||||||
crtc,
|
crtc,
|
||||||
|
mode,
|
||||||
|
connectors,
|
||||||
self.logger.new(o!("crtc" => format!("{:?}", crtc))),
|
self.logger.new(o!("crtc" => format!("{:?}", crtc))),
|
||||||
)?);
|
)?);
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use drm::buffer::Buffer;
|
use drm::buffer::Buffer;
|
||||||
use drm::control::atomic::AtomicModeReq;
|
use drm::control::atomic::AtomicModeReq;
|
||||||
use drm::control::Device as ControlDevice;
|
use drm::control::Device as ControlDevice;
|
||||||
use drm::control::{connector, crtc, framebuffer, plane, property, AtomicCommitFlags, Mode, PlaneType};
|
use drm::control::{connector, crtc, dumbbuffer::DumbBuffer, framebuffer, plane, property, AtomicCommitFlags, Mode, PlaneType};
|
||||||
use drm::Device as BasicDevice;
|
use drm::Device as BasicDevice;
|
||||||
|
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
|
@ -26,8 +26,8 @@ pub struct CursorState {
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||||
pub struct State {
|
pub struct State {
|
||||||
pub mode: Option<Mode>,
|
pub mode: Mode,
|
||||||
pub blob: Option<property::Value<'static>>,
|
pub blob: property::Value<'static>,
|
||||||
pub connectors: HashSet<connector::Handle>,
|
pub connectors: HashSet<connector::Handle>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,6 +45,7 @@ pub(super) struct AtomicDrmSurfaceInternal<A: AsRawFd + 'static> {
|
||||||
pub(super) state: RwLock<State>,
|
pub(super) state: RwLock<State>,
|
||||||
pub(super) pending: RwLock<State>,
|
pub(super) pending: RwLock<State>,
|
||||||
pub(super) logger: ::slog::Logger,
|
pub(super) logger: ::slog::Logger,
|
||||||
|
init_buffer: Cell<Option<(DumbBuffer, framebuffer::Handle)>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<A: AsRawFd + 'static> AsRawFd for AtomicDrmSurfaceInternal<A> {
|
impl<A: AsRawFd + 'static> AsRawFd for AtomicDrmSurfaceInternal<A> {
|
||||||
|
@ -57,26 +58,36 @@ impl<A: AsRawFd + 'static> BasicDevice for AtomicDrmSurfaceInternal<A> {}
|
||||||
impl<A: AsRawFd + 'static> ControlDevice for AtomicDrmSurfaceInternal<A> {}
|
impl<A: AsRawFd + 'static> ControlDevice for AtomicDrmSurfaceInternal<A> {}
|
||||||
|
|
||||||
impl<A: AsRawFd + 'static> AtomicDrmSurfaceInternal<A> {
|
impl<A: AsRawFd + 'static> AtomicDrmSurfaceInternal<A> {
|
||||||
pub(crate) fn new(dev: Rc<Dev<A>>, crtc: crtc::Handle, logger: ::slog::Logger) -> Result<Self, Error> {
|
pub(crate) fn new(dev: Rc<Dev<A>>, crtc: crtc::Handle, mode: Mode, connectors: &[connector::Handle], logger: ::slog::Logger) -> Result<Self, Error> {
|
||||||
let crtc_info = dev.get_crtc(crtc).compat().map_err(|source| Error::Access {
|
let crtc_info = dev.get_crtc(crtc).compat().map_err(|source| Error::Access {
|
||||||
errmsg: "Error loading crtc info",
|
errmsg: "Error loading crtc info",
|
||||||
dev: dev.dev_path(),
|
dev: dev.dev_path(),
|
||||||
source,
|
source,
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let mode = crtc_info.mode();
|
// If we have no current mode, we create a fake one, which will not match (and thus gets overriden on the commit below).
|
||||||
let blob = match mode {
|
// A better fix would probably be making mode an `Option`, but that would mean
|
||||||
Some(mode) => Some(
|
// we need to be sure, we require a mode to always be set without relying on the compiler.
|
||||||
dev.create_property_blob(mode)
|
// So we cheat, because it works and is easier to handle later.
|
||||||
.compat()
|
let current_mode = crtc_info.mode().unwrap_or_else(|| unsafe { std::mem::zeroed() });
|
||||||
.map_err(|source| Error::Access {
|
let current_blob = match crtc_info.mode() {
|
||||||
errmsg: "Failed to create Property Blob for mode",
|
Some(mode) => dev.create_property_blob(mode)
|
||||||
dev: dev.dev_path(),
|
.compat()
|
||||||
source,
|
.map_err(|source| Error::Access {
|
||||||
})?,
|
errmsg: "Failed to create Property Blob for mode",
|
||||||
),
|
dev: dev.dev_path(),
|
||||||
None => None,
|
source,
|
||||||
|
})?,
|
||||||
|
None => property::Value::Unknown(0),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let blob = dev.create_property_blob(mode)
|
||||||
|
.compat()
|
||||||
|
.map_err(|source| Error::Access {
|
||||||
|
errmsg: "Failed to create Property Blob for mode",
|
||||||
|
dev: dev.dev_path(),
|
||||||
|
source,
|
||||||
|
})?;
|
||||||
|
|
||||||
let res_handles = ControlDevice::resource_handles(&*dev)
|
let res_handles = ControlDevice::resource_handles(&*dev)
|
||||||
.compat()
|
.compat()
|
||||||
|
@ -86,12 +97,8 @@ impl<A: AsRawFd + 'static> AtomicDrmSurfaceInternal<A> {
|
||||||
source,
|
source,
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let mut state = State {
|
|
||||||
mode,
|
|
||||||
blob,
|
|
||||||
connectors: HashSet::new(),
|
|
||||||
};
|
|
||||||
|
|
||||||
|
let mut current_connectors = HashSet::new();
|
||||||
for conn in res_handles.connectors() {
|
for conn in res_handles.connectors() {
|
||||||
let crtc_prop = dev
|
let crtc_prop = dev
|
||||||
.prop_mapping
|
.prop_mapping
|
||||||
|
@ -113,7 +120,7 @@ impl<A: AsRawFd + 'static> AtomicDrmSurfaceInternal<A> {
|
||||||
crtc_prop_info.value_type().convert_value(val)
|
crtc_prop_info.value_type().convert_value(val)
|
||||||
{
|
{
|
||||||
if conn_crtc == crtc {
|
if conn_crtc == crtc {
|
||||||
state.connectors.insert(*conn);
|
current_connectors.insert(*conn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -121,13 +128,23 @@ impl<A: AsRawFd + 'static> AtomicDrmSurfaceInternal<A> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
let state = State {
|
||||||
|
mode: current_mode,
|
||||||
|
blob: current_blob,
|
||||||
|
connectors: current_connectors,
|
||||||
|
};
|
||||||
|
let pending = State {
|
||||||
|
mode,
|
||||||
|
blob,
|
||||||
|
connectors: connectors.into_iter().copied().collect(),
|
||||||
|
};
|
||||||
|
|
||||||
let (primary, cursor) =
|
let (primary, cursor) =
|
||||||
AtomicDrmSurfaceInternal::find_planes(&dev, crtc).ok_or(Error::NoSuitablePlanes {
|
AtomicDrmSurfaceInternal::find_planes(&dev, crtc).ok_or(Error::NoSuitablePlanes {
|
||||||
crtc,
|
crtc,
|
||||||
dev: dev.dev_path(),
|
dev: dev.dev_path(),
|
||||||
})?;
|
})?;
|
||||||
Ok(AtomicDrmSurfaceInternal {
|
let surface = AtomicDrmSurfaceInternal {
|
||||||
dev,
|
dev,
|
||||||
crtc,
|
crtc,
|
||||||
cursor: CursorState {
|
cursor: CursorState {
|
||||||
|
@ -136,10 +153,22 @@ impl<A: AsRawFd + 'static> AtomicDrmSurfaceInternal<A> {
|
||||||
hotspot: Cell::new((0, 0)),
|
hotspot: Cell::new((0, 0)),
|
||||||
},
|
},
|
||||||
planes: Planes { primary, cursor },
|
planes: Planes { primary, cursor },
|
||||||
state: RwLock::new(state.clone()),
|
state: RwLock::new(state),
|
||||||
pending: RwLock::new(state),
|
pending: RwLock::new(pending),
|
||||||
logger,
|
logger,
|
||||||
})
|
init_buffer: Cell::new(None),
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(surface)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A: AsRawFd + 'static> Drop for AtomicDrmSurfaceInternal<A> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
if let Some((db, fb)) = self.init_buffer.take() {
|
||||||
|
let _ = self.destroy_framebuffer(fb);
|
||||||
|
let _ = self.destroy_dumb_buffer(db);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -159,11 +188,11 @@ impl<A: AsRawFd + 'static> Surface for AtomicDrmSurfaceInternal<A> {
|
||||||
self.pending.read().unwrap().connectors.clone()
|
self.pending.read().unwrap().connectors.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn current_mode(&self) -> Option<Mode> {
|
fn current_mode(&self) -> Mode {
|
||||||
self.state.read().unwrap().mode
|
self.state.read().unwrap().mode
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pending_mode(&self) -> Option<Mode> {
|
fn pending_mode(&self) -> Mode {
|
||||||
self.pending.read().unwrap().mode
|
self.pending.read().unwrap().mode
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -180,15 +209,15 @@ impl<A: AsRawFd + 'static> Surface for AtomicDrmSurfaceInternal<A> {
|
||||||
let mut pending = self.pending.write().unwrap();
|
let mut pending = self.pending.write().unwrap();
|
||||||
|
|
||||||
// check if the connector can handle the current mode
|
// check if the connector can handle the current mode
|
||||||
if info.modes().contains(pending.mode.as_ref().unwrap()) {
|
if info.modes().contains(&pending.mode) {
|
||||||
// check if config is supported
|
// check if config is supported
|
||||||
let req = self.build_request(
|
let req = self.build_request(
|
||||||
&mut [conn].iter(),
|
&mut [conn].iter(),
|
||||||
&mut [].iter(),
|
&mut [].iter(),
|
||||||
&self.planes,
|
&self.planes,
|
||||||
None,
|
None,
|
||||||
pending.mode,
|
Some(pending.mode),
|
||||||
pending.blob,
|
Some(pending.blob),
|
||||||
)?;
|
)?;
|
||||||
self.atomic_commit(
|
self.atomic_commit(
|
||||||
&[AtomicCommitFlags::AllowModeset, AtomicCommitFlags::TestOnly],
|
&[AtomicCommitFlags::AllowModeset, AtomicCommitFlags::TestOnly],
|
||||||
|
@ -202,7 +231,7 @@ impl<A: AsRawFd + 'static> Surface for AtomicDrmSurfaceInternal<A> {
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(Error::ModeNotSuitable(pending.mode.unwrap()))
|
Err(Error::ModeNotSuitable(pending.mode))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -215,8 +244,8 @@ impl<A: AsRawFd + 'static> Surface for AtomicDrmSurfaceInternal<A> {
|
||||||
&mut [conn].iter(),
|
&mut [conn].iter(),
|
||||||
&self.planes,
|
&self.planes,
|
||||||
None,
|
None,
|
||||||
pending.mode,
|
Some(pending.mode),
|
||||||
pending.blob,
|
Some(pending.blob),
|
||||||
)?;
|
)?;
|
||||||
self.atomic_commit(
|
self.atomic_commit(
|
||||||
&[AtomicCommitFlags::AllowModeset, AtomicCommitFlags::TestOnly],
|
&[AtomicCommitFlags::AllowModeset, AtomicCommitFlags::TestOnly],
|
||||||
|
@ -244,8 +273,8 @@ impl<A: AsRawFd + 'static> Surface for AtomicDrmSurfaceInternal<A> {
|
||||||
&mut removed,
|
&mut removed,
|
||||||
&self.planes,
|
&self.planes,
|
||||||
None,
|
None,
|
||||||
pending.mode,
|
Some(pending.mode),
|
||||||
pending.blob,
|
Some(pending.blob),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
self.atomic_commit(
|
self.atomic_commit(
|
||||||
|
@ -259,30 +288,26 @@ impl<A: AsRawFd + 'static> Surface for AtomicDrmSurfaceInternal<A> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn use_mode(&self, mode: Option<Mode>) -> Result<(), Error> {
|
fn use_mode(&self, mode: Mode) -> Result<(), Error> {
|
||||||
let mut pending = self.pending.write().unwrap();
|
let mut pending = self.pending.write().unwrap();
|
||||||
|
|
||||||
// check if new config is supported
|
// check if new config is supported
|
||||||
let new_blob = Some(match mode {
|
let new_blob = self
|
||||||
Some(mode) => self
|
|
||||||
.dev
|
|
||||||
.create_property_blob(mode)
|
.create_property_blob(mode)
|
||||||
.compat()
|
.compat()
|
||||||
.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.dev_path(),
|
dev: self.dev_path(),
|
||||||
source,
|
source,
|
||||||
})?,
|
})?;
|
||||||
None => property::Value::Unknown(0),
|
|
||||||
});
|
|
||||||
|
|
||||||
let req = self.build_request(
|
let req = self.build_request(
|
||||||
&mut pending.connectors.iter(),
|
&mut pending.connectors.iter(),
|
||||||
&mut [].iter(),
|
&mut [].iter(),
|
||||||
&self.planes,
|
&self.planes,
|
||||||
None,
|
None,
|
||||||
mode,
|
Some(mode),
|
||||||
new_blob,
|
Some(new_blob),
|
||||||
)?;
|
)?;
|
||||||
if let Err(err) = self
|
if let Err(err) = self
|
||||||
.atomic_commit(
|
.atomic_commit(
|
||||||
|
@ -292,7 +317,7 @@ impl<A: AsRawFd + 'static> Surface for AtomicDrmSurfaceInternal<A> {
|
||||||
.compat()
|
.compat()
|
||||||
.map_err(|_| Error::TestFailed(self.crtc))
|
.map_err(|_| Error::TestFailed(self.crtc))
|
||||||
{
|
{
|
||||||
let _ = self.dev.destroy_property_blob(new_blob.unwrap().into());
|
let _ = self.dev.destroy_property_blob(new_blob.into());
|
||||||
return Err(err);
|
return Err(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -343,7 +368,7 @@ impl<A: AsRawFd + 'static> RawSurface for AtomicDrmSurfaceInternal<A> {
|
||||||
info!(
|
info!(
|
||||||
self.logger,
|
self.logger,
|
||||||
"Setting new mode: {:?}",
|
"Setting new mode: {:?}",
|
||||||
pending.mode.as_ref().unwrap().name()
|
pending.mode.name()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -355,8 +380,8 @@ impl<A: AsRawFd + 'static> RawSurface for AtomicDrmSurfaceInternal<A> {
|
||||||
&mut removed,
|
&mut removed,
|
||||||
&self.planes,
|
&self.planes,
|
||||||
Some(framebuffer),
|
Some(framebuffer),
|
||||||
pending.mode,
|
Some(pending.mode),
|
||||||
pending.blob,
|
Some(pending.blob),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
if let Err(err) = self
|
if let Err(err) = self
|
||||||
|
@ -380,15 +405,13 @@ impl<A: AsRawFd + 'static> RawSurface for AtomicDrmSurfaceInternal<A> {
|
||||||
&mut [].iter(),
|
&mut [].iter(),
|
||||||
&self.planes,
|
&self.planes,
|
||||||
Some(framebuffer),
|
Some(framebuffer),
|
||||||
current.mode,
|
Some(current.mode),
|
||||||
current.blob,
|
Some(current.blob),
|
||||||
)?
|
)?
|
||||||
} else {
|
} else {
|
||||||
if current.mode != pending.mode {
|
if current.mode != pending.mode {
|
||||||
if let Some(blob) = current.blob {
|
if let Err(err) = self.dev.destroy_property_blob(current.blob.into()) {
|
||||||
if let Err(err) = self.dev.destroy_property_blob(blob.into()) {
|
warn!(self.logger, "Failed to destory old mode property blob: {}", err);
|
||||||
warn!(self.logger, "Failed to destory old mode property blob: {}", err);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*current = pending.clone();
|
*current = pending.clone();
|
||||||
|
@ -834,11 +857,11 @@ impl<A: AsRawFd + 'static> Surface for AtomicDrmSurface<A> {
|
||||||
self.0.pending_connectors()
|
self.0.pending_connectors()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn current_mode(&self) -> Option<Mode> {
|
fn current_mode(&self) -> Mode {
|
||||||
self.0.current_mode()
|
self.0.current_mode()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pending_mode(&self) -> Option<Mode> {
|
fn pending_mode(&self) -> Mode {
|
||||||
self.0.pending_mode()
|
self.0.pending_mode()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -854,7 +877,7 @@ impl<A: AsRawFd + 'static> Surface for AtomicDrmSurface<A> {
|
||||||
self.0.set_connectors(connectors)
|
self.0.set_connectors(connectors)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn use_mode(&self, mode: Option<Mode>) -> Result<(), Error> {
|
fn use_mode(&self, mode: Mode) -> Result<(), Error> {
|
||||||
self.0.use_mode(mode)
|
self.0.use_mode(mode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -244,10 +244,10 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fallback_device_impl!(clear_handler, &mut Self);
|
fallback_device_impl!(clear_handler, &mut Self);
|
||||||
fn create_surface(&mut self, crtc: crtc::Handle) -> Result<Self::Surface, E> {
|
fn create_surface(&mut self, crtc: crtc::Handle, mode: Mode, connectors: &[connector::Handle]) -> Result<Self::Surface, E> {
|
||||||
match self {
|
match self {
|
||||||
FallbackDevice::Preference(dev) => Ok(FallbackSurface::Preference(dev.create_surface(crtc)?)),
|
FallbackDevice::Preference(dev) => Ok(FallbackSurface::Preference(dev.create_surface(crtc, mode, connectors)?)),
|
||||||
FallbackDevice::Fallback(dev) => Ok(FallbackSurface::Fallback(dev.create_surface(crtc)?)),
|
FallbackDevice::Fallback(dev) => Ok(FallbackSurface::Fallback(dev.create_surface(crtc, mode, connectors)?)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fallback_device_impl!(process_events, &mut Self);
|
fallback_device_impl!(process_events, &mut Self);
|
||||||
|
@ -297,9 +297,9 @@ where
|
||||||
fallback_surface_impl!(add_connector, &Self, Result<(), E>, conn: connector::Handle);
|
fallback_surface_impl!(add_connector, &Self, Result<(), E>, conn: connector::Handle);
|
||||||
fallback_surface_impl!(remove_connector, &Self, Result<(), E>, conn: connector::Handle);
|
fallback_surface_impl!(remove_connector, &Self, Result<(), E>, conn: connector::Handle);
|
||||||
fallback_surface_impl!(set_connectors, &Self, Result<(), E>, conns: &[connector::Handle]);
|
fallback_surface_impl!(set_connectors, &Self, Result<(), E>, conns: &[connector::Handle]);
|
||||||
fallback_surface_impl!(current_mode, &Self, Option<Mode>);
|
fallback_surface_impl!(current_mode, &Self, Mode);
|
||||||
fallback_surface_impl!(pending_mode, &Self, Option<Mode>);
|
fallback_surface_impl!(pending_mode, &Self, Mode);
|
||||||
fallback_surface_impl!(use_mode, &Self, Result<(), E>, mode: Option<Mode>);
|
fallback_surface_impl!(use_mode, &Self, Result<(), E>, mode: Mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E, C, S1, S2> RawSurface for FallbackSurface<S1, S2>
|
impl<E, C, S1, S2> RawSurface for FallbackSurface<S1, S2>
|
||||||
|
|
|
@ -40,6 +40,9 @@ pub enum Error {
|
||||||
/// The given crtc is already in use by another backend
|
/// The given crtc is already in use by another backend
|
||||||
#[error("Crtc `{0:?}` is already in use by another backend")]
|
#[error("Crtc `{0:?}` is already in use by another backend")]
|
||||||
CrtcAlreadyInUse(crtc::Handle),
|
CrtcAlreadyInUse(crtc::Handle),
|
||||||
|
/// This operation would result in a surface without connectors.
|
||||||
|
#[error("Surface of crtc `{0:?}` would have no connectors, which is not accepted")]
|
||||||
|
SurfaceWithoutConnectors(crtc::Handle),
|
||||||
/// No encoder was found for a given connector on the set crtc
|
/// No encoder was found for a given connector on the set crtc
|
||||||
#[error("No encoder found for the given connector '{connector:?}' on crtc `{crtc:?}`")]
|
#[error("No encoder found for the given connector '{connector:?}' on crtc `{crtc:?}`")]
|
||||||
NoSuitableEncoder {
|
NoSuitableEncoder {
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
//! Take a look at `anvil`s source code for an example of this.
|
//! Take a look at `anvil`s source code for an example of this.
|
||||||
//!
|
//!
|
||||||
|
|
||||||
use drm::control::{connector, crtc, encoder, framebuffer, plane, ResourceHandles};
|
use drm::control::{connector, crtc, encoder, framebuffer, plane, Mode, ResourceHandles};
|
||||||
use drm::SystemError as DrmError;
|
use drm::SystemError as DrmError;
|
||||||
use nix::libc::dev_t;
|
use nix::libc::dev_t;
|
||||||
use std::os::unix::io::{AsRawFd, RawFd};
|
use std::os::unix::io::{AsRawFd, RawFd};
|
||||||
|
@ -40,11 +40,13 @@ pub enum Error<U: std::error::Error + std::fmt::Debug + std::fmt::Display + 'sta
|
||||||
Underlying(#[source] U),
|
Underlying(#[source] U),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Arguments = (crtc::Handle, Mode, Vec<connector::Handle>);
|
||||||
|
|
||||||
/// Representation of an egl device to create egl rendering surfaces
|
/// Representation of an egl device to create egl rendering surfaces
|
||||||
pub struct EglDevice<B, D>
|
pub struct EglDevice<B, D>
|
||||||
where
|
where
|
||||||
B: Backend<Surface = <D as Device>::Surface> + 'static,
|
B: Backend<Surface = <D as Device>::Surface> + 'static,
|
||||||
D: Device + NativeDisplay<B, Arguments = crtc::Handle> + 'static,
|
D: Device + NativeDisplay<B, Arguments = Arguments> + 'static,
|
||||||
<D as Device>::Surface: NativeSurface,
|
<D as Device>::Surface: NativeSurface,
|
||||||
{
|
{
|
||||||
dev: EGLDisplay<B, D>,
|
dev: EGLDisplay<B, D>,
|
||||||
|
@ -56,7 +58,7 @@ where
|
||||||
impl<B, D> AsRawFd for EglDevice<B, D>
|
impl<B, D> AsRawFd for EglDevice<B, D>
|
||||||
where
|
where
|
||||||
B: Backend<Surface = <D as Device>::Surface> + 'static,
|
B: Backend<Surface = <D as Device>::Surface> + 'static,
|
||||||
D: Device + NativeDisplay<B, Arguments = crtc::Handle> + 'static,
|
D: Device + NativeDisplay<B, Arguments = Arguments> + 'static,
|
||||||
<D as Device>::Surface: NativeSurface,
|
<D as Device>::Surface: NativeSurface,
|
||||||
{
|
{
|
||||||
fn as_raw_fd(&self) -> RawFd {
|
fn as_raw_fd(&self) -> RawFd {
|
||||||
|
@ -67,7 +69,7 @@ where
|
||||||
impl<B, D> EglDevice<B, D>
|
impl<B, D> EglDevice<B, D>
|
||||||
where
|
where
|
||||||
B: Backend<Surface = <D as Device>::Surface> + 'static,
|
B: Backend<Surface = <D as Device>::Surface> + 'static,
|
||||||
D: Device + NativeDisplay<B, Arguments = crtc::Handle> + 'static,
|
D: Device + NativeDisplay<B, Arguments = Arguments> + 'static,
|
||||||
<D as Device>::Surface: NativeSurface,
|
<D as Device>::Surface: NativeSurface,
|
||||||
{
|
{
|
||||||
/// Try to create a new [`EglDevice`] from an open device.
|
/// Try to create a new [`EglDevice`] from an open device.
|
||||||
|
@ -122,7 +124,7 @@ where
|
||||||
struct InternalDeviceHandler<B, D>
|
struct InternalDeviceHandler<B, D>
|
||||||
where
|
where
|
||||||
B: Backend<Surface = <D as Device>::Surface> + 'static,
|
B: Backend<Surface = <D as Device>::Surface> + 'static,
|
||||||
D: Device + NativeDisplay<B, Arguments = crtc::Handle> + 'static,
|
D: Device + NativeDisplay<B, Arguments = Arguments> + 'static,
|
||||||
<D as Device>::Surface: NativeSurface,
|
<D as Device>::Surface: NativeSurface,
|
||||||
{
|
{
|
||||||
handler: Box<dyn DeviceHandler<Device = EglDevice<B, D>> + 'static>,
|
handler: Box<dyn DeviceHandler<Device = EglDevice<B, D>> + 'static>,
|
||||||
|
@ -131,7 +133,7 @@ where
|
||||||
impl<B, D> DeviceHandler for InternalDeviceHandler<B, D>
|
impl<B, D> DeviceHandler for InternalDeviceHandler<B, D>
|
||||||
where
|
where
|
||||||
B: Backend<Surface = <D as Device>::Surface> + 'static,
|
B: Backend<Surface = <D as Device>::Surface> + 'static,
|
||||||
D: Device + NativeDisplay<B, Arguments = crtc::Handle> + 'static,
|
D: Device + NativeDisplay<B, Arguments = Arguments> + 'static,
|
||||||
<D as Device>::Surface: NativeSurface,
|
<D as Device>::Surface: NativeSurface,
|
||||||
{
|
{
|
||||||
type Device = D;
|
type Device = D;
|
||||||
|
@ -147,7 +149,7 @@ where
|
||||||
impl<B, D> Device for EglDevice<B, D>
|
impl<B, D> Device for EglDevice<B, D>
|
||||||
where
|
where
|
||||||
B: Backend<Surface = <D as Device>::Surface> + 'static,
|
B: Backend<Surface = <D as Device>::Surface> + 'static,
|
||||||
D: Device + NativeDisplay<B, Arguments = crtc::Handle> + 'static,
|
D: Device + NativeDisplay<B, Arguments = Arguments> + 'static,
|
||||||
<D as Device>::Surface: NativeSurface,
|
<D as Device>::Surface: NativeSurface,
|
||||||
{
|
{
|
||||||
type Surface = EglSurface<<D as Device>::Surface>;
|
type Surface = EglSurface<<D as Device>::Surface>;
|
||||||
|
@ -169,6 +171,8 @@ where
|
||||||
fn create_surface(
|
fn create_surface(
|
||||||
&mut self,
|
&mut self,
|
||||||
crtc: crtc::Handle,
|
crtc: crtc::Handle,
|
||||||
|
mode: Mode,
|
||||||
|
connectors: &[connector::Handle],
|
||||||
) -> Result<Self::Surface, <Self::Surface as Surface>::Error> {
|
) -> Result<Self::Surface, <Self::Surface as Surface>::Error> {
|
||||||
info!(self.logger, "Initializing EglSurface");
|
info!(self.logger, "Initializing EglSurface");
|
||||||
|
|
||||||
|
@ -182,7 +186,7 @@ where
|
||||||
context.get_pixel_format(),
|
context.get_pixel_format(),
|
||||||
self.default_requirements.double_buffer,
|
self.default_requirements.double_buffer,
|
||||||
context.get_config_id(),
|
context.get_config_id(),
|
||||||
crtc,
|
(crtc, mode, Vec::from(connectors)),
|
||||||
)
|
)
|
||||||
.map_err(Error::EGL)?;
|
.map_err(Error::EGL)?;
|
||||||
|
|
||||||
|
@ -221,7 +225,7 @@ where
|
||||||
impl<B, D> EGLGraphicsBackend for EglDevice<B, D>
|
impl<B, D> EGLGraphicsBackend for EglDevice<B, D>
|
||||||
where
|
where
|
||||||
B: Backend<Surface = <D as Device>::Surface> + 'static,
|
B: Backend<Surface = <D as Device>::Surface> + 'static,
|
||||||
D: Device + NativeDisplay<B, Arguments = crtc::Handle> + 'static,
|
D: Device + NativeDisplay<B, Arguments = Arguments> + 'static,
|
||||||
<D as Device>::Surface: NativeSurface,
|
<D as Device>::Surface: NativeSurface,
|
||||||
{
|
{
|
||||||
fn bind_wl_display(&self, display: &Display) -> Result<EGLBufferReader, EGLError> {
|
fn bind_wl_display(&self, display: &Display) -> Result<EGLBufferReader, EGLError> {
|
||||||
|
@ -232,7 +236,7 @@ where
|
||||||
impl<B, D> Drop for EglDevice<B, D>
|
impl<B, D> Drop for EglDevice<B, D>
|
||||||
where
|
where
|
||||||
B: Backend<Surface = <D as Device>::Surface> + 'static,
|
B: Backend<Surface = <D as Device>::Surface> + 'static,
|
||||||
D: Device + NativeDisplay<B, Arguments = crtc::Handle> + 'static,
|
D: Device + NativeDisplay<B, Arguments = Arguments> + 'static,
|
||||||
<D as Device>::Surface: NativeSurface,
|
<D as Device>::Surface: NativeSurface,
|
||||||
{
|
{
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
//! to an open [`Session`](::backend::session::Session).
|
//! to an open [`Session`](::backend::session::Session).
|
||||||
//!
|
//!
|
||||||
|
|
||||||
use drm::control::crtc;
|
use drm::control::{crtc, connector, Mode};
|
||||||
use std::os::unix::io::RawFd;
|
use std::os::unix::io::RawFd;
|
||||||
|
|
||||||
use super::EglDevice;
|
use super::EglDevice;
|
||||||
|
@ -22,7 +22,7 @@ impl<S, B, D> AsSessionObserver<EglDeviceObserver<S>> for EglDevice<B, D>
|
||||||
where
|
where
|
||||||
S: SessionObserver + 'static,
|
S: SessionObserver + 'static,
|
||||||
B: Backend<Surface = <D as Device>::Surface> + 'static,
|
B: Backend<Surface = <D as Device>::Surface> + 'static,
|
||||||
D: Device + NativeDisplay<B, Arguments = crtc::Handle> + AsSessionObserver<S> + 'static,
|
D: Device + NativeDisplay<B, Arguments = (crtc::Handle, Mode, Vec<connector::Handle>)> + AsSessionObserver<S> + 'static,
|
||||||
<D as Device>::Surface: NativeSurface,
|
<D as Device>::Surface: NativeSurface,
|
||||||
{
|
{
|
||||||
fn observer(&mut self) -> EglDeviceObserver<S> {
|
fn observer(&mut self) -> EglDeviceObserver<S> {
|
||||||
|
|
|
@ -53,15 +53,15 @@ where
|
||||||
self.surface.set_connectors(connectors).map_err(Error::Underlying)
|
self.surface.set_connectors(connectors).map_err(Error::Underlying)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn current_mode(&self) -> Option<Mode> {
|
fn current_mode(&self) -> Mode {
|
||||||
self.surface.current_mode()
|
self.surface.current_mode()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pending_mode(&self) -> Option<Mode> {
|
fn pending_mode(&self) -> Mode {
|
||||||
self.surface.pending_mode()
|
self.surface.pending_mode()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn use_mode(&self, mode: Option<Mode>) -> Result<(), Self::Error> {
|
fn use_mode(&self, mode: Mode) -> Result<(), Self::Error> {
|
||||||
self.surface.use_mode(mode).map_err(Error::Underlying)
|
self.surface.use_mode(mode).map_err(Error::Underlying)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -100,7 +100,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_framebuffer_dimensions(&self) -> (u32, u32) {
|
fn get_framebuffer_dimensions(&self) -> (u32, u32) {
|
||||||
let (w, h) = self.pending_mode().map(|mode| mode.size()).unwrap_or((1, 1));
|
let (w, h) = self.pending_mode().size();
|
||||||
(w as u32, h as u32)
|
(w as u32, h as u32)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ use crate::backend::graphics::SwapBuffersError;
|
||||||
|
|
||||||
use super::{Error, GbmDevice, GbmSurface};
|
use super::{Error, GbmDevice, GbmSurface};
|
||||||
|
|
||||||
use drm::control::{crtc, Device as ControlDevice};
|
use drm::control::{crtc, connector, Device as ControlDevice, Mode};
|
||||||
use gbm::AsRaw;
|
use gbm::AsRaw;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
@ -52,7 +52,7 @@ impl<D: RawDevice + 'static> Backend for Gbm<D> {
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<D: RawDevice + ControlDevice + 'static> NativeDisplay<Gbm<D>> for GbmDevice<D> {
|
unsafe impl<D: RawDevice + ControlDevice + 'static> NativeDisplay<Gbm<D>> for GbmDevice<D> {
|
||||||
type Arguments = crtc::Handle;
|
type Arguments = (crtc::Handle, Mode, Vec<connector::Handle>);
|
||||||
type Error = Error<<<D as Device>::Surface as Surface>::Error>;
|
type Error = Error<<<D as Device>::Surface as Surface>::Error>;
|
||||||
|
|
||||||
fn is_backend(&self) -> bool {
|
fn is_backend(&self) -> bool {
|
||||||
|
@ -63,8 +63,8 @@ unsafe impl<D: RawDevice + ControlDevice + 'static> NativeDisplay<Gbm<D>> for Gb
|
||||||
Ok(self.dev.borrow().as_raw() as *const _)
|
Ok(self.dev.borrow().as_raw() as *const _)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_surface(&mut self, crtc: crtc::Handle) -> Result<GbmSurface<D>, Self::Error> {
|
fn create_surface(&mut self, args: Self::Arguments) -> Result<GbmSurface<D>, Self::Error> {
|
||||||
Device::create_surface(self, crtc)
|
Device::create_surface(self, args.0, args.1, &args.2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
|
|
||||||
use super::{Device, DeviceHandler, RawDevice, ResourceHandles, Surface};
|
use super::{Device, DeviceHandler, RawDevice, ResourceHandles, Surface};
|
||||||
|
|
||||||
use drm::control::{connector, crtc, encoder, framebuffer, plane, Device as ControlDevice};
|
use drm::control::{connector, crtc, encoder, framebuffer, plane, Device as ControlDevice, Mode};
|
||||||
use drm::SystemError as DrmError;
|
use drm::SystemError as DrmError;
|
||||||
use gbm::{self, BufferObjectFlags, Format as GbmFormat};
|
use gbm::{self, BufferObjectFlags, Format as GbmFormat};
|
||||||
use nix::libc::dev_t;
|
use nix::libc::dev_t;
|
||||||
|
@ -33,9 +33,6 @@ pub enum Error<U: std::error::Error + std::fmt::Debug + std::fmt::Display + 'sta
|
||||||
/// Creation of GBM surface failed
|
/// Creation of GBM surface failed
|
||||||
#[error("Creation of GBM surface failed")]
|
#[error("Creation of GBM surface failed")]
|
||||||
SurfaceCreationFailed(#[source] io::Error),
|
SurfaceCreationFailed(#[source] io::Error),
|
||||||
/// No mode is set, blocking the current operation
|
|
||||||
#[error("No mode is currently set")]
|
|
||||||
NoModeSet,
|
|
||||||
/// Creation of GBM buffer object failed
|
/// Creation of GBM buffer object failed
|
||||||
#[error("Creation of GBM buffer object failed")]
|
#[error("Creation of GBM buffer object failed")]
|
||||||
BufferCreationFailed(#[source] io::Error),
|
BufferCreationFailed(#[source] io::Error),
|
||||||
|
@ -159,17 +156,18 @@ impl<D: RawDevice + ControlDevice + 'static> Device for GbmDevice<D> {
|
||||||
fn create_surface(
|
fn create_surface(
|
||||||
&mut self,
|
&mut self,
|
||||||
crtc: crtc::Handle,
|
crtc: crtc::Handle,
|
||||||
|
mode: Mode,
|
||||||
|
connectors: &[connector::Handle],
|
||||||
) -> Result<GbmSurface<D>, Error<<<D as Device>::Surface as Surface>::Error>> {
|
) -> Result<GbmSurface<D>, Error<<<D as Device>::Surface as Surface>::Error>> {
|
||||||
info!(self.logger, "Initializing GbmSurface");
|
info!(self.logger, "Initializing GbmSurface");
|
||||||
|
|
||||||
let drm_surface =
|
let drm_surface =
|
||||||
Device::create_surface(&mut **self.dev.borrow_mut(), crtc).map_err(Error::Underlying)?;
|
Device::create_surface(&mut **self.dev.borrow_mut(), crtc, mode, connectors).map_err(Error::Underlying)?;
|
||||||
|
|
||||||
// initialize the surface
|
// initialize the surface
|
||||||
let (w, h) = drm_surface
|
let (w, h) = drm_surface
|
||||||
.pending_mode()
|
.pending_mode()
|
||||||
.map(|mode| mode.size())
|
.size();
|
||||||
.unwrap_or((1, 1));
|
|
||||||
let surface = self
|
let surface = self
|
||||||
.dev
|
.dev
|
||||||
.borrow()
|
.borrow()
|
||||||
|
|
|
@ -93,8 +93,6 @@ impl<D: RawDevice + 'static> GbmSurfaceInternal<D> {
|
||||||
pub fn recreate(&self) -> Result<(), Error<<<D as Device>::Surface as Surface>::Error>> {
|
pub fn recreate(&self) -> Result<(), Error<<<D as Device>::Surface as Surface>::Error>> {
|
||||||
let (w, h) = self
|
let (w, h) = self
|
||||||
.pending_mode()
|
.pending_mode()
|
||||||
.or_else(|| self.current_mode())
|
|
||||||
.ok_or(Error::NoModeSet)?
|
|
||||||
.size();
|
.size();
|
||||||
|
|
||||||
// Recreate the surface and the related resources to match the new
|
// Recreate the surface and the related resources to match the new
|
||||||
|
@ -167,15 +165,15 @@ impl<D: RawDevice + 'static> Surface for GbmSurfaceInternal<D> {
|
||||||
self.crtc.set_connectors(connectors).map_err(Error::Underlying)
|
self.crtc.set_connectors(connectors).map_err(Error::Underlying)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn current_mode(&self) -> Option<Mode> {
|
fn current_mode(&self) -> Mode {
|
||||||
self.crtc.current_mode()
|
self.crtc.current_mode()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pending_mode(&self) -> Option<Mode> {
|
fn pending_mode(&self) -> Mode {
|
||||||
self.crtc.pending_mode()
|
self.crtc.pending_mode()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn use_mode(&self, mode: Option<Mode>) -> Result<(), Self::Error> {
|
fn use_mode(&self, mode: Mode) -> Result<(), Self::Error> {
|
||||||
self.crtc.use_mode(mode).map_err(Error::Underlying)
|
self.crtc.use_mode(mode).map_err(Error::Underlying)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -325,15 +323,15 @@ impl<D: RawDevice + 'static> Surface for GbmSurface<D> {
|
||||||
self.0.set_connectors(connectors)
|
self.0.set_connectors(connectors)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn current_mode(&self) -> Option<Mode> {
|
fn current_mode(&self) -> Mode {
|
||||||
self.0.current_mode()
|
self.0.current_mode()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pending_mode(&self) -> Option<Mode> {
|
fn pending_mode(&self) -> Mode {
|
||||||
self.0.pending_mode()
|
self.0.pending_mode()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn use_mode(&self, mode: Option<Mode>) -> Result<(), Self::Error> {
|
fn use_mode(&self, mode: Mode) -> Result<(), Self::Error> {
|
||||||
self.0.use_mode(mode)
|
self.0.use_mode(mode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,24 +11,24 @@
|
||||||
use super::{common::Error, DevPath, Device, DeviceHandler, RawDevice};
|
use super::{common::Error, DevPath, Device, DeviceHandler, RawDevice};
|
||||||
|
|
||||||
use drm::control::{
|
use drm::control::{
|
||||||
connector, crtc, encoder, framebuffer, plane, Device as ControlDevice, Event, ResourceHandles,
|
connector, crtc, encoder, framebuffer, plane, Device as ControlDevice, Event, Mode, ResourceHandles,
|
||||||
};
|
};
|
||||||
use drm::{Device as BasicDevice, SystemError as DrmError};
|
use drm::{Device as BasicDevice, SystemError as DrmError};
|
||||||
use nix::libc::dev_t;
|
use nix::libc::dev_t;
|
||||||
use nix::sys::stat::fstat;
|
use nix::sys::stat::fstat;
|
||||||
|
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::HashMap;
|
||||||
use std::os::unix::io::{AsRawFd, RawFd};
|
use std::os::unix::io::{AsRawFd, RawFd};
|
||||||
use std::rc::{Rc, Weak};
|
use std::rc::{Rc, Weak};
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
use std::sync::{Arc, RwLock};
|
use std::sync::Arc;
|
||||||
|
|
||||||
use failure::{Fail, ResultExt};
|
use failure::{Fail, ResultExt};
|
||||||
|
|
||||||
mod surface;
|
mod surface;
|
||||||
pub use self::surface::LegacyDrmSurface;
|
pub use self::surface::LegacyDrmSurface;
|
||||||
use self::surface::{LegacyDrmSurfaceInternal, State};
|
use self::surface::LegacyDrmSurfaceInternal;
|
||||||
|
|
||||||
#[cfg(feature = "backend_session")]
|
#[cfg(feature = "backend_session")]
|
||||||
pub mod session;
|
pub mod session;
|
||||||
|
@ -241,7 +241,7 @@ impl<A: AsRawFd + 'static> Device for LegacyDrmDevice<A> {
|
||||||
let _ = self.handler.take();
|
let _ = self.handler.take();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_surface(&mut self, crtc: crtc::Handle) -> Result<LegacyDrmSurface<A>, Error> {
|
fn create_surface(&mut self, crtc: crtc::Handle, mode: Mode, connectors: &[connector::Handle]) -> Result<LegacyDrmSurface<A>, Error> {
|
||||||
if self.backends.borrow().contains_key(&crtc) {
|
if self.backends.borrow().contains_key(&crtc) {
|
||||||
return Err(Error::CrtcAlreadyInUse(crtc));
|
return Err(Error::CrtcAlreadyInUse(crtc));
|
||||||
}
|
}
|
||||||
|
@ -250,8 +250,12 @@ impl<A: AsRawFd + 'static> Device for LegacyDrmDevice<A> {
|
||||||
return Err(Error::DeviceInactive);
|
return Err(Error::DeviceInactive);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if connectors.is_empty() {
|
||||||
|
return Err(Error::SurfaceWithoutConnectors(crtc));
|
||||||
|
}
|
||||||
|
|
||||||
let backend = Rc::new(LegacyDrmSurfaceInternal::new(
|
let backend = Rc::new(LegacyDrmSurfaceInternal::new(
|
||||||
self.dev.clone(), crtc,
|
self.dev.clone(), crtc, mode, connectors,
|
||||||
self.logger.new(o!("crtc" => format!("{:?}", crtc))),
|
self.logger.new(o!("crtc" => format!("{:?}", crtc))),
|
||||||
)?);
|
)?);
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ use drm::control::{
|
||||||
};
|
};
|
||||||
use drm::Device as BasicDevice;
|
use drm::Device as BasicDevice;
|
||||||
|
|
||||||
|
use std::cell::Cell;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::os::unix::io::{AsRawFd, RawFd};
|
use std::os::unix::io::{AsRawFd, RawFd};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
@ -20,7 +21,7 @@ use failure::{Fail, ResultExt};
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||||
pub struct State {
|
pub struct State {
|
||||||
pub mode: Option<Mode>,
|
pub mode: Mode,
|
||||||
pub connectors: HashSet<connector::Handle>,
|
pub connectors: HashSet<connector::Handle>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,6 +31,7 @@ pub(super) struct LegacyDrmSurfaceInternal<A: AsRawFd + 'static> {
|
||||||
pub(super) state: RwLock<State>,
|
pub(super) state: RwLock<State>,
|
||||||
pub(super) pending: RwLock<State>,
|
pub(super) pending: RwLock<State>,
|
||||||
pub(super) logger: ::slog::Logger,
|
pub(super) logger: ::slog::Logger,
|
||||||
|
init_buffer: Cell<Option<(DumbBuffer, framebuffer::Handle)>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<A: AsRawFd + 'static> AsRawFd for LegacyDrmSurfaceInternal<A> {
|
impl<A: AsRawFd + 'static> AsRawFd for LegacyDrmSurfaceInternal<A> {
|
||||||
|
@ -96,18 +98,18 @@ impl<A: AsRawFd + 'static> Surface for LegacyDrmSurfaceInternal<A> {
|
||||||
self.pending.read().unwrap().connectors.clone()
|
self.pending.read().unwrap().connectors.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn current_mode(&self) -> Option<Mode> {
|
fn current_mode(&self) -> Mode {
|
||||||
self.state.read().unwrap().mode
|
self.state.read().unwrap().mode
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pending_mode(&self) -> Option<Mode> {
|
fn pending_mode(&self) -> Mode {
|
||||||
self.pending.read().unwrap().mode
|
self.pending.read().unwrap().mode
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_connector(&self, conn: connector::Handle) -> Result<(), Error> {
|
fn add_connector(&self, conn: connector::Handle) -> Result<(), Error> {
|
||||||
let mut pending = self.pending.write().unwrap();
|
let mut pending = self.pending.write().unwrap();
|
||||||
|
|
||||||
if self.check_connector(conn, pending.mode.as_ref().unwrap())? {
|
if self.check_connector(conn, &pending.mode)? {
|
||||||
pending.connectors.insert(conn);
|
pending.connectors.insert(conn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,7 +126,7 @@ impl<A: AsRawFd + 'static> Surface for LegacyDrmSurfaceInternal<A> {
|
||||||
|
|
||||||
if connectors
|
if connectors
|
||||||
.iter()
|
.iter()
|
||||||
.map(|conn| self.check_connector(*conn, pending.mode.as_ref().unwrap()))
|
.map(|conn| self.check_connector(*conn, &pending.mode))
|
||||||
.collect::<Result<Vec<bool>, _>>()?
|
.collect::<Result<Vec<bool>, _>>()?
|
||||||
.iter()
|
.iter()
|
||||||
.all(|v| *v)
|
.all(|v| *v)
|
||||||
|
@ -135,25 +137,23 @@ impl<A: AsRawFd + 'static> Surface for LegacyDrmSurfaceInternal<A> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn use_mode(&self, mode: Option<Mode>) -> Result<(), Error> {
|
fn use_mode(&self, mode: Mode) -> Result<(), Error> {
|
||||||
let mut pending = self.pending.write().unwrap();
|
let mut pending = self.pending.write().unwrap();
|
||||||
|
|
||||||
// check the connectors to see if this mode is supported
|
// check the connectors to see if this mode is supported
|
||||||
if let Some(mode) = mode {
|
for connector in &pending.connectors {
|
||||||
for connector in &pending.connectors {
|
if !self
|
||||||
if !self
|
.get_connector(*connector)
|
||||||
.get_connector(*connector)
|
.compat()
|
||||||
.compat()
|
.map_err(|source| Error::Access {
|
||||||
.map_err(|source| Error::Access {
|
errmsg: "Error loading connector info",
|
||||||
errmsg: "Error loading connector info",
|
dev: self.dev_path(),
|
||||||
dev: self.dev_path(),
|
source,
|
||||||
source,
|
})?
|
||||||
})?
|
.modes()
|
||||||
.modes()
|
.contains(&mode)
|
||||||
.contains(&mode)
|
{
|
||||||
{
|
return Err(Error::ModeNotSuitable(mode));
|
||||||
return Err(Error::ModeNotSuitable(mode));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -211,7 +211,7 @@ impl<A: AsRawFd + 'static> RawSurface for LegacyDrmSurfaceInternal<A> {
|
||||||
info!(
|
info!(
|
||||||
self.logger,
|
self.logger,
|
||||||
"Setting new mode: {:?}",
|
"Setting new mode: {:?}",
|
||||||
pending.mode.as_ref().unwrap().name()
|
pending.mode.name()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -226,7 +226,7 @@ impl<A: AsRawFd + 'static> RawSurface for LegacyDrmSurfaceInternal<A> {
|
||||||
.iter()
|
.iter()
|
||||||
.copied()
|
.copied()
|
||||||
.collect::<Vec<connector::Handle>>(),
|
.collect::<Vec<connector::Handle>>(),
|
||||||
pending.mode,
|
Some(pending.mode),
|
||||||
)
|
)
|
||||||
.compat()
|
.compat()
|
||||||
.map_err(|source| Error::Access {
|
.map_err(|source| Error::Access {
|
||||||
|
@ -266,7 +266,7 @@ impl<A: AsRawFd + 'static> RawSurface for LegacyDrmSurfaceInternal<A> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<A: AsRawFd + 'static> LegacyDrmSurfaceInternal<A> {
|
impl<A: AsRawFd + 'static> LegacyDrmSurfaceInternal<A> {
|
||||||
pub(crate) fn new(dev: Rc<Dev<A>>, crtc: crtc::Handle, logger: ::slog::Logger) -> Result<LegacyDrmSurfaceInternal<A>, Error> {
|
pub(crate) fn new(dev: Rc<Dev<A>>, crtc: crtc::Handle, mode: Mode, connectors: &[connector::Handle], logger: ::slog::Logger) -> Result<LegacyDrmSurfaceInternal<A>, Error> {
|
||||||
// Try to enumarate the current state to set the initial state variable correctly
|
// Try to enumarate the current state to set the initial state variable correctly
|
||||||
let crtc_info = dev.get_crtc(crtc).compat().map_err(|source| Error::Access {
|
let crtc_info = dev.get_crtc(crtc).compat().map_err(|source| Error::Access {
|
||||||
errmsg: "Error loading crtc info",
|
errmsg: "Error loading crtc info",
|
||||||
|
@ -304,14 +304,20 @@ impl<A: AsRawFd + 'static> LegacyDrmSurfaceInternal<A> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let state = State { current_mode, current_connectors };
|
// If we have no current mode, we create a fake one, which will not match (and thus gets overriden on the commit below).
|
||||||
|
// A better fix would probably be making mode an `Option`, but that would mean
|
||||||
|
// we need to be sure, we require a mode to always be set without relying on the compiler.
|
||||||
|
// So we cheat, because it works and is easier to handle later.
|
||||||
|
let state = State { mode: current_mode.unwrap_or_else(|| unsafe { std::mem::zeroed() }), connectors: current_connectors };
|
||||||
|
let pending = State { mode, connectors: connectors.into_iter().copied().collect() };
|
||||||
|
|
||||||
let surface = LegacyDrmSurfaceInternal {
|
let surface = LegacyDrmSurfaceInternal {
|
||||||
dev,
|
dev,
|
||||||
crtc,
|
crtc,
|
||||||
state: RwLock::new(state),
|
state: RwLock::new(state),
|
||||||
pending: RwLock::new(state.clone()),
|
pending: RwLock::new(pending),
|
||||||
logger,
|
logger,
|
||||||
|
init_buffer: Cell::new(None),
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(surface)
|
Ok(surface)
|
||||||
|
@ -371,6 +377,10 @@ impl<A: AsRawFd + 'static> Drop for LegacyDrmSurfaceInternal<A> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
// ignore failure at this point
|
// ignore failure at this point
|
||||||
let _ = self.set_cursor(self.crtc, Option::<&DumbBuffer>::None);
|
let _ = self.set_cursor(self.crtc, Option::<&DumbBuffer>::None);
|
||||||
|
if let Some((db, fb)) = self.init_buffer.take() {
|
||||||
|
let _ = self.destroy_framebuffer(fb);
|
||||||
|
let _ = self.destroy_dumb_buffer(db);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -419,11 +429,11 @@ impl<A: AsRawFd + 'static> Surface for LegacyDrmSurface<A> {
|
||||||
self.0.pending_connectors()
|
self.0.pending_connectors()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn current_mode(&self) -> Option<Mode> {
|
fn current_mode(&self) -> Mode {
|
||||||
self.0.current_mode()
|
self.0.current_mode()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pending_mode(&self) -> Option<Mode> {
|
fn pending_mode(&self) -> Mode {
|
||||||
self.0.pending_mode()
|
self.0.pending_mode()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -439,7 +449,7 @@ impl<A: AsRawFd + 'static> Surface for LegacyDrmSurface<A> {
|
||||||
self.0.set_connectors(connectors)
|
self.0.set_connectors(connectors)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn use_mode(&self, mode: Option<Mode>) -> Result<(), Error> {
|
fn use_mode(&self, mode: Mode) -> Result<(), Error> {
|
||||||
self.0.use_mode(mode)
|
self.0.use_mode(mode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -94,16 +94,23 @@ pub trait Device: AsRawFd + DevPath {
|
||||||
|
|
||||||
/// Creates a new rendering surface.
|
/// Creates a new rendering surface.
|
||||||
///
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
/// Initialization of surfaces happens through the types provided by
|
/// Initialization of surfaces happens through the types provided by
|
||||||
/// [`drm-rs`](drm).
|
/// [`drm-rs`](drm).
|
||||||
///
|
///
|
||||||
/// [`crtc`](drm::control::crtc)s represent scanout engines
|
/// - [`crtc`](drm::control::crtc)s represent scanout engines of the device pointing to one framebuffer. \
|
||||||
/// of the device pointer to one framebuffer.
|
/// Their responsibility is to read the data of the framebuffer and export it into an "Encoder". \
|
||||||
/// Their responsibility is to read the data of the framebuffer and export it into an "Encoder".
|
/// The number of crtc's represent the number of independant output devices the hardware may handle.
|
||||||
/// The number of crtc's represent the number of independant output devices the hardware may handle.
|
/// - [`mode`](drm::control::Mode) describes the resolution and rate of images produced by the crtc and \
|
||||||
|
/// has to be compatible with the provided `connectors`.
|
||||||
|
/// - [`connectors`] - List of connectors driven by the crtc. At least one(!) connector needs to be \
|
||||||
|
/// attached to a crtc in smithay.
|
||||||
fn create_surface(
|
fn create_surface(
|
||||||
&mut self,
|
&mut self,
|
||||||
crtc: crtc::Handle,
|
crtc: crtc::Handle,
|
||||||
|
mode: Mode,
|
||||||
|
connectors: &[connector::Handle]
|
||||||
) -> Result<Self::Surface, <Self::Surface as Surface>::Error>;
|
) -> Result<Self::Surface, <Self::Surface as Surface>::Error>;
|
||||||
|
|
||||||
/// Processes any open events of the underlying file descriptor.
|
/// Processes any open events of the underlying file descriptor.
|
||||||
|
@ -181,11 +188,10 @@ pub trait Surface {
|
||||||
fn set_connectors(&self, connectors: &[connector::Handle]) -> Result<(), Self::Error>;
|
fn set_connectors(&self, connectors: &[connector::Handle]) -> Result<(), Self::Error>;
|
||||||
/// Returns the currently active [`Mode`](drm::control::Mode)
|
/// Returns the currently active [`Mode`](drm::control::Mode)
|
||||||
/// of the underlying [`crtc`](drm::control::crtc)
|
/// of the underlying [`crtc`](drm::control::crtc)
|
||||||
/// if any.
|
fn current_mode(&self) -> Mode;
|
||||||
fn current_mode(&self) -> Option<Mode>;
|
|
||||||
/// Returns the currently pending [`Mode`](drm::control::Mode)
|
/// Returns the currently pending [`Mode`](drm::control::Mode)
|
||||||
/// to be used after the next commit, if any.
|
/// to be used after the next commit.
|
||||||
fn pending_mode(&self) -> Option<Mode>;
|
fn pending_mode(&self) -> Mode;
|
||||||
/// Tries to set a new [`Mode`](drm::control::Mode)
|
/// Tries to set a new [`Mode`](drm::control::Mode)
|
||||||
/// to be used after the next commit.
|
/// to be used after the next commit.
|
||||||
///
|
///
|
||||||
|
@ -196,7 +202,7 @@ pub trait Surface {
|
||||||
/// *Note*: Only on a [`RawSurface`] you may directly trigger
|
/// *Note*: Only on a [`RawSurface`] you may directly trigger
|
||||||
/// a [`commit`](RawSurface::commit). Other [`Surface`]s provide their
|
/// a [`commit`](RawSurface::commit). Other [`Surface`]s provide their
|
||||||
/// own methods that *may* trigger a commit, you will need to read their docs.
|
/// own methods that *may* trigger a commit, you will need to read their docs.
|
||||||
fn use_mode(&self, mode: Option<Mode>) -> Result<(), Self::Error>;
|
fn use_mode(&self, mode: Mode) -> Result<(), Self::Error>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An open bare crtc without any rendering abstractions
|
/// An open bare crtc without any rendering abstractions
|
||||||
|
|
Loading…
Reference in New Issue