Store DrmBackend in EventLoop state
This commit is contained in:
parent
0758ec98ba
commit
518f7dbdfc
|
@ -40,7 +40,4 @@ backend_libinput = ["input"]
|
||||||
renderer_glium = ["glium"]
|
renderer_glium = ["glium"]
|
||||||
|
|
||||||
[replace]
|
[replace]
|
||||||
"wayland-server:0.9.9" = { git = "https://github.com/Drakulix/wayland-rs", branch = "raw_handler_access"}
|
|
||||||
"wayland-protocols:0.9.9" = { git = "https://github.com/Drakulix/wayland-rs", branch = "raw_handler_access"}
|
|
||||||
"wayland-client:0.9.9" = { git = "https://github.com/Drakulix/wayland-rs", branch = "raw_handler_access"}
|
|
||||||
"drm:0.2.1" = { git = "https://github.com/Drakulix/drm-rs", branch = "future" }
|
"drm:0.2.1" = { git = "https://github.com/Drakulix/drm-rs", branch = "future" }
|
||||||
|
|
|
@ -19,9 +19,8 @@ use drm::control::encoder::Info as EncoderInfo;
|
||||||
use glium::Surface;
|
use glium::Surface;
|
||||||
use helpers::{shell_implementation, surface_implementation, GliumDrawer, Roles, SurfaceData};
|
use helpers::{shell_implementation, surface_implementation, GliumDrawer, Roles, SurfaceData};
|
||||||
use slog::{Drain, Logger};
|
use slog::{Drain, Logger};
|
||||||
use smithay::backend::drm::{drm_device_bind, DrmBackend, DrmDevice, DrmHandler, Id};
|
use smithay::backend::drm::{drm_device_bind, DrmBackend, DrmDevice, DrmHandler};
|
||||||
use smithay::backend::graphics::egl::EGLGraphicsBackend;
|
use smithay::backend::graphics::egl::EGLGraphicsBackend;
|
||||||
use smithay::backend::graphics::glium::{GliumGraphicsBackend, IntoGlium};
|
|
||||||
use smithay::compositor::{compositor_init, CompositorToken, SubsurfaceRole, TraversalAction};
|
use smithay::compositor::{compositor_init, CompositorToken, SubsurfaceRole, TraversalAction};
|
||||||
use smithay::compositor::roles::Role;
|
use smithay::compositor::roles::Role;
|
||||||
use smithay::shell::{shell_init, ShellState};
|
use smithay::shell::{shell_init, ShellState};
|
||||||
|
@ -48,7 +47,7 @@ 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 =
|
let mut device: DrmDevice<GliumDrawer<DrmBackend>> =
|
||||||
DrmDevice::new_from_file(options.clone().open("/dev/dri/card0").unwrap(), log.clone()).unwrap();
|
DrmDevice::new_from_file(options.clone().open("/dev/dri/card0").unwrap(), log.clone()).unwrap();
|
||||||
|
|
||||||
// Get a set of all modesetting resource handles (excluding planes):
|
// Get a set of all modesetting resource handles (excluding planes):
|
||||||
|
@ -80,8 +79,8 @@ fn main() {
|
||||||
let mode = connector_info.modes()[0]; // Use first mode (usually highest resoltion, but in reality you should filter and sort and check and match with other connectors, if you use more then one.)
|
let mode = connector_info.modes()[0]; // Use first mode (usually highest resoltion, but in reality you should filter and sort and check and match with other connectors, if you use more then one.)
|
||||||
|
|
||||||
// Initialize the hardware backend
|
// Initialize the hardware backend
|
||||||
let renderer = device
|
let renderer_token = device
|
||||||
.create_backend(crtc, mode, vec![connector_info.handle()])
|
.create_backend(&mut event_loop, crtc, mode, vec![connector_info.handle()])
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -104,10 +103,12 @@ fn main() {
|
||||||
/*
|
/*
|
||||||
* Initialize glium
|
* Initialize glium
|
||||||
*/
|
*/
|
||||||
let drawer = GliumDrawer::new(renderer.into_glium());
|
{
|
||||||
|
let drawer = event_loop.state().get(&renderer_token);
|
||||||
let mut frame = drawer.draw();
|
let mut frame = drawer.draw();
|
||||||
frame.clear_color(0.8, 0.8, 0.9, 1.0);
|
frame.clear_color(0.8, 0.8, 0.9, 1.0);
|
||||||
frame.finish().unwrap();
|
frame.finish().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Add a listening socket:
|
* Add a listening socket:
|
||||||
|
@ -122,7 +123,6 @@ fn main() {
|
||||||
&mut event_loop,
|
&mut event_loop,
|
||||||
device,
|
device,
|
||||||
DrmHandlerImpl {
|
DrmHandlerImpl {
|
||||||
drawer,
|
|
||||||
shell_state_token,
|
shell_state_token,
|
||||||
compositor_token,
|
compositor_token,
|
||||||
logger: log,
|
logger: log,
|
||||||
|
@ -133,20 +133,21 @@ fn main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct DrmHandlerImpl {
|
pub struct DrmHandlerImpl {
|
||||||
drawer: GliumDrawer<GliumGraphicsBackend<DrmBackend>>,
|
|
||||||
shell_state_token: StateToken<ShellState<SurfaceData, Roles, (), ()>>,
|
shell_state_token: StateToken<ShellState<SurfaceData, Roles, (), ()>>,
|
||||||
compositor_token: CompositorToken<SurfaceData, Roles, ()>,
|
compositor_token: CompositorToken<SurfaceData, Roles, ()>,
|
||||||
logger: ::slog::Logger,
|
logger: ::slog::Logger,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DrmHandler for DrmHandlerImpl {
|
impl DrmHandler<GliumDrawer<DrmBackend>> for DrmHandlerImpl {
|
||||||
fn ready(&mut self, evlh: &mut EventLoopHandle, _id: Id, _frame: u32, _duration: Duration) {
|
fn ready(&mut self, evlh: &mut EventLoopHandle, _device: &mut DrmDevice<GliumDrawer<DrmBackend>>,
|
||||||
let mut frame = self.drawer.draw();
|
backend: &StateToken<GliumDrawer<DrmBackend>>, _frame: u32, _duration: Duration) {
|
||||||
|
let state = evlh.state();
|
||||||
|
let drawer = state.get(backend);
|
||||||
|
let mut frame = drawer.draw();
|
||||||
frame.clear_color(0.8, 0.8, 0.9, 1.0);
|
frame.clear_color(0.8, 0.8, 0.9, 1.0);
|
||||||
// redraw the frame, in a simple but inneficient way
|
// redraw the frame, in a simple but inneficient way
|
||||||
{
|
{
|
||||||
let screen_dimensions = self.drawer.get_framebuffer_dimensions();
|
let screen_dimensions = drawer.get_framebuffer_dimensions();
|
||||||
let state = evlh.state();
|
|
||||||
for toplevel_surface in state.get(&self.shell_state_token).toplevel_surfaces() {
|
for toplevel_surface in state.get(&self.shell_state_token).toplevel_surfaces() {
|
||||||
if let Some(wl_surface) = toplevel_surface.get_surface() {
|
if let Some(wl_surface) = toplevel_surface.get_surface() {
|
||||||
// this surface is a root of a subsurface tree that needs to be drawn
|
// this surface is a root of a subsurface tree that needs to be drawn
|
||||||
|
@ -163,13 +164,7 @@ impl DrmHandler for DrmHandlerImpl {
|
||||||
x += subdata.x;
|
x += subdata.x;
|
||||||
y += subdata.y;
|
y += subdata.y;
|
||||||
}
|
}
|
||||||
self.drawer.render(
|
drawer.render(&mut frame, contents, (w, h), (x, y), screen_dimensions);
|
||||||
&mut frame,
|
|
||||||
contents,
|
|
||||||
(w, h),
|
|
||||||
(x, y),
|
|
||||||
screen_dimensions,
|
|
||||||
);
|
|
||||||
TraversalAction::DoChildren((x, y))
|
TraversalAction::DoChildren((x, y))
|
||||||
} else {
|
} else {
|
||||||
// we are not display, so our children are neither
|
// we are not display, so our children are neither
|
||||||
|
@ -184,7 +179,8 @@ impl DrmHandler for DrmHandlerImpl {
|
||||||
frame.finish().unwrap();
|
frame.finish().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn error(&mut self, _evlh: &mut EventLoopHandle, error: IoError) {
|
fn error(&mut self, _evlh: &mut EventLoopHandle, _device: &mut DrmDevice<GliumDrawer<DrmBackend>>,
|
||||||
|
error: IoError) {
|
||||||
panic!("{:?}", error);
|
panic!("{:?}", error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
use glium;
|
use glium;
|
||||||
use glium::Surface;
|
use glium::{Frame, Surface};
|
||||||
use glium::index::PrimitiveType;
|
use glium::index::PrimitiveType;
|
||||||
|
use smithay::backend::graphics::egl::EGLGraphicsBackend;
|
||||||
|
use smithay::backend::graphics::glium::GliumGraphicsBackend;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
|
@ -12,23 +13,25 @@ struct Vertex {
|
||||||
|
|
||||||
implement_vertex!(Vertex, position, tex_coords);
|
implement_vertex!(Vertex, position, tex_coords);
|
||||||
|
|
||||||
pub struct GliumDrawer<F> {
|
pub struct GliumDrawer<F: EGLGraphicsBackend + 'static> {
|
||||||
display: F,
|
display: GliumGraphicsBackend<F>,
|
||||||
vertex_buffer: glium::VertexBuffer<Vertex>,
|
vertex_buffer: glium::VertexBuffer<Vertex>,
|
||||||
index_buffer: glium::IndexBuffer<u16>,
|
index_buffer: glium::IndexBuffer<u16>,
|
||||||
program: glium::Program,
|
program: glium::Program,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F> Deref for GliumDrawer<F> {
|
impl<F: EGLGraphicsBackend + 'static> Deref for GliumDrawer<F> {
|
||||||
type Target = F;
|
type Target = F;
|
||||||
|
|
||||||
fn deref(&self) -> &F {
|
fn deref(&self) -> &F {
|
||||||
&self.display
|
&*self.display
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F: glium::backend::Facade> GliumDrawer<F> {
|
impl<T: Into<GliumGraphicsBackend<T>> + EGLGraphicsBackend + 'static> From<T> for GliumDrawer<T> {
|
||||||
pub fn new(display: F) -> GliumDrawer<F> {
|
fn from(backend: T) -> GliumDrawer<T> {
|
||||||
|
let display = backend.into();
|
||||||
|
|
||||||
// building the vertex buffer, which contains all the vertices that we will draw
|
// building the vertex buffer, which contains all the vertices that we will draw
|
||||||
let vertex_buffer = glium::VertexBuffer::new(
|
let vertex_buffer = glium::VertexBuffer::new(
|
||||||
&display,
|
&display,
|
||||||
|
@ -93,7 +96,9 @@ impl<F: glium::backend::Facade> GliumDrawer<F> {
|
||||||
program,
|
program,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<F: EGLGraphicsBackend + 'static> GliumDrawer<F> {
|
||||||
pub fn render(&self, target: &mut glium::Frame, contents: &[u8], surface_dimensions: (u32, u32),
|
pub fn render(&self, target: &mut glium::Frame, contents: &[u8], surface_dimensions: (u32, u32),
|
||||||
surface_location: (i32, i32), screen_size: (u32, u32)) {
|
surface_location: (i32, i32), screen_size: (u32, u32)) {
|
||||||
let image = glium::texture::RawImage2d {
|
let image = glium::texture::RawImage2d {
|
||||||
|
@ -130,4 +135,9 @@ impl<F: glium::backend::Facade> GliumDrawer<F> {
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn draw(&self) -> Frame {
|
||||||
|
self.display.draw()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,6 @@ extern crate slog_async;
|
||||||
extern crate slog_term;
|
extern crate slog_term;
|
||||||
#[macro_use(define_roles)]
|
#[macro_use(define_roles)]
|
||||||
extern crate smithay;
|
extern crate smithay;
|
||||||
extern crate wayland_protocols;
|
|
||||||
extern crate wayland_server;
|
extern crate wayland_server;
|
||||||
|
|
||||||
mod helpers;
|
mod helpers;
|
||||||
|
@ -16,8 +15,6 @@ use glium::Surface;
|
||||||
use helpers::{shell_implementation, surface_implementation, GliumDrawer};
|
use helpers::{shell_implementation, surface_implementation, GliumDrawer};
|
||||||
use slog::{Drain, Logger};
|
use slog::{Drain, Logger};
|
||||||
use smithay::backend::graphics::egl::EGLGraphicsBackend;
|
use smithay::backend::graphics::egl::EGLGraphicsBackend;
|
||||||
|
|
||||||
use smithay::backend::graphics::glium::IntoGlium;
|
|
||||||
use smithay::backend::input::InputBackend;
|
use smithay::backend::input::InputBackend;
|
||||||
use smithay::backend::winit;
|
use smithay::backend::winit;
|
||||||
use smithay::compositor::{compositor_init, SubsurfaceRole, TraversalAction};
|
use smithay::compositor::{compositor_init, SubsurfaceRole, TraversalAction};
|
||||||
|
@ -57,7 +54,7 @@ fn main() {
|
||||||
/*
|
/*
|
||||||
* Initialize glium
|
* Initialize glium
|
||||||
*/
|
*/
|
||||||
let drawer = GliumDrawer::new(renderer.into_glium());
|
let drawer = GliumDrawer::from(renderer);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Add a listening socket:
|
* Add a listening socket:
|
||||||
|
|
|
@ -8,18 +8,9 @@ use drm::control::ResourceInfo;
|
||||||
use gbm::{BufferObject, BufferObjectFlags, Format as GbmFormat, Surface as GbmSurface, SurfaceBufferHandle};
|
use gbm::{BufferObject, BufferObjectFlags, Format as GbmFormat, Surface as GbmSurface, SurfaceBufferHandle};
|
||||||
use image::{ImageBuffer, Rgba};
|
use image::{ImageBuffer, Rgba};
|
||||||
use nix::c_void;
|
use nix::c_void;
|
||||||
use std::cell::{Cell, RefCell};
|
use std::cell::Cell;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
/// Backend based on a `DrmDevice` and a given crtc
|
|
||||||
pub struct DrmBackend(Rc<RefCell<DrmBackendInternal>>);
|
|
||||||
|
|
||||||
impl DrmBackend {
|
|
||||||
pub(crate) fn new(drm: Rc<RefCell<DrmBackendInternal>>) -> DrmBackend {
|
|
||||||
DrmBackend(drm)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Dependency graph
|
Dependency graph
|
||||||
- drm
|
- drm
|
||||||
|
@ -32,7 +23,7 @@ impl DrmBackend {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pub(crate) struct GbmTypes<'dev, 'context> {
|
pub(crate) struct GbmTypes<'dev, 'context> {
|
||||||
cursor: BufferObject<'dev, ()>,
|
cursor: Cell<BufferObject<'dev, ()>>,
|
||||||
surface: Surface<'context>,
|
surface: Surface<'context>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,60 +61,32 @@ rental! {
|
||||||
}
|
}
|
||||||
use self::graphics::{Graphics, Surface};
|
use self::graphics::{Graphics, Surface};
|
||||||
|
|
||||||
/// Id of a `DrmBackend` related to its `DrmDevice`.
|
|
||||||
///
|
|
||||||
/// Used to track which `DrmBackend` finished page-flipping
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
||||||
pub struct Id(usize);
|
|
||||||
|
|
||||||
impl Id {
|
/// Backend based on a `DrmDevice` and a given crtc
|
||||||
pub(crate) fn raw(&self) -> usize {
|
pub struct DrmBackend {
|
||||||
self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) struct DrmBackendInternal {
|
|
||||||
graphics: Graphics,
|
graphics: Graphics,
|
||||||
crtc: crtc::Handle,
|
crtc: crtc::Handle,
|
||||||
mode: Mode,
|
mode: Mode,
|
||||||
connectors: Vec<connector::Handle>,
|
connectors: Vec<connector::Handle>,
|
||||||
own_id: Id,
|
|
||||||
logger: ::slog::Logger,
|
logger: ::slog::Logger,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DrmBackendInternal {
|
impl DrmBackend {
|
||||||
pub(crate) fn new<I, L>(context: Rc<devices::Context>, crtc: crtc::Handle, mode: Mode, connectors: I,
|
pub(crate) fn new(context: Rc<devices::Context>, crtc: crtc::Handle, mode: Mode,
|
||||||
own_id: usize, logger: L)
|
connectors: Vec<connector::Handle>, logger: ::slog::Logger)
|
||||||
-> Result<DrmBackendInternal>
|
-> Result<DrmBackend> {
|
||||||
where
|
|
||||||
I: Into<Vec<connector::Handle>>,
|
|
||||||
L: Into<Option<::slog::Logger>>,
|
|
||||||
{
|
|
||||||
// logger already initialized by the DrmDevice
|
// logger already initialized by the DrmDevice
|
||||||
let log = ::slog_or_stdlog(logger);
|
let log = ::slog_or_stdlog(logger);
|
||||||
info!(log, "Initializing DrmBackend");
|
info!(log, "Initializing DrmBackend");
|
||||||
|
|
||||||
let connectors = connectors.into();
|
|
||||||
|
|
||||||
// check the connectors, if they suite the mode
|
|
||||||
for connector in connectors.iter() {
|
|
||||||
if !connector::Info::load_from_device(context.head().head(), *connector)
|
|
||||||
.chain_err(|| ErrorKind::DrmDev(format!("{:?}", context.head().head())))?
|
|
||||||
.modes()
|
|
||||||
.contains(&mode)
|
|
||||||
{
|
|
||||||
bail!(ErrorKind::ModeNotSuitable(mode))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let (w, h) = mode.size();
|
let (w, h) = mode.size();
|
||||||
|
|
||||||
Ok(DrmBackendInternal {
|
Ok(DrmBackend {
|
||||||
graphics: Graphics::try_new(context, |context| {
|
graphics: Graphics::try_new(context, |context| {
|
||||||
Ok(GbmTypes {
|
Ok(GbmTypes {
|
||||||
cursor: {
|
cursor: {
|
||||||
// Create an unused cursor buffer (we don't want an Option here)
|
// Create an unused cursor buffer (we don't want an Option here)
|
||||||
context
|
Cell::new(context
|
||||||
.devices
|
.devices
|
||||||
.gbm
|
.gbm
|
||||||
.create_buffer_object(
|
.create_buffer_object(
|
||||||
|
@ -132,7 +95,7 @@ impl DrmBackendInternal {
|
||||||
GbmFormat::ARGB8888,
|
GbmFormat::ARGB8888,
|
||||||
&[BufferObjectFlags::Cursor, BufferObjectFlags::Write],
|
&[BufferObjectFlags::Cursor, BufferObjectFlags::Write],
|
||||||
)
|
)
|
||||||
.chain_err(|| ErrorKind::GbmInitFailed)?
|
.chain_err(|| ErrorKind::GbmInitFailed)?)
|
||||||
},
|
},
|
||||||
surface: Surface::try_new(
|
surface: Surface::try_new(
|
||||||
{
|
{
|
||||||
|
@ -202,7 +165,6 @@ impl DrmBackendInternal {
|
||||||
crtc,
|
crtc,
|
||||||
mode,
|
mode,
|
||||||
connectors,
|
connectors,
|
||||||
own_id: Id(own_id),
|
|
||||||
logger: log.clone(),
|
logger: log.clone(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -225,85 +187,67 @@ impl DrmBackendInternal {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn is_crtc(&self, crtc: crtc::Handle) -> bool {
|
|
||||||
crtc == self.crtc
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DrmBackend {
|
|
||||||
/// Add a connector to backend
|
/// Add a connector to backend
|
||||||
///
|
///
|
||||||
/// # Errors
|
/// # Errors
|
||||||
///
|
///
|
||||||
/// Errors if the new connector does not support the currently set `Mode`
|
/// Errors if the new connector does not support the currently set `Mode`
|
||||||
pub fn add_connector(&mut self, connector: connector::Handle) -> Result<()> {
|
pub fn add_connector(&mut self, connector: connector::Handle) -> Result<()> {
|
||||||
let info =
|
let info = connector::Info::load_from_device(self.graphics.head().head().head(), connector)
|
||||||
connector::Info::load_from_device(self.0.borrow().graphics.head().head().head(), connector)
|
|
||||||
.chain_err(|| {
|
.chain_err(|| {
|
||||||
ErrorKind::DrmDev(format!(
|
ErrorKind::DrmDev(format!("{:?}", self.graphics.head().head().head()))
|
||||||
"{:?}",
|
|
||||||
self.0.borrow().graphics.head().head().head()
|
|
||||||
))
|
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
// check if the connector can handle the current mode
|
// check if the connector can handle the current mode
|
||||||
let mut internal = self.0.borrow_mut();
|
if info.modes().contains(&self.mode) {
|
||||||
if info.modes().contains(&internal.mode) {
|
|
||||||
// check if there is a valid encoder
|
// check if there is a valid encoder
|
||||||
let encoders = info.encoders()
|
let encoders = info.encoders()
|
||||||
.iter()
|
.iter()
|
||||||
.map(|encoder| {
|
.map(|encoder| {
|
||||||
encoder::Info::load_from_device(self.0.borrow().graphics.head().head().head(), *encoder)
|
encoder::Info::load_from_device(self.graphics.head().head().head(), *encoder).chain_err(
|
||||||
.chain_err(|| {
|
|| ErrorKind::DrmDev(format!("{:?}", self.graphics.head().head().head())),
|
||||||
ErrorKind::DrmDev(format!(
|
)
|
||||||
"{:?}",
|
|
||||||
self.0.borrow().graphics.head().head().head()
|
|
||||||
))
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
.collect::<Result<Vec<encoder::Info>>>()?;
|
.collect::<Result<Vec<encoder::Info>>>()?;
|
||||||
|
|
||||||
// and if any encoder supports the selected crtc
|
// and if any encoder supports the selected crtc
|
||||||
if !encoders
|
if !encoders
|
||||||
.iter()
|
.iter()
|
||||||
.any(|encoder| encoder.supports_crtc(self.0.borrow().crtc))
|
.any(|encoder| encoder.supports_crtc(self.crtc))
|
||||||
{
|
{
|
||||||
bail!(ErrorKind::NoSuitableEncoder(info, self.0.borrow().crtc));
|
bail!(ErrorKind::NoSuitableEncoder(info, self.crtc));
|
||||||
}
|
}
|
||||||
|
|
||||||
info!(
|
info!(
|
||||||
self.0.borrow().logger,
|
self.logger,
|
||||||
"Adding new connector: {:?}",
|
"Adding new connector: {:?}",
|
||||||
info.connector_type()
|
info.connector_type()
|
||||||
);
|
);
|
||||||
internal.connectors.push(connector);
|
self.connectors.push(connector);
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
bail!(ErrorKind::ModeNotSuitable(self.0.borrow().mode))
|
bail!(ErrorKind::ModeNotSuitable(self.mode))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a copy of the currently set connectors
|
/// Returns the currently set connectors
|
||||||
pub fn used_connectors(&self) -> Vec<connector::Handle> {
|
pub fn used_connectors(&self) -> &[connector::Handle] {
|
||||||
// thanks to the RefCell we can sadly not return a `&[connector::Handle]`
|
&*self.connectors
|
||||||
self.0.borrow().connectors.clone()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Removes a currently set connector
|
/// Removes a currently set connector
|
||||||
pub fn remove_connector(&mut self, connector: connector::Handle) {
|
pub fn remove_connector(&mut self, connector: connector::Handle) {
|
||||||
if let Ok(info) =
|
if let Ok(info) = connector::Info::load_from_device(self.graphics.head().head().head(), connector) {
|
||||||
connector::Info::load_from_device(self.0.borrow().graphics.head().head().head(), connector)
|
|
||||||
{
|
|
||||||
info!(
|
info!(
|
||||||
self.0.borrow().logger,
|
self.logger,
|
||||||
"Removing connector: {:?}",
|
"Removing connector: {:?}",
|
||||||
info.connector_type()
|
info.connector_type()
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
info!(self.0.borrow().logger, "Removing unknown connector");
|
info!(self.logger, "Removing unknown connector");
|
||||||
}
|
}
|
||||||
|
|
||||||
self.0.borrow_mut().connectors.retain(|x| *x != connector);
|
self.connectors.retain(|x| *x != connector);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Changes the currently set mode
|
/// Changes the currently set mode
|
||||||
|
@ -315,13 +259,10 @@ impl DrmBackend {
|
||||||
/// Other errors might occur.
|
/// Other errors might occur.
|
||||||
pub fn use_mode(&mut self, mode: Mode) -> Result<()> {
|
pub fn use_mode(&mut self, mode: Mode) -> Result<()> {
|
||||||
// check the connectors
|
// check the connectors
|
||||||
for connector in self.0.borrow().connectors.iter() {
|
for connector in self.connectors.iter() {
|
||||||
if !connector::Info::load_from_device(self.0.borrow().graphics.head().head().head(), *connector)
|
if !connector::Info::load_from_device(self.graphics.head().head().head(), *connector)
|
||||||
.chain_err(|| {
|
.chain_err(|| {
|
||||||
ErrorKind::DrmDev(format!(
|
ErrorKind::DrmDev(format!("{:?}", self.graphics.head().head().head()))
|
||||||
"{:?}",
|
|
||||||
self.0.borrow().graphics.head().head().head()
|
|
||||||
))
|
|
||||||
})?
|
})?
|
||||||
.modes()
|
.modes()
|
||||||
.contains(&mode)
|
.contains(&mode)
|
||||||
|
@ -332,21 +273,25 @@ impl DrmBackend {
|
||||||
|
|
||||||
// borrow & clone stuff because rust cannot figure out the upcoming
|
// borrow & clone stuff because rust cannot figure out the upcoming
|
||||||
// closure otherwise.
|
// closure otherwise.
|
||||||
let crtc = self.0.borrow().crtc;
|
let crtc = self.crtc;
|
||||||
let mut internal = self.0.borrow_mut();
|
let connectors_ref = &self.connectors;
|
||||||
let connectors = internal.connectors.clone();
|
let logger_ref = &self.logger;
|
||||||
let logger = internal.logger.clone();
|
|
||||||
|
|
||||||
let (w, h) = mode.size();
|
let (w, h) = mode.size();
|
||||||
|
|
||||||
internal.graphics.rent_all_mut(|graphics| -> Result<()> {
|
self.graphics.rent_all_mut(|graphics| -> Result<()> {
|
||||||
// Recreate the surface and the related resources to match the new
|
// Recreate the surface and the related resources to match the new
|
||||||
// resolution.
|
// resolution.
|
||||||
debug!(logger, "Reinitializing surface for new mode: {}:{}", w, h);
|
debug!(
|
||||||
|
logger_ref,
|
||||||
|
"Reinitializing surface for new mode: {}:{}",
|
||||||
|
w,
|
||||||
|
h
|
||||||
|
);
|
||||||
graphics.gbm.surface = Surface::try_new(
|
graphics.gbm.surface = Surface::try_new(
|
||||||
{
|
{
|
||||||
// create a new gbm surface
|
// create a new gbm surface
|
||||||
debug!(logger, "Creating GbmSurface");
|
debug!(logger_ref, "Creating GbmSurface");
|
||||||
Box::new(graphics
|
Box::new(graphics
|
||||||
.context
|
.context
|
||||||
.devices
|
.devices
|
||||||
|
@ -361,7 +306,7 @@ impl DrmBackend {
|
||||||
},
|
},
|
||||||
|surface| {
|
|surface| {
|
||||||
// create an egl surface from the gbm one
|
// create an egl surface from the gbm one
|
||||||
debug!(logger, "Creating EGLSurface");
|
debug!(logger_ref, "Creating EGLSurface");
|
||||||
let egl_surface = graphics.context.egl.create_surface(&surface)?;
|
let egl_surface = graphics.context.egl.create_surface(&surface)?;
|
||||||
|
|
||||||
// make it active for the first `crtc::set`
|
// make it active for the first `crtc::set`
|
||||||
|
@ -378,18 +323,22 @@ impl DrmBackend {
|
||||||
let mut front_bo = surface
|
let mut front_bo = surface
|
||||||
.lock_front_buffer()
|
.lock_front_buffer()
|
||||||
.chain_err(|| ErrorKind::FailedToSwap)?;
|
.chain_err(|| ErrorKind::FailedToSwap)?;
|
||||||
debug!(logger, "FrontBuffer color format: {:?}", front_bo.format());
|
debug!(
|
||||||
|
logger_ref,
|
||||||
|
"FrontBuffer color format: {:?}",
|
||||||
|
front_bo.format()
|
||||||
|
);
|
||||||
// we need a framebuffer per front_buffer
|
// we need a framebuffer per front_buffer
|
||||||
let fb = framebuffer::create(graphics.context.devices.drm, &*front_bo).chain_err(|| {
|
let fb = framebuffer::create(graphics.context.devices.drm, &*front_bo).chain_err(|| {
|
||||||
ErrorKind::DrmDev(format!("{:?}", graphics.context.devices.drm))
|
ErrorKind::DrmDev(format!("{:?}", graphics.context.devices.drm))
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
debug!(logger, "Initialize screen");
|
debug!(logger_ref, "Initialize screen");
|
||||||
crtc::set(
|
crtc::set(
|
||||||
graphics.context.devices.drm,
|
graphics.context.devices.drm,
|
||||||
crtc,
|
crtc,
|
||||||
fb.handle(),
|
fb.handle(),
|
||||||
&connectors,
|
connectors_ref,
|
||||||
(0, 0),
|
(0, 0),
|
||||||
Some(mode),
|
Some(mode),
|
||||||
).chain_err(|| {
|
).chain_err(|| {
|
||||||
|
@ -410,25 +359,17 @@ impl DrmBackend {
|
||||||
Ok(())
|
Ok(())
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
info!(logger, "Setting new mode: {:?}", mode.name());
|
info!(self.logger, "Setting new mode: {:?}", mode.name());
|
||||||
internal.mode = mode;
|
self.mode = mode;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checks of the `DrmBackend` is of the given `Id`
|
|
||||||
///
|
|
||||||
/// Only produces valid results, if the `Id` is from the `DrmDevice`,
|
|
||||||
/// that created this backend.
|
|
||||||
pub fn is(&self, id: Id) -> bool {
|
|
||||||
self.0.borrow().own_id == id
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for DrmBackend {
|
impl Drop for DrmBackend {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
// Drop framebuffers attached to the userdata of the gbm surface buffers.
|
// Drop framebuffers attached to the userdata of the gbm surface buffers.
|
||||||
// (They don't implement drop, as they need the device)
|
// (They don't implement drop, as they need the device)
|
||||||
self.0.borrow_mut().graphics.rent_all_mut(|graphics| {
|
self.graphics.rent_all_mut(|graphics| {
|
||||||
if let Some(fb) = graphics.gbm.surface.rent(|egl| {
|
if let Some(fb) = graphics.gbm.surface.rent(|egl| {
|
||||||
if let Some(mut next) = egl.buffers.next_buffer.take() {
|
if let Some(mut next) = egl.buffers.next_buffer.take() {
|
||||||
return next.take_userdata();
|
return next.take_userdata();
|
||||||
|
@ -459,29 +400,25 @@ impl GraphicsBackend for DrmBackend {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
fn set_cursor_position(&self, x: u32, y: u32) -> Result<()> {
|
fn set_cursor_position(&self, x: u32, y: u32) -> Result<()> {
|
||||||
trace!(self.0.borrow().logger, "Move the cursor to {},{}", x, y);
|
trace!(self.logger, "Move the cursor to {},{}", x, y);
|
||||||
crtc::move_cursor(
|
crtc::move_cursor(
|
||||||
self.0.borrow().graphics.head().head().head(),
|
self.graphics.head().head().head(),
|
||||||
self.0.borrow().crtc,
|
self.crtc,
|
||||||
(x as i32, y as i32),
|
(x as i32, y as i32),
|
||||||
).chain_err(|| {
|
).chain_err(|| {
|
||||||
ErrorKind::DrmDev(format!(
|
ErrorKind::DrmDev(format!("{:?}", self.graphics.head().head().head()))
|
||||||
"{:?}",
|
|
||||||
self.0.borrow().graphics.head().head().head()
|
|
||||||
))
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_cursor_representation(&self, buffer: ImageBuffer<Rgba<u8>, Vec<u8>>, hotspot: (u32, u32))
|
fn set_cursor_representation(&self, buffer: ImageBuffer<Rgba<u8>, Vec<u8>>, hotspot: (u32, u32))
|
||||||
-> Result<()> {
|
-> Result<()> {
|
||||||
let (w, h) = buffer.dimensions();
|
let (w, h) = buffer.dimensions();
|
||||||
debug!(self.0.borrow().logger, "Importing cursor");
|
|
||||||
|
debug!(self.logger, "Importing cursor");
|
||||||
|
|
||||||
|
self.graphics.rent_all(|graphics| -> Result<()> {
|
||||||
|
graphics.gbm.cursor.set({
|
||||||
// import the cursor into a buffer we can render
|
// import the cursor into a buffer we can render
|
||||||
self.0
|
|
||||||
.borrow_mut()
|
|
||||||
.graphics
|
|
||||||
.rent_all_mut(|graphics| -> Result<()> {
|
|
||||||
graphics.gbm.cursor = {
|
|
||||||
let mut cursor = graphics
|
let mut cursor = graphics
|
||||||
.context
|
.context
|
||||||
.devices
|
.devices
|
||||||
|
@ -496,47 +433,39 @@ impl GraphicsBackend for DrmBackend {
|
||||||
cursor
|
cursor
|
||||||
.write(&*buffer.into_raw())
|
.write(&*buffer.into_raw())
|
||||||
.chain_err(|| ErrorKind::GbmInitFailed)?;
|
.chain_err(|| ErrorKind::GbmInitFailed)?;
|
||||||
cursor
|
|
||||||
};
|
|
||||||
Ok(())
|
|
||||||
})?;
|
|
||||||
|
|
||||||
trace!(self.0.borrow().logger, "Set the new imported cursor");
|
trace!(self.logger, "Set the new imported cursor");
|
||||||
|
|
||||||
// and set it
|
// and set it
|
||||||
if crtc::set_cursor2(
|
if crtc::set_cursor2(
|
||||||
self.0.borrow().graphics.head().head().head(),
|
self.graphics.head().head().head(),
|
||||||
self.0.borrow().crtc,
|
self.crtc,
|
||||||
self.0
|
Buffer::handle(&cursor),
|
||||||
.borrow()
|
|
||||||
.graphics
|
|
||||||
.rent(|gbm| Buffer::handle(&gbm.cursor)),
|
|
||||||
(w, h),
|
(w, h),
|
||||||
(hotspot.0 as i32, hotspot.1 as i32),
|
(hotspot.0 as i32, hotspot.1 as i32),
|
||||||
).is_err()
|
).is_err()
|
||||||
{
|
{
|
||||||
crtc::set_cursor(
|
crtc::set_cursor(
|
||||||
self.0.borrow().graphics.head().head().head(),
|
self.graphics.head().head().head(),
|
||||||
self.0.borrow().crtc,
|
self.crtc,
|
||||||
self.0
|
Buffer::handle(&cursor),
|
||||||
.borrow()
|
|
||||||
.graphics
|
|
||||||
.rent(|gbm| Buffer::handle(&gbm.cursor)),
|
|
||||||
(w, h),
|
(w, h),
|
||||||
).chain_err(|| {
|
).chain_err(|| {
|
||||||
ErrorKind::DrmDev(format!(
|
ErrorKind::DrmDev(format!("{:?}", self.graphics.head().head().head()))
|
||||||
"{:?}",
|
})?;
|
||||||
self.0.borrow().graphics.head().head().head()
|
|
||||||
))
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// and store it
|
||||||
|
cursor
|
||||||
|
});
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EGLGraphicsBackend for DrmBackend {
|
impl EGLGraphicsBackend for DrmBackend {
|
||||||
fn swap_buffers(&self) -> ::std::result::Result<(), SwapBuffersError> {
|
fn swap_buffers(&self) -> ::std::result::Result<(), SwapBuffersError> {
|
||||||
self.0.borrow().graphics.rent_all(|graphics| {
|
self.graphics.rent_all(|graphics| {
|
||||||
// We cannot call lock_front_buffer anymore without releasing the previous buffer, which will happen when the page flip is done
|
// We cannot call lock_front_buffer anymore without releasing the previous buffer, which will happen when the page flip is done
|
||||||
if graphics.gbm.surface.rent(|egl| {
|
if graphics.gbm.surface.rent(|egl| {
|
||||||
let next = egl.buffers.next_buffer.take();
|
let next = egl.buffers.next_buffer.take();
|
||||||
|
@ -544,7 +473,7 @@ impl EGLGraphicsBackend for DrmBackend {
|
||||||
egl.buffers.next_buffer.set(next);
|
egl.buffers.next_buffer.set(next);
|
||||||
res
|
res
|
||||||
}) {
|
}) {
|
||||||
warn!(self.0.borrow().logger, "Tried to swap a DrmBackend with a queued flip");
|
warn!(self.logger, "Tried to swap a DrmBackend with a queued flip");
|
||||||
return Err(SwapBuffersError::AlreadySwapped);
|
return Err(SwapBuffersError::AlreadySwapped);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -570,48 +499,36 @@ impl EGLGraphicsBackend for DrmBackend {
|
||||||
};
|
};
|
||||||
surface.egl.buffers.next_buffer.set(Some(next_bo));
|
surface.egl.buffers.next_buffer.set(Some(next_bo));
|
||||||
|
|
||||||
trace!(self.0.borrow().logger, "Queueing Page flip");
|
trace!(self.logger, "Queueing Page flip");
|
||||||
|
|
||||||
let id: Id = self.0.borrow().own_id;
|
|
||||||
|
|
||||||
// and flip
|
// and flip
|
||||||
crtc::page_flip(graphics.context.devices.drm, self.0.borrow().crtc, fb.handle(), &[crtc::PageFlipFlags::PageFlipEvent], id).map_err(|_| SwapBuffersError::ContextLost)
|
crtc::page_flip(graphics.context.devices.drm, self.crtc, fb.handle(), &[crtc::PageFlipFlags::PageFlipEvent], self.crtc).map_err(|_| SwapBuffersError::ContextLost)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn get_proc_address(&self, symbol: &str) -> *const c_void {
|
unsafe fn get_proc_address(&self, symbol: &str) -> *const c_void {
|
||||||
self.0
|
self.graphics
|
||||||
.borrow()
|
|
||||||
.graphics
|
|
||||||
.head()
|
.head()
|
||||||
.rent(|context| context.get_proc_address(symbol))
|
.rent(|context| context.get_proc_address(symbol))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_framebuffer_dimensions(&self) -> (u32, u32) {
|
fn get_framebuffer_dimensions(&self) -> (u32, u32) {
|
||||||
let (w, h) = self.0.borrow().mode.size();
|
let (w, h) = self.mode.size();
|
||||||
(w as u32, h as u32)
|
(w as u32, h as u32)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_current(&self) -> bool {
|
fn is_current(&self) -> bool {
|
||||||
self.0
|
self.graphics.head().rent(|context| context.is_current())
|
||||||
.borrow()
|
|
||||||
.graphics
|
|
||||||
.head()
|
|
||||||
.rent(|context| context.is_current())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn make_current(&self) -> ::std::result::Result<(), SwapBuffersError> {
|
unsafe fn make_current(&self) -> ::std::result::Result<(), SwapBuffersError> {
|
||||||
self.0
|
self.graphics
|
||||||
.borrow()
|
|
||||||
.graphics
|
|
||||||
.rent(|gbm| gbm.surface.rent(|egl| egl.surface.make_current()))
|
.rent(|gbm| gbm.surface.rent(|egl| egl.surface.make_current()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_pixel_format(&self) -> PixelFormat {
|
fn get_pixel_format(&self) -> PixelFormat {
|
||||||
self.0
|
self.graphics
|
||||||
.borrow()
|
|
||||||
.graphics
|
|
||||||
.head()
|
.head()
|
||||||
.rent(|context| context.get_pixel_format())
|
.rent(|context| context.get_pixel_format())
|
||||||
}
|
}
|
||||||
|
|
|
@ -191,20 +191,21 @@ use drm::control::{connector, crtc, encoder, Mode, ResourceInfo};
|
||||||
use drm::control::Device as ControlDevice;
|
use drm::control::Device as ControlDevice;
|
||||||
use gbm::Device as GbmDevice;
|
use gbm::Device as GbmDevice;
|
||||||
use nix;
|
use nix;
|
||||||
use std::cell::RefCell;
|
use std::collections::HashMap;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{Error as IoError, Result as IoResult};
|
use std::io::{Error as IoError, Result as IoResult};
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
use std::ops::Deref;
|
||||||
use std::os::unix::io::{AsRawFd, RawFd};
|
use std::os::unix::io::{AsRawFd, RawFd};
|
||||||
use std::rc::{Rc, Weak};
|
use std::rc::Rc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use wayland_server::EventLoopHandle;
|
use wayland_server::{EventLoopHandle, StateToken};
|
||||||
use wayland_server::sources::{FdEventSource, FdEventSourceImpl, READ};
|
use wayland_server::sources::{FdEventSource, FdEventSourceImpl, READ};
|
||||||
|
|
||||||
mod backend;
|
mod backend;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
|
|
||||||
pub use self::backend::{DrmBackend, Id};
|
pub use self::backend::DrmBackend;
|
||||||
use self::backend::DrmBackendInternal;
|
|
||||||
use self::error::*;
|
use self::error::*;
|
||||||
|
|
||||||
/// Internal struct as required by the drm crate
|
/// Internal struct as required by the drm crate
|
||||||
|
@ -255,13 +256,13 @@ rental! {
|
||||||
use self::devices::{Context, Devices};
|
use self::devices::{Context, Devices};
|
||||||
|
|
||||||
/// Representation of an open drm device node to create rendering backends
|
/// Representation of an open drm device node to create rendering backends
|
||||||
pub struct DrmDevice {
|
pub struct DrmDevice<B: Deref<Target = DrmBackend> + 'static> {
|
||||||
context: Rc<Context>,
|
context: Rc<Context>,
|
||||||
backends: Vec<Weak<RefCell<DrmBackendInternal>>>,
|
backends: HashMap<crtc::Handle, StateToken<B>>,
|
||||||
logger: ::slog::Logger,
|
logger: ::slog::Logger,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DrmDevice {
|
impl<B: From<DrmBackend> + Deref<Target = DrmBackend> + 'static> DrmDevice<B> {
|
||||||
/// Create a new `DrmDevice` from a raw file descriptor
|
/// Create a new `DrmDevice` from a raw file descriptor
|
||||||
///
|
///
|
||||||
/// Returns an error of opening the device failed or context creation was not
|
/// Returns an error of opening the device failed or context creation was not
|
||||||
|
@ -358,7 +359,7 @@ impl DrmDevice {
|
||||||
context: Rc::new(Context::try_new(
|
context: Rc::new(Context::try_new(
|
||||||
Box::new(Devices::try_new(Box::new(drm), |drm| {
|
Box::new(Devices::try_new(Box::new(drm), |drm| {
|
||||||
debug!(log, "Creating gbm device");
|
debug!(log, "Creating gbm device");
|
||||||
GbmDevice::new_from_drm::<DrmDevice>(drm).chain_err(|| ErrorKind::GbmInitFailed)
|
GbmDevice::new_from_drm::<DrmDevice<B>>(drm).chain_err(|| ErrorKind::GbmInitFailed)
|
||||||
})?),
|
})?),
|
||||||
|devices| {
|
|devices| {
|
||||||
debug!(log, "Creating egl context from gbm device");
|
debug!(log, "Creating egl context from gbm device");
|
||||||
|
@ -375,7 +376,7 @@ impl DrmDevice {
|
||||||
).map_err(Error::from)
|
).map_err(Error::from)
|
||||||
},
|
},
|
||||||
)?),
|
)?),
|
||||||
backends: Vec::new(),
|
backends: HashMap::new(),
|
||||||
logger: log,
|
logger: log,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -385,29 +386,32 @@ impl DrmDevice {
|
||||||
///
|
///
|
||||||
/// Errors if initialization fails or the mode is not available on all given
|
/// Errors if initialization fails or the mode is not available on all given
|
||||||
/// connectors.
|
/// connectors.
|
||||||
pub fn create_backend<I>(&mut self, crtc: crtc::Handle, mode: Mode, connectors: I) -> Result<DrmBackend>
|
pub fn create_backend<I>(&mut self, evlh: &mut EventLoopHandle, crtc: crtc::Handle, mode: Mode,
|
||||||
|
connectors: I)
|
||||||
|
-> Result<StateToken<B>>
|
||||||
where
|
where
|
||||||
I: Into<Vec<connector::Handle>>,
|
I: Into<Vec<connector::Handle>>,
|
||||||
{
|
{
|
||||||
for backend in self.backends.iter() {
|
if self.backends.contains_key(&crtc) {
|
||||||
if let Some(backend) = backend.upgrade() {
|
bail!(ErrorKind::CrtcAlreadyInUse(crtc));
|
||||||
if backend.borrow().is_crtc(crtc) {
|
|
||||||
bail!(ErrorKind::CrtcAlreadyInUse(crtc))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if the given connectors and crtc match
|
// check if the given connectors and crtc match
|
||||||
let connectors = connectors.into();
|
let connectors = connectors.into();
|
||||||
|
|
||||||
// check if we have an encoder for every connector
|
// check if we have an encoder for every connector and the mode mode
|
||||||
for connector in connectors.iter() {
|
for connector in connectors.iter() {
|
||||||
let con_info = connector::Info::load_from_device(self.context.head().head(), *connector)
|
let con_info = connector::Info::load_from_device(self.context.head().head(), *connector)
|
||||||
.chain_err(|| {
|
.chain_err(|| {
|
||||||
ErrorKind::DrmDev(format!("{:?}", self.context.head().head()))
|
ErrorKind::DrmDev(format!("{:?}", self.context.head().head()))
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
// then check for every connector which encoders it does support
|
// check the mode
|
||||||
|
if !con_info.modes().contains(&mode) {
|
||||||
|
bail!(ErrorKind::ModeNotSuitable(mode));
|
||||||
|
}
|
||||||
|
|
||||||
|
// check for every connector which encoders it does support
|
||||||
let encoders = con_info
|
let encoders = con_info
|
||||||
.encoders()
|
.encoders()
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -426,59 +430,50 @@ impl DrmDevice {
|
||||||
|
|
||||||
// configuration is valid, the kernel will figure out the rest
|
// configuration is valid, the kernel will figure out the rest
|
||||||
|
|
||||||
let own_id = self.backends.len();
|
let logger = self.logger.new(o!("crtc" => format!("{:?}", crtc)));
|
||||||
let logger = self.logger.new(
|
let backend = DrmBackend::new(self.context.clone(), crtc, mode, connectors, logger)?;
|
||||||
o!("id" => format!("{}", own_id), "crtc" => format!("{:?}", crtc)),
|
let token = evlh.state().insert(backend.into());
|
||||||
);
|
self.backends.insert(crtc, token.clone());
|
||||||
|
|
||||||
let backend = Rc::new(RefCell::new(DrmBackendInternal::new(
|
Ok(token)
|
||||||
self.context.clone(),
|
|
||||||
crtc,
|
|
||||||
mode,
|
|
||||||
connectors,
|
|
||||||
own_id,
|
|
||||||
logger,
|
|
||||||
)?));
|
|
||||||
|
|
||||||
self.backends.push(Rc::downgrade(&backend));
|
|
||||||
|
|
||||||
Ok(DrmBackend::new(backend))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// for users convinience and FdEventSource registering
|
// for users convinience and FdEventSource registering
|
||||||
impl AsRawFd for DrmDevice {
|
impl<B: Deref<Target = DrmBackend> + 'static> AsRawFd for DrmDevice<B> {
|
||||||
fn as_raw_fd(&self) -> RawFd {
|
fn as_raw_fd(&self) -> RawFd {
|
||||||
self.context.head().head().as_raw_fd()
|
self.context.head().head().as_raw_fd()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl BasicDevice for DrmDevice {}
|
impl<B: Deref<Target = DrmBackend> + 'static> BasicDevice for DrmDevice<B> {}
|
||||||
impl ControlDevice for DrmDevice {}
|
impl<B: Deref<Target = DrmBackend> + 'static> ControlDevice for DrmDevice<B> {}
|
||||||
|
|
||||||
/// Handler for drm node events
|
/// Handler for drm node events
|
||||||
///
|
///
|
||||||
/// See module-level documentation for its use
|
/// See module-level documentation for its use
|
||||||
pub trait DrmHandler {
|
pub trait DrmHandler<B: Deref<Target = DrmBackend> + 'static> {
|
||||||
/// A `DrmBackend` has finished swapping buffers and new frame can now
|
/// A `DrmBackend` has finished swapping buffers and new frame can now
|
||||||
/// (and should be immediately) be rendered.
|
/// (and should be immediately) be rendered.
|
||||||
///
|
///
|
||||||
/// The `id` argument is the `Id` of the `DrmBackend` that finished rendering,
|
/// The `id` argument is the `Id` of the `DrmBackend` that finished rendering,
|
||||||
/// check using `DrmBackend::is`.
|
/// check using `DrmBackend::is`.
|
||||||
fn ready(&mut self, evlh: &mut EventLoopHandle, id: Id, frame: u32, duration: Duration);
|
fn ready(&mut self, evlh: &mut EventLoopHandle, device: &mut DrmDevice<B>, backend: &StateToken<B>,
|
||||||
|
frame: u32, duration: Duration);
|
||||||
/// The `DrmDevice` has thrown an error.
|
/// The `DrmDevice` has thrown an error.
|
||||||
///
|
///
|
||||||
/// The related backends are most likely *not* usable anymore and
|
/// The related backends are most likely *not* usable anymore and
|
||||||
/// the whole stack has to be recreated.
|
/// the whole stack has to be recreated.
|
||||||
fn error(&mut self, evlh: &mut EventLoopHandle, error: IoError);
|
fn error(&mut self, evlh: &mut EventLoopHandle, device: &mut DrmDevice<B>, error: IoError);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Bind a `DrmDevice` to an EventLoop,
|
/// Bind a `DrmDevice` to an EventLoop,
|
||||||
///
|
///
|
||||||
/// This will cause it to recieve events and feed them into an `DrmHandler`
|
/// This will cause it to recieve events and feed them into an `DrmHandler`
|
||||||
pub fn drm_device_bind<H>(evlh: &mut EventLoopHandle, device: DrmDevice, handler: H)
|
pub fn drm_device_bind<B, H>(evlh: &mut EventLoopHandle, device: DrmDevice<B>, handler: H)
|
||||||
-> IoResult<FdEventSource<(DrmDevice, H)>>
|
-> IoResult<FdEventSource<(DrmDevice<B>, H)>>
|
||||||
where
|
where
|
||||||
H: DrmHandler + 'static,
|
B: Deref<Target = DrmBackend> + 'static,
|
||||||
|
H: DrmHandler<B> + 'static,
|
||||||
{
|
{
|
||||||
evlh.add_fd_event_source(
|
evlh.add_fd_event_source(
|
||||||
device.as_raw_fd(),
|
device.as_raw_fd(),
|
||||||
|
@ -488,28 +483,44 @@ where
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fd_event_source_implementation<H>() -> FdEventSourceImpl<(DrmDevice, H)>
|
fn fd_event_source_implementation<B, H>() -> FdEventSourceImpl<(DrmDevice<B>, H)>
|
||||||
where
|
where
|
||||||
H: DrmHandler + 'static,
|
B: Deref<Target = DrmBackend> + 'static,
|
||||||
|
H: DrmHandler<B> + 'static,
|
||||||
{
|
{
|
||||||
FdEventSourceImpl {
|
FdEventSourceImpl {
|
||||||
ready: |evlh, id, _, _| {
|
ready: |evlh, id, _, _| {
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
|
|
||||||
let &mut (ref dev, ref mut handler) = id;
|
let &mut (ref mut dev, ref mut handler) = id;
|
||||||
|
|
||||||
struct PageFlipHandler<'a, 'b, H: DrmHandler + 'static>(&'a mut H, &'b mut EventLoopHandle);
|
struct PageFlipHandler<
|
||||||
|
'a,
|
||||||
|
'b,
|
||||||
|
B: Deref<Target = DrmBackend> + 'static,
|
||||||
|
H: DrmHandler<B> + 'static,
|
||||||
|
> {
|
||||||
|
handler: &'a mut H,
|
||||||
|
evlh: &'b mut EventLoopHandle,
|
||||||
|
_marker: PhantomData<B>,
|
||||||
|
};
|
||||||
|
|
||||||
impl<'a, 'b, H: DrmHandler + 'static> crtc::PageFlipHandler<DrmDevice> for PageFlipHandler<'a, 'b, H> {
|
impl<'a, 'b, B, H> crtc::PageFlipHandler<DrmDevice<B>> for PageFlipHandler<'a, 'b, B, H>
|
||||||
fn handle_event(&mut self, device: &DrmDevice, frame: u32, duration: Duration,
|
where
|
||||||
|
B: Deref<Target = DrmBackend> + 'static,
|
||||||
|
H: DrmHandler<B> + 'static,
|
||||||
|
{
|
||||||
|
fn handle_event(&mut self, device: &mut DrmDevice<B>, frame: u32, duration: Duration,
|
||||||
userdata: Box<Any>) {
|
userdata: Box<Any>) {
|
||||||
let id: Id = *userdata.downcast().unwrap();
|
let crtc_id: crtc::Handle = *userdata.downcast().unwrap();
|
||||||
if let Some(backend) = device.backends[id.raw()].upgrade() {
|
let token = device.backends.get(&crtc_id).cloned();
|
||||||
|
if let Some(token) = token {
|
||||||
// we can now unlock the buffer
|
// we can now unlock the buffer
|
||||||
backend.borrow().unlock_buffer();
|
(**self.evlh.state().get(&token)).unlock_buffer();
|
||||||
trace!(device.logger, "Handling event for backend {:?}", id.raw());
|
trace!(device.logger, "Handling event for backend {:?}", crtc_id);
|
||||||
// and then call the user to render the next frame
|
// and then call the user to render the next frame
|
||||||
self.0.ready(self.1, id, frame, duration);
|
self.handler
|
||||||
|
.ready(self.evlh, device, &token, frame, duration);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -518,13 +529,17 @@ where
|
||||||
dev,
|
dev,
|
||||||
2,
|
2,
|
||||||
None::<&mut ()>,
|
None::<&mut ()>,
|
||||||
Some(&mut PageFlipHandler(handler, evlh)),
|
Some(&mut PageFlipHandler {
|
||||||
|
handler,
|
||||||
|
evlh,
|
||||||
|
_marker: PhantomData,
|
||||||
|
}),
|
||||||
None::<&mut ()>,
|
None::<&mut ()>,
|
||||||
).unwrap();
|
).unwrap();
|
||||||
},
|
},
|
||||||
error: |evlh, id, _, error| {
|
error: |evlh, id, _, error| {
|
||||||
warn!(id.0.logger, "DrmDevice errored: {}", error);
|
warn!(id.0.logger, "DrmDevice errored: {}", error);
|
||||||
id.1.error(evlh, error);
|
id.1.error(evlh, &mut id.0, error);
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,6 @@ use glium::backend::{Backend, Context, Facade};
|
||||||
use glium::debug::DebugCallbackBehavior;
|
use glium::debug::DebugCallbackBehavior;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::os::raw::c_void;
|
use std::os::raw::c_void;
|
||||||
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
impl From<SwapBuffersError> for GliumSwapBuffersError {
|
impl From<SwapBuffersError> for GliumSwapBuffersError {
|
||||||
|
@ -69,15 +68,9 @@ impl<T: EGLGraphicsBackend> Facade for GliumGraphicsBackend<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Converter trait to expose `glium` compatibility for all `EGLGraphicsBackend`s
|
impl<T: EGLGraphicsBackend + 'static> From<T> for GliumGraphicsBackend<T> {
|
||||||
pub trait IntoGlium: EGLGraphicsBackend + Sized {
|
fn from(backend: T) -> Self {
|
||||||
/// Wrap the given `EGLGraphicsBackend` to a `GliumGraphicBackend`
|
GliumGraphicsBackend::new(backend)
|
||||||
fn into_glium(self) -> GliumGraphicsBackend<Self>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: EGLGraphicsBackend + 'static> IntoGlium for T {
|
|
||||||
fn into_glium(self) -> GliumGraphicsBackend<Self> {
|
|
||||||
GliumGraphicsBackend::new(self)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue