lint: fmt

This commit is contained in:
Victor Brekenfeld 2020-04-30 19:03:02 +02:00
parent 31b6d84442
commit 9300e35093
28 changed files with 623 additions and 307 deletions

View File

@ -16,7 +16,10 @@ use smithay::backend::egl::display::EGLBufferReader;
use smithay::{ use smithay::{
backend::{ backend::{
egl::{BufferAccessError, EGLImages, Format}, egl::{BufferAccessError, EGLImages, Format},
graphics::{gl::GLGraphicsBackend, glium::{GliumGraphicsBackend, Frame}}, graphics::{
gl::GLGraphicsBackend,
glium::{Frame, GliumGraphicsBackend},
},
}, },
reexports::wayland_server::protocol::{wl_buffer, wl_surface}, reexports::wayland_server::protocol::{wl_buffer, wl_surface},
wayland::{ wayland::{
@ -159,7 +162,10 @@ impl<F: GLGraphicsBackend + 'static> GliumDrawer<F> {
let images = if let Some(display) = &self.egl_buffer_reader.borrow().as_ref() { let images = if let Some(display) = &self.egl_buffer_reader.borrow().as_ref() {
display.egl_buffer_contents(buffer) display.egl_buffer_contents(buffer)
} else { } else {
Err(BufferAccessError::NotManaged(buffer, smithay::backend::egl::EGLError::BadDisplay)) Err(BufferAccessError::NotManaged(
buffer,
smithay::backend::egl::EGLError::BadDisplay,
))
}; };
match images { match images {
Ok(images) => { Ok(images) => {

View File

@ -319,7 +319,9 @@ 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, connector_info.modes()[0], &[connector_info.handle()]).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(),
); );

View File

@ -56,7 +56,8 @@ fn main() {
let mut options = OpenOptions::new(); let mut options = OpenOptions::new();
options.read(true); options.read(true);
options.write(true); options.write(true);
let mut device = AtomicDrmDevice::new(options.open("/dev/dri/card0").unwrap(), true, log.clone()).unwrap(); let mut device =
AtomicDrmDevice::new(options.open("/dev/dri/card0").unwrap(), true, log.clone()).unwrap();
// Get a set of all modesetting resource handles (excluding planes): // Get a set of all modesetting resource handles (excluding planes):
let res_handles = Device::resource_handles(&device).unwrap(); let res_handles = Device::resource_handles(&device).unwrap();
@ -96,7 +97,11 @@ 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, mode, &[connector_info.handle()]).unwrap()); let surface = Rc::new(
device
.create_surface(crtc, mode, &[connector_info.handle()])
.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() {

View File

@ -40,7 +40,8 @@ fn main() {
let mut options = OpenOptions::new(); let mut options = OpenOptions::new();
options.read(true); options.read(true);
options.write(true); options.write(true);
let mut device = LegacyDrmDevice::new(options.open("/dev/dri/card0").unwrap(), true, log.clone()).unwrap(); let mut device =
LegacyDrmDevice::new(options.open("/dev/dri/card0").unwrap(), true, log.clone()).unwrap();
// Get a set of all modesetting resource handles (excluding planes): // Get a set of all modesetting resource handles (excluding planes):
let res_handles = Device::resource_handles(&device).unwrap(); let res_handles = Device::resource_handles(&device).unwrap();
@ -78,7 +79,11 @@ 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, mode, &[connector_info.handle()]).unwrap()); let surface = Rc::new(
device
.create_surface(crtc, mode, &[connector_info.handle()])
.unwrap(),
);
/* /*
* Lets create buffers and framebuffers. * Lets create buffers and framebuffers.

View File

@ -19,7 +19,8 @@ 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, Mode, 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};
@ -199,7 +200,7 @@ impl<A: AsRawFd + 'static> AtomicDrmDevice<A> {
/// - `logger` - Optional [`slog::Logger`] to be used by this device. /// - `logger` - Optional [`slog::Logger`] to be used by this device.
/// ///
/// # Return /// # Return
/// ///
/// Returns an error if the file is no valid drm node or the device is not accessible. /// Returns an error if the file is no valid drm node or the device is not accessible.
pub fn new<L>(fd: A, disable_connectors: bool, logger: L) -> Result<Self, Error> pub fn new<L>(fd: A, disable_connectors: bool, logger: L) -> Result<Self, Error>
where where
@ -279,25 +280,38 @@ impl<A: AsRawFd + 'static> AtomicDrmDevice<A> {
// Disable all connectors as initial state // Disable all connectors as initial state
let mut req = AtomicModeReq::new(); let mut req = AtomicModeReq::new();
for conn in res_handles.connectors() { for conn in res_handles.connectors() {
let prop = dev.prop_mapping.0.get(&conn) let prop = dev
.expect("Unknown handle").get("CRTC_ID") .prop_mapping
.0
.get(&conn)
.expect("Unknown handle")
.get("CRTC_ID")
.expect("Unknown property CRTC_ID"); .expect("Unknown property CRTC_ID");
req.add_property(*conn, *prop, property::Value::CRTC(None)); req.add_property(*conn, *prop, property::Value::CRTC(None));
} }
// A crtc without a connector has no mode, we also need to reset that. // A crtc without a connector has no mode, we also need to reset that.
// Otherwise the commit will not be accepted. // Otherwise the commit will not be accepted.
for crtc in res_handles.crtcs() { for crtc in res_handles.crtcs() {
let active_prop = dev.prop_mapping.1.get(&crtc) let active_prop = dev
.expect("Unknown handle").get("ACTIVE") .prop_mapping
.1
.get(&crtc)
.expect("Unknown handle")
.get("ACTIVE")
.expect("Unknown property ACTIVE"); .expect("Unknown property ACTIVE");
let mode_prop = dev.prop_mapping.1.get(&crtc) let mode_prop = dev
.expect("Unknown handle").get("MODE_ID") .prop_mapping
.1
.get(&crtc)
.expect("Unknown handle")
.get("MODE_ID")
.expect("Unknown property MODE_ID"); .expect("Unknown property MODE_ID");
req.add_property(*crtc, *mode_prop, property::Value::Unknown(0)); req.add_property(*crtc, *mode_prop, property::Value::Unknown(0));
req.add_property(*crtc, *active_prop, property::Value::Boolean(false)); req.add_property(*crtc, *active_prop, property::Value::Boolean(false));
} }
dev.atomic_commit(&[AtomicCommitFlags::AllowModeset], req) dev.atomic_commit(&[AtomicCommitFlags::AllowModeset], req)
.compat().map_err(|source| Error::Access { .compat()
.map_err(|source| Error::Access {
errmsg: "Failed to disable connectors", errmsg: "Failed to disable connectors",
dev: dev.dev_path(), dev: dev.dev_path(),
source, source,
@ -339,7 +353,12 @@ impl<A: AsRawFd + 'static> Device for AtomicDrmDevice<A> {
let _ = self.handler.take(); let _ = self.handler.take();
} }
fn create_surface(&mut self, crtc: crtc::Handle, mode: Mode, connectors: &[connector::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));
} }

View File

@ -3,8 +3,9 @@
//! to an open [`Session`](::backend::session::Session). //! to an open [`Session`](::backend::session::Session).
//! //!
use drm::control::{crtc, property, Device as ControlDevice, AtomicCommitFlags, atomic::AtomicModeReq}; use drm::control::{atomic::AtomicModeReq, crtc, property, AtomicCommitFlags, Device as ControlDevice};
use drm::Device as BasicDevice; use drm::Device as BasicDevice;
use failure::ResultExt;
use nix::libc::dev_t; use nix::libc::dev_t;
use nix::sys::stat; use nix::sys::stat;
use std::cell::RefCell; use std::cell::RefCell;
@ -13,7 +14,6 @@ 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; use std::sync::Arc;
use failure::ResultExt;
use super::{AtomicDrmDevice, AtomicDrmSurfaceInternal, Dev}; use super::{AtomicDrmDevice, AtomicDrmSurfaceInternal, Dev};
use crate::backend::drm::{common::Error, DevPath}; use crate::backend::drm::{common::Error, DevPath};
@ -114,31 +114,44 @@ impl<A: AsRawFd + 'static> AtomicDrmDeviceObserver<A> {
.map_err(|source| Error::Access { .map_err(|source| Error::Access {
errmsg: "Error loading drm resources", errmsg: "Error loading drm resources",
dev: dev.dev_path(), dev: dev.dev_path(),
source source,
})?; })?;
// Disable all connectors (otherwise we might run into conflicting commits when restarting the rendering loop) // Disable all connectors (otherwise we might run into conflicting commits when restarting the rendering loop)
let mut req = AtomicModeReq::new(); let mut req = AtomicModeReq::new();
for conn in res_handles.connectors() { for conn in res_handles.connectors() {
let prop = dev.prop_mapping.0.get(&conn) let prop = dev
.expect("Unknown handle").get("CRTC_ID") .prop_mapping
.0
.get(&conn)
.expect("Unknown handle")
.get("CRTC_ID")
.expect("Unknown property CRTC_ID"); .expect("Unknown property CRTC_ID");
req.add_property(*conn, *prop, property::Value::CRTC(None)); req.add_property(*conn, *prop, property::Value::CRTC(None));
} }
// A crtc without a connector has no mode, we also need to reset that. // A crtc without a connector has no mode, we also need to reset that.
// Otherwise the commit will not be accepted. // Otherwise the commit will not be accepted.
for crtc in res_handles.crtcs() { for crtc in res_handles.crtcs() {
let mode_prop = dev.prop_mapping.1.get(&crtc) let mode_prop = dev
.expect("Unknown handle").get("MODE_ID") .prop_mapping
.1
.get(&crtc)
.expect("Unknown handle")
.get("MODE_ID")
.expect("Unknown property MODE_ID"); .expect("Unknown property MODE_ID");
let active_prop = dev.prop_mapping.1.get(&crtc) let active_prop = dev
.expect("Unknown handle").get("ACTIVE") .prop_mapping
.1
.get(&crtc)
.expect("Unknown handle")
.get("ACTIVE")
.expect("Unknown property ACTIVE"); .expect("Unknown property ACTIVE");
req.add_property(*crtc, *active_prop, property::Value::Boolean(false)); req.add_property(*crtc, *active_prop, property::Value::Boolean(false));
req.add_property(*crtc, *mode_prop, property::Value::Unknown(0)); req.add_property(*crtc, *mode_prop, property::Value::Unknown(0));
} }
dev.atomic_commit(&[AtomicCommitFlags::AllowModeset], req) dev.atomic_commit(&[AtomicCommitFlags::AllowModeset], req)
.compat().map_err(|source| Error::Access { .compat()
.map_err(|source| Error::Access {
errmsg: "Failed to disable connectors", errmsg: "Failed to disable connectors",
dev: dev.dev_path(), dev: dev.dev_path(),
source, source,

View File

@ -1,14 +1,16 @@
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, dumbbuffer::DumbBuffer, 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;
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;
use std::sync::{RwLock, atomic::Ordering}; use std::sync::{atomic::Ordering, RwLock};
use failure::ResultExt as FailureResultExt; use failure::ResultExt as FailureResultExt;
@ -57,20 +59,27 @@ 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, mode: Mode, connectors: &[connector::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,
})?; })?;
// If we have no current mode, we create a fake one, which will not match (and thus gets overriden on the commit below). // 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 // 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. // 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. // So we cheat, because it works and is easier to handle later.
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) => dev.create_property_blob(mode) Some(mode) => dev
.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",
@ -79,8 +88,9 @@ impl<A: AsRawFd + 'static> AtomicDrmSurfaceInternal<A> {
})?, })?,
None => property::Value::Unknown(0), None => property::Value::Unknown(0),
}; };
let blob = dev.create_property_blob(mode) let blob = dev
.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",
@ -96,7 +106,6 @@ impl<A: AsRawFd + 'static> AtomicDrmSurfaceInternal<A> {
source, source,
})?; })?;
let mut current_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
@ -163,16 +172,22 @@ impl<A: AsRawFd + 'static> AtomicDrmSurfaceInternal<A> {
fn create_test_buffer(&self, mode: &Mode) -> Result<framebuffer::Handle, Error> { fn create_test_buffer(&self, mode: &Mode) -> Result<framebuffer::Handle, Error> {
let (w, h) = mode.size(); let (w, h) = mode.size();
let db = self.create_dumb_buffer((w as u32, h as u32), drm::buffer::format::PixelFormat::ARGB8888).compat().map_err(|source| Error::Access { let db = self
errmsg: "Failed to create dumb buffer", .create_dumb_buffer((w as u32, h as u32), drm::buffer::format::PixelFormat::ARGB8888)
dev: self.dev_path(), .compat()
source .map_err(|source| Error::Access {
})?; errmsg: "Failed to create dumb buffer",
let fb = self.add_framebuffer(&db).compat().map_err(|source| Error::Access { dev: self.dev_path(),
errmsg: "Failed to create framebuffer", source,
dev: self.dev_path(), })?;
source let fb = self
})?; .add_framebuffer(&db)
.compat()
.map_err(|source| Error::Access {
errmsg: "Failed to create framebuffer",
dev: self.dev_path(),
source,
})?;
if let Some((old_db, old_fb)) = self.test_buffer.replace(Some((db, fb))) { if let Some((old_db, old_fb)) = self.test_buffer.replace(Some((db, fb))) {
let _ = self.destroy_framebuffer(old_fb); let _ = self.destroy_framebuffer(old_fb);
let _ = self.destroy_dumb_buffer(old_db); let _ = self.destroy_dumb_buffer(old_db);
@ -210,17 +225,32 @@ impl<A: AsRawFd + 'static> Drop for AtomicDrmSurfaceInternal<A> {
let current = self.state.read().unwrap(); let current = self.state.read().unwrap();
let mut req = AtomicModeReq::new(); let mut req = AtomicModeReq::new();
for conn in current.connectors.iter() { for conn in current.connectors.iter() {
let prop = self.dev.prop_mapping.0.get(&conn) let prop = self
.expect("Unknown Handle").get("CRTC_ID") .dev
.prop_mapping
.0
.get(&conn)
.expect("Unknown Handle")
.get("CRTC_ID")
.expect("Unknown property CRTC_ID"); .expect("Unknown property CRTC_ID");
req.add_property(*conn, *prop, property::Value::CRTC(None)); req.add_property(*conn, *prop, property::Value::CRTC(None));
} }
let active_prop = self.dev.prop_mapping.1.get(&self.crtc) let active_prop = self
.expect("Unknown Handle").get("ACTIVE") .dev
.expect("Unknown property ACTIVE"); .prop_mapping
let mode_prop = self.dev.prop_mapping.1.get(&self.crtc) .1
.expect("Unknown Handle").get("MODE_ID") .get(&self.crtc)
.expect("Unknown property MODE_ID"); .expect("Unknown Handle")
.get("ACTIVE")
.expect("Unknown property ACTIVE");
let mode_prop = self
.dev
.prop_mapping
.1
.get(&self.crtc)
.expect("Unknown Handle")
.get("MODE_ID")
.expect("Unknown property MODE_ID");
req.add_property(self.crtc, *active_prop, property::Value::Boolean(false)); req.add_property(self.crtc, *active_prop, property::Value::Boolean(false));
req.add_property(self.crtc, *mode_prop, property::Value::Unknown(0)); req.add_property(self.crtc, *mode_prop, property::Value::Unknown(0));
@ -335,7 +365,7 @@ impl<A: AsRawFd + 'static> Surface for AtomicDrmSurfaceInternal<A> {
if connectors.is_empty() { if connectors.is_empty() {
return Err(Error::SurfaceWithoutConnectors(self.crtc)); return Err(Error::SurfaceWithoutConnectors(self.crtc));
} }
if !self.dev.active.load(Ordering::SeqCst) { if !self.dev.active.load(Ordering::SeqCst) {
return Err(Error::DeviceInactive); return Err(Error::DeviceInactive);
} }
@ -376,14 +406,14 @@ impl<A: AsRawFd + 'static> Surface for AtomicDrmSurfaceInternal<A> {
// check if new config is supported // check if new config is supported
let new_blob = self let new_blob = self
.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,
})?; })?;
let test_fb = Some(self.create_test_buffer(&pending.mode)?); let test_fb = Some(self.create_test_buffer(&pending.mode)?);
let req = self.build_request( let req = self.build_request(
&mut pending.connectors.iter(), &mut pending.connectors.iter(),
@ -453,11 +483,7 @@ impl<A: AsRawFd + 'static> RawSurface for AtomicDrmSurfaceInternal<A> {
} }
if current.mode != pending.mode { if current.mode != pending.mode {
info!( info!(self.logger, "Setting new mode: {:?}", pending.mode.name());
self.logger,
"Setting new mode: {:?}",
pending.mode.name()
);
} }
trace!(self.logger, "Testing screen config"); trace!(self.logger, "Testing screen config");
@ -533,25 +559,25 @@ impl<A: AsRawFd + 'static> RawSurface for AtomicDrmSurfaceInternal<A> {
return Err(Error::DeviceInactive); return Err(Error::DeviceInactive);
} }
let req = self let req = self.build_request(
.build_request( &mut [].iter(),
&mut [].iter(), &mut [].iter(),
&mut [].iter(), &self.planes,
&self.planes, Some(framebuffer),
Some(framebuffer), None,
None, None,
None, )?;
)?;
trace!(self.logger, "Queueing page flip: {:#?}", req); trace!(self.logger, "Queueing page flip: {:#?}", req);
self.atomic_commit( self.atomic_commit(
&[AtomicCommitFlags::PageFlipEvent, AtomicCommitFlags::Nonblock], &[AtomicCommitFlags::PageFlipEvent, AtomicCommitFlags::Nonblock],
req, req,
) )
.compat().map_err(|source| Error::Access { .compat()
.map_err(|source| Error::Access {
errmsg: "Page flip commit failed", errmsg: "Page flip commit failed",
dev: self.dev_path(), dev: self.dev_path(),
source source,
})?; })?;
Ok(()) Ok(())

View File

@ -22,8 +22,8 @@ use drm::{
#[cfg(feature = "renderer_gl")] #[cfg(feature = "renderer_gl")]
use nix::libc::c_void; use nix::libc::c_void;
use nix::libc::dev_t; use nix::libc::dev_t;
use std::os::unix::io::{AsRawFd, RawFd};
use std::env; use std::env;
use std::os::unix::io::{AsRawFd, RawFd};
#[cfg(feature = "use_system_lib")] #[cfg(feature = "use_system_lib")]
use wayland_server::Display; use wayland_server::Display;
@ -175,15 +175,17 @@ impl<A: AsRawFd + Clone + 'static> FallbackDevice<AtomicDrmDevice<A>, LegacyDrmD
info!(log, "Trying to initialize AtomicDrmDevice"); info!(log, "Trying to initialize AtomicDrmDevice");
if env::var("SMITHAY_USE_LEGACY") if env::var("SMITHAY_USE_LEGACY")
.map(|x| .map(|x| {
x == "1" x == "1" || x.to_lowercase() == "true" || x.to_lowercase() == "yes" || x.to_lowercase() == "y"
|| x.to_lowercase() == "true" })
|| x.to_lowercase() == "yes" .unwrap_or(false)
|| x.to_lowercase() == "y"
).unwrap_or(false)
{ {
info!(log, "SMITHAY_USE_LEGACY is set. Forcing LegacyDrmDevice."); info!(log, "SMITHAY_USE_LEGACY is set. Forcing LegacyDrmDevice.");
return Ok(FallbackDevice::Fallback(LegacyDrmDevice::new(fd, disable_connectors, log)?)); return Ok(FallbackDevice::Fallback(LegacyDrmDevice::new(
fd,
disable_connectors,
log,
)?));
} }
match AtomicDrmDevice::new(fd.clone(), disable_connectors, log.clone()) { match AtomicDrmDevice::new(fd.clone(), disable_connectors, log.clone()) {
@ -191,7 +193,11 @@ impl<A: AsRawFd + Clone + 'static> FallbackDevice<AtomicDrmDevice<A>, LegacyDrmD
Err(err) => { Err(err) => {
error!(log, "Failed to initialize preferred AtomicDrmDevice: {}", err); error!(log, "Failed to initialize preferred AtomicDrmDevice: {}", err);
info!(log, "Falling back to fallback LegacyDrmDevice"); info!(log, "Falling back to fallback LegacyDrmDevice");
Ok(FallbackDevice::Fallback(LegacyDrmDevice::new(fd, disable_connectors, log)?)) Ok(FallbackDevice::Fallback(LegacyDrmDevice::new(
fd,
disable_connectors,
log,
)?))
} }
} }
} }
@ -257,10 +263,19 @@ where
} }
} }
fallback_device_impl!(clear_handler, &mut Self); fallback_device_impl!(clear_handler, &mut Self);
fn create_surface(&mut self, crtc: crtc::Handle, mode: Mode, connectors: &[connector::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, mode, connectors)?)), FallbackDevice::Preference(dev) => Ok(FallbackSurface::Preference(
FallbackDevice::Fallback(dev) => Ok(FallbackSurface::Fallback(dev.create_surface(crtc, mode, connectors)?)), dev.create_surface(crtc, mode, connectors)?,
)),
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);

View File

@ -3,9 +3,9 @@
//! and [`Surface`](::backend::drm::Surface) implementations of the `backend::drm` module. //! and [`Surface`](::backend::drm::Surface) implementations of the `backend::drm` module.
//! //!
use crate::backend::graphics::SwapBuffersError;
use drm::control::{connector, crtc, Mode, RawResourceHandle}; use drm::control::{connector, crtc, Mode, RawResourceHandle};
use std::path::PathBuf; use std::path::PathBuf;
use crate::backend::graphics::SwapBuffersError;
pub mod fallback; pub mod fallback;
@ -81,10 +81,17 @@ impl Into<SwapBuffersError> for Error {
dev: _, dev: _,
source, source,
} if match source.get_ref() { } if match source.get_ref() {
drm::SystemError::Unknown { errno: nix::errno::Errno::EBUSY } => true, drm::SystemError::Unknown {
drm::SystemError::Unknown { errno: nix::errno::Errno::EINTR } => true, errno: nix::errno::Errno::EBUSY,
} => true,
drm::SystemError::Unknown {
errno: nix::errno::Errno::EINTR,
} => true,
_ => false, _ => false,
} => SwapBuffersError::TemporaryFailure(Box::new(source)), } =>
{
SwapBuffersError::TemporaryFailure(Box::new(source))
}
x => SwapBuffersError::ContextLost(Box::new(x)), x => SwapBuffersError::ContextLost(Box::new(x)),
} }
} }

View File

@ -17,9 +17,9 @@ use wayland_server::Display;
use super::{Device, DeviceHandler, Surface}; use super::{Device, DeviceHandler, Surface};
use crate::backend::egl::native::{Backend, NativeDisplay, NativeSurface}; use crate::backend::egl::native::{Backend, NativeDisplay, NativeSurface};
use crate::backend::egl::{Error as EGLError, EGLError as RawEGLError, SurfaceCreationError};
#[cfg(feature = "use_system_lib")] #[cfg(feature = "use_system_lib")]
use crate::backend::egl::{display::EGLBufferReader, EGLGraphicsBackend}; use crate::backend::egl::{display::EGLBufferReader, EGLGraphicsBackend};
use crate::backend::egl::{EGLError as RawEGLError, Error as EGLError, SurfaceCreationError};
mod surface; mod surface;
pub use self::surface::*; pub use self::surface::*;
@ -49,7 +49,9 @@ type Arguments = (crtc::Handle, Mode, Vec<connector::Handle>);
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 = Arguments, Error=<<D as Device>::Surface as Surface>::Error> + 'static, D: Device
+ NativeDisplay<B, Arguments = Arguments, Error = <<D as Device>::Surface as Surface>::Error>
+ 'static,
<D as Device>::Surface: NativeSurface, <D as Device>::Surface: NativeSurface,
{ {
dev: EGLDisplay<B, D>, dev: EGLDisplay<B, D>,
@ -61,7 +63,9 @@ 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 = Arguments, Error=<<D as Device>::Surface as Surface>::Error> + 'static, D: Device
+ NativeDisplay<B, Arguments = Arguments, Error = <<D as Device>::Surface as Surface>::Error>
+ 'static,
<D as Device>::Surface: NativeSurface, <D as Device>::Surface: NativeSurface,
{ {
fn as_raw_fd(&self) -> RawFd { fn as_raw_fd(&self) -> RawFd {
@ -72,7 +76,9 @@ 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 = Arguments, Error=<<D as Device>::Surface as Surface>::Error> + 'static, D: Device
+ NativeDisplay<B, Arguments = Arguments, Error = <<D as Device>::Surface as Surface>::Error>
+ '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.
@ -127,7 +133,9 @@ 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 = Arguments, Error=<<D as Device>::Surface as Surface>::Error> + 'static, D: Device
+ NativeDisplay<B, Arguments = Arguments, Error = <<D as Device>::Surface as Surface>::Error>
+ '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>,
@ -136,7 +144,9 @@ 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 = Arguments, Error=<<D as Device>::Surface as Surface>::Error> + 'static, D: Device
+ NativeDisplay<B, Arguments = Arguments, Error = <<D as Device>::Surface as Surface>::Error>
+ 'static,
<D as Device>::Surface: NativeSurface, <D as Device>::Surface: NativeSurface,
{ {
type Device = D; type Device = D;
@ -152,7 +162,9 @@ 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 = Arguments, Error=<<D as Device>::Surface as Surface>::Error> + 'static, D: Device
+ NativeDisplay<B, Arguments = Arguments, Error = <<D as Device>::Surface as Surface>::Error>
+ '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>;
@ -231,7 +243,9 @@ 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 = Arguments, Error=<<D as Device>::Surface as Surface>::Error> + 'static, D: Device
+ NativeDisplay<B, Arguments = Arguments, Error = <<D as Device>::Surface as Surface>::Error>
+ '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> {
@ -242,7 +256,9 @@ 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 = Arguments, Error=<<D as Device>::Surface as Surface>::Error> + 'static, D: Device
+ NativeDisplay<B, Arguments = Arguments, Error = <<D as Device>::Surface as Surface>::Error>
+ 'static,
<D as Device>::Surface: NativeSurface, <D as Device>::Surface: NativeSurface,
{ {
fn drop(&mut self) { fn drop(&mut self) {

View File

@ -3,7 +3,7 @@
//! to an open [`Session`](::backend::session::Session). //! to an open [`Session`](::backend::session::Session).
//! //!
use drm::control::{crtc, connector, Mode}; use drm::control::{connector, crtc, Mode};
use std::os::unix::io::RawFd; use std::os::unix::io::RawFd;
use super::EglDevice; use super::EglDevice;
@ -22,7 +22,13 @@ 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, Mode, Vec<connector::Handle>), Error=<<D as Device>::Surface as Surface>::Error> + AsSessionObserver<S> + 'static, D: Device
+ NativeDisplay<
B,
Arguments = (crtc::Handle, Mode, Vec<connector::Handle>),
Error = <<D as Device>::Surface as Surface>::Error,
> + 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> {

View File

@ -22,7 +22,7 @@ where
} }
impl<N> Surface for EglSurface<N> impl<N> Surface for EglSurface<N>
where where
N: native::NativeSurface + Surface, N: native::NativeSurface + Surface,
{ {
type Connectors = <N as Surface>::Connectors; type Connectors = <N as Surface>::Connectors;
@ -99,7 +99,9 @@ where
Ok(x) => x, Ok(x) => x,
Err(x) => x.into(), Err(x) => x.into(),
}) })
} else { Ok(()) } } else {
Ok(())
}
} }
fn get_proc_address(&self, symbol: &str) -> *const c_void { fn get_proc_address(&self, symbol: &str) -> *const c_void {
@ -116,7 +118,9 @@ where
} }
unsafe fn make_current(&self) -> ::std::result::Result<(), SwapBuffersError> { unsafe fn make_current(&self) -> ::std::result::Result<(), SwapBuffersError> {
self.context.make_current_with_surface(&self.surface).map_err(Into::into) self.context
.make_current_with_surface(&self.surface)
.map_err(Into::into)
} }
fn get_pixel_format(&self) -> PixelFormat { fn get_pixel_format(&self) -> PixelFormat {

View File

@ -7,11 +7,11 @@
use crate::backend::drm::{Device, RawDevice, Surface}; use crate::backend::drm::{Device, RawDevice, Surface};
use crate::backend::egl::ffi; use crate::backend::egl::ffi;
use crate::backend::egl::native::{Backend, NativeDisplay, NativeSurface}; use crate::backend::egl::native::{Backend, NativeDisplay, NativeSurface};
use crate::backend::egl::{Error as EglBackendError, EGLError, wrap_egl_call}; use crate::backend::egl::{wrap_egl_call, EGLError, Error as EglBackendError};
use super::{Error, GbmDevice, GbmSurface}; use super::{Error, GbmDevice, GbmSurface};
use drm::control::{crtc, connector, Device as ControlDevice, Mode}; use drm::control::{connector, crtc, Device as ControlDevice, Mode};
use gbm::AsRaw; use gbm::AsRaw;
use std::marker::PhantomData; use std::marker::PhantomData;
use std::ptr; use std::ptr;
@ -36,13 +36,19 @@ impl<D: RawDevice + 'static> Backend for Gbm<D> {
{ {
if has_dp_extension("EGL_KHR_platform_gbm") && ffi::egl::GetPlatformDisplay::is_loaded() { if has_dp_extension("EGL_KHR_platform_gbm") && ffi::egl::GetPlatformDisplay::is_loaded() {
trace!(log, "EGL Display Initialization via EGL_KHR_platform_gbm"); trace!(log, "EGL Display Initialization via EGL_KHR_platform_gbm");
wrap_egl_call(|| ffi::egl::GetPlatformDisplay(ffi::egl::PLATFORM_GBM_KHR, display as *mut _, ptr::null())) wrap_egl_call(|| {
ffi::egl::GetPlatformDisplay(ffi::egl::PLATFORM_GBM_KHR, display as *mut _, ptr::null())
})
} else if has_dp_extension("EGL_MESA_platform_gbm") && ffi::egl::GetPlatformDisplayEXT::is_loaded() { } else if has_dp_extension("EGL_MESA_platform_gbm") && ffi::egl::GetPlatformDisplayEXT::is_loaded() {
trace!(log, "EGL Display Initialization via EGL_MESA_platform_gbm"); trace!(log, "EGL Display Initialization via EGL_MESA_platform_gbm");
wrap_egl_call(|| ffi::egl::GetPlatformDisplayEXT(ffi::egl::PLATFORM_GBM_MESA, display as *mut _, ptr::null())) wrap_egl_call(|| {
ffi::egl::GetPlatformDisplayEXT(ffi::egl::PLATFORM_GBM_MESA, display as *mut _, ptr::null())
})
} else if has_dp_extension("EGL_MESA_platform_gbm") && ffi::egl::GetPlatformDisplay::is_loaded() { } else if has_dp_extension("EGL_MESA_platform_gbm") && ffi::egl::GetPlatformDisplay::is_loaded() {
trace!(log, "EGL Display Initialization via EGL_MESA_platform_gbm"); trace!(log, "EGL Display Initialization via EGL_MESA_platform_gbm");
wrap_egl_call(|| ffi::egl::GetPlatformDisplay(ffi::egl::PLATFORM_GBM_MESA, display as *mut _, ptr::null())) wrap_egl_call(|| {
ffi::egl::GetPlatformDisplay(ffi::egl::PLATFORM_GBM_MESA, display as *mut _, ptr::null())
})
} else { } else {
trace!(log, "Default EGL Display Initialization via GetDisplay"); trace!(log, "Default EGL Display Initialization via GetDisplay");
wrap_egl_call(|| ffi::egl::GetDisplay(display as *mut _)) wrap_egl_call(|| ffi::egl::GetDisplay(display as *mut _))

View File

@ -171,13 +171,11 @@ impl<D: RawDevice + ControlDevice + 'static> Device for GbmDevice<D> {
) -> 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, mode, connectors)
Device::create_surface(&mut **self.dev.borrow_mut(), crtc, mode, connectors).map_err(Error::Underlying)?; .map_err(Error::Underlying)?;
// initialize the surface // initialize the surface
let (w, h) = drm_surface let (w, h) = drm_surface.pending_mode().size();
.pending_mode()
.size();
let surface = self let surface = self
.dev .dev
.borrow() .borrow()
@ -260,18 +258,26 @@ impl<D: RawDevice + ControlDevice + 'static> Drop for GbmDevice<D> {
impl<E> Into<SwapBuffersError> for Error<E> impl<E> Into<SwapBuffersError> for Error<E>
where where
E: std::error::Error + Into<SwapBuffersError> + 'static E: std::error::Error + Into<SwapBuffersError> + 'static,
{ {
fn into(self) -> SwapBuffersError { fn into(self) -> SwapBuffersError {
match self { match self {
Error::FrontBuffersExhausted => SwapBuffersError::AlreadySwapped, Error::FrontBuffersExhausted => SwapBuffersError::AlreadySwapped,
Error::FramebufferCreationFailed(x) if match x.get_ref() { Error::FramebufferCreationFailed(x)
&drm::SystemError::Unknown { errno: nix::errno::Errno::EBUSY } => true, if match x.get_ref() {
&drm::SystemError::Unknown { errno: nix::errno::Errno::EINTR } => true, &drm::SystemError::Unknown {
_ => false errno: nix::errno::Errno::EBUSY,
} => SwapBuffersError::TemporaryFailure(Box::new(x)), } => true,
&drm::SystemError::Unknown {
errno: nix::errno::Errno::EINTR,
} => true,
_ => false,
} =>
{
SwapBuffersError::TemporaryFailure(Box::new(x))
}
Error::Underlying(x) => x.into(), Error::Underlying(x) => x.into(),
x => SwapBuffersError::ContextLost(Box::new(x)), x => SwapBuffersError::ContextLost(Box::new(x)),
} }
} }
} }

View File

@ -29,8 +29,8 @@ pub struct GbmDeviceObserver<
impl< impl<
O: SessionObserver + 'static, O: SessionObserver + 'static,
S: CursorBackend<CursorFormat=dyn drm::buffer::Buffer> + RawSurface + 'static, S: CursorBackend<CursorFormat = dyn drm::buffer::Buffer> + RawSurface + 'static,
D: RawDevice<Surface=S> + drm::control::Device + AsSessionObserver<O> + 'static, D: RawDevice<Surface = S> + drm::control::Device + AsSessionObserver<O> + 'static,
> AsSessionObserver<GbmDeviceObserver<O, D>> for GbmDevice<D> > AsSessionObserver<GbmDeviceObserver<O, D>> for GbmDevice<D>
{ {
fn observer(&mut self) -> GbmDeviceObserver<O, D> { fn observer(&mut self) -> GbmDeviceObserver<O, D> {
@ -44,8 +44,8 @@ impl<
impl< impl<
O: SessionObserver + 'static, O: SessionObserver + 'static,
S: CursorBackend<CursorFormat=dyn drm::buffer::Buffer> + RawSurface + 'static, S: CursorBackend<CursorFormat = dyn drm::buffer::Buffer> + RawSurface + 'static,
D: RawDevice<Surface=S> + drm::control::Device + AsSessionObserver<O> + 'static, D: RawDevice<Surface = S> + drm::control::Device + AsSessionObserver<O> + 'static,
> SessionObserver for GbmDeviceObserver<O, D> > SessionObserver for GbmDeviceObserver<O, D>
{ {
fn pause(&mut self, devnum: Option<(u32, u32)>) { fn pause(&mut self, devnum: Option<(u32, u32)>) {
@ -81,9 +81,7 @@ impl<
let &(ref cursor, ref hotspot): &(BufferObject<()>, (u32, u32)) = let &(ref cursor, ref hotspot): &(BufferObject<()>, (u32, u32)) =
unsafe { &*backend.cursor.as_ptr() }; unsafe { &*backend.cursor.as_ptr() };
if backend.crtc.set_cursor_representation(cursor, *hotspot) if backend.crtc.set_cursor_representation(cursor, *hotspot).is_err() {
.is_err()
{
if let Err(err) = backend.dev.borrow().set_cursor(*crtc, Some(cursor)) { if let Err(err) = backend.dev.borrow().set_cursor(*crtc, Some(cursor)) {
error!(self.logger, "Failed to reset cursor. Error: {}", err); error!(self.logger, "Failed to reset cursor. Error: {}", err);
} }

View File

@ -2,9 +2,9 @@ use super::super::{Device, RawDevice, RawSurface, Surface};
use super::Error; use super::Error;
use drm::control::{connector, crtc, framebuffer, Device as ControlDevice, Mode}; use drm::control::{connector, crtc, framebuffer, Device as ControlDevice, Mode};
use failure::ResultExt;
use gbm::{self, BufferObject, BufferObjectFlags, Format as GbmFormat, SurfaceBufferHandle}; use gbm::{self, BufferObject, BufferObjectFlags, Format as GbmFormat, SurfaceBufferHandle};
use image::{ImageBuffer, Rgba}; use image::{ImageBuffer, Rgba};
use failure::ResultExt;
use std::cell::{Cell, RefCell}; use std::cell::{Cell, RefCell};
use std::rc::Rc; use std::rc::Rc;
@ -89,9 +89,7 @@ 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().size();
.pending_mode()
.size();
// Recreate the surface and the related resources to match the new // Recreate the surface and the related resources to match the new
// resolution. // resolution.

View File

@ -100,7 +100,7 @@ impl<A: AsRawFd + 'static> LegacyDrmDevice<A> {
/// - `logger` - Optional [`slog::Logger`] to be used by this device. /// - `logger` - Optional [`slog::Logger`] to be used by this device.
/// ///
/// # Return /// # Return
/// ///
/// Returns an error if the file is no valid drm node or the device is not accessible. /// Returns an error if the file is no valid drm node or the device is not accessible.
pub fn new<L>(dev: A, disable_connectors: bool, logger: L) -> Result<Self, Error> pub fn new<L>(dev: A, disable_connectors: bool, logger: L) -> Result<Self, Error>
where where
@ -190,33 +190,55 @@ impl<A: AsRawFd + 'static> LegacyDrmDevice<A> {
} }
impl<A: AsRawFd + 'static> Dev<A> { impl<A: AsRawFd + 'static> Dev<A> {
pub(in crate::backend::drm::legacy) fn set_connector_state(&self, connectors: impl Iterator<Item=connector::Handle>, enabled: bool) -> Result<(), Error> { pub(in crate::backend::drm::legacy) fn set_connector_state(
&self,
connectors: impl Iterator<Item = connector::Handle>,
enabled: bool,
) -> Result<(), Error> {
for conn in connectors { for conn in connectors {
let info = self.get_connector(conn).compat().map_err(|source| Error::Access { let info = self
.get_connector(conn)
.compat()
.map_err(|source| Error::Access {
errmsg: "Failed to get connector infos", errmsg: "Failed to get connector infos",
dev: self.dev_path(), dev: self.dev_path(),
source source,
})?; })?;
if info.state() == connector::State::Connected { if info.state() == connector::State::Connected {
let props = self.get_properties(conn).compat().map_err(|source| Error::Access { let props = self
errmsg: "Failed to get properties for connector", .get_properties(conn)
dev: self.dev_path(), .compat()
source .map_err(|source| Error::Access {
})?; errmsg: "Failed to get properties for connector",
dev: self.dev_path(),
source,
})?;
let (handles, _) = props.as_props_and_values(); let (handles, _) = props.as_props_and_values();
for handle in handles { for handle in handles {
let info = self.get_property(*handle).compat().map_err(|source| Error::Access { let info = self
errmsg: "Failed to get property of connector", .get_property(*handle)
dev: self.dev_path(), .compat()
source .map_err(|source| Error::Access {
})?; errmsg: "Failed to get property of connector",
dev: self.dev_path(),
source,
})?;
if info.name().to_str().map(|x| x == "DPMS").unwrap_or(false) { if info.name().to_str().map(|x| x == "DPMS").unwrap_or(false) {
self.set_property(conn, *handle, if enabled { 0 /*DRM_MODE_DPMS_ON*/} else { 3 /*DRM_MODE_DPMS_OFF*/}) self.set_property(
.compat().map_err(|source| Error::Access { conn,
errmsg: "Failed to set property of connector", *handle,
dev: self.dev_path(), if enabled {
source 0 /*DRM_MODE_DPMS_ON*/
})?; } else {
3 /*DRM_MODE_DPMS_OFF*/
},
)
.compat()
.map_err(|source| Error::Access {
errmsg: "Failed to set property of connector",
dev: self.dev_path(),
source,
})?;
} }
} }
} }
@ -249,7 +271,12 @@ impl<A: AsRawFd + 'static> Device for LegacyDrmDevice<A> {
let _ = self.handler.take(); let _ = self.handler.take();
} }
fn create_surface(&mut self, crtc: crtc::Handle, mode: Mode, connectors: &[connector::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));
} }
@ -263,7 +290,10 @@ impl<A: AsRawFd + 'static> Device for LegacyDrmDevice<A> {
} }
let backend = Rc::new(LegacyDrmSurfaceInternal::new( let backend = Rc::new(LegacyDrmSurfaceInternal::new(
self.dev.clone(), crtc, mode, connectors, self.dev.clone(),
crtc,
mode,
connectors,
self.logger.new(o!("crtc" => format!("{:?}", crtc))), self.logger.new(o!("crtc" => format!("{:?}", crtc))),
)?); )?);

View File

@ -5,6 +5,7 @@
use drm::control::{crtc, Device as ControlDevice}; use drm::control::{crtc, Device as ControlDevice};
use drm::Device as BasicDevice; use drm::Device as BasicDevice;
use failure::ResultExt;
use nix::libc::dev_t; use nix::libc::dev_t;
use nix::sys::stat; use nix::sys::stat;
use std::cell::RefCell; use std::cell::RefCell;
@ -13,9 +14,8 @@ 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; use std::sync::Arc;
use failure::ResultExt;
use super::{Dev, LegacyDrmDevice, LegacyDrmSurfaceInternal, Error, DevPath}; use super::{Dev, DevPath, Error, LegacyDrmDevice, LegacyDrmSurfaceInternal};
use crate::backend::session::{AsSessionObserver, SessionObserver}; use crate::backend::session::{AsSessionObserver, SessionObserver};
/// [`SessionObserver`](SessionObserver) /// [`SessionObserver`](SessionObserver)
@ -112,24 +112,27 @@ impl<A: AsRawFd + 'static> LegacyDrmDeviceObserver<A> {
dev: dev.dev_path(), dev: dev.dev_path(),
source, source,
})?; })?;
let mut used_connectors = HashSet::new(); let mut used_connectors = HashSet::new();
if let Some(backends) = self.backends.upgrade() { if let Some(backends) = self.backends.upgrade() {
for surface in backends.borrow().values().filter_map(Weak::upgrade) { for surface in backends.borrow().values().filter_map(Weak::upgrade) {
let mut current = surface.state.write().unwrap(); let mut current = surface.state.write().unwrap();
let pending = surface.pending.read().unwrap(); let pending = surface.pending.read().unwrap();
// store (soon to be) used connectors // store (soon to be) used connectors
used_connectors.extend(pending.connectors.clone()); used_connectors.extend(pending.connectors.clone());
// set current connectors // set current connectors
current.connectors.clear(); current.connectors.clear();
for conn in res_handles.connectors() { for conn in res_handles.connectors() {
let conn_info = dev.get_connector(*conn).compat().map_err(|source| Error::Access { let conn_info =
errmsg: "Could not load connector info", dev.get_connector(*conn)
dev: dev.dev_path(), .compat()
source, .map_err(|source| Error::Access {
})?; errmsg: "Could not load connector info",
dev: dev.dev_path(),
source,
})?;
if let Some(enc) = conn_info.current_encoder() { if let Some(enc) = conn_info.current_encoder() {
let enc_info = dev.get_encoder(enc).compat().map_err(|source| Error::Access { let enc_info = dev.get_encoder(enc).compat().map_err(|source| Error::Access {
errmsg: "Could not load encoder info", errmsg: "Could not load encoder info",
@ -143,11 +146,14 @@ impl<A: AsRawFd + 'static> LegacyDrmDeviceObserver<A> {
} }
// set current mode // set current mode
let crtc_info = dev.get_crtc(surface.crtc).compat().map_err(|source| Error::Access { let crtc_info = dev
errmsg: "Could not load crtc info", .get_crtc(surface.crtc)
dev: dev.dev_path(), .compat()
source, .map_err(|source| Error::Access {
})?; errmsg: "Could not load crtc info",
dev: dev.dev_path(),
source,
})?;
// If we have no current mode, we create a fake one, which will not match (and thus gets overriden on the commit below). // 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 // A better fix would probably be making mode an `Option`, but that would mean
@ -162,7 +168,7 @@ impl<A: AsRawFd + 'static> LegacyDrmDeviceObserver<A> {
let unused = used_connectors.difference(&all_set); let unused = used_connectors.difference(&all_set);
dev.set_connector_state(unused.copied(), false)?; dev.set_connector_state(unused.copied(), false)?;
} }
Ok(()) Ok(())
} }
} }

View File

@ -8,7 +8,7 @@ use drm::Device as BasicDevice;
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;
use std::sync::{RwLock, atomic::Ordering}; use std::sync::{atomic::Ordering, RwLock};
use crate::backend::drm::{common::Error, DevPath, RawSurface, Surface}; use crate::backend::drm::{common::Error, DevPath, RawSurface, Surface};
use crate::backend::graphics::CursorBackend; use crate::backend::graphics::CursorBackend;
@ -115,7 +115,7 @@ impl<A: AsRawFd + 'static> Surface for LegacyDrmSurfaceInternal<A> {
if !self.dev.active.load(Ordering::SeqCst) { if !self.dev.active.load(Ordering::SeqCst) {
return Err(Error::DeviceInactive); return Err(Error::DeviceInactive);
} }
let mut pending = self.pending.write().unwrap(); let mut pending = self.pending.write().unwrap();
if self.check_connector(conn, &pending.mode)? { if self.check_connector(conn, &pending.mode)? {
@ -140,7 +140,7 @@ impl<A: AsRawFd + 'static> Surface for LegacyDrmSurfaceInternal<A> {
if connectors.is_empty() { if connectors.is_empty() {
return Err(Error::SurfaceWithoutConnectors(self.crtc)); return Err(Error::SurfaceWithoutConnectors(self.crtc));
} }
if !self.dev.active.load(Ordering::SeqCst) { if !self.dev.active.load(Ordering::SeqCst) {
return Err(Error::DeviceInactive); return Err(Error::DeviceInactive);
} }
@ -241,11 +241,7 @@ impl<A: AsRawFd + 'static> RawSurface for LegacyDrmSurfaceInternal<A> {
self.dev.set_connector_state(added.copied(), true)?; self.dev.set_connector_state(added.copied(), true)?;
if current.mode != pending.mode { if current.mode != pending.mode {
info!( info!(self.logger, "Setting new mode: {:?}", pending.mode.name());
self.logger,
"Setting new mode: {:?}",
pending.mode.name()
);
} }
} }
@ -286,7 +282,7 @@ impl<A: AsRawFd + 'static> RawSurface for LegacyDrmSurfaceInternal<A> {
fn page_flip(&self, framebuffer: framebuffer::Handle) -> Result<(), Error> { fn page_flip(&self, framebuffer: framebuffer::Handle) -> Result<(), Error> {
trace!(self.logger, "Queueing Page flip"); trace!(self.logger, "Queueing Page flip");
if !self.dev.active.load(Ordering::SeqCst) { if !self.dev.active.load(Ordering::SeqCst) {
return Err(Error::DeviceInactive); return Err(Error::DeviceInactive);
} }
@ -297,7 +293,8 @@ impl<A: AsRawFd + 'static> RawSurface for LegacyDrmSurfaceInternal<A> {
framebuffer, framebuffer,
&[PageFlipFlags::PageFlipEvent], &[PageFlipFlags::PageFlipEvent],
None, None,
).compat() )
.compat()
.map_err(|source| Error::Access { .map_err(|source| Error::Access {
errmsg: "Failed to page flip", errmsg: "Failed to page flip",
dev: self.dev_path(), dev: self.dev_path(),
@ -307,7 +304,13 @@ 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, mode: Mode, connectors: &[connector::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",
@ -349,9 +352,15 @@ impl<A: AsRawFd + 'static> LegacyDrmSurfaceInternal<A> {
// A better fix would probably be making mode an `Option`, but that would mean // 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. // 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. // 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 state = State {
let pending = State { mode, connectors: connectors.into_iter().copied().collect() }; 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,
@ -424,11 +433,14 @@ impl<A: AsRawFd + 'static> Drop for LegacyDrmSurfaceInternal<A> {
// by the device, when switching back // by the device, when switching back
return; return;
} }
let _ = self.set_cursor(self.crtc, Option::<&DumbBuffer>::None); let _ = self.set_cursor(self.crtc, Option::<&DumbBuffer>::None);
// disable connectors again // disable connectors again
let current = self.state.read().unwrap(); let current = self.state.read().unwrap();
if let Ok(_) = self.dev.set_connector_state(current.connectors.iter().copied(), false) { if let Ok(_) = self
.dev
.set_connector_state(current.connectors.iter().copied(), false)
{
// null commit // null commit
let _ = self.set_crtc(self.crtc, None, (0, 0), &[], None); let _ = self.set_crtc(self.crtc, None, (0, 0), &[], None);
} }

View File

@ -108,7 +108,7 @@ pub trait Device: AsRawFd + DevPath {
&mut self, &mut self,
crtc: crtc::Handle, crtc: crtc::Handle,
mode: Mode, mode: Mode,
connectors: &[connector::Handle] 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.

View File

@ -1,6 +1,6 @@
//! EGL context related structs //! EGL context related structs
use super::{ffi, Error, MakeCurrentError, wrap_egl_call}; use super::{ffi, wrap_egl_call, Error, MakeCurrentError};
use crate::backend::egl::display::{EGLDisplay, EGLDisplayHandle}; use crate::backend::egl::display::{EGLDisplay, EGLDisplayHandle};
use crate::backend::egl::native::NativeSurface; use crate::backend::egl::native::NativeSurface;
use crate::backend::egl::{native, EGLSurface}; use crate::backend::egl::{native, EGLSurface};
@ -100,7 +100,8 @@ impl EGLContext {
ptr::null(), ptr::null(),
context_attributes.as_ptr(), context_attributes.as_ptr(),
) )
}).map_err(Error::CreationFailed)?; })
.map_err(Error::CreationFailed)?;
info!(log, "EGL context created"); info!(log, "EGL context created");
@ -119,16 +120,15 @@ impl EGLContext {
/// ///
/// This function is marked unsafe, because the context cannot be made current /// This function is marked unsafe, because the context cannot be made current
/// on multiple threads. /// on multiple threads.
pub unsafe fn make_current_with_surface<N>( pub unsafe fn make_current_with_surface<N>(&self, surface: &EGLSurface<N>) -> Result<(), MakeCurrentError>
&self,
surface: &EGLSurface<N>,
) -> Result<(), MakeCurrentError>
where where
N: NativeSurface, N: NativeSurface,
{ {
let surface_ptr = surface.surface.get(); let surface_ptr = surface.surface.get();
wrap_egl_call(|| ffi::egl::MakeCurrent(**self.display, surface_ptr, surface_ptr, self.context)).map(|_| ()).map_err(Into::into) wrap_egl_call(|| ffi::egl::MakeCurrent(**self.display, surface_ptr, surface_ptr, self.context))
.map(|_| ())
.map_err(Into::into)
} }
/// Makes the OpenGL context the current context in the current thread with no surface bound. /// Makes the OpenGL context the current context in the current thread with no surface bound.
@ -138,7 +138,16 @@ impl EGLContext {
/// This function is marked unsafe, because the context cannot be made current /// This function is marked unsafe, because the context cannot be made current
/// on multiple threads without being unbound again (see `unbind`) /// on multiple threads without being unbound again (see `unbind`)
pub unsafe fn make_current(&self) -> Result<(), MakeCurrentError> { pub unsafe fn make_current(&self) -> Result<(), MakeCurrentError> {
wrap_egl_call(|| ffi::egl::MakeCurrent(**self.display, ffi::egl::NO_SURFACE, ffi::egl::NO_SURFACE, self.context)).map(|_| ()).map_err(Into::into) wrap_egl_call(|| {
ffi::egl::MakeCurrent(
**self.display,
ffi::egl::NO_SURFACE,
ffi::egl::NO_SURFACE,
self.context,
)
})
.map(|_| ())
.map_err(Into::into)
} }
/// Returns true if the OpenGL context is the current one in the thread. /// Returns true if the OpenGL context is the current one in the thread.
@ -155,13 +164,20 @@ impl EGLContext {
pub fn get_pixel_format(&self) -> PixelFormat { pub fn get_pixel_format(&self) -> PixelFormat {
self.pixel_format self.pixel_format
} }
/// Unbinds this context from the current thread, if set. /// Unbinds this context from the current thread, if set.
/// ///
/// This does nothing if this context is not the current context /// This does nothing if this context is not the current context
pub fn unbind(&self) -> Result<(), MakeCurrentError> { pub fn unbind(&self) -> Result<(), MakeCurrentError> {
if self.is_current() { if self.is_current() {
wrap_egl_call(|| unsafe { ffi::egl::MakeCurrent(**self.display, ffi::egl::NO_SURFACE, ffi::egl::NO_SURFACE, ffi::egl::NO_CONTEXT)})?; wrap_egl_call(|| unsafe {
ffi::egl::MakeCurrent(
**self.display,
ffi::egl::NO_SURFACE,
ffi::egl::NO_SURFACE,
ffi::egl::NO_CONTEXT,
)
})?;
} }
Ok(()) Ok(())
} }
@ -311,7 +327,7 @@ impl PixelFormatRequirements {
if self.stereoscopy { if self.stereoscopy {
error!(logger, "Stereoscopy is currently unsupported (sorry!)"); error!(logger, "Stereoscopy is currently unsupported (sorry!)");
return Err(()); return Err(());
} }
Ok(()) Ok(())

View File

@ -3,7 +3,8 @@
#[cfg(feature = "use_system_lib")] #[cfg(feature = "use_system_lib")]
use crate::backend::egl::EGLGraphicsBackend; use crate::backend::egl::EGLGraphicsBackend;
use crate::backend::egl::{ use crate::backend::egl::{
ffi, get_proc_address, native, BufferAccessError, SurfaceCreationError, EGLContext, EGLImages, EGLSurface, Error, Format, EGLError, wrap_egl_call, ffi, get_proc_address, native, wrap_egl_call, BufferAccessError, EGLContext, EGLError, EGLImages,
EGLSurface, Error, Format, SurfaceCreationError,
}; };
use std::sync::Arc; use std::sync::Arc;
@ -94,7 +95,9 @@ impl<B: native::Backend, N: native::NativeDisplay<B>> EGLDisplay<B, N> {
// the first step is to query the list of extensions without any display, if supported // the first step is to query the list of extensions without any display, if supported
let dp_extensions = unsafe { let dp_extensions = unsafe {
let p = wrap_egl_call(|| ffi::egl::QueryString(ffi::egl::NO_DISPLAY, ffi::egl::EXTENSIONS as i32)).map_err(Error::InitFailed)?; let p =
wrap_egl_call(|| ffi::egl::QueryString(ffi::egl::NO_DISPLAY, ffi::egl::EXTENSIONS as i32))
.map_err(Error::InitFailed)?;
// this possibility is available only with EGL 1.5 or EGL_EXT_platform_base, otherwise // this possibility is available only with EGL 1.5 or EGL_EXT_platform_base, otherwise
// `eglQueryString` returns an error // `eglQueryString` returns an error
@ -108,14 +111,20 @@ impl<B: native::Backend, N: native::NativeDisplay<B>> EGLDisplay<B, N> {
}; };
debug!(log, "EGL No-Display Extensions: {:?}", dp_extensions); debug!(log, "EGL No-Display Extensions: {:?}", dp_extensions);
let display = unsafe { B::get_display(ptr, |e: &str| dp_extensions.iter().any(|s| s == e), log.clone()).map_err(Error::DisplayNotSupported)? }; let display = unsafe {
B::get_display(ptr, |e: &str| dp_extensions.iter().any(|s| s == e), log.clone())
.map_err(Error::DisplayNotSupported)?
};
let egl_version = { let egl_version = {
let mut major: MaybeUninit<ffi::egl::types::EGLint> = MaybeUninit::uninit(); let mut major: MaybeUninit<ffi::egl::types::EGLint> = MaybeUninit::uninit();
let mut minor: MaybeUninit<ffi::egl::types::EGLint> = MaybeUninit::uninit(); let mut minor: MaybeUninit<ffi::egl::types::EGLint> = MaybeUninit::uninit();
wrap_egl_call(|| unsafe { ffi::egl::Initialize(display, major.as_mut_ptr(), minor.as_mut_ptr()) }).map_err(Error::InitFailed)?; wrap_egl_call(|| unsafe {
ffi::egl::Initialize(display, major.as_mut_ptr(), minor.as_mut_ptr())
})
.map_err(Error::InitFailed)?;
let major = unsafe { major.assume_init() }; let major = unsafe { major.assume_init() };
let minor = unsafe { minor.assume_init() }; let minor = unsafe { minor.assume_init() };
@ -128,7 +137,12 @@ impl<B: native::Backend, N: native::NativeDisplay<B>> EGLDisplay<B, N> {
// the list of extensions supported by the client once initialized is different from the // the list of extensions supported by the client once initialized is different from the
// list of extensions obtained earlier // list of extensions obtained earlier
let extensions = if egl_version >= (1, 2) { let extensions = if egl_version >= (1, 2) {
let p = unsafe { CStr::from_ptr(wrap_egl_call(|| ffi::egl::QueryString(display, ffi::egl::EXTENSIONS as i32)).map_err(Error::InitFailed)?) }; let p = unsafe {
CStr::from_ptr(
wrap_egl_call(|| ffi::egl::QueryString(display, ffi::egl::EXTENSIONS as i32))
.map_err(Error::InitFailed)?,
)
};
let list = String::from_utf8(p.to_bytes().to_vec()).unwrap_or_else(|_| String::new()); let list = String::from_utf8(p.to_bytes().to_vec()).unwrap_or_else(|_| String::new());
list.split(' ').map(|e| e.to_string()).collect::<Vec<_>>() list.split(' ').map(|e| e.to_string()).collect::<Vec<_>>()
} else { } else {
@ -139,7 +153,8 @@ impl<B: native::Backend, N: native::NativeDisplay<B>> EGLDisplay<B, N> {
if egl_version >= (1, 2) { if egl_version >= (1, 2) {
return Err(Error::OpenGlesNotSupported(None)); return Err(Error::OpenGlesNotSupported(None));
} }
wrap_egl_call(|| unsafe { ffi::egl::BindAPI(ffi::egl::OPENGL_ES_API) }).map_err(|source| Error::OpenGlesNotSupported(Some(source)))?; wrap_egl_call(|| unsafe { ffi::egl::BindAPI(ffi::egl::OPENGL_ES_API) })
.map_err(|source| Error::OpenGlesNotSupported(Some(source)))?;
Ok(EGLDisplay { Ok(EGLDisplay {
native: RefCell::new(native), native: RefCell::new(native),
@ -212,7 +227,8 @@ impl<B: native::Backend, N: native::NativeDisplay<B>> EGLDisplay<B, N> {
} }
}; };
reqs.create_attributes(&mut out, &self.logger).map_err(|()| Error::NoAvailablePixelFormat)?; reqs.create_attributes(&mut out, &self.logger)
.map_err(|()| Error::NoAvailablePixelFormat)?;
out.push(ffi::egl::NONE as c_int); out.push(ffi::egl::NONE as c_int);
out out
@ -228,7 +244,8 @@ impl<B: native::Backend, N: native::NativeDisplay<B>> EGLDisplay<B, N> {
0, 0,
&mut num_configs, &mut num_configs,
) )
}).map_err(Error::ConfigFailed)?; })
.map_err(Error::ConfigFailed)?;
if num_configs == 0 { if num_configs == 0 {
return Err(Error::NoAvailablePixelFormat); return Err(Error::NoAvailablePixelFormat);
} }
@ -242,8 +259,11 @@ impl<B: native::Backend, N: native::NativeDisplay<B>> EGLDisplay<B, N> {
num_configs, num_configs,
&mut num_configs, &mut num_configs,
) )
}).map_err(Error::ConfigFailed)?; })
unsafe { config_ids.set_len(num_configs as usize); } .map_err(Error::ConfigFailed)?;
unsafe {
config_ids.set_len(num_configs as usize);
}
// TODO: Deeper swap intervals might have some uses // TODO: Deeper swap intervals might have some uses
let desired_swap_interval = if attributes.vsync { 1 } else { 0 }; let desired_swap_interval = if attributes.vsync { 1 } else { 0 };
@ -252,24 +272,28 @@ impl<B: native::Backend, N: native::NativeDisplay<B>> EGLDisplay<B, N> {
.into_iter() .into_iter()
.map(|config| unsafe { .map(|config| unsafe {
let mut min_swap_interval = 0; let mut min_swap_interval = 0;
wrap_egl_call(|| ffi::egl::GetConfigAttrib( wrap_egl_call(|| {
**self.display, ffi::egl::GetConfigAttrib(
config, **self.display,
ffi::egl::MIN_SWAP_INTERVAL as ffi::egl::types::EGLint, config,
&mut min_swap_interval, ffi::egl::MIN_SWAP_INTERVAL as ffi::egl::types::EGLint,
))?; &mut min_swap_interval,
)
})?;
if desired_swap_interval < min_swap_interval { if desired_swap_interval < min_swap_interval {
return Ok(None); return Ok(None);
} }
let mut max_swap_interval = 0; let mut max_swap_interval = 0;
wrap_egl_call(|| ffi::egl::GetConfigAttrib( wrap_egl_call(|| {
**self.display, ffi::egl::GetConfigAttrib(
config, **self.display,
ffi::egl::MAX_SWAP_INTERVAL as ffi::egl::types::EGLint, config,
&mut max_swap_interval, ffi::egl::MAX_SWAP_INTERVAL as ffi::egl::types::EGLint,
))?; &mut max_swap_interval,
)
})?;
if desired_swap_interval > max_swap_interval { if desired_swap_interval > max_swap_interval {
return Ok(None); return Ok(None);
@ -277,8 +301,11 @@ impl<B: native::Backend, N: native::NativeDisplay<B>> EGLDisplay<B, N> {
Ok(Some(config)) Ok(Some(config))
}) })
.collect::<Result<Vec<Option<ffi::egl::types::EGLConfig>>, EGLError>>().map_err(Error::ConfigFailed)? .collect::<Result<Vec<Option<ffi::egl::types::EGLConfig>>, EGLError>>()
.into_iter().flat_map(|x| x).collect::<Vec<_>>(); .map_err(Error::ConfigFailed)?
.into_iter()
.flat_map(|x| x)
.collect::<Vec<_>>();
if config_ids.is_empty() { if config_ids.is_empty() {
return Err(Error::NoAvailablePixelFormat); return Err(Error::NoAvailablePixelFormat);
@ -291,12 +318,15 @@ impl<B: native::Backend, N: native::NativeDisplay<B>> EGLDisplay<B, N> {
macro_rules! attrib { macro_rules! attrib {
($display:expr, $config:expr, $attr:expr) => {{ ($display:expr, $config:expr, $attr:expr) => {{
let mut value = MaybeUninit::uninit(); let mut value = MaybeUninit::uninit();
wrap_egl_call(|| ffi::egl::GetConfigAttrib( wrap_egl_call(|| {
**$display, ffi::egl::GetConfigAttrib(
$config, **$display,
$attr as ffi::egl::types::EGLint, $config,
value.as_mut_ptr(), $attr as ffi::egl::types::EGLint,
)).map_err(Error::ConfigFailed)?; value.as_mut_ptr(),
)
})
.map_err(Error::ConfigFailed)?;
value.assume_init() value.assume_init()
}}; }};
}; };
@ -343,7 +373,11 @@ impl<B: native::Backend, N: native::NativeDisplay<B>> EGLDisplay<B, N> {
args: N::Arguments, args: N::Arguments,
) -> Result<EGLSurface<B::Surface>, SurfaceCreationError<N::Error>> { ) -> Result<EGLSurface<B::Surface>, SurfaceCreationError<N::Error>> {
trace!(self.logger, "Creating EGL window surface."); trace!(self.logger, "Creating EGL window surface.");
let surface = self.native.borrow_mut().create_surface(args).map_err(SurfaceCreationError::NativeSurfaceCreationFailed)?; let surface = self
.native
.borrow_mut()
.create_surface(args)
.map_err(SurfaceCreationError::NativeSurfaceCreationFailed)?;
EGLSurface::new( EGLSurface::new(
self.display.clone(), self.display.clone(),
@ -356,7 +390,8 @@ impl<B: native::Backend, N: native::NativeDisplay<B>> EGLDisplay<B, N> {
.map(|x| { .map(|x| {
debug!(self.logger, "EGL surface successfully created"); debug!(self.logger, "EGL surface successfully created");
x x
}).map_err(SurfaceCreationError::EGLSurfaceCreationFailed) })
.map_err(SurfaceCreationError::EGLSurfaceCreationFailed)
} }
/// Returns the runtime egl version of this display /// Returns the runtime egl version of this display
@ -407,7 +442,10 @@ impl<B: native::Backend, N: native::NativeDisplay<B>> EGLGraphicsBackend for EGL
if !self.extensions.iter().any(|s| s == "EGL_WL_bind_wayland_display") { if !self.extensions.iter().any(|s| s == "EGL_WL_bind_wayland_display") {
return Err(Error::EglExtensionNotSupported(&["EGL_WL_bind_wayland_display"])); return Err(Error::EglExtensionNotSupported(&["EGL_WL_bind_wayland_display"]));
} }
wrap_egl_call(|| unsafe { ffi::egl::BindWaylandDisplayWL(**self.display, display.c_ptr() as *mut _) }).map_err(Error::OtherEGLDisplayAlreadyBound)?; wrap_egl_call(|| unsafe {
ffi::egl::BindWaylandDisplayWL(**self.display, display.c_ptr() as *mut _)
})
.map_err(Error::OtherEGLDisplayAlreadyBound)?;
Ok(EGLBufferReader::new(self.display.clone(), display.c_ptr())) Ok(EGLBufferReader::new(self.display.clone(), display.c_ptr()))
} }
} }
@ -454,8 +492,9 @@ impl EGLBufferReader {
ffi::egl::EGL_TEXTURE_FORMAT, ffi::egl::EGL_TEXTURE_FORMAT,
&mut format, &mut format,
) )
}).map_err(|source| BufferAccessError::NotManaged(buffer.clone(), source))?; })
.map_err(|source| BufferAccessError::NotManaged(buffer.clone(), source))?;
let format = match format { let format = match format {
x if x == ffi::egl::TEXTURE_RGB as i32 => Format::RGB, x if x == ffi::egl::TEXTURE_RGB as i32 => Format::RGB,
x if x == ffi::egl::TEXTURE_RGBA as i32 => Format::RGBA, x if x == ffi::egl::TEXTURE_RGBA as i32 => Format::RGBA,
@ -474,7 +513,8 @@ impl EGLBufferReader {
ffi::egl::WIDTH as i32, ffi::egl::WIDTH as i32,
&mut width, &mut width,
) )
}).map_err(|source| BufferAccessError::NotManaged(buffer.clone(), source))?; })
.map_err(|source| BufferAccessError::NotManaged(buffer.clone(), source))?;
let mut height: i32 = 0; let mut height: i32 = 0;
wrap_egl_call(|| unsafe { wrap_egl_call(|| unsafe {
@ -484,7 +524,8 @@ impl EGLBufferReader {
ffi::egl::HEIGHT as i32, ffi::egl::HEIGHT as i32,
&mut height, &mut height,
) )
}).map_err(|source| BufferAccessError::NotManaged(buffer.clone(), source))?; })
.map_err(|source| BufferAccessError::NotManaged(buffer.clone(), source))?;
let mut inverted: i32 = 0; let mut inverted: i32 = 0;
wrap_egl_call(|| unsafe { wrap_egl_call(|| unsafe {
@ -494,7 +535,8 @@ impl EGLBufferReader {
ffi::egl::WAYLAND_Y_INVERTED_WL, ffi::egl::WAYLAND_Y_INVERTED_WL,
&mut inverted, &mut inverted,
) )
}).map_err(|source| BufferAccessError::NotManaged(buffer.clone(), source))?; })
.map_err(|source| BufferAccessError::NotManaged(buffer.clone(), source))?;
let mut images = Vec::with_capacity(format.num_planes()); let mut images = Vec::with_capacity(format.num_planes());
for i in 0..format.num_planes() { for i in 0..format.num_planes() {
@ -512,7 +554,8 @@ impl EGLBufferReader {
buffer.as_ref().c_ptr() as *mut _, buffer.as_ref().c_ptr() as *mut _,
out.as_ptr(), out.as_ptr(),
) )
}).map_err(BufferAccessError::EGLImageCreationFailed)?; })
.map_err(BufferAccessError::EGLImageCreationFailed)?;
image image
}); });
} }

View File

@ -48,7 +48,9 @@ pub enum Error {
#[derive(thiserror::Error, Debug)] #[derive(thiserror::Error, Debug)]
pub enum EGLError { pub enum EGLError {
/// EGL is not initialized, or could not be initialized, for the specified EGL display connection. /// EGL is not initialized, or could not be initialized, for the specified EGL display connection.
#[error("EGL is not initialized, or could not be initialized, for the specified EGL display connection.")] #[error(
"EGL is not initialized, or could not be initialized, for the specified EGL display connection."
)]
NotInitialized, NotInitialized,
/// EGL cannot access a requested resource (for example a context is bound in another thread). /// EGL cannot access a requested resource (for example a context is bound in another thread).
#[error("EGL cannot access a requested resource (for example a context is bound in another thread).")] #[error("EGL cannot access a requested resource (for example a context is bound in another thread).")]
@ -90,7 +92,7 @@ pub enum EGLError {
#[error("A power management event has occurred. The application must destroy all contexts and reinitialise OpenGL ES state and objects to continue rendering.")] #[error("A power management event has occurred. The application must destroy all contexts and reinitialise OpenGL ES state and objects to continue rendering.")]
ContextLost, ContextLost,
/// An unknown error /// An unknown error
#[error("An unknown error ({0:x})")] #[error("An unknown error ({0:x})")]
Unknown(u32), Unknown(u32),
} }
@ -127,4 +129,4 @@ impl EGLError {
pub(crate) fn wrap_egl_call<R, F: FnOnce() -> R>(call: F) -> Result<R, EGLError> { pub(crate) fn wrap_egl_call<R, F: FnOnce() -> R>(call: F) -> Result<R, EGLError> {
let res = call(); let res = call();
EGLError::from_last_call().map(|()| res) EGLError::from_last_call().map(|()| res)
} }

View File

@ -19,7 +19,10 @@
//! of an EGL-based [`WlBuffer`](wayland_server::protocol::wl_buffer::WlBuffer) for rendering. //! of an EGL-based [`WlBuffer`](wayland_server::protocol::wl_buffer::WlBuffer) for rendering.
#[cfg(feature = "renderer_gl")] #[cfg(feature = "renderer_gl")]
use crate::backend::graphics::{SwapBuffersError as GraphicsSwapBuffersError, gl::{ffi as gl_ffi, GLGraphicsBackend}}; use crate::backend::graphics::{
gl::{ffi as gl_ffi, GLGraphicsBackend},
SwapBuffersError as GraphicsSwapBuffersError,
};
use nix::libc::c_uint; use nix::libc::c_uint;
use std::fmt; use std::fmt;
#[cfg(feature = "wayland_frontend")] #[cfg(feature = "wayland_frontend")]
@ -116,7 +119,7 @@ pub enum SurfaceCreationError<E: std::error::Error + 'static> {
NativeSurfaceCreationFailed(#[source] E), NativeSurfaceCreationFailed(#[source] E),
/// EGL surface creation failed /// EGL surface creation failed
#[error("EGL surface creation failed. Err: {0:}")] #[error("EGL surface creation failed. Err: {0:}")]
EGLSurfaceCreationFailed(#[source] EGLError) EGLSurfaceCreationFailed(#[source] EGLError),
} }
/// Error that can happen when swapping buffers. /// Error that can happen when swapping buffers.
@ -134,14 +137,18 @@ pub enum SwapBuffersError<E: std::error::Error + 'static> {
} }
impl<E: std::error::Error> std::convert::TryFrom<SwapBuffersError<E>> for GraphicsSwapBuffersError { impl<E: std::error::Error> std::convert::TryFrom<SwapBuffersError<E>> for GraphicsSwapBuffersError {
type Error=E; type Error = E;
fn try_from(value: SwapBuffersError<E>) -> Result<Self, Self::Error> { fn try_from(value: SwapBuffersError<E>) -> Result<Self, Self::Error> {
match value { match value {
// bad surface is answered with a surface recreation in `swap_buffers` // bad surface is answered with a surface recreation in `swap_buffers`
x @ SwapBuffersError::EGLSwapBuffers(EGLError::BadSurface) => Ok(GraphicsSwapBuffersError::TemporaryFailure(Box::new(x))), x @ SwapBuffersError::EGLSwapBuffers(EGLError::BadSurface) => {
Ok(GraphicsSwapBuffersError::TemporaryFailure(Box::new(x)))
}
// the rest is either never happening or are unrecoverable // the rest is either never happening or are unrecoverable
x @ SwapBuffersError::EGLSwapBuffers(_) => Ok(GraphicsSwapBuffersError::ContextLost(Box::new(x))), x @ SwapBuffersError::EGLSwapBuffers(_) => Ok(GraphicsSwapBuffersError::ContextLost(Box::new(x))),
x @ SwapBuffersError::EGLCreateWindowSurface(_) => Ok(GraphicsSwapBuffersError::ContextLost(Box::new(x))), x @ SwapBuffersError::EGLCreateWindowSurface(_) => {
Ok(GraphicsSwapBuffersError::ContextLost(Box::new(x)))
}
SwapBuffersError::Underlying(e) => Err(e), SwapBuffersError::Underlying(e) => Err(e),
} }
} }
@ -164,16 +171,22 @@ impl From<MakeCurrentError> for GraphicsSwapBuffersError {
Except for the first case all of these recoverable. This conversation is mostly used in winit & EglSurface, where compatible context and surfaces are build. Except for the first case all of these recoverable. This conversation is mostly used in winit & EglSurface, where compatible context and surfaces are build.
*/ */
x @ MakeCurrentError(EGLError::BadAccess) => GraphicsSwapBuffersError::TemporaryFailure(Box::new(x)), x @ MakeCurrentError(EGLError::BadAccess) => {
GraphicsSwapBuffersError::TemporaryFailure(Box::new(x))
}
// BadSurface would result in a recreation in `eglSwapBuffers` -> recoverable // BadSurface would result in a recreation in `eglSwapBuffers` -> recoverable
x @ MakeCurrentError(EGLError::BadSurface) => GraphicsSwapBuffersError::TemporaryFailure(Box::new(x)), x @ MakeCurrentError(EGLError::BadSurface) => {
GraphicsSwapBuffersError::TemporaryFailure(Box::new(x))
}
/* /*
From khronos docs: From khronos docs:
If the previous context of the calling thread has unflushed commands, and the previous surface is no longer valid, an EGL_BAD_CURRENT_SURFACE error is generated. If the previous context of the calling thread has unflushed commands, and the previous surface is no longer valid, an EGL_BAD_CURRENT_SURFACE error is generated.
This does not consern this or future `makeCurrent`-calls. This does not consern this or future `makeCurrent`-calls.
*/ */
x @ MakeCurrentError(EGLError::BadCurrentSurface) => GraphicsSwapBuffersError::TemporaryFailure(Box::new(x)), x @ MakeCurrentError(EGLError::BadCurrentSurface) => {
GraphicsSwapBuffersError::TemporaryFailure(Box::new(x))
}
// the rest is either never happening or are unrecoverable // the rest is either never happening or are unrecoverable
x => GraphicsSwapBuffersError::ContextLost(Box::new(x)), x => GraphicsSwapBuffersError::ContextLost(Box::new(x)),
} }

View File

@ -1,6 +1,6 @@
//! Type safe native types for safe context/surface creation //! Type safe native types for safe context/surface creation
use super::{ffi, Error, EGLError, wrap_egl_call}; use super::{ffi, wrap_egl_call, EGLError, Error};
#[cfg(feature = "backend_winit")] #[cfg(feature = "backend_winit")]
use std::ptr; use std::ptr;
@ -47,11 +47,19 @@ impl Backend for Wayland {
{ {
if has_dp_extension("EGL_KHR_platform_wayland") && ffi::egl::GetPlatformDisplay::is_loaded() { if has_dp_extension("EGL_KHR_platform_wayland") && ffi::egl::GetPlatformDisplay::is_loaded() {
trace!(log, "EGL Display Initialization via EGL_KHR_platform_wayland"); trace!(log, "EGL Display Initialization via EGL_KHR_platform_wayland");
wrap_egl_call(|| ffi::egl::GetPlatformDisplay(ffi::egl::PLATFORM_WAYLAND_KHR, display as *mut _, ptr::null())) wrap_egl_call(|| {
ffi::egl::GetPlatformDisplay(ffi::egl::PLATFORM_WAYLAND_KHR, display as *mut _, ptr::null())
})
} else if has_dp_extension("EGL_EXT_platform_wayland") && ffi::egl::GetPlatformDisplayEXT::is_loaded() } else if has_dp_extension("EGL_EXT_platform_wayland") && ffi::egl::GetPlatformDisplayEXT::is_loaded()
{ {
trace!(log, "EGL Display Initialization via EGL_EXT_platform_wayland"); trace!(log, "EGL Display Initialization via EGL_EXT_platform_wayland");
wrap_egl_call(|| ffi::egl::GetPlatformDisplayEXT(ffi::egl::PLATFORM_WAYLAND_EXT, display as *mut _, ptr::null())) wrap_egl_call(|| {
ffi::egl::GetPlatformDisplayEXT(
ffi::egl::PLATFORM_WAYLAND_EXT,
display as *mut _,
ptr::null(),
)
})
} else { } else {
trace!(log, "Default EGL Display Initialization via GetDisplay"); trace!(log, "Default EGL Display Initialization via GetDisplay");
wrap_egl_call(|| ffi::egl::GetDisplay(display as *mut _)) wrap_egl_call(|| ffi::egl::GetDisplay(display as *mut _))
@ -79,10 +87,14 @@ impl Backend for X11 {
{ {
if has_dp_extension("EGL_KHR_platform_x11") && ffi::egl::GetPlatformDisplay::is_loaded() { if has_dp_extension("EGL_KHR_platform_x11") && ffi::egl::GetPlatformDisplay::is_loaded() {
trace!(log, "EGL Display Initialization via EGL_KHR_platform_x11"); trace!(log, "EGL Display Initialization via EGL_KHR_platform_x11");
wrap_egl_call(|| ffi::egl::GetPlatformDisplay(ffi::egl::PLATFORM_X11_KHR, display as *mut _, ptr::null())) wrap_egl_call(|| {
ffi::egl::GetPlatformDisplay(ffi::egl::PLATFORM_X11_KHR, display as *mut _, ptr::null())
})
} else if has_dp_extension("EGL_EXT_platform_x11") && ffi::egl::GetPlatformDisplayEXT::is_loaded() { } else if has_dp_extension("EGL_EXT_platform_x11") && ffi::egl::GetPlatformDisplayEXT::is_loaded() {
trace!(log, "EGL Display Initialization via EGL_EXT_platform_x11"); trace!(log, "EGL Display Initialization via EGL_EXT_platform_x11");
wrap_egl_call(|| ffi::egl::GetPlatformDisplayEXT(ffi::egl::PLATFORM_X11_EXT, display as *mut _, ptr::null())) wrap_egl_call(|| {
ffi::egl::GetPlatformDisplayEXT(ffi::egl::PLATFORM_X11_EXT, display as *mut _, ptr::null())
})
} else { } else {
trace!(log, "Default EGL Display Initialization via GetDisplay"); trace!(log, "Default EGL Display Initialization via GetDisplay");
wrap_egl_call(|| ffi::egl::GetDisplay(display as *mut _)) wrap_egl_call(|| ffi::egl::GetDisplay(display as *mut _))
@ -203,7 +215,9 @@ pub unsafe trait NativeSurface {
#[derive(Debug)] #[derive(Debug)]
pub enum Never {} pub enum Never {}
impl std::fmt::Display for Never { impl std::fmt::Display for Never {
fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { unreachable!() } fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
unreachable!()
}
} }
impl std::error::Error for Never {} impl std::error::Error for Never {}
@ -222,8 +236,8 @@ unsafe impl NativeSurface for XlibWindow {
unsafe impl NativeSurface for wegl::WlEglSurface { unsafe impl NativeSurface for wegl::WlEglSurface {
// type Error = !; // type Error = !;
type Error = Never; type Error = Never;
fn ptr(&self) -> ffi::NativeWindowType { fn ptr(&self) -> ffi::NativeWindowType {
self.ptr() as *const _ self.ptr() as *const _
} }
} }

View File

@ -1,6 +1,6 @@
//! EGL surface related structs //! EGL surface related structs
use super::{ffi, native, EGLError, SwapBuffersError, wrap_egl_call}; use super::{ffi, native, wrap_egl_call, EGLError, SwapBuffersError};
use crate::backend::egl::display::EGLDisplayHandle; use crate::backend::egl::display::EGLDisplayHandle;
use crate::backend::graphics::PixelFormat; use crate::backend::graphics::PixelFormat;
use nix::libc::c_int; use nix::libc::c_int;
@ -90,23 +90,32 @@ impl<N: native::NativeSurface> EGLSurface<N> {
wrap_egl_call(|| unsafe { ffi::egl::SwapBuffers(**self.display, surface as *const _) }) wrap_egl_call(|| unsafe { ffi::egl::SwapBuffers(**self.display, surface as *const _) })
.map_err(SwapBuffersError::EGLSwapBuffers) .map_err(SwapBuffersError::EGLSwapBuffers)
.and_then(|_| self.native.swap_buffers().map_err(SwapBuffersError::Underlying)) .and_then(|_| self.native.swap_buffers().map_err(SwapBuffersError::Underlying))
} else { Ok(()) }; } else {
Ok(())
};
// workaround for missing `PartialEq` impl // workaround for missing `PartialEq` impl
let is_bad_surface = if let Err(SwapBuffersError::EGLSwapBuffers(EGLError::BadSurface)) = result { true } else { false }; let is_bad_surface = if let Err(SwapBuffersError::EGLSwapBuffers(EGLError::BadSurface)) = result {
true
} else {
false
};
if self.native.needs_recreation() || surface.is_null() || is_bad_surface { if self.native.needs_recreation() || surface.is_null() || is_bad_surface {
self.native.recreate().map_err(SwapBuffersError::Underlying)?; self.native.recreate().map_err(SwapBuffersError::Underlying)?;
if !surface.is_null() { if !surface.is_null() {
let _ = unsafe { ffi::egl::DestroySurface(**self.display, surface as *const _) }; let _ = unsafe { ffi::egl::DestroySurface(**self.display, surface as *const _) };
} }
self.surface.set(unsafe { self.surface.set(unsafe {
wrap_egl_call(|| ffi::egl::CreateWindowSurface( wrap_egl_call(|| {
**self.display, ffi::egl::CreateWindowSurface(
self.config_id, **self.display,
self.native.ptr(), self.config_id,
self.surface_attributes.as_ptr(), self.native.ptr(),
)).map_err(SwapBuffersError::EGLCreateWindowSurface)? self.surface_attributes.as_ptr(),
)
})
.map_err(SwapBuffersError::EGLCreateWindowSurface)?
}); });
} }

View File

@ -47,7 +47,10 @@ impl<T: GLGraphicsBackend + 'static> GliumGraphicsBackend<T> {
/// Note that destroying a [`Frame`] is immediate, even if vsync is enabled. /// Note that destroying a [`Frame`] is immediate, even if vsync is enabled.
#[inline] #[inline]
pub fn draw(&self) -> Frame { pub fn draw(&self) -> Frame {
Frame(glium::Frame::new(self.context.clone(), self.backend.get_framebuffer_dimensions()), self.error_channel.clone()) Frame(
glium::Frame::new(self.context.clone(), self.backend.get_framebuffer_dimensions()),
self.error_channel.clone(),
)
} }
/// Borrow the underlying backend. /// Borrow the underlying backend.
@ -89,7 +92,7 @@ unsafe impl<T: GLGraphicsBackend> Backend for InternalBackend<T> {
SwapBuffersError::ContextLost(err) => { SwapBuffersError::ContextLost(err) => {
self.1.set(Some(err)); self.1.set(Some(err));
GliumSwapBuffersError::ContextLost GliumSwapBuffersError::ContextLost
}, }
SwapBuffersError::TemporaryFailure(err) => { SwapBuffersError::TemporaryFailure(err) => {
self.1.set(Some(err)); self.1.set(Some(err));
GliumSwapBuffersError::AlreadySwapped GliumSwapBuffersError::AlreadySwapped
@ -97,7 +100,9 @@ unsafe impl<T: GLGraphicsBackend> Backend for InternalBackend<T> {
// I do not think, this may happen, but why not // I do not think, this may happen, but why not
SwapBuffersError::AlreadySwapped => GliumSwapBuffersError::AlreadySwapped, SwapBuffersError::AlreadySwapped => GliumSwapBuffersError::AlreadySwapped,
}) })
} else { Ok(()) } } else {
Ok(())
}
} }
unsafe fn get_proc_address(&self, symbol: &str) -> *const c_void { unsafe fn get_proc_address(&self, symbol: &str) -> *const c_void {
@ -121,15 +126,15 @@ unsafe impl<T: GLGraphicsBackend> Backend for InternalBackend<T> {
} }
/// Omplementation of `glium::Surface`, targeting the default framebuffer. /// Omplementation of `glium::Surface`, targeting the default framebuffer.
/// ///
/// The back- and front-buffers are swapped when you call `finish`. /// The back- and front-buffers are swapped when you call `finish`.
/// ///
/// You **must** call either `finish` or `set_finish` or else the destructor will panic. /// You **must** call either `finish` or `set_finish` or else the destructor will panic.
pub struct Frame(glium::Frame, Rc<Cell<Option<Box<dyn std::error::Error>>>>); pub struct Frame(glium::Frame, Rc<Cell<Option<Box<dyn std::error::Error>>>>);
impl Frame { impl Frame {
/// Stop drawing, swap the buffers, and consume the Frame. /// Stop drawing, swap the buffers, and consume the Frame.
/// ///
/// See the documentation of [`SwapBuffersError`] about what is being returned. /// See the documentation of [`SwapBuffersError`] about what is being returned.
pub fn finish(mut self) -> Result<(), SwapBuffersError> { pub fn finish(mut self) -> Result<(), SwapBuffersError> {
self.set_finish() self.set_finish()
@ -143,21 +148,28 @@ impl Frame {
let err = self.1.take(); let err = self.1.take();
match (res, err) { match (res, err) {
(Ok(()), _) => Ok(()), (Ok(()), _) => Ok(()),
(Err(GliumSwapBuffersError::AlreadySwapped), Some(err)) => Err(SwapBuffersError::TemporaryFailure(err)), (Err(GliumSwapBuffersError::AlreadySwapped), Some(err)) => {
Err(SwapBuffersError::TemporaryFailure(err))
}
(Err(GliumSwapBuffersError::AlreadySwapped), None) => Err(SwapBuffersError::AlreadySwapped), (Err(GliumSwapBuffersError::AlreadySwapped), None) => Err(SwapBuffersError::AlreadySwapped),
(Err(GliumSwapBuffersError::ContextLost), Some(err)) => Err(SwapBuffersError::ContextLost(err)), (Err(GliumSwapBuffersError::ContextLost), Some(err)) => Err(SwapBuffersError::ContextLost(err)),
_ => unreachable!(), _ => unreachable!(),
} }
} }
} }
impl glium::Surface for Frame { impl glium::Surface for Frame {
fn clear(&mut self, rect: Option<&glium::Rect>, color: Option<(f32, f32, f32, f32)>, color_srgb: bool, fn clear(
depth: Option<f32>, stencil: Option<i32>) &mut self,
{ rect: Option<&glium::Rect>,
color: Option<(f32, f32, f32, f32)>,
color_srgb: bool,
depth: Option<f32>,
stencil: Option<i32>,
) {
self.0.clear(rect, color, color_srgb, depth, stencil) self.0.clear(rect, color, color_srgb, depth, stencil)
} }
fn get_dimensions(&self) -> (u32, u32) { fn get_dimensions(&self) -> (u32, u32) {
self.0.get_dimensions() self.0.get_dimensions()
} }
@ -170,37 +182,62 @@ impl glium::Surface for Frame {
self.0.get_stencil_buffer_bits() self.0.get_stencil_buffer_bits()
} }
fn draw<'a, 'b, V, I, U>(&mut self, v: V, i: I, program: &glium::Program, uniforms: &U, fn draw<'a, 'b, V, I, U>(
draw_parameters: &glium::draw_parameters::DrawParameters<'_>) -> Result<(), glium::DrawError> where &mut self,
V: glium::vertex::MultiVerticesSource<'b>, I: Into<glium::index::IndicesSource<'a>>, v: V,
U: glium::uniforms::Uniforms i: I,
program: &glium::Program,
uniforms: &U,
draw_parameters: &glium::draw_parameters::DrawParameters<'_>,
) -> Result<(), glium::DrawError>
where
V: glium::vertex::MultiVerticesSource<'b>,
I: Into<glium::index::IndicesSource<'a>>,
U: glium::uniforms::Uniforms,
{ {
self.0.draw(v, i, program, uniforms, draw_parameters) self.0.draw(v, i, program, uniforms, draw_parameters)
} }
fn blit_from_frame(&self, source_rect: &glium::Rect, target_rect: &glium::BlitTarget, fn blit_from_frame(
filter: glium::uniforms::MagnifySamplerFilter) &self,
{ source_rect: &glium::Rect,
target_rect: &glium::BlitTarget,
filter: glium::uniforms::MagnifySamplerFilter,
) {
self.0.blit_from_frame(source_rect, target_rect, filter); self.0.blit_from_frame(source_rect, target_rect, filter);
} }
fn blit_from_simple_framebuffer(&self, source: &glium::framebuffer::SimpleFrameBuffer<'_>, fn blit_from_simple_framebuffer(
source_rect: &glium::Rect, target_rect: &glium::BlitTarget, &self,
filter: glium::uniforms::MagnifySamplerFilter) source: &glium::framebuffer::SimpleFrameBuffer<'_>,
{ source_rect: &glium::Rect,
self.0.blit_from_simple_framebuffer(source, source_rect, target_rect, filter) target_rect: &glium::BlitTarget,
filter: glium::uniforms::MagnifySamplerFilter,
) {
self.0
.blit_from_simple_framebuffer(source, source_rect, target_rect, filter)
} }
fn blit_from_multioutput_framebuffer(&self, source: &glium::framebuffer::MultiOutputFrameBuffer<'_>, fn blit_from_multioutput_framebuffer(
source_rect: &glium::Rect, target_rect: &glium::BlitTarget, &self,
filter: glium::uniforms::MagnifySamplerFilter) source: &glium::framebuffer::MultiOutputFrameBuffer<'_>,
{ source_rect: &glium::Rect,
self.0.blit_from_multioutput_framebuffer(source, source_rect, target_rect, filter) target_rect: &glium::BlitTarget,
filter: glium::uniforms::MagnifySamplerFilter,
) {
self.0
.blit_from_multioutput_framebuffer(source, source_rect, target_rect, filter)
} }
fn blit_color<S>(&self, source_rect: &glium::Rect, target: &S, target_rect: &glium::BlitTarget, fn blit_color<S>(
filter: glium::uniforms::MagnifySamplerFilter) where S: glium::Surface &self,
source_rect: &glium::Rect,
target: &S,
target_rect: &glium::BlitTarget,
filter: glium::uniforms::MagnifySamplerFilter,
) where
S: glium::Surface,
{ {
self.0.blit_color(source_rect, target, target_rect, filter) self.0.blit_color(source_rect, target, target_rect, filter)
} }
} }

View File

@ -50,7 +50,7 @@ pub enum Error {
EGL(#[from] EGLError), EGL(#[from] EGLError),
/// Surface Creation failed /// Surface Creation failed
#[error("Surface creation failed: {0}")] #[error("Surface creation failed: {0}")]
SurfaceCreationError(#[from] SurfaceCreationError<EGLError>) SurfaceCreationError(#[from] SurfaceCreationError<EGLError>),
} }
enum Window { enum Window {
@ -281,7 +281,9 @@ impl GLGraphicsBackend for WinitGraphicsBackend {
fn swap_buffers(&self) -> ::std::result::Result<(), SwapBuffersError> { fn swap_buffers(&self) -> ::std::result::Result<(), SwapBuffersError> {
trace!(self.logger, "Swapping buffers"); trace!(self.logger, "Swapping buffers");
match *self.window { match *self.window {
Window::Wayland { ref surface, .. } => surface.swap_buffers().map_err(|err| err.try_into().unwrap()), Window::Wayland { ref surface, .. } => {
surface.swap_buffers().map_err(|err| err.try_into().unwrap())
}
Window::X11 { ref surface, .. } => surface.swap_buffers().map_err(|err| err.try_into().unwrap()), Window::X11 { ref surface, .. } => surface.swap_buffers().map_err(|err| err.try_into().unwrap()),
} }
} }