This commit is contained in:
Victor Brekenfeld 2021-04-29 00:32:47 +02:00
parent 36bf5618ed
commit 52c01535d0
31 changed files with 1389 additions and 915 deletions

View File

@ -9,9 +9,7 @@ use smithay::reexports::nix::libc::dev_t;
use std::collections::HashMap; use std::collections::HashMap;
#[cfg(feature = "egl")] #[cfg(feature = "egl")]
use smithay::backend::egl::{ use smithay::backend::egl::{display::EGLBufferReader, BufferAccessError as EGLBufferAccessError, EGLBuffer};
display::EGLBufferReader, BufferAccessError as EGLBufferAccessError, EGLBuffer,
};
use smithay::{ use smithay::{
reexports::wayland_server::protocol::wl_buffer::WlBuffer, reexports::wayland_server::protocol::wl_buffer::WlBuffer,
wayland::shm::{with_buffer_contents as shm_buffer_contents, BufferAccessError}, wayland::shm::{with_buffer_contents as shm_buffer_contents, BufferAccessError},
@ -76,7 +74,7 @@ impl BufferUtils {
let egl_buffer = match result { let egl_buffer = match result {
Ok(egl) => Some(egl), Ok(egl) => Some(egl),
Err(EGLBufferAccessError::NotManaged(_)) => { None }, Err(EGLBufferAccessError::NotManaged(_)) => None,
Err(err) => { Err(err) => {
error!(self.log, "EGL error"; "err" => format!("{:?}", err)); error!(self.log, "EGL error"; "err" => format!("{:?}", err));
return Err(buffer); return Err(buffer);
@ -112,7 +110,7 @@ pub struct BufferTextures<T> {
#[cfg(feature = "udev")] #[cfg(feature = "udev")]
impl<T: Texture> BufferTextures<T> { impl<T: Texture> BufferTextures<T> {
#[cfg(feature = "egl")] #[cfg(feature = "egl")]
pub fn load_texture<'a, R: Renderer<TextureId=T>>( pub fn load_texture<'a, R: Renderer<TextureId = T>>(
&'a mut self, &'a mut self,
id: u64, id: u64,
renderer: &mut R, renderer: &mut R,
@ -136,7 +134,7 @@ impl<T: Texture> BufferTextures<T> {
} }
#[cfg(not(feature = "egl"))] #[cfg(not(feature = "egl"))]
pub fn load_texture<'a, R: Renderer<Texture=T>>( pub fn load_texture<'a, R: Renderer<Texture = T>>(
&'a mut self, &'a mut self,
id: u64, id: u64,
renderer: &mut R, renderer: &mut R,
@ -149,7 +147,7 @@ impl<T: Texture> BufferTextures<T> {
self.load_shm_texture(id, renderer, texture_destruction_callback) self.load_shm_texture(id, renderer, texture_destruction_callback)
} }
fn load_shm_texture<'a, R: Renderer<TextureId=T>>( fn load_shm_texture<'a, R: Renderer<TextureId = T>>(
&'a mut self, &'a mut self,
id: u64, id: u64,
renderer: &mut R, renderer: &mut R,

View File

@ -1,19 +1,12 @@
#![allow(clippy::too_many_arguments)] #![allow(clippy::too_many_arguments)]
use std::{ use std::{cell::RefCell, rc::Rc, sync::mpsc::Sender};
cell::RefCell,
rc::Rc,
sync::mpsc::Sender,
};
use slog::Logger; use slog::Logger;
use smithay::{ use smithay::{
backend::renderer::{Renderer, Texture, Transform},
backend::SwapBuffersError, backend::SwapBuffersError,
backend::renderer::{Renderer, Transform, Texture}, reexports::{calloop::LoopHandle, wayland_server::protocol::wl_surface},
reexports::{
calloop::LoopHandle,
wayland_server::protocol::wl_surface,
},
utils::Rectangle, utils::Rectangle,
wayland::{ wayland::{
compositor::{roles::Role, SubsurfaceRole, TraversalAction}, compositor::{roles::Role, SubsurfaceRole, TraversalAction},
@ -22,8 +15,8 @@ use smithay::{
}, },
}; };
use crate::buffer_utils::{BufferTextures, BufferUtils};
use crate::shell::{MyCompositorToken, MyWindowMap, SurfaceData}; use crate::shell::{MyCompositorToken, MyWindowMap, SurfaceData};
use crate::buffer_utils::{BufferUtils, BufferTextures};
pub fn draw_cursor<R, E, T>( pub fn draw_cursor<R, E, T>(
renderer: &mut R, renderer: &mut R,
@ -35,10 +28,10 @@ pub fn draw_cursor<R, E, T>(
token: MyCompositorToken, token: MyCompositorToken,
log: &Logger, log: &Logger,
) -> Result<(), SwapBuffersError> ) -> Result<(), SwapBuffersError>
where where
R: Renderer<Error=E, TextureId=T>, R: Renderer<Error = E, TextureId = T>,
E: std::error::Error + Into<SwapBuffersError>, E: std::error::Error + Into<SwapBuffersError>,
T: Texture + 'static, T: Texture + 'static,
{ {
let (dx, dy) = match token.with_role_data::<CursorImageRole, _, _>(surface, |data| data.hotspot) { let (dx, dy) = match token.with_role_data::<CursorImageRole, _, _>(surface, |data| data.hotspot) {
Ok(h) => h, Ok(h) => h,
@ -50,7 +43,16 @@ pub fn draw_cursor<R, E, T>(
(0, 0) (0, 0)
} }
}; };
draw_surface_tree(renderer, renderer_id, texture_destruction_callback, buffer_utils, surface, (x - dx, y - dy), token, log) draw_surface_tree(
renderer,
renderer_id,
texture_destruction_callback,
buffer_utils,
surface,
(x - dx, y - dy),
token,
log,
)
} }
fn draw_surface_tree<R, E, T>( fn draw_surface_tree<R, E, T>(
@ -63,10 +65,10 @@ fn draw_surface_tree<R, E, T>(
compositor_token: MyCompositorToken, compositor_token: MyCompositorToken,
log: &Logger, log: &Logger,
) -> Result<(), SwapBuffersError> ) -> Result<(), SwapBuffersError>
where where
R: Renderer<Error=E, TextureId=T>, R: Renderer<Error = E, TextureId = T>,
E: std::error::Error + Into<SwapBuffersError>, E: std::error::Error + Into<SwapBuffersError>,
T: Texture + 'static, T: Texture + 'static,
{ {
let mut result = Ok(()); let mut result = Ok(());
@ -85,7 +87,7 @@ fn draw_surface_tree<R, E, T>(
// already logged the error // already logged the error
Err(err) => { Err(err) => {
warn!(log, "Error loading buffer: {:?}", err); warn!(log, "Error loading buffer: {:?}", err);
}, }
}; };
} }
} }
@ -133,15 +135,23 @@ fn draw_surface_tree<R, E, T>(
if let Some(ref data) = attributes.user_data.get::<RefCell<SurfaceData>>() { if let Some(ref data) = attributes.user_data.get::<RefCell<SurfaceData>>() {
let mut data = data.borrow_mut(); let mut data = data.borrow_mut();
let (sub_x, sub_y) = data.current_state.sub_location; let (sub_x, sub_y) = data.current_state.sub_location;
if let Some(buffer_textures) = data.texture.as_mut().and_then(|x| x.downcast_mut::<BufferTextures<T>>()) { if let Some(buffer_textures) = data
.texture
.as_mut()
.and_then(|x| x.downcast_mut::<BufferTextures<T>>())
{
// we need to re-extract the subsurface offset, as the previous closure // we need to re-extract the subsurface offset, as the previous closure
// only passes it to our children // only passes it to our children
if Role::<SubsurfaceRole>::has(role) { if Role::<SubsurfaceRole>::has(role) {
x += sub_x; x += sub_x;
y += sub_y; y += sub_y;
} }
let texture = buffer_textures.load_texture(renderer_id, renderer, texture_destruction_callback).unwrap(); let texture = buffer_textures
if let Err(err) = renderer.render_texture_at(texture, (x, y), Transform::Normal /* TODO */, 1.0) { .load_texture(renderer_id, renderer, texture_destruction_callback)
.unwrap();
if let Err(err) =
renderer.render_texture_at(texture, (x, y), Transform::Normal /* TODO */, 1.0)
{
result = Err(err.into()); result = Err(err.into());
} }
} }
@ -163,40 +173,38 @@ pub fn draw_windows<R, E, T>(
compositor_token: MyCompositorToken, compositor_token: MyCompositorToken,
log: &::slog::Logger, log: &::slog::Logger,
) -> Result<(), SwapBuffersError> ) -> Result<(), SwapBuffersError>
where where
R: Renderer<Error=E, TextureId=T>, R: Renderer<Error = E, TextureId = T>,
E: std::error::Error + Into<SwapBuffersError>, E: std::error::Error + Into<SwapBuffersError>,
T: Texture + 'static, T: Texture + 'static,
{ {
let mut result = Ok(()); let mut result = Ok(());
// redraw the frame, in a simple but inneficient way // redraw the frame, in a simple but inneficient way
window_map.with_windows_from_bottom_to_top( window_map.with_windows_from_bottom_to_top(|toplevel_surface, mut initial_place, bounding_box| {
|toplevel_surface, mut initial_place, bounding_box| { // skip windows that do not overlap with a given output
// skip windows that do not overlap with a given output if let Some(output) = output_rect {
if let Some(output) = output_rect { if !output.overlaps(bounding_box) {
if !output.overlaps(bounding_box) { return;
return;
}
initial_place.0 -= output.x;
} }
if let Some(wl_surface) = toplevel_surface.get_surface() { initial_place.0 -= output.x;
// this surface is a root of a subsurface tree that needs to be drawn }
if let Err(err) = draw_surface_tree( if let Some(wl_surface) = toplevel_surface.get_surface() {
renderer, // this surface is a root of a subsurface tree that needs to be drawn
renderer_id, if let Err(err) = draw_surface_tree(
texture_destruction_callback, renderer,
buffer_utils, renderer_id,
&wl_surface, texture_destruction_callback,
initial_place, buffer_utils,
compositor_token, &wl_surface,
log, initial_place,
) { compositor_token,
result = Err(err); log,
} ) {
result = Err(err);
} }
}, }
); });
result result
} }
@ -211,10 +219,10 @@ pub fn draw_dnd_icon<R, E, T>(
token: MyCompositorToken, token: MyCompositorToken,
log: &::slog::Logger, log: &::slog::Logger,
) -> Result<(), SwapBuffersError> ) -> Result<(), SwapBuffersError>
where where
R: Renderer<Error=E, TextureId=T>, R: Renderer<Error = E, TextureId = T>,
E: std::error::Error + Into<SwapBuffersError>, E: std::error::Error + Into<SwapBuffersError>,
T: Texture + 'static, T: Texture + 'static,
{ {
if !token.has_role::<DnDIconRole>(surface) { if !token.has_role::<DnDIconRole>(surface) {
warn!( warn!(
@ -222,23 +230,37 @@ pub fn draw_dnd_icon<R, E, T>(
"Trying to display as a dnd icon a surface that does not have the DndIcon role." "Trying to display as a dnd icon a surface that does not have the DndIcon role."
); );
} }
draw_surface_tree(renderer, renderer_id, texture_destruction_callback, buffer_utils, surface, (x, y), token, log) draw_surface_tree(
renderer,
renderer_id,
texture_destruction_callback,
buffer_utils,
surface,
(x, y),
token,
log,
)
} }
pub fn schedule_initial_render<R: Renderer + 'static, Data: 'static>( pub fn schedule_initial_render<R: Renderer + 'static, Data: 'static>(
renderer: Rc<RefCell<R>>, renderer: Rc<RefCell<R>>,
evt_handle: &LoopHandle<Data>, evt_handle: &LoopHandle<Data>,
logger: ::slog::Logger, logger: ::slog::Logger,
) ) where
where <R as Renderer>::Error: Into<SwapBuffersError>,
<R as Renderer>::Error: Into<SwapBuffersError>
{ {
let result = { let result = {
let mut renderer = renderer.borrow_mut(); let mut renderer = renderer.borrow_mut();
// Does not matter if we render an empty frame // Does not matter if we render an empty frame
renderer.begin(1, 1, Transform::Normal).map_err(Into::<SwapBuffersError>::into) renderer
.and_then(|_| renderer.clear([0.8, 0.8, 0.9, 1.0]).map_err(Into::<SwapBuffersError>::into)) .begin(1, 1, Transform::Normal)
.and_then(|_| renderer.finish()) .map_err(Into::<SwapBuffersError>::into)
.and_then(|_| {
renderer
.clear([0.8, 0.8, 0.9, 1.0])
.map_err(Into::<SwapBuffersError>::into)
})
.and_then(|_| renderer.finish())
}; };
if let Err(err) = result { if let Err(err) = result {
match err { match err {

View File

@ -5,7 +5,7 @@ use std::{
os::unix::io::{AsRawFd, RawFd}, os::unix::io::{AsRawFd, RawFd},
path::PathBuf, path::PathBuf,
rc::Rc, rc::Rc,
sync::{atomic::Ordering, Arc, Mutex, mpsc}, sync::{atomic::Ordering, mpsc, Arc, Mutex},
time::Duration, time::Duration,
}; };
@ -14,27 +14,16 @@ use slog::Logger;
use smithay::{ use smithay::{
backend::{ backend::{
SwapBuffersError, drm::{device_bind, DevPath, DeviceHandler, DrmDevice, DrmError, DrmRenderSurface},
drm::{ egl::{display::EGLBufferReader, EGLContext, EGLDisplay},
DrmDevice,
DeviceHandler,
device_bind,
DrmRenderSurface,
DrmError,
DevPath,
},
egl::{EGLDisplay, EGLContext, display::EGLBufferReader},
renderer::{
Transform,
Renderer,
gles2::{
Gles2Renderer,
Gles2Texture,
},
},
libinput::{LibinputInputBackend, LibinputSessionInterface}, libinput::{LibinputInputBackend, LibinputSessionInterface},
renderer::{
gles2::{Gles2Renderer, Gles2Texture},
Renderer, Transform,
},
session::{auto::AutoSession, Session, Signal as SessionSignal}, session::{auto::AutoSession, Session, Signal as SessionSignal},
udev::{primary_gpu, UdevBackend, UdevEvent}, udev::{primary_gpu, UdevBackend, UdevEvent},
SwapBuffersError,
}, },
reexports::{ reexports::{
calloop::{ calloop::{
@ -45,16 +34,13 @@ use smithay::{
drm::{ drm::{
self, self,
control::{ control::{
Device as ControlDevice,
connector::{Info as ConnectorInfo, State as ConnectorState}, connector::{Info as ConnectorInfo, State as ConnectorState},
crtc, crtc,
encoder::Info as EncoderInfo, encoder::Info as EncoderInfo,
Device as ControlDevice,
}, },
}, },
gbm::{ gbm::{BufferObject as GbmBuffer, Device as GbmDevice},
BufferObject as GbmBuffer,
Device as GbmDevice,
},
input::Libinput, input::Libinput,
nix::{fcntl::OFlag, sys::stat::dev_t}, nix::{fcntl::OFlag, sys::stat::dev_t},
wayland_server::{ wayland_server::{
@ -72,9 +58,9 @@ use smithay::{
}; };
use crate::buffer_utils::BufferUtils; use crate::buffer_utils::BufferUtils;
use crate::drawing::*;
use crate::shell::{MyWindowMap, Roles}; use crate::shell::{MyWindowMap, Roles};
use crate::state::AnvilState; use crate::state::AnvilState;
use crate::drawing::*;
#[derive(Clone)] #[derive(Clone)]
pub struct SessionFd(RawFd); pub struct SessionFd(RawFd);
@ -358,7 +344,9 @@ impl<Data: 'static> UdevHandlerImpl<Data> {
}; };
if let Entry::Vacant(entry) = backends.entry(crtc) { if let Entry::Vacant(entry) = backends.entry(crtc) {
info!(logger, "Trying to setup connector {:?}-{} with crtc {:?}", info!(
logger,
"Trying to setup connector {:?}-{} with crtc {:?}",
connector_info.interface(), connector_info.interface(),
connector_info.interface_id(), connector_info.interface_id(),
crtc, crtc,
@ -377,25 +365,26 @@ impl<Data: 'static> UdevHandlerImpl<Data> {
continue; continue;
} }
}; };
let surface = match device.create_surface(crtc, primary, connector_info.modes()[0], &[connector_info.handle()]) { let surface = match device.create_surface(
crtc,
primary,
connector_info.modes()[0],
&[connector_info.handle()],
) {
Ok(surface) => surface, Ok(surface) => surface,
Err(err) => { Err(err) => {
warn!(logger, "Failed to create drm surface: {}", err); warn!(logger, "Failed to create drm surface: {}", err);
continue; continue;
} }
}; };
let renderer = match DrmRenderSurface::new( let renderer =
surface, match DrmRenderSurface::new(surface, gbm.clone(), renderer, logger.clone()) {
gbm.clone(), Ok(renderer) => renderer,
renderer, Err(err) => {
logger.clone() warn!(logger, "Failed to create rendering surface: {}", err);
) { continue;
Ok(renderer) => renderer, }
Err(err) => { };
warn!(logger, "Failed to create rendering surface: {}", err);
continue;
}
};
output_map.push(MyOutput::new( output_map.push(MyOutput::new(
display, display,
@ -430,34 +419,36 @@ impl<Data: 'static> UdevHandlerImpl<Data> {
match { match {
let fd = SessionFd(fd); let fd = SessionFd(fd);
( (
DrmDevice::new( DrmDevice::new(fd.clone(), true, self.logger.clone()),
fd.clone(), GbmDevice::new(fd),
true,
self.logger.clone(),
),
GbmDevice::new(
fd
),
) )
} } {
{
(Ok(drm), Ok(gbm)) => Some((drm, gbm)), (Ok(drm), Ok(gbm)) => Some((drm, gbm)),
(Err(err), _) => { (Err(err), _) => {
warn!(self.logger, "Skipping device {:?}, because of drm error: {}", device_id, err); warn!(
self.logger,
"Skipping device {:?}, because of drm error: {}", device_id, err
);
None None
}, }
(_, Err(err)) => { (_, Err(err)) => {
// TODO try DumbBuffer allocator in this case // TODO try DumbBuffer allocator in this case
warn!(self.logger, "Skipping device {:?}, because of gbm error: {}", device_id, err); warn!(
self.logger,
"Skipping device {:?}, because of gbm error: {}", device_id, err
);
None None
}, }
} }
}) })
{ {
let egl = match EGLDisplay::new(&gbm, self.logger.clone()) { let egl = match EGLDisplay::new(&gbm, self.logger.clone()) {
Ok(display) => display, Ok(display) => display,
Err(err) => { Err(err) => {
warn!(self.logger, "Skipping device {:?}, because of egl display error: {}", device_id, err); warn!(
self.logger,
"Skipping device {:?}, because of egl display error: {}", device_id, err
);
return; return;
} }
}; };
@ -470,15 +461,17 @@ impl<Data: 'static> UdevHandlerImpl<Data> {
self.logger, self.logger,
"Initializing EGL Hardware Acceleration via {:?}", path "Initializing EGL Hardware Acceleration via {:?}", path
); );
*self.egl_buffer_reader.borrow_mut() = *self.egl_buffer_reader.borrow_mut() = egl.bind_wl_display(&*self.display.borrow()).ok();
egl.bind_wl_display(&*self.display.borrow()).ok();
} }
} }
let context = match EGLContext::new(&egl, self.logger.clone()) { let context = match EGLContext::new(&egl, self.logger.clone()) {
Ok(context) => context, Ok(context) => context,
Err(err) => { Err(err) => {
warn!(self.logger, "Skipping device {:?}, because of egl context error: {}", device_id, err); warn!(
self.logger,
"Skipping device {:?}, because of egl context error: {}", device_id, err
);
return; return;
} }
}; };
@ -498,7 +491,9 @@ impl<Data: 'static> UdevHandlerImpl<Data> {
let pointer_image = { let pointer_image = {
let context = EGLContext::new_shared(&egl, &context, self.logger.clone()).unwrap(); let context = EGLContext::new_shared(&egl, &context, self.logger.clone()).unwrap();
let mut renderer = unsafe { Gles2Renderer::new(context, self.logger.clone()).unwrap() }; let mut renderer = unsafe { Gles2Renderer::new(context, self.logger.clone()).unwrap() };
renderer.import_bitmap(&self.pointer_image).expect("Failed to load pointer") renderer
.import_bitmap(&self.pointer_image)
.expect("Failed to load pointer")
}; };
// Set the handler. // Set the handler.
@ -674,35 +669,34 @@ impl DrmRenderer {
) { ) {
if let Some(surface) = self.backends.borrow().get(&crtc) { if let Some(surface) = self.backends.borrow().get(&crtc) {
let result = DrmRenderer::render_surface( let result = DrmRenderer::render_surface(
&mut *surface.borrow_mut(), &mut *surface.borrow_mut(),
&self.texture_destruction_callback.0, &self.texture_destruction_callback.0,
&self.buffer_utils, &self.buffer_utils,
self.device_id, self.device_id,
crtc, crtc,
&mut *self.window_map.borrow_mut(), &mut *self.window_map.borrow_mut(),
&mut *self.output_map.borrow_mut(), &mut *self.output_map.borrow_mut(),
&self.compositor_token, &self.compositor_token,
&*self.pointer_location.borrow(), &*self.pointer_location.borrow(),
&self.pointer_image, &self.pointer_image,
&*self.dnd_icon.lock().unwrap(), &*self.dnd_icon.lock().unwrap(),
&mut *self.cursor_status.lock().unwrap(), &mut *self.cursor_status.lock().unwrap(),
&self.logger &self.logger,
); );
if let Err(err) = result { if let Err(err) = result {
warn!(self.logger, "Error during rendering: {:?}", err); warn!(self.logger, "Error during rendering: {:?}", err);
let reschedule = let reschedule = match err {
match err { SwapBuffersError::AlreadySwapped => false,
SwapBuffersError::AlreadySwapped => false, SwapBuffersError::TemporaryFailure(err) => !matches!(
SwapBuffersError::TemporaryFailure(err) => { err.downcast_ref::<DrmError>(),
!matches!(err.downcast_ref::<DrmError>(), Some(&DrmError::DeviceInactive)
Some(&DrmError::DeviceInactive) | | Some(&DrmError::Access {
Some(&DrmError::Access { source: drm::SystemError::PermissionDenied,
source: drm::SystemError::PermissionDenied, ..
.. })
})) ),
} SwapBuffersError::ContextLost(err) => panic!("Rendering loop lost: {}", err),
SwapBuffersError::ContextLost(err) => panic!("Rendering loop lost: {}", err), };
};
if reschedule { if reschedule {
debug!(self.logger, "Rescheduling"); debug!(self.logger, "Rescheduling");
@ -809,7 +803,16 @@ impl DrmRenderer {
{ {
if let Some(ref wl_surface) = dnd_icon.as_ref() { if let Some(ref wl_surface) = dnd_icon.as_ref() {
if wl_surface.as_ref().is_alive() { if wl_surface.as_ref().is_alive() {
draw_dnd_icon(surface, device_id, texture_destruction_callback, buffer_utils, wl_surface, (ptr_x, ptr_y), *compositor_token, logger)?; draw_dnd_icon(
surface,
device_id,
texture_destruction_callback,
buffer_utils,
wl_surface,
(ptr_x, ptr_y),
*compositor_token,
logger,
)?;
} }
} }
} }

View File

@ -3,7 +3,7 @@ use std::{cell::RefCell, rc::Rc, sync::atomic::Ordering, time::Duration};
//#[cfg(feature = "egl")] //#[cfg(feature = "egl")]
//use smithay::backend::egl::EGLGraphicsBackend; //use smithay::backend::egl::EGLGraphicsBackend;
use smithay::{ use smithay::{
backend::{renderer::Renderer, input::InputBackend, winit, SwapBuffersError}, backend::{input::InputBackend, renderer::Renderer, winit, SwapBuffersError},
reexports::{ reexports::{
calloop::EventLoop, calloop::EventLoop,
wayland_server::{protocol::wl_output, Display}, wayland_server::{protocol::wl_output, Display},
@ -16,9 +16,9 @@ use smithay::{
use slog::Logger; use slog::Logger;
use crate::state::AnvilState;
use crate::buffer_utils::BufferUtils; use crate::buffer_utils::BufferUtils;
use crate::drawing::*; use crate::drawing::*;
use crate::state::AnvilState;
pub fn run_winit( pub fn run_winit(
display: Rc<RefCell<Display>>, display: Rc<RefCell<Display>>,
@ -111,10 +111,22 @@ pub fn run_winit(
// drawing logic // drawing logic
{ {
renderer.begin().expect("Failed to render frame"); renderer.begin().expect("Failed to render frame");
renderer.clear([0.8, 0.8, 0.9, 1.0]).expect("Failed to clear frame"); renderer
.clear([0.8, 0.8, 0.9, 1.0])
.expect("Failed to clear frame");
// draw the windows // draw the windows
draw_windows(&mut renderer, 0, &texture_send, &buffer_utils, &*state.window_map.borrow(), None, state.ctoken, &log).expect("Failed to renderer windows"); draw_windows(
&mut renderer,
0,
&texture_send,
&buffer_utils,
&*state.window_map.borrow(),
None,
state.ctoken,
&log,
)
.expect("Failed to renderer windows");
let (x, y) = *state.pointer_location.borrow(); let (x, y) = *state.pointer_location.borrow();
// draw the dnd icon if any // draw the dnd icon if any
@ -122,7 +134,17 @@ pub fn run_winit(
let guard = state.dnd_icon.lock().unwrap(); let guard = state.dnd_icon.lock().unwrap();
if let Some(ref surface) = *guard { if let Some(ref surface) = *guard {
if surface.as_ref().is_alive() { if surface.as_ref().is_alive() {
draw_dnd_icon(&mut renderer, 0, &texture_send, &buffer_utils, surface, (x as i32, y as i32), state.ctoken, &log).expect("Failed to render dnd icon"); draw_dnd_icon(
&mut renderer,
0,
&texture_send,
&buffer_utils,
surface,
(x as i32, y as i32),
state.ctoken,
&log,
)
.expect("Failed to render dnd icon");
} }
} }
} }
@ -141,7 +163,17 @@ pub fn run_winit(
// draw as relevant // draw as relevant
if let CursorImageStatus::Image(ref surface) = *guard { if let CursorImageStatus::Image(ref surface) = *guard {
renderer.window().set_cursor_visible(false); renderer.window().set_cursor_visible(false);
draw_cursor(&mut renderer, 0, &texture_send, &buffer_utils, surface, (x as i32, y as i32), state.ctoken, &log).expect("Failed to render cursor"); draw_cursor(
&mut renderer,
0,
&texture_send,
&buffer_utils,
surface,
(x as i32, y as i32),
state.ctoken,
&log,
)
.expect("Failed to render cursor");
} else { } else {
renderer.window().set_cursor_visible(true); renderer.window().set_cursor_visible(true);
} }
@ -153,7 +185,6 @@ pub fn run_winit(
} }
} }
if event_loop if event_loop
.dispatch(Some(Duration::from_millis(16)), &mut state) .dispatch(Some(Duration::from_millis(16)), &mut state)
.is_err() .is_err()

View File

@ -6,28 +6,18 @@ extern crate slog;
use slog::Drain; use slog::Drain;
use smithay::{ use smithay::{
backend::{ backend::{
allocator::{Format, Fourcc, Modifier, Swapchain, Slot, dumb::DumbBuffer}, allocator::{dumb::DumbBuffer, Format, Fourcc, Modifier, Slot, Swapchain},
drm::{ drm::{device_bind, DeviceHandler, DrmDevice, DrmError, DrmSurface},
DrmError,
DrmDevice, DrmSurface,
DeviceHandler,
device_bind,
}
}, },
reexports::{ reexports::{
calloop::EventLoop, calloop::EventLoop,
drm::{ drm::control::{connector::State as ConnectorState, crtc, framebuffer, Device as ControlDevice},
control::{
connector::State as ConnectorState, crtc, framebuffer,
Device as ControlDevice,
},
},
}, },
}; };
use std::{ use std::{
fs::{File, OpenOptions}, fs::{File, OpenOptions},
os::unix::io::{AsRawFd, RawFd},
io::Error as IoError, io::Error as IoError,
os::unix::io::{AsRawFd, RawFd},
rc::Rc, rc::Rc,
sync::Mutex, sync::Mutex,
}; };
@ -54,10 +44,11 @@ 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 fd = FdWrapper { file: Rc::new(options.open("/dev/dri/card0").unwrap()) }; let fd = FdWrapper {
file: Rc::new(options.open("/dev/dri/card0").unwrap()),
};
let mut device = let mut device = DrmDevice::new(fd.clone(), true, log.clone()).unwrap();
DrmDevice::new(fd.clone(), 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 = ControlDevice::resource_handles(&device).unwrap(); let res_handles = ControlDevice::resource_handles(&device).unwrap();
@ -105,7 +96,15 @@ fn main() {
*/ */
let (w, h) = mode.size(); let (w, h) = mode.size();
let allocator = DrmDevice::new(fd, false, log.clone()).unwrap(); let allocator = DrmDevice::new(fd, false, log.clone()).unwrap();
let mut swapchain = Swapchain::new(allocator, w.into(), h.into(), Format { code: Fourcc::Argb8888, modifier: Modifier::Invalid }); let mut swapchain = Swapchain::new(
allocator,
w.into(),
h.into(),
Format {
code: Fourcc::Argb8888,
modifier: Modifier::Invalid,
},
);
let first_buffer: Slot<DumbBuffer<FdWrapper>, _> = swapchain.acquire().unwrap().unwrap(); let first_buffer: Slot<DumbBuffer<FdWrapper>, _> = swapchain.acquire().unwrap().unwrap();
let framebuffer = surface.add_framebuffer(&first_buffer.handle, 32, 32).unwrap(); let framebuffer = surface.add_framebuffer(&first_buffer.handle, 32, 32).unwrap();
first_buffer.set_userdata(framebuffer); first_buffer.set_userdata(framebuffer);
@ -133,7 +132,8 @@ fn main() {
} }
pub struct DrmHandlerImpl { pub struct DrmHandlerImpl {
swapchain: Swapchain<DrmDevice<FdWrapper>, DumbBuffer<FdWrapper>, framebuffer::Handle, DumbBuffer<FdWrapper>>, swapchain:
Swapchain<DrmDevice<FdWrapper>, DumbBuffer<FdWrapper>, framebuffer::Handle, DumbBuffer<FdWrapper>>,
current: Slot<DumbBuffer<FdWrapper>, framebuffer::Handle>, current: Slot<DumbBuffer<FdWrapper>, framebuffer::Handle>,
surface: Rc<DrmSurface<FdWrapper>>, surface: Rc<DrmSurface<FdWrapper>>,
} }

View File

@ -1,6 +1,6 @@
use super::{Buffer, Format, Modifier}; use super::{Buffer, Format, Modifier};
use std::sync::{Arc, Weak};
use std::os::unix::io::RawFd; use std::os::unix::io::RawFd;
use std::sync::{Arc, Weak};
const MAX_PLANES: usize = 4; const MAX_PLANES: usize = 4;
@ -68,9 +68,11 @@ impl Dmabuf {
fds: &[RawFd], fds: &[RawFd],
) -> Option<Dmabuf> { ) -> Option<Dmabuf> {
if offsets.len() < planes if offsets.len() < planes
|| strides.len() < planes || strides.len() < planes
|| fds.len() < planes || fds.len() < planes
|| planes == 0 || planes > MAX_PLANES { || planes == 0
|| planes > MAX_PLANES
{
return None; return None;
} }
@ -82,9 +84,24 @@ impl Dmabuf {
Some(Dmabuf(Arc::new(DmabufInternal { Some(Dmabuf(Arc::new(DmabufInternal {
num_planes: planes, num_planes: planes,
offsets: [*offsets.next().unwrap(), *offsets.next().unwrap(), *offsets.next().unwrap(), *offsets.next().unwrap()], offsets: [
strides: [*strides.next().unwrap(), *strides.next().unwrap(), *strides.next().unwrap(), *strides.next().unwrap()], *offsets.next().unwrap(),
fds: [*fds.next().unwrap(), *fds.next().unwrap(), *fds.next().unwrap(), *fds.next().unwrap()], *offsets.next().unwrap(),
*offsets.next().unwrap(),
*offsets.next().unwrap(),
],
strides: [
*strides.next().unwrap(),
*strides.next().unwrap(),
*strides.next().unwrap(),
*strides.next().unwrap(),
],
fds: [
*fds.next().unwrap(),
*fds.next().unwrap(),
*fds.next().unwrap(),
*fds.next().unwrap(),
],
width: src.width(), width: src.width(),
height: src.height(), height: src.height(),
@ -105,8 +122,7 @@ impl Dmabuf {
} }
pub fn has_modifier(&self) -> bool { pub fn has_modifier(&self) -> bool {
self.0.format.modifier != Modifier::Invalid && self.0.format.modifier != Modifier::Invalid && self.0.format.modifier != Modifier::Linear
self.0.format.modifier != Modifier::Linear
} }
pub fn weak(&self) -> WeakDmabuf { pub fn weak(&self) -> WeakDmabuf {

View File

@ -2,7 +2,7 @@ use std::os::unix::io::AsRawFd;
use std::sync::Arc; use std::sync::Arc;
use drm::buffer::Buffer as DrmBuffer; use drm::buffer::Buffer as DrmBuffer;
use drm::control::{Device as ControlDevice, dumbbuffer::DumbBuffer as Handle}; use drm::control::{dumbbuffer::DumbBuffer as Handle, Device as ControlDevice};
use super::{Allocator, Buffer, Format}; use super::{Allocator, Buffer, Format};
use crate::backend::drm::device::{DrmDevice, DrmDeviceInternal, FdWrapper}; use crate::backend::drm::device::{DrmDevice, DrmDeviceInternal, FdWrapper};
@ -16,8 +16,13 @@ pub struct DumbBuffer<A: AsRawFd + 'static> {
impl<A: AsRawFd + 'static> Allocator<DumbBuffer<A>> for DrmDevice<A> { impl<A: AsRawFd + 'static> Allocator<DumbBuffer<A>> for DrmDevice<A> {
type Error = drm::SystemError; type Error = drm::SystemError;
fn create_buffer(&mut self, width: u32, height: u32, format: Format) -> Result<DumbBuffer<A>, Self::Error> { fn create_buffer(
let handle = self.create_dumb_buffer((width, height), format.code, 32/* TODO */)?; &mut self,
width: u32,
height: u32,
format: Format,
) -> Result<DumbBuffer<A>, Self::Error> {
let handle = self.create_dumb_buffer((width, height), format.code, 32 /* TODO */)?;
Ok(DumbBuffer { Ok(DumbBuffer {
fd: match &*self.internal { fd: match &*self.internal {

View File

@ -1,6 +1,6 @@
use super::{dmabuf::Dmabuf, Allocator, Buffer, Format, Fourcc, Modifier};
use gbm::{BufferObject as GbmBuffer, BufferObjectFlags, Device as GbmDevice};
use std::os::unix::io::AsRawFd; use std::os::unix::io::AsRawFd;
use gbm::{BufferObject as GbmBuffer, Device as GbmDevice, BufferObjectFlags};
use super::{Allocator, Buffer, Format, Fourcc, Modifier, dmabuf::Dmabuf};
impl<A: AsRawFd + 'static, T> Allocator<GbmBuffer<T>> for GbmDevice<A> { impl<A: AsRawFd + 'static, T> Allocator<GbmBuffer<T>> for GbmDevice<A> {
type Error = std::io::Error; type Error = std::io::Error;
@ -13,7 +13,12 @@ impl<A: AsRawFd + 'static, T> Allocator<GbmBuffer<T>> for GbmDevice<A> {
} }
self.create_buffer_object(width, height, format.code, usage) self.create_buffer_object(width, height, format.code, usage)
} else { } else {
self.create_buffer_object_with_modifiers(width, height, format.code, Some(format.modifier).into_iter()) self.create_buffer_object_with_modifiers(
width,
height,
format.code,
Some(format.modifier).into_iter(),
)
} }
} }
} }
@ -77,15 +82,23 @@ impl<T> std::convert::TryFrom<GbmBuffer<T>> for Dmabuf {
return Err(GbmConvertError::InvalidFD); return Err(GbmConvertError::InvalidFD);
} }
let offsets = (0i32..planes).map(|i| buf.offset(i)).collect::<Result<Vec<u32>, gbm::DeviceDestroyedError>>()?; let offsets = (0i32..planes)
let strides = (0i32..planes).map(|i| buf.stride_for_plane(i)).collect::<Result<Vec<u32>, gbm::DeviceDestroyedError>>()?; .map(|i| buf.offset(i))
.collect::<Result<Vec<u32>, gbm::DeviceDestroyedError>>()?;
let strides = (0i32..planes)
.map(|i| buf.stride_for_plane(i))
.collect::<Result<Vec<u32>, gbm::DeviceDestroyedError>>()?;
Ok(Dmabuf::new(buf, planes as usize, &offsets, &strides, &fds).unwrap()) Ok(Dmabuf::new(buf, planes as usize, &offsets, &strides, &fds).unwrap())
} }
} }
impl Dmabuf { impl Dmabuf {
pub fn import<A: AsRawFd + 'static, T>(&self, gbm: &GbmDevice<A>, usage: BufferObjectFlags) -> std::io::Result<GbmBuffer<T>> { pub fn import<A: AsRawFd + 'static, T>(
&self,
gbm: &GbmDevice<A>,
usage: BufferObjectFlags,
) -> std::io::Result<GbmBuffer<T>> {
let buf = &*self.0; let buf = &*self.0;
if self.has_modifier() || buf.num_planes > 1 || buf.offsets[0] != 0 { if self.has_modifier() || buf.num_planes > 1 || buf.offsets[0] != 0 {
gbm.import_buffer_object_from_dma_buf_with_modifiers( gbm.import_buffer_object_from_dma_buf_with_modifiers(
@ -106,7 +119,11 @@ impl Dmabuf {
buf.height, buf.height,
buf.strides[0], buf.strides[0],
buf.format.code, buf.format.code,
if buf.format.modifier == Modifier::Linear { usage | BufferObjectFlags::LINEAR } else { usage }, if buf.format.modifier == Modifier::Linear {
usage | BufferObjectFlags::LINEAR
} else {
usage
},
) )
} }
} }

View File

@ -1,18 +1,23 @@
#[cfg(feature = "backend_gbm")] pub mod dmabuf;
pub mod gbm;
#[cfg(feature = "backend_drm")] #[cfg(feature = "backend_drm")]
pub mod dumb; pub mod dumb;
pub mod dmabuf; #[cfg(feature = "backend_gbm")]
pub mod gbm;
mod swapchain; mod swapchain;
pub use swapchain::{Slot, Swapchain, SwapchainError}; pub use swapchain::{Slot, Swapchain, SwapchainError};
pub use drm_fourcc::{DrmFormat as Format, DrmFourcc as Fourcc, DrmModifier as Modifier, DrmVendor as Vendor, UnrecognizedFourcc, UnrecognizedVendor}; pub use drm_fourcc::{
DrmFormat as Format, DrmFourcc as Fourcc, DrmModifier as Modifier, DrmVendor as Vendor,
UnrecognizedFourcc, UnrecognizedVendor,
};
pub trait Buffer { pub trait Buffer {
fn width(&self) -> u32; fn width(&self) -> u32;
fn height(&self) -> u32; fn height(&self) -> u32;
fn size(&self) -> (u32, u32) { (self.width(), self.height()) } fn size(&self) -> (u32, u32) {
(self.width(), self.height())
}
fn format(&self) -> Format; fn format(&self) -> Format;
} }

View File

@ -1,6 +1,9 @@
use std::convert::TryInto; use std::convert::TryInto;
use std::sync::{Arc, Mutex, MutexGuard, atomic::{AtomicBool, Ordering}};
use std::ops::Deref; use std::ops::Deref;
use std::sync::{
atomic::{AtomicBool, Ordering},
Arc, Mutex, MutexGuard,
};
use crate::backend::allocator::{Allocator, Buffer, Format}; use crate::backend::allocator::{Allocator, Buffer, Format};
@ -84,12 +87,12 @@ where
impl<A, B, D, U, E1, E2> Swapchain<A, B, U, D> impl<A, B, D, U, E1, E2> Swapchain<A, B, U, D>
where where
A: Allocator<B, Error=E1>, A: Allocator<B, Error = E1>,
B: Buffer + TryInto<D, Error=E2>, B: Buffer + TryInto<D, Error = E2>,
D: Buffer, D: Buffer,
E1: std::error::Error + 'static, E1: std::error::Error + 'static,
E2: std::error::Error + 'static, E2: std::error::Error + 'static,
U: 'static U: 'static,
{ {
pub fn new(allocator: A, width: u32, height: u32, format: Format) -> Swapchain<A, B, U, D> { pub fn new(allocator: A, width: u32, height: u32, format: Format) -> Swapchain<A, B, U, D> {
Swapchain { Swapchain {
@ -107,8 +110,10 @@ where
if free_slot.buffer.is_none() { if free_slot.buffer.is_none() {
free_slot.buffer = Arc::new(Some( free_slot.buffer = Arc::new(Some(
self.allocator self.allocator
.create_buffer(self.width, self.height, self.format).map_err(SwapchainError::AllocationError)? .create_buffer(self.width, self.height, self.format)
.try_into().map_err(SwapchainError::ConversionError)? .map_err(SwapchainError::AllocationError)?
.try_into()
.map_err(SwapchainError::ConversionError)?,
)); ));
} }
assert!(free_slot.buffer.is_some()); assert!(free_slot.buffer.is_some());
@ -116,7 +121,6 @@ where
if !free_slot.acquired.swap(true, Ordering::SeqCst) { if !free_slot.acquired.swap(true, Ordering::SeqCst) {
return Ok(Some(free_slot.clone())); return Ok(Some(free_slot.clone()));
} }
} }
// no free slots // no free slots

View File

@ -1,9 +1,15 @@
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::{Arc, atomic::{AtomicBool, Ordering}};
use std::os::unix::io::AsRawFd; use std::os::unix::io::AsRawFd;
use std::sync::{
atomic::{AtomicBool, Ordering},
Arc,
};
use drm::control::atomic::AtomicModeReq; use drm::control::atomic::AtomicModeReq;
use drm::control::{Device as ControlDevice, AtomicCommitFlags, PropertyValueSet, ResourceHandle, crtc, connector, framebuffer, plane, property}; use drm::control::{
connector, crtc, framebuffer, plane, property, AtomicCommitFlags, Device as ControlDevice,
PropertyValueSet, ResourceHandle,
};
use super::{DevPath, FdWrapper}; use super::{DevPath, FdWrapper};
use crate::backend::drm::error::Error; use crate::backend::drm::error::Error;
@ -31,8 +37,12 @@ pub struct AtomicDrmDevice<A: AsRawFd + 'static> {
} }
impl<A: AsRawFd + 'static> AtomicDrmDevice<A> { impl<A: AsRawFd + 'static> AtomicDrmDevice<A> {
pub fn new(fd: Arc<FdWrapper<A>>, active: Arc<AtomicBool>, disable_connectors: bool, logger: ::slog::Logger) -> Result<Self, Error> pub fn new(
{ fd: Arc<FdWrapper<A>>,
active: Arc<AtomicBool>,
disable_connectors: bool,
logger: ::slog::Logger,
) -> Result<Self, Error> {
let mut dev = AtomicDrmDevice { let mut dev = AtomicDrmDevice {
fd, fd,
active, active,
@ -42,17 +52,16 @@ impl<A: AsRawFd + 'static> AtomicDrmDevice<A> {
}; };
// Enumerate (and save) the current device state. // Enumerate (and save) the current device state.
let res_handles = dev.fd.resource_handles() let res_handles = dev.fd.resource_handles().map_err(|source| Error::Access {
.map_err(|source| Error::Access { errmsg: "Error loading drm resources",
errmsg: "Error loading drm resources", dev: dev.fd.dev_path(),
dev: dev.fd.dev_path(), source,
source, })?;
})?;
let plane_handles = dev.fd.plane_handles().map_err(|source| Error::Access { let plane_handles = dev.fd.plane_handles().map_err(|source| Error::Access {
errmsg: "Error loading planes", errmsg: "Error loading planes",
dev: dev.fd.dev_path(), dev: dev.fd.dev_path(),
source source,
})?; })?;
let planes = plane_handles.planes(); let planes = plane_handles.planes();
@ -167,12 +176,11 @@ impl<A: AsRawFd + 'static> AtomicDrmDevice<A> {
// on top of the state the previous compositor left the device in. // on top of the state the previous compositor left the device in.
// This is because we do commits per surface and not per device, so we do a global // This is because we do commits per surface and not per device, so we do a global
// commit here, to fix any conflicts. // commit here, to fix any conflicts.
let res_handles = self.fd.resource_handles() let res_handles = self.fd.resource_handles().map_err(|source| Error::Access {
.map_err(|source| Error::Access { errmsg: "Error loading drm resources",
errmsg: "Error loading drm resources", dev: self.fd.dev_path(),
dev: self.fd.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();
@ -206,7 +214,8 @@ impl<A: AsRawFd + 'static> AtomicDrmDevice<A> {
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));
} }
self.fd.atomic_commit(&[AtomicCommitFlags::AllowModeset], req) self.fd
.atomic_commit(&[AtomicCommitFlags::AllowModeset], req)
.map_err(|source| Error::Access { .map_err(|source| Error::Access {
errmsg: "Failed to disable connectors", errmsg: "Failed to disable connectors",
dev: self.fd.dev_path(), dev: self.fd.dev_path(),

View File

@ -1,8 +1,11 @@
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::{Arc, atomic::{AtomicBool, Ordering}};
use std::os::unix::io::AsRawFd; use std::os::unix::io::AsRawFd;
use std::sync::{
atomic::{AtomicBool, Ordering},
Arc,
};
use drm::control::{Device as ControlDevice, crtc, connector}; use drm::control::{connector, crtc, Device as ControlDevice};
use super::{DevPath, FdWrapper}; use super::{DevPath, FdWrapper};
use crate::backend::drm::error::Error; use crate::backend::drm::error::Error;
@ -15,8 +18,12 @@ pub struct LegacyDrmDevice<A: AsRawFd + 'static> {
} }
impl<A: AsRawFd + 'static> LegacyDrmDevice<A> { impl<A: AsRawFd + 'static> LegacyDrmDevice<A> {
pub fn new(fd: Arc<FdWrapper<A>>, active: Arc<AtomicBool>, disable_connectors: bool, logger: slog::Logger) -> Result<Self, Error> pub fn new(
{ fd: Arc<FdWrapper<A>>,
active: Arc<AtomicBool>,
disable_connectors: bool,
logger: slog::Logger,
) -> Result<Self, Error> {
let mut dev = LegacyDrmDevice { let mut dev = LegacyDrmDevice {
fd, fd,
active, active,
@ -27,12 +34,11 @@ impl<A: AsRawFd + 'static> LegacyDrmDevice<A> {
// Enumerate (and save) the current device state. // Enumerate (and save) the current device state.
// We need to keep the previous device configuration to restore the state later, // We need to keep the previous device configuration to restore the state later,
// so we query everything, that we can set. // so we query everything, that we can set.
let res_handles = dev.fd.resource_handles() let res_handles = dev.fd.resource_handles().map_err(|source| Error::Access {
.map_err(|source| Error::Access { errmsg: "Error loading drm resources",
errmsg: "Error loading drm resources", dev: dev.fd.dev_path(),
dev: dev.fd.dev_path(), source,
source, })?;
})?;
for &con in res_handles.connectors() { for &con in res_handles.connectors() {
let con_info = dev.fd.get_connector(con).map_err(|source| Error::Access { let con_info = dev.fd.get_connector(con).map_err(|source| Error::Access {
errmsg: "Error loading connector info", errmsg: "Error loading connector info",
@ -60,7 +66,6 @@ impl<A: AsRawFd + 'static> LegacyDrmDevice<A> {
} }
} }
// If the user does not explicitly requests us to skip this, // If the user does not explicitly requests us to skip this,
// we clear out the complete connector<->crtc mapping on device creation. // we clear out the complete connector<->crtc mapping on device creation.
// //
@ -83,17 +88,18 @@ impl<A: AsRawFd + 'static> LegacyDrmDevice<A> {
})?; })?;
set_connector_state(&*self.fd, res_handles.connectors().iter().copied(), false)?; set_connector_state(&*self.fd, res_handles.connectors().iter().copied(), false)?;
for crtc in res_handles.crtcs() { for crtc in res_handles.crtcs() {
// null commit (necessary to trigger removal on the kernel side with the legacy api.) // null commit (necessary to trigger removal on the kernel side with the legacy api.)
self.fd.set_crtc(*crtc, None, (0, 0), &[], None) self.fd
.map_err(|source| Error::Access { .set_crtc(*crtc, None, (0, 0), &[], None)
errmsg: "Error setting crtc", .map_err(|source| Error::Access {
dev: self.fd.dev_path(), errmsg: "Error setting crtc",
source, dev: self.fd.dev_path(),
})?; source,
} })?;
}
Ok(()) Ok(())
} }
} }
@ -127,38 +133,32 @@ pub fn set_connector_state<D>(
enabled: bool, enabled: bool,
) -> Result<(), Error> ) -> Result<(), Error>
where where
D: ControlDevice D: ControlDevice,
{ {
// for every connector... // for every connector...
for conn in connectors { for conn in connectors {
let info = dev let info = dev.get_connector(conn).map_err(|source| Error::Access {
.get_connector(conn) errmsg: "Failed to get connector infos",
.map_err(|source| Error::Access { dev: dev.dev_path(),
errmsg: "Failed to get connector infos", source,
dev: dev.dev_path(), })?;
source,
})?;
// that is currently connected ... // that is currently connected ...
if info.state() == connector::State::Connected { if info.state() == connector::State::Connected {
// get a list of it's properties. // get a list of it's properties.
let props = dev let props = dev.get_properties(conn).map_err(|source| Error::Access {
.get_properties(conn) errmsg: "Failed to get properties for connector",
.map_err(|source| Error::Access { dev: dev.dev_path(),
errmsg: "Failed to get properties for connector", source,
dev: dev.dev_path(), })?;
source,
})?;
let (handles, _) = props.as_props_and_values(); let (handles, _) = props.as_props_and_values();
// for every handle ... // for every handle ...
for handle in handles { for handle in handles {
// get information of that property // get information of that property
let info = dev let info = dev.get_property(*handle).map_err(|source| Error::Access {
.get_property(*handle) errmsg: "Failed to get property of connector",
.map_err(|source| Error::Access { dev: dev.dev_path(),
errmsg: "Failed to get property of connector", source,
dev: dev.dev_path(), })?;
source,
})?;
// to find out, if we got the handle of the "DPMS" property ... // to find out, if we got the handle of the "DPMS" property ...
if info.name().to_str().map(|x| x == "DPMS").unwrap_or(false) { if info.name().to_str().map(|x| x == "DPMS").unwrap_or(false) {
// so we can use that to turn on / off the connector // so we can use that to turn on / off the connector

View File

@ -1,24 +1,27 @@
use std::rc::Rc;
use std::cell::RefCell; use std::cell::RefCell;
use std::collections::HashSet; use std::collections::HashSet;
use std::convert::TryFrom; use std::convert::TryFrom;
use std::sync::{Arc, atomic::AtomicBool};
use std::path::PathBuf;
use std::os::unix::io::{AsRawFd, RawFd}; use std::os::unix::io::{AsRawFd, RawFd};
use std::path::PathBuf;
use std::rc::Rc;
use std::sync::{atomic::AtomicBool, Arc};
use calloop::{generic::Generic, InsertError, LoopHandle, Source}; use calloop::{generic::Generic, InsertError, LoopHandle, Source};
use drm::{Device as BasicDevice, ClientCapability, DriverCapability}; use drm::control::{
use drm::control::{ResourceHandles, PlaneResourceHandles, Device as ControlDevice, Event, Mode, PlaneType, crtc, plane, connector, property}; connector, crtc, plane, property, Device as ControlDevice, Event, Mode, PlaneResourceHandles, PlaneType,
ResourceHandles,
};
use drm::{ClientCapability, Device as BasicDevice, DriverCapability};
use nix::libc::dev_t; use nix::libc::dev_t;
use nix::sys::stat::fstat; use nix::sys::stat::fstat;
pub(super) mod atomic; pub(super) mod atomic;
pub(super) mod legacy; pub(super) mod legacy;
use super::error::Error;
use super::surface::{atomic::AtomicDrmSurface, legacy::LegacyDrmSurface, DrmSurface, DrmSurfaceInternal};
use crate::backend::allocator::{Format, Fourcc, Modifier};
use atomic::AtomicDrmDevice; use atomic::AtomicDrmDevice;
use legacy::LegacyDrmDevice; use legacy::LegacyDrmDevice;
use super::surface::{DrmSurface, DrmSurfaceInternal, atomic::AtomicDrmSurface, legacy::LegacyDrmSurface};
use super::error::Error;
use crate::backend::allocator::{Fourcc, Format, Modifier};
pub struct DrmDevice<A: AsRawFd + 'static> { pub struct DrmDevice<A: AsRawFd + 'static> {
pub(super) dev_id: dev_t, pub(super) dev_id: dev_t,
@ -92,9 +95,7 @@ impl<A: AsRawFd + 'static> DrmDevice<A> {
let log = crate::slog_or_fallback(logger).new(o!("smithay_module" => "backend_drm")); let log = crate::slog_or_fallback(logger).new(o!("smithay_module" => "backend_drm"));
info!(log, "DrmDevice initializing"); info!(log, "DrmDevice initializing");
let dev_id = fstat(fd.as_raw_fd()) let dev_id = fstat(fd.as_raw_fd()).map_err(Error::UnableToGetDeviceId)?.st_rdev;
.map_err(Error::UnableToGetDeviceId)?
.st_rdev;
let active = Arc::new(AtomicBool::new(true)); let active = Arc::new(AtomicBool::new(true));
let dev = Arc::new({ let dev = Arc::new({
let mut dev = FdWrapper { let mut dev = FdWrapper {
@ -115,7 +116,9 @@ impl<A: AsRawFd + 'static> DrmDevice<A> {
dev dev
}); });
let has_universal_planes = dev.set_client_capability(ClientCapability::UniversalPlanes, true).is_ok(); let has_universal_planes = dev
.set_client_capability(ClientCapability::UniversalPlanes, true)
.is_ok();
let resources = dev.resource_handles().map_err(|source| Error::Access { let resources = dev.resource_handles().map_err(|source| Error::Access {
errmsg: "Error loading resource handles", errmsg: "Error loading resource handles",
dev: dev.dev_path(), dev: dev.dev_path(),
@ -126,7 +129,12 @@ impl<A: AsRawFd + 'static> DrmDevice<A> {
dev: dev.dev_path(), dev: dev.dev_path(),
source, source,
})?; })?;
let internal = Arc::new(DrmDevice::create_internal(dev, active, disable_connectors, log.clone())?); let internal = Arc::new(DrmDevice::create_internal(
dev,
active,
disable_connectors,
log.clone(),
)?);
Ok(DrmDevice { Ok(DrmDevice {
dev_id, dev_id,
@ -141,7 +149,12 @@ impl<A: AsRawFd + 'static> DrmDevice<A> {
}) })
} }
fn create_internal(dev: Arc<FdWrapper<A>>, active: Arc<AtomicBool>, disable_connectors: bool, log: ::slog::Logger) -> Result<DrmDeviceInternal<A>, Error> { fn create_internal(
dev: Arc<FdWrapper<A>>,
active: Arc<AtomicBool>,
disable_connectors: bool,
log: ::slog::Logger,
) -> Result<DrmDeviceInternal<A>, Error> {
let force_legacy = std::env::var("SMITHAY_USE_LEGACY") let force_legacy = std::env::var("SMITHAY_USE_LEGACY")
.map(|x| { .map(|x| {
x == "1" || x.to_lowercase() == "true" || x.to_lowercase() == "yes" || x.to_lowercase() == "y" x == "1" || x.to_lowercase() == "true" || x.to_lowercase() == "yes" || x.to_lowercase() == "y"
@ -152,12 +165,14 @@ impl<A: AsRawFd + 'static> DrmDevice<A> {
info!(log, "SMITHAY_USE_LEGACY is set. Forcing LegacyDrmDevice."); info!(log, "SMITHAY_USE_LEGACY is set. Forcing LegacyDrmDevice.");
}; };
Ok(if dev.set_client_capability(ClientCapability::Atomic, true).is_ok() && !force_legacy { Ok(
DrmDeviceInternal::Atomic(AtomicDrmDevice::new(dev, active, disable_connectors, log)?) if dev.set_client_capability(ClientCapability::Atomic, true).is_ok() && !force_legacy {
} else { DrmDeviceInternal::Atomic(AtomicDrmDevice::new(dev, active, disable_connectors, log)?)
info!(log, "Falling back to LegacyDrmDevice"); } else {
DrmDeviceInternal::Legacy(LegacyDrmDevice::new(dev, active, disable_connectors, log)?) info!(log, "Falling back to LegacyDrmDevice");
}) DrmDeviceInternal::Legacy(LegacyDrmDevice::new(dev, active, disable_connectors, log)?)
},
)
} }
pub fn process_events(&mut self) { pub fn process_events(&mut self) {
@ -224,9 +239,15 @@ impl<A: AsRawFd + 'static> DrmDevice<A> {
let filter = info.possible_crtcs(); let filter = info.possible_crtcs();
if self.resources.filter_crtcs(filter).contains(crtc) { if self.resources.filter_crtcs(filter).contains(crtc) {
match self.plane_type(*plane)? { match self.plane_type(*plane)? {
PlaneType::Primary => { primary = Some(*plane); }, PlaneType::Primary => {
PlaneType::Cursor => { cursor = Some(*plane); }, primary = Some(*plane);
PlaneType::Overlay => { overlay.push(*plane); }, }
PlaneType::Cursor => {
cursor = Some(*plane);
}
PlaneType::Overlay => {
overlay.push(*plane);
}
}; };
} }
} }
@ -234,7 +255,11 @@ impl<A: AsRawFd + 'static> DrmDevice<A> {
Ok(Planes { Ok(Planes {
primary: primary.expect("Crtc has no primary plane"), primary: primary.expect("Crtc has no primary plane"),
cursor, cursor,
overlay: if self.has_universal_planes { Some(overlay) } else { None }, overlay: if self.has_universal_planes {
Some(overlay)
} else {
None
},
}) })
} }
@ -262,7 +287,13 @@ impl<A: AsRawFd + 'static> DrmDevice<A> {
unreachable!() unreachable!()
} }
pub fn create_surface(&self, crtc: crtc::Handle, plane: plane::Handle, mode: Mode, connectors: &[connector::Handle]) -> Result<DrmSurface<A>, Error> { pub fn create_surface(
&self,
crtc: crtc::Handle,
plane: plane::Handle,
mode: Mode,
connectors: &[connector::Handle],
) -> Result<DrmSurface<A>, Error> {
if connectors.is_empty() { if connectors.is_empty() {
return Err(Error::SurfaceWithoutConnectors(crtc)); return Err(Error::SurfaceWithoutConnectors(crtc));
} }
@ -270,7 +301,7 @@ impl<A: AsRawFd + 'static> DrmDevice<A> {
let info = self.get_plane(plane).map_err(|source| Error::Access { let info = self.get_plane(plane).map_err(|source| Error::Access {
errmsg: "Failed to get plane info", errmsg: "Failed to get plane info",
dev: self.dev_path(), dev: self.dev_path(),
source source,
})?; })?;
let filter = info.possible_crtcs(); let filter = info.possible_crtcs();
if !self.resources.filter_crtcs(filter).contains(&crtc) { if !self.resources.filter_crtcs(filter).contains(&crtc) {
@ -288,13 +319,29 @@ impl<A: AsRawFd + 'static> DrmDevice<A> {
_ => unreachable!(), _ => unreachable!(),
}; };
DrmSurfaceInternal::Atomic(AtomicDrmSurface::new(self.internal.clone(), active, crtc, plane, mapping, mode, connectors, self.logger.clone())?) DrmSurfaceInternal::Atomic(AtomicDrmSurface::new(
self.internal.clone(),
active,
crtc,
plane,
mapping,
mode,
connectors,
self.logger.clone(),
)?)
} else { } else {
if self.plane_type(plane)? != PlaneType::Primary { if self.plane_type(plane)? != PlaneType::Primary {
return Err(Error::NonPrimaryPlane(plane)); return Err(Error::NonPrimaryPlane(plane));
} }
DrmSurfaceInternal::Legacy(LegacyDrmSurface::new(self.internal.clone(), active, crtc, mode, connectors, self.logger.clone())?) DrmSurfaceInternal::Legacy(LegacyDrmSurface::new(
self.internal.clone(),
active,
crtc,
mode,
connectors,
self.logger.clone(),
)?)
}; };
// get plane formats // get plane formats
@ -304,18 +351,25 @@ impl<A: AsRawFd + 'static> DrmDevice<A> {
source, source,
})?; })?;
let mut formats = HashSet::new(); let mut formats = HashSet::new();
for code in plane_info.formats().iter().flat_map(|x| Fourcc::try_from(*x).ok()) { for code in plane_info
.formats()
.iter()
.flat_map(|x| Fourcc::try_from(*x).ok())
{
formats.insert(Format { formats.insert(Format {
code, code,
modifier: Modifier::Invalid, modifier: Modifier::Invalid,
}); });
} }
if let (Ok(1), &DrmSurfaceInternal::Atomic(ref surf)) = (self.get_driver_capability(DriverCapability::AddFB2Modifiers), &internal) { if let (Ok(1), &DrmSurfaceInternal::Atomic(ref surf)) = (
self.get_driver_capability(DriverCapability::AddFB2Modifiers),
&internal,
) {
let set = self.get_properties(plane).map_err(|source| Error::Access { let set = self.get_properties(plane).map_err(|source| Error::Access {
errmsg: "Failed to query properties", errmsg: "Failed to query properties",
dev: self.dev_path(), dev: self.dev_path(),
source source,
})?; })?;
if let Ok(prop) = surf.plane_prop_handle(plane, "IN_FORMATS") { if let Ok(prop) = surf.plane_prop_handle(plane, "IN_FORMATS") {
let prop_info = self.get_property(prop).map_err(|source| Error::Access { let prop_info = self.get_property(prop).map_err(|source| Error::Access {
@ -324,7 +378,11 @@ impl<A: AsRawFd + 'static> DrmDevice<A> {
source, source,
})?; })?;
let (handles, raw_values) = set.as_props_and_values(); let (handles, raw_values) = set.as_props_and_values();
let raw_value = raw_values[handles.iter().enumerate().find_map(|(i, handle)| if *handle == prop { Some(i) } else { None }).unwrap()]; let raw_value = raw_values[handles
.iter()
.enumerate()
.find_map(|(i, handle)| if *handle == prop { Some(i) } else { None })
.unwrap()];
if let property::Value::Blob(blob) = prop_info.value_type().convert_value(raw_value) { if let property::Value::Blob(blob) = prop_info.value_type().convert_value(raw_value) {
let data = self.get_property_blob(blob).map_err(|source| Error::Access { let data = self.get_property_blob(blob).map_err(|source| Error::Access {
errmsg: "Failed to query property blob data", errmsg: "Failed to query property blob data",
@ -337,8 +395,14 @@ impl<A: AsRawFd + 'static> DrmDevice<A> {
let fmt_mod_blob_ptr = data.as_ptr() as *const drm_ffi::drm_format_modifier_blob; let fmt_mod_blob_ptr = data.as_ptr() as *const drm_ffi::drm_format_modifier_blob;
let fmt_mod_blob = &*fmt_mod_blob_ptr; let fmt_mod_blob = &*fmt_mod_blob_ptr;
let formats_ptr: *const u32 = fmt_mod_blob_ptr.cast::<u8>().offset(fmt_mod_blob.formats_offset as isize) as *const _; let formats_ptr: *const u32 = fmt_mod_blob_ptr
let modifiers_ptr: *const drm_ffi::drm_format_modifier = fmt_mod_blob_ptr.cast::<u8>().offset(fmt_mod_blob.modifiers_offset as isize) as *const _; .cast::<u8>()
.offset(fmt_mod_blob.formats_offset as isize)
as *const _;
let modifiers_ptr: *const drm_ffi::drm_format_modifier = fmt_mod_blob_ptr
.cast::<u8>()
.offset(fmt_mod_blob.modifiers_offset as isize)
as *const _;
let formats_ptr = formats_ptr as *const u32; let formats_ptr = formats_ptr as *const u32;
let modifiers_ptr = modifiers_ptr as *const drm_ffi::drm_format_modifier; let modifiers_ptr = modifiers_ptr as *const drm_ffi::drm_format_modifier;
@ -346,13 +410,15 @@ impl<A: AsRawFd + 'static> DrmDevice<A> {
let mod_info = modifiers_ptr.offset(i as isize).read_unaligned(); let mod_info = modifiers_ptr.offset(i as isize).read_unaligned();
for j in 0..64 { for j in 0..64 {
if mod_info.formats & (1u64 << j) != 0 { if mod_info.formats & (1u64 << j) != 0 {
let code = Fourcc::try_from(formats_ptr.offset((j + mod_info.offset) as isize).read_unaligned()).ok(); let code = Fourcc::try_from(
formats_ptr
.offset((j + mod_info.offset) as isize)
.read_unaligned(),
)
.ok();
let modifier = Modifier::from(mod_info.modifier); let modifier = Modifier::from(mod_info.modifier);
if let Some(code) = code { if let Some(code) = code {
formats.insert(Format { formats.insert(Format { code, modifier });
code,
modifier,
});
} }
} }
} }
@ -377,7 +443,10 @@ impl<A: AsRawFd + 'static> DrmDevice<A> {
}); });
} }
info!(self.logger, "Supported scan-out formats for plane ({:?}): {:?}", plane, formats); info!(
self.logger,
"Supported scan-out formats for plane ({:?}): {:?}", plane, formats
);
Ok(DrmSurface { Ok(DrmSurface {
crtc, crtc,

View File

@ -1,7 +1,7 @@
//use crate::backend::graphics::SwapBuffersError; //use crate::backend::graphics::SwapBuffersError;
use crate::backend::SwapBuffersError;
use drm::control::{connector, crtc, plane, Mode, RawResourceHandle}; use drm::control::{connector, crtc, plane, Mode, RawResourceHandle};
use std::path::PathBuf; use std::path::PathBuf;
use crate::backend::SwapBuffersError;
/// Errors thrown by the [`DrmDevice`](::backend::drm::DrmDevice) /// Errors thrown by the [`DrmDevice`](::backend::drm::DrmDevice)
/// and the [`DrmSurface`](::backend::drm::DrmSurface). /// and the [`DrmSurface`](::backend::drm::DrmSurface).
@ -66,14 +66,15 @@ impl From<Error> for SwapBuffersError {
x @ Error::DeviceInactive => SwapBuffersError::TemporaryFailure(Box::new(x)), x @ Error::DeviceInactive => SwapBuffersError::TemporaryFailure(Box::new(x)),
Error::Access { Error::Access {
errmsg, dev, source, .. errmsg, dev, source, ..
} if matches!(source, } if matches!(
drm::SystemError::PermissionDenied | source,
drm::SystemError::Unknown { drm::SystemError::PermissionDenied
errno: nix::errno::Errno::EBUSY, | drm::SystemError::Unknown {
} | errno: nix::errno::Errno::EBUSY,
drm::SystemError::Unknown { }
errno: nix::errno::Errno::EINTR, | drm::SystemError::Unknown {
} errno: nix::errno::Errno::EINTR,
}
) => ) =>
{ {
SwapBuffersError::TemporaryFailure(Box::new(Error::Access { errmsg, dev, source })) SwapBuffersError::TemporaryFailure(Box::new(Error::Access { errmsg, dev, source }))

View File

@ -1,11 +1,11 @@
pub(crate) mod device; pub(crate) mod device;
pub(self) mod surface;
pub(self) mod error; pub(self) mod error;
pub(self) mod session;
mod render; mod render;
pub(self) mod session;
pub(self) mod surface;
pub use device::{DrmDevice, DrmSource, DeviceHandler, device_bind, Planes, DevPath}; pub use device::{device_bind, DevPath, DeviceHandler, DrmDevice, DrmSource, Planes};
pub use surface::DrmSurface;
pub use error::Error as DrmError; pub use error::Error as DrmError;
pub use session::DrmDeviceObserver;
pub use render::{DrmRenderSurface, Error as DrmRenderError}; pub use render::{DrmRenderSurface, Error as DrmRenderError};
pub use session::DrmDeviceObserver;
pub use surface::DrmSurface;

View File

@ -1,20 +1,22 @@
use std::os::unix::io::AsRawFd;
use std::collections::HashSet; use std::collections::HashSet;
use std::convert::TryInto; use std::convert::TryInto;
use std::os::unix::io::AsRawFd;
use std::sync::Arc; use std::sync::Arc;
use cgmath::Matrix3; use cgmath::Matrix3;
use drm::buffer::PlanarBuffer; use drm::buffer::PlanarBuffer;
use drm::control::{Device, Mode, crtc, connector, framebuffer, plane}; use drm::control::{connector, crtc, framebuffer, plane, Device, Mode};
use gbm::{Device as GbmDevice, BufferObject, BufferObjectFlags}; use gbm::{BufferObject, BufferObjectFlags, Device as GbmDevice};
#[cfg(feature = "wayland_frontend")] #[cfg(feature = "wayland_frontend")]
use wayland_server::protocol::{wl_shm, wl_buffer}; use wayland_server::protocol::{wl_buffer, wl_shm};
use crate::backend::SwapBuffersError; use super::{device::DevPath, surface::DrmSurfaceInternal, DrmError, DrmSurface};
use crate::backend::allocator::{Allocator, Format, Fourcc, Modifier, Swapchain, SwapchainError, Slot, Buffer, dmabuf::Dmabuf}; use crate::backend::allocator::{
use crate::backend::renderer::{Renderer, Bind, Transform, Texture}; dmabuf::Dmabuf, Allocator, Buffer, Format, Fourcc, Modifier, Slot, Swapchain, SwapchainError,
};
use crate::backend::egl::EGLBuffer; use crate::backend::egl::EGLBuffer;
use super::{DrmSurface, DrmError, device::DevPath, surface::DrmSurfaceInternal}; use crate::backend::renderer::{Bind, Renderer, Texture, Transform};
use crate::backend::SwapBuffersError;
pub struct DrmRenderSurface< pub struct DrmRenderSurface<
D: AsRawFd + 'static, D: AsRawFd + 'static,
@ -33,16 +35,20 @@ pub struct DrmRenderSurface<
impl<D, A, B, R, E1, E2, E3> DrmRenderSurface<D, A, R, B> impl<D, A, B, R, E1, E2, E3> DrmRenderSurface<D, A, R, B>
where where
D: AsRawFd + 'static, D: AsRawFd + 'static,
A: Allocator<B, Error=E1>, A: Allocator<B, Error = E1>,
B: Buffer + TryInto<Dmabuf, Error=E2>, B: Buffer + TryInto<Dmabuf, Error = E2>,
R: Bind<Dmabuf> + Renderer<Error=E3>, R: Bind<Dmabuf> + Renderer<Error = E3>,
E1: std::error::Error + 'static, E1: std::error::Error + 'static,
E2: std::error::Error + 'static, E2: std::error::Error + 'static,
E3: std::error::Error + 'static, E3: std::error::Error + 'static,
{ {
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
pub fn new<L: Into<Option<::slog::Logger>>>(drm: DrmSurface<D>, allocator: A, renderer: R, log: L) -> Result<DrmRenderSurface<D, A, R, B>, Error<E1, E2, E3>> pub fn new<L: Into<Option<::slog::Logger>>>(
{ drm: DrmSurface<D>,
allocator: A,
renderer: R,
log: L,
) -> Result<DrmRenderSurface<D, A, R, B>, Error<E1, E2, E3>> {
// we cannot simply pick the first supported format of the intersection of *all* formats, because: // we cannot simply pick the first supported format of the intersection of *all* formats, because:
// - we do not want something like Abgr4444, which looses color information // - we do not want something like Abgr4444, which looses color information
// - some formats might perform terribly // - some formats might perform terribly
@ -56,13 +62,28 @@ where
let logger = crate::slog_or_fallback(log).new(o!("backend" => "drm_render")); let logger = crate::slog_or_fallback(log).new(o!("backend" => "drm_render"));
// select a format // select a format
let plane_formats = drm.supported_formats().iter().filter(|fmt| fmt.code == code).cloned().collect::<HashSet<_>>(); let plane_formats = drm
let renderer_formats = Bind::<Dmabuf>::supported_formats(&renderer).expect("Dmabuf renderer without formats") .supported_formats()
.iter().filter(|fmt| fmt.code == code).cloned().collect::<HashSet<_>>(); .iter()
.filter(|fmt| fmt.code == code)
.cloned()
.collect::<HashSet<_>>();
let renderer_formats = Bind::<Dmabuf>::supported_formats(&renderer)
.expect("Dmabuf renderer without formats")
.iter()
.filter(|fmt| fmt.code == code)
.cloned()
.collect::<HashSet<_>>();
trace!(logger, "Remaining plane formats: {:?}", plane_formats); trace!(logger, "Remaining plane formats: {:?}", plane_formats);
trace!(logger, "Remaining renderer formats: {:?}", renderer_formats); trace!(logger, "Remaining renderer formats: {:?}", renderer_formats);
debug!(logger, "Remaining intersected formats: {:?}", plane_formats.intersection(&renderer_formats).collect::<HashSet<_>>()); debug!(
logger,
"Remaining intersected formats: {:?}",
plane_formats
.intersection(&renderer_formats)
.collect::<HashSet<_>>()
);
if plane_formats.is_empty() { if plane_formats.is_empty() {
return Err(Error::NoSupportedPlaneFormat); return Err(Error::NoSupportedPlaneFormat);
@ -74,38 +95,48 @@ where
// Special case: if a format supports explicit LINEAR (but no implicit Modifiers) // Special case: if a format supports explicit LINEAR (but no implicit Modifiers)
// and the other doesn't support any modifier, force LINEAR. This will force the allocator to // and the other doesn't support any modifier, force LINEAR. This will force the allocator to
// create a buffer with a LINEAR layout instead of an implicit modifier. // create a buffer with a LINEAR layout instead of an implicit modifier.
if if (plane_formats.len() == 1
(plane_formats.len() == 1 && && plane_formats.iter().next().unwrap().modifier == Modifier::Invalid
plane_formats.iter().next().unwrap().modifier == Modifier::Invalid && renderer_formats.iter().all(|x| x.modifier != Modifier::Invalid)
&& renderer_formats.iter().all(|x| x.modifier != Modifier::Invalid) && renderer_formats.iter().any(|x| x.modifier == Modifier::Linear))
&& renderer_formats.iter().any(|x| x.modifier == Modifier::Linear) || (renderer_formats.len() == 1
) || (renderer_formats.len() == 1 && && renderer_formats.iter().next().unwrap().modifier == Modifier::Invalid
renderer_formats.iter().next().unwrap().modifier == Modifier::Invalid
&& plane_formats.iter().all(|x| x.modifier != Modifier::Invalid) && plane_formats.iter().all(|x| x.modifier != Modifier::Invalid)
&& plane_formats.iter().any(|x| x.modifier == Modifier::Linear) && plane_formats.iter().any(|x| x.modifier == Modifier::Linear))
) { {
vec![Format { vec![Format {
code, code,
modifier: Modifier::Linear, modifier: Modifier::Linear,
}] }]
} else { } else {
plane_formats.intersection(&renderer_formats).cloned().collect::<Vec<_>>() plane_formats
.intersection(&renderer_formats)
.cloned()
.collect::<Vec<_>>()
} }
}; };
debug!(logger, "Testing Formats: {:?}", formats); debug!(logger, "Testing Formats: {:?}", formats);
// Test explicit formats first // Test explicit formats first
let drm = Arc::new(drm); let drm = Arc::new(drm);
let iter = formats.iter().filter(|x| x.modifier != Modifier::Invalid && x.modifier != Modifier::Linear) let iter = formats
.iter()
.filter(|x| x.modifier != Modifier::Invalid && x.modifier != Modifier::Linear)
.chain(formats.iter().find(|x| x.modifier == Modifier::Linear)) .chain(formats.iter().find(|x| x.modifier == Modifier::Linear))
.chain(formats.iter().find(|x| x.modifier == Modifier::Invalid)).cloned(); .chain(formats.iter().find(|x| x.modifier == Modifier::Invalid))
.cloned();
DrmRenderSurface::new_internal(drm, allocator, renderer, iter, logger) DrmRenderSurface::new_internal(drm, allocator, renderer, iter, logger)
} }
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
fn new_internal(drm: Arc<DrmSurface<D>>, allocator: A, mut renderer: R, mut formats: impl Iterator<Item=Format>, logger: ::slog::Logger) -> Result<DrmRenderSurface<D, A, R, B>, Error<E1, E2, E3>> fn new_internal(
{ drm: Arc<DrmSurface<D>>,
allocator: A,
mut renderer: R,
mut formats: impl Iterator<Item = Format>,
logger: ::slog::Logger,
) -> Result<DrmRenderSurface<D, A, R, B>, Error<E1, E2, E3>> {
let format = formats.next().ok_or(Error::NoSupportedPlaneFormat)?; let format = formats.next().ok_or(Error::NoSupportedPlaneFormat)?;
let mode = drm.pending_mode(); let mode = drm.pending_mode();
@ -117,16 +148,28 @@ where
{ {
let dmabuf: Dmabuf = (*buffer).clone(); let dmabuf: Dmabuf = (*buffer).clone();
match renderer.bind(dmabuf).map_err(Error::<E1, E2, E3>::RenderError) match renderer
.and_then(|_| renderer.begin(mode.size().0 as u32, mode.size().1 as u32, Transform::Normal).map_err(Error::RenderError)) .bind(dmabuf)
.and_then(|_| renderer.clear([0.0, 0.0, 0.0, 1.0]).map_err(Error::RenderError)) .map_err(Error::<E1, E2, E3>::RenderError)
.and_then(|_| renderer.finish().map_err(|_| Error::InitialRenderingError)) .and_then(|_| {
.and_then(|_| renderer.unbind().map_err(Error::RenderError)) renderer
.begin(mode.size().0 as u32, mode.size().1 as u32, Transform::Normal)
.map_err(Error::RenderError)
})
.and_then(|_| renderer.clear([0.0, 0.0, 0.0, 1.0]).map_err(Error::RenderError))
.and_then(|_| renderer.finish().map_err(|_| Error::InitialRenderingError))
.and_then(|_| renderer.unbind().map_err(Error::RenderError))
{ {
Ok(_) => {}, Ok(_) => {}
Err(err) => { Err(err) => {
warn!(logger, "Rendering failed with format {:?}: {}", format, err); warn!(logger, "Rendering failed with format {:?}: {}", format, err);
return DrmRenderSurface::new_internal(drm, swapchain.allocator, renderer, formats, logger); return DrmRenderSurface::new_internal(
drm,
swapchain.allocator,
renderer,
formats,
logger,
);
} }
} }
} }
@ -135,8 +178,7 @@ where
let fb = bo.userdata().unwrap().unwrap().fb; let fb = bo.userdata().unwrap().unwrap().fb;
buffer.set_userdata(bo); buffer.set_userdata(bo);
match drm.test_buffer(fb, &mode, true) match drm.test_buffer(fb, &mode, true) {
{
Ok(_) => { Ok(_) => {
debug!(logger, "Success, choosen format: {:?}", format); debug!(logger, "Success, choosen format: {:?}", format);
let buffers = Buffers::new(drm.clone(), gbm, buffer); let buffers = Buffers::new(drm.clone(), gbm, buffer);
@ -148,9 +190,12 @@ where
buffers, buffers,
current_buffer: None, current_buffer: None,
}) })
}, }
Err(err) => { Err(err) => {
warn!(logger, "Mode-setting failed with buffer format {:?}: {}", format, err); warn!(
logger,
"Mode-setting failed with buffer format {:?}: {}", format, err
);
DrmRenderSurface::new_internal(drm, swapchain.allocator, renderer, formats, logger) DrmRenderSurface::new_internal(drm, swapchain.allocator, renderer, formats, logger)
} }
} }
@ -159,7 +204,7 @@ where
pub fn queue_frame(&mut self) -> Result<(), Error<E1, E2, E3>> { pub fn queue_frame(&mut self) -> Result<(), Error<E1, E2, E3>> {
let mode = self.drm.pending_mode(); let mode = self.drm.pending_mode();
let (width, height) = (mode.size().0 as u32, mode.size().1 as u32); let (width, height) = (mode.size().0 as u32, mode.size().1 as u32);
self.begin(width, height, Transform::Flipped180/* TODO */) self.begin(width, height, Transform::Flipped180 /* TODO */)
} }
pub fn drop_frame(&mut self) -> Result<(), SwapBuffersError> { pub fn drop_frame(&mut self) -> Result<(), SwapBuffersError> {
@ -219,13 +264,12 @@ where
} }
} }
impl<D, A, B, T, R, E1, E2, E3> Renderer for DrmRenderSurface<D, A, R, B> impl<D, A, B, T, R, E1, E2, E3> Renderer for DrmRenderSurface<D, A, R, B>
where where
D: AsRawFd + 'static, D: AsRawFd + 'static,
A: Allocator<B, Error=E1>, A: Allocator<B, Error = E1>,
B: Buffer + TryInto<Dmabuf, Error=E2>, B: Buffer + TryInto<Dmabuf, Error = E2>,
R: Bind<Dmabuf> + Renderer<Error=E3, TextureId=T>, R: Bind<Dmabuf> + Renderer<Error = E3, TextureId = T>,
T: Texture, T: Texture,
E1: std::error::Error + 'static, E1: std::error::Error + 'static,
E2: std::error::Error + 'static, E2: std::error::Error + 'static,
@ -235,7 +279,10 @@ where
type TextureId = T; type TextureId = T;
#[cfg(feature = "image")] #[cfg(feature = "image")]
fn import_bitmap<C: std::ops::Deref<Target=[u8]>>(&mut self, image: &image::ImageBuffer<image::Rgba<u8>, C>) -> Result<Self::TextureId, Self::Error> { fn import_bitmap<C: std::ops::Deref<Target = [u8]>>(
&mut self,
image: &image::ImageBuffer<image::Rgba<u8>, C>,
) -> Result<Self::TextureId, Self::Error> {
self.renderer.import_bitmap(image).map_err(Error::RenderError) self.renderer.import_bitmap(image).map_err(Error::RenderError)
} }
@ -266,15 +313,24 @@ where
let slot = self.swapchain.acquire()?.ok_or(Error::NoFreeSlotsError)?; let slot = self.swapchain.acquire()?.ok_or(Error::NoFreeSlotsError)?;
self.renderer.bind((*slot).clone()).map_err(Error::RenderError)?; self.renderer.bind((*slot).clone()).map_err(Error::RenderError)?;
self.current_buffer = Some(slot); self.current_buffer = Some(slot);
self.renderer.begin(width, height, transform).map_err(Error::RenderError) self.renderer
.begin(width, height, transform)
.map_err(Error::RenderError)
} }
fn clear(&mut self, color: [f32; 4]) -> Result<(), Self::Error> { fn clear(&mut self, color: [f32; 4]) -> Result<(), Self::Error> {
self.renderer.clear(color).map_err(Error::RenderError) self.renderer.clear(color).map_err(Error::RenderError)
} }
fn render_texture(&mut self, texture: &Self::TextureId, matrix: Matrix3<f32>, alpha: f32) -> Result<(), Self::Error> { fn render_texture(
self.renderer.render_texture(texture, matrix, alpha).map_err(Error::RenderError) &mut self,
texture: &Self::TextureId,
matrix: Matrix3<f32>,
alpha: f32,
) -> Result<(), Self::Error> {
self.renderer
.render_texture(texture, matrix, alpha)
.map_err(Error::RenderError)
} }
fn finish(&mut self) -> Result<(), SwapBuffersError> { fn finish(&mut self) -> Result<(), SwapBuffersError> {
@ -284,7 +340,10 @@ where
let result = self.renderer.finish(); let result = self.renderer.finish();
if result.is_ok() { if result.is_ok() {
match self.buffers.queue::<E1, E2, E3>(self.current_buffer.take().unwrap()) { match self
.buffers
.queue::<E1, E2, E3>(self.current_buffer.take().unwrap())
{
Ok(()) => {} Ok(()) => {}
Err(Error::DrmError(drm)) => return Err(drm.into()), Err(Error::DrmError(drm)) => return Err(drm.into()),
Err(Error::GbmError(err)) => return Err(SwapBuffersError::ContextLost(Box::new(err))), Err(Error::GbmError(err)) => return Err(SwapBuffersError::ContextLost(Box::new(err))),
@ -318,7 +377,11 @@ impl<D> Buffers<D>
where where
D: AsRawFd + 'static, D: AsRawFd + 'static,
{ {
pub fn new(drm: Arc<DrmSurface<D>>, gbm: GbmDevice<gbm::FdWrapper>, slot: Slot<Dmabuf, BufferObject<FbHandle<D>>>) -> Buffers<D> { pub fn new(
drm: Arc<DrmSurface<D>>,
gbm: GbmDevice<gbm::FdWrapper>,
slot: Slot<Dmabuf, BufferObject<FbHandle<D>>>,
) -> Buffers<D> {
Buffers { Buffers {
drm, drm,
gbm, gbm,
@ -328,7 +391,10 @@ where
} }
} }
pub fn queue<E1, E2, E3>(&mut self, slot: Slot<Dmabuf, BufferObject<FbHandle<D>>>) -> Result<(), Error<E1, E2, E3>> pub fn queue<E1, E2, E3>(
&mut self,
slot: Slot<Dmabuf, BufferObject<FbHandle<D>>>,
) -> Result<(), Error<E1, E2, E3>>
where where
E1: std::error::Error + 'static, E1: std::error::Error + 'static,
E2: std::error::Error + 'static, E2: std::error::Error + 'static,
@ -386,7 +452,11 @@ where
} }
} }
fn import_dmabuf<A, E1, E2, E3>(drm: &Arc<DrmSurface<A>>, gbm: &GbmDevice<gbm::FdWrapper>, buffer: &Dmabuf) -> Result<BufferObject<FbHandle<A>>, Error<E1, E2, E3>> fn import_dmabuf<A, E1, E2, E3>(
drm: &Arc<DrmSurface<A>>,
gbm: &GbmDevice<gbm::FdWrapper>,
buffer: &Dmabuf,
) -> Result<BufferObject<FbHandle<A>>, Error<E1, E2, E3>>
where where
A: AsRawFd + 'static, A: AsRawFd + 'static,
E1: std::error::Error + 'static, E1: std::error::Error + 'static,
@ -405,26 +475,23 @@ where
DrmSurfaceInternal::Legacy(surf) => surf.logger.clone(), DrmSurfaceInternal::Legacy(surf) => surf.logger.clone(),
}; };
let fb = match let fb = match if modifier.is_some() {
if modifier.is_some() { let num = bo.plane_count().unwrap();
let num = bo.plane_count().unwrap(); let modifiers = [
let modifiers = [ modifier,
modifier, if num > 1 { modifier } else { None },
if num > 1 { modifier } else { None }, if num > 2 { modifier } else { None },
if num > 2 { modifier } else { None }, if num > 3 { modifier } else { None },
if num > 3 { modifier } else { None }, ];
]; drm.add_planar_framebuffer(&bo, &modifiers, drm_ffi::DRM_MODE_FB_MODIFIERS)
drm.add_planar_framebuffer(&bo, &modifiers, drm_ffi::DRM_MODE_FB_MODIFIERS) } else {
} else { drm.add_planar_framebuffer(&bo, &[None, None, None, None], 0)
drm.add_planar_framebuffer(&bo, &[None, None, None, None], 0) } {
}
{
Ok(fb) => fb, Ok(fb) => fb,
Err(source) => { Err(source) => {
// We only support this as a fallback of last resort for ARGB8888 visuals, // We only support this as a fallback of last resort for ARGB8888 visuals,
// like xf86-video-modesetting does. // like xf86-video-modesetting does.
if drm::buffer::Buffer::format(&bo) != Fourcc::Argb8888 if drm::buffer::Buffer::format(&bo) != Fourcc::Argb8888 || bo.handles()[1].is_some() {
|| bo.handles()[1].is_some() {
return Err(Error::DrmError(DrmError::Access { return Err(Error::DrmError(DrmError::Access {
errmsg: "Failed to add framebuffer", errmsg: "Failed to add framebuffer",
dev: drm.dev_path(), dev: drm.dev_path(),
@ -432,17 +499,15 @@ where
})); }));
} }
debug!(logger, "Failed to add framebuffer, trying legacy method"); debug!(logger, "Failed to add framebuffer, trying legacy method");
drm.add_framebuffer(&bo, 32, 32).map_err(|source| DrmError::Access { drm.add_framebuffer(&bo, 32, 32)
errmsg: "Failed to add framebuffer", .map_err(|source| DrmError::Access {
dev: drm.dev_path(), errmsg: "Failed to add framebuffer",
source, dev: drm.dev_path(),
})? source,
})?
} }
}; };
bo.set_userdata(FbHandle { bo.set_userdata(FbHandle { drm: drm.clone(), fb }).unwrap();
drm: drm.clone(),
fb,
}).unwrap();
Ok(bo) Ok(bo)
} }
@ -471,21 +536,21 @@ where
#[error("The swapchain encounted an error: {0}")] #[error("The swapchain encounted an error: {0}")]
SwapchainError(#[from] SwapchainError<E1, E2>), SwapchainError(#[from] SwapchainError<E1, E2>),
#[error("The renderer encounted an error: {0}")] #[error("The renderer encounted an error: {0}")]
RenderError(#[source] E3) RenderError(#[source] E3),
} }
impl< impl<
E1: std::error::Error + 'static, E1: std::error::Error + 'static,
E2: std::error::Error + 'static, E2: std::error::Error + 'static,
E3: std::error::Error + Into<SwapBuffersError> + 'static, E3: std::error::Error + Into<SwapBuffersError> + 'static,
> From<Error<E1, E2, E3>> for SwapBuffersError { > From<Error<E1, E2, E3>> for SwapBuffersError
{
fn from(err: Error<E1, E2, E3>) -> SwapBuffersError { fn from(err: Error<E1, E2, E3>) -> SwapBuffersError {
match err { match err {
x @ Error::NoSupportedPlaneFormat x @ Error::NoSupportedPlaneFormat
| x @ Error::NoSupportedRendererFormat | x @ Error::NoSupportedRendererFormat
| x @ Error::FormatsNotCompatible | x @ Error::FormatsNotCompatible
| x @ Error::InitialRenderingError | x @ Error::InitialRenderingError => SwapBuffersError::ContextLost(Box::new(x)),
=> SwapBuffersError::ContextLost(Box::new(x)),
x @ Error::NoFreeSlotsError => SwapBuffersError::TemporaryFailure(Box::new(x)), x @ Error::NoFreeSlotsError => SwapBuffersError::TemporaryFailure(Box::new(x)),
Error::DrmError(err) => err.into(), Error::DrmError(err) => err.into(),
Error::GbmError(err) => SwapBuffersError::ContextLost(Box::new(err)), Error::GbmError(err) => SwapBuffersError::ContextLost(Box::new(err)),

View File

@ -1,5 +1,8 @@
use std::sync::{Arc, Weak, atomic::{AtomicBool, Ordering}};
use std::os::unix::io::{AsRawFd, RawFd}; use std::os::unix::io::{AsRawFd, RawFd};
use std::sync::{
atomic::{AtomicBool, Ordering},
Arc, Weak,
};
use drm::Device as BasicDevice; use drm::Device as BasicDevice;
use nix::libc::dev_t; use nix::libc::dev_t;

View File

@ -6,11 +6,14 @@ use drm::control::{
use std::collections::HashSet; use std::collections::HashSet;
use std::os::unix::io::AsRawFd; use std::os::unix::io::AsRawFd;
use std::sync::{atomic::{AtomicBool, Ordering}, Arc, Mutex, RwLock}; use std::sync::{
atomic::{AtomicBool, Ordering},
Arc, Mutex, RwLock,
};
use crate::backend::drm::{ use crate::backend::drm::{
device::{DevPath, DrmDeviceInternal},
device::atomic::Mapping, device::atomic::Mapping,
device::{DevPath, DrmDeviceInternal},
error::Error, error::Error,
}; };
@ -48,7 +51,11 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
let logger = logger.new(o!("smithay_module" => "backend_drm_atomic", "drm_module" => "surface")); let logger = logger.new(o!("smithay_module" => "backend_drm_atomic", "drm_module" => "surface"));
info!( info!(
logger, logger,
"Initializing drm surface ({:?}:{:?}) with mode {:?} and connectors {:?}", crtc, plane, mode, connectors "Initializing drm surface ({:?}:{:?}) with mode {:?} and connectors {:?}",
crtc,
plane,
mode,
connectors
); );
let crtc_info = fd.get_crtc(crtc).map_err(|source| Error::Access { let crtc_info = fd.get_crtc(crtc).map_err(|source| Error::Access {
@ -63,30 +70,25 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
// 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) => fd Some(mode) => fd.create_property_blob(&mode).map_err(|source| Error::Access {
.create_property_blob(&mode)
.map_err(|source| Error::Access {
errmsg: "Failed to create Property Blob for mode",
dev: fd.dev_path(),
source,
})?,
None => property::Value::Unknown(0),
};
let blob = fd
.create_property_blob(&mode)
.map_err(|source| Error::Access {
errmsg: "Failed to create Property Blob for mode", errmsg: "Failed to create Property Blob for mode",
dev: fd.dev_path(), dev: fd.dev_path(),
source, source,
})?; })?,
None => property::Value::Unknown(0),
};
let res_handles = fd.resource_handles() let blob = fd.create_property_blob(&mode).map_err(|source| Error::Access {
.map_err(|source| Error::Access { errmsg: "Failed to create Property Blob for mode",
errmsg: "Error loading drm resources", dev: fd.dev_path(),
dev: fd.dev_path(), source,
source, })?;
})?;
let res_handles = fd.resource_handles().map_err(|source| Error::Access {
errmsg: "Error loading drm resources",
dev: fd.dev_path(),
source,
})?;
// the current set of connectors are those, that already have the correct `CRTC_ID` set. // the current set of connectors are those, that already have the correct `CRTC_ID` set.
// so we collect them for `current_state` and set the user-given once in `pending_state`. // so we collect them for `current_state` and set the user-given once in `pending_state`.
@ -94,8 +96,7 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
// If they don't match, `commit_pending` will return true and they will be changed on the next `commit`. // If they don't match, `commit_pending` will return true and they will be changed on the next `commit`.
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 = let crtc_prop = prop_mapping
prop_mapping
.0 .0
.get(&conn) .get(&conn)
.expect("Unknown handle") .expect("Unknown handle")
@ -105,8 +106,7 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
name: "CRTC_ID", name: "CRTC_ID",
}) })
.map(|x| *x)?; .map(|x| *x)?;
if let (Ok(crtc_prop_info), Ok(props)) = (fd.get_property(crtc_prop), fd.get_properties(*conn)) if let (Ok(crtc_prop_info), Ok(props)) = (fd.get_property(crtc_prop), fd.get_properties(*conn)) {
{
let (ids, vals) = props.as_props_and_values(); let (ids, vals) = props.as_props_and_values();
for (&id, &val) in ids.iter().zip(vals.iter()) { for (&id, &val) in ids.iter().zip(vals.iter()) {
if id == crtc_prop { if id == crtc_prop {
@ -152,14 +152,20 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
// here we create a dumbbuffer for that purpose. // here we create a dumbbuffer for that purpose.
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.fd let db = self
.create_dumb_buffer((w as u32, h as u32), crate::backend::allocator::Fourcc::Argb8888, 32) .fd
.create_dumb_buffer(
(w as u32, h as u32),
crate::backend::allocator::Fourcc::Argb8888,
32,
)
.map_err(|source| Error::Access { .map_err(|source| Error::Access {
errmsg: "Failed to create dumb buffer", errmsg: "Failed to create dumb buffer",
dev: self.fd.dev_path(), dev: self.fd.dev_path(),
source, source,
})?; })?;
let fb = self.fd let fb = self
.fd
.add_framebuffer(&db, 32, 32) .add_framebuffer(&db, 32, 32)
.map_err(|source| Error::Access { .map_err(|source| Error::Access {
errmsg: "Failed to create framebuffer", errmsg: "Failed to create framebuffer",
@ -198,13 +204,11 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
return Err(Error::DeviceInactive); return Err(Error::DeviceInactive);
} }
let info = self.fd let info = self.fd.get_connector(conn).map_err(|source| Error::Access {
.get_connector(conn) errmsg: "Error loading connector info",
.map_err(|source| Error::Access { dev: self.fd.dev_path(),
errmsg: "Error loading connector info", source,
dev: self.fd.dev_path(), })?;
source,
})?;
let mut pending = self.pending.write().unwrap(); let mut pending = self.pending.write().unwrap();
@ -219,11 +223,12 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
Some(pending.mode), Some(pending.mode),
Some(pending.blob), Some(pending.blob),
)?; )?;
self.fd.atomic_commit( self.fd
&[AtomicCommitFlags::AllowModeset, AtomicCommitFlags::TestOnly], .atomic_commit(
req, &[AtomicCommitFlags::AllowModeset, AtomicCommitFlags::TestOnly],
) req,
.map_err(|_| Error::TestFailed(self.crtc))?; )
.map_err(|_| Error::TestFailed(self.crtc))?;
// seems to be, lets add the connector // seems to be, lets add the connector
pending.connectors.insert(conn); pending.connectors.insert(conn);
@ -255,11 +260,12 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
Some(pending.mode), Some(pending.mode),
Some(pending.blob), Some(pending.blob),
)?; )?;
self.fd.atomic_commit( self.fd
&[AtomicCommitFlags::AllowModeset, AtomicCommitFlags::TestOnly], .atomic_commit(
req, &[AtomicCommitFlags::AllowModeset, AtomicCommitFlags::TestOnly],
) req,
.map_err(|_| Error::TestFailed(self.crtc))?; )
.map_err(|_| Error::TestFailed(self.crtc))?;
// seems to be, lets remove the connector // seems to be, lets remove the connector
pending.connectors.remove(&conn); pending.connectors.remove(&conn);
@ -293,11 +299,12 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
Some(pending.blob), Some(pending.blob),
)?; )?;
self.fd.atomic_commit( self.fd
&[AtomicCommitFlags::AllowModeset, AtomicCommitFlags::TestOnly], .atomic_commit(
req, &[AtomicCommitFlags::AllowModeset, AtomicCommitFlags::TestOnly],
) req,
.map_err(|_| Error::TestFailed(self.crtc))?; )
.map_err(|_| Error::TestFailed(self.crtc))?;
pending.connectors = conns; pending.connectors = conns;
@ -312,7 +319,8 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
let mut pending = self.pending.write().unwrap(); let mut pending = self.pending.write().unwrap();
// check if new config is supported // check if new config is supported
let new_blob = self.fd let new_blob = self
.fd
.create_property_blob(&mode) .create_property_blob(&mode)
.map_err(|source| Error::Access { .map_err(|source| Error::Access {
errmsg: "Failed to create Property Blob for mode", errmsg: "Failed to create Property Blob for mode",
@ -329,7 +337,8 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
Some(mode), Some(mode),
Some(new_blob), Some(new_blob),
)?; )?;
if let Err(err) = self.fd if let Err(err) = self
.fd
.atomic_commit( .atomic_commit(
&[AtomicCommitFlags::AllowModeset, AtomicCommitFlags::TestOnly], &[AtomicCommitFlags::AllowModeset, AtomicCommitFlags::TestOnly],
req, req,
@ -403,7 +412,8 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
Some(pending.blob), Some(pending.blob),
)?; )?;
if let Err(err) = self.fd if let Err(err) = self
.fd
.atomic_commit( .atomic_commit(
&[AtomicCommitFlags::AllowModeset, AtomicCommitFlags::TestOnly], &[AtomicCommitFlags::AllowModeset, AtomicCommitFlags::TestOnly],
req.clone(), req.clone(),
@ -429,7 +439,8 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
}; };
debug!(self.logger, "Setting screen: {:?}", req); debug!(self.logger, "Setting screen: {:?}", req);
let result = self.fd let result = self
.fd
.atomic_commit( .atomic_commit(
if event { if event {
&[ &[
@ -441,10 +452,7 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
AtomicCommitFlags::Nonblock, AtomicCommitFlags::Nonblock,
] ]
} else { } else {
&[ &[AtomicCommitFlags::AllowModeset, AtomicCommitFlags::Nonblock]
AtomicCommitFlags::AllowModeset,
AtomicCommitFlags::Nonblock,
]
}, },
req, req,
) )
@ -480,19 +488,20 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
// If we would set anything here, that would require a modeset, this would fail, // If we would set anything here, that would require a modeset, this would fail,
// indicating a problem in our assumptions. // indicating a problem in our assumptions.
trace!(self.logger, "Queueing page flip: {:?}", req); trace!(self.logger, "Queueing page flip: {:?}", req);
self.fd.atomic_commit( self.fd
if event { .atomic_commit(
&[AtomicCommitFlags::PageFlipEvent, AtomicCommitFlags::Nonblock] if event {
} else { &[AtomicCommitFlags::PageFlipEvent, AtomicCommitFlags::Nonblock]
&[AtomicCommitFlags::Nonblock] } else {
}, &[AtomicCommitFlags::Nonblock]
req, },
) req,
.map_err(|source| Error::Access { )
errmsg: "Page flip commit failed", .map_err(|source| Error::Access {
dev: self.fd.dev_path(), errmsg: "Page flip commit failed",
source, dev: self.fd.dev_path(),
})?; source,
})?;
Ok(()) Ok(())
} }
@ -502,7 +511,8 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
return Err(Error::DeviceInactive); return Err(Error::DeviceInactive);
} }
let blob = self.fd let blob = self
.fd
.create_property_blob(&mode) .create_property_blob(&mode)
.map_err(|source| Error::Access { .map_err(|source| Error::Access {
errmsg: "Failed to create Property Blob for mode", errmsg: "Failed to create Property Blob for mode",
@ -524,10 +534,16 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
self.plane, self.plane,
Some(fb), Some(fb),
Some(*mode), Some(*mode),
Some(blob) Some(blob),
)?; )?;
let result = self.fd.atomic_commit(&[AtomicCommitFlags::AllowModeset, AtomicCommitFlags::TestOnly], req).is_ok(); let result = self
.fd
.atomic_commit(
&[AtomicCommitFlags::AllowModeset, AtomicCommitFlags::TestOnly],
req,
)
.is_ok();
Ok(result) Ok(result)
} }
@ -536,8 +552,7 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
handle: connector::Handle, handle: connector::Handle,
name: &'static str, name: &'static str,
) -> Result<property::Handle, Error> { ) -> Result<property::Handle, Error> {
self self.prop_mapping
.prop_mapping
.0 .0
.get(&handle) .get(&handle)
.expect("Unknown handle") .expect("Unknown handle")
@ -549,9 +564,12 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
.map(|x| *x) .map(|x| *x)
} }
pub(crate) fn crtc_prop_handle(&self, handle: crtc::Handle, name: &'static str) -> Result<property::Handle, Error> { pub(crate) fn crtc_prop_handle(
self &self,
.prop_mapping handle: crtc::Handle,
name: &'static str,
) -> Result<property::Handle, Error> {
self.prop_mapping
.1 .1
.get(&handle) .get(&handle)
.expect("Unknown handle") .expect("Unknown handle")
@ -569,8 +587,7 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
handle: framebuffer::Handle, handle: framebuffer::Handle,
name: &'static str, name: &'static str,
) -> Result<property::Handle, Error> { ) -> Result<property::Handle, Error> {
self self.prop_mapping
.prop_mapping
.2 .2
.get(&handle) .get(&handle)
.expect("Unknown handle") .expect("Unknown handle")
@ -587,8 +604,7 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
handle: plane::Handle, handle: plane::Handle,
name: &'static str, name: &'static str,
) -> Result<property::Handle, Error> { ) -> Result<property::Handle, Error> {
self self.prop_mapping
.prop_mapping
.3 .3
.get(&handle) .get(&handle)
.expect("Unknown handle") .expect("Unknown handle")
@ -733,10 +749,12 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
property::Value::Framebuffer(None), property::Value::Framebuffer(None),
); );
self.fd.atomic_commit(&[AtomicCommitFlags::TestOnly], req.clone()) self.fd
.atomic_commit(&[AtomicCommitFlags::TestOnly], req.clone())
.map_err(|_| Error::TestFailed(self.crtc))?; .map_err(|_| Error::TestFailed(self.crtc))?;
self.fd.atomic_commit(&[AtomicCommitFlags::Nonblock], req) self.fd
.atomic_commit(&[AtomicCommitFlags::Nonblock], req)
.map_err(|source| Error::Access { .map_err(|source| Error::Access {
errmsg: "Failed to commit on clear_plane", errmsg: "Failed to commit on clear_plane",
dev: self.fd.dev_path(), dev: self.fd.dev_path(),
@ -763,10 +781,7 @@ impl<A: AsRawFd + 'static> Drop for AtomicDrmSurface<A> {
// other ttys that use no cursor, might not clear it themselves. // other ttys that use no cursor, might not clear it themselves.
// This makes sure our cursor won't stay visible. // This makes sure our cursor won't stay visible.
if let Err(err) = self.clear_plane() { if let Err(err) = self.clear_plane() {
warn!( warn!(self.logger, "Failed to clear plane on {:?}: {}", self.crtc, err);
self.logger,
"Failed to clear plane on {:?}: {}", self.crtc, err
);
} }
// disable connectors again // disable connectors again

View File

@ -1,15 +1,15 @@
use drm::control::{ use drm::control::{connector, crtc, encoder, framebuffer, Device as ControlDevice, Mode, PageFlipFlags};
connector, crtc, encoder, framebuffer, Device as ControlDevice, Mode,
PageFlipFlags,
};
use std::collections::HashSet; use std::collections::HashSet;
use std::os::unix::io::AsRawFd; use std::os::unix::io::AsRawFd;
use std::sync::{atomic::{AtomicBool, Ordering}, Arc, RwLock}; use std::sync::{
atomic::{AtomicBool, Ordering},
Arc, RwLock,
};
use crate::backend::drm::{ use crate::backend::drm::{
device::{DevPath, DrmDeviceInternal},
device::legacy::set_connector_state, device::legacy::set_connector_state,
device::{DevPath, DrmDeviceInternal},
error::Error, error::Error,
}; };
@ -54,12 +54,11 @@ impl<A: AsRawFd + 'static> LegacyDrmSurface<A> {
let current_mode = crtc_info.mode(); let current_mode = crtc_info.mode();
let mut current_connectors = HashSet::new(); let mut current_connectors = HashSet::new();
let res_handles = fd.resource_handles() let res_handles = fd.resource_handles().map_err(|source| Error::Access {
.map_err(|source| Error::Access { errmsg: "Error loading drm resources",
errmsg: "Error loading drm resources", dev: fd.dev_path(),
dev: fd.dev_path(), source,
source, })?;
})?;
for &con in res_handles.connectors() { for &con in res_handles.connectors() {
let con_info = fd.get_connector(con).map_err(|source| Error::Access { let con_info = fd.get_connector(con).map_err(|source| Error::Access {
errmsg: "Error loading connector info", errmsg: "Error loading connector info",
@ -179,7 +178,8 @@ impl<A: AsRawFd + 'static> LegacyDrmSurface<A> {
// check the connectors to see if this mode is supported // check the connectors to see if this mode is supported
for connector in &pending.connectors { for connector in &pending.connectors {
if !self.fd if !self
.fd
.get_connector(*connector) .get_connector(*connector)
.map_err(|source| Error::Access { .map_err(|source| Error::Access {
errmsg: "Error loading connector info", errmsg: "Error loading connector info",
@ -229,7 +229,8 @@ impl<A: AsRawFd + 'static> LegacyDrmSurface<A> {
if conn_removed { if conn_removed {
// null commit (necessary to trigger removal on the kernel side with the legacy api.) // null commit (necessary to trigger removal on the kernel side with the legacy api.)
self.fd.set_crtc(self.crtc, None, (0, 0), &[], None) self.fd
.set_crtc(self.crtc, None, (0, 0), &[], None)
.map_err(|source| Error::Access { .map_err(|source| Error::Access {
errmsg: "Error setting crtc", errmsg: "Error setting crtc",
dev: self.fd.dev_path(), dev: self.fd.dev_path(),
@ -253,22 +254,23 @@ impl<A: AsRawFd + 'static> LegacyDrmSurface<A> {
debug!(self.logger, "Setting screen"); debug!(self.logger, "Setting screen");
// do a modeset and attach the given framebuffer // do a modeset and attach the given framebuffer
self.fd.set_crtc( self.fd
self.crtc, .set_crtc(
Some(framebuffer), self.crtc,
(0, 0), Some(framebuffer),
&pending (0, 0),
.connectors &pending
.iter() .connectors
.copied() .iter()
.collect::<Vec<connector::Handle>>(), .copied()
Some(pending.mode), .collect::<Vec<connector::Handle>>(),
) Some(pending.mode),
.map_err(|source| Error::Access { )
errmsg: "Error setting crtc", .map_err(|source| Error::Access {
dev: self.fd.dev_path(), errmsg: "Error setting crtc",
source, dev: self.fd.dev_path(),
})?; source,
})?;
*current = pending.clone(); *current = pending.clone();
@ -306,7 +308,11 @@ impl<A: AsRawFd + 'static> LegacyDrmSurface<A> {
&*self.fd, &*self.fd,
self.crtc, self.crtc,
framebuffer, framebuffer,
if event { &[PageFlipFlags::PageFlipEvent] } else { &[] }, if event {
&[PageFlipFlags::PageFlipEvent]
} else {
&[]
},
None, None,
) )
.map_err(|source| Error::Access { .map_err(|source| Error::Access {
@ -324,17 +330,20 @@ impl<A: AsRawFd + 'static> LegacyDrmSurface<A> {
let pending = self.pending.read().unwrap(); let pending = self.pending.read().unwrap();
debug!(self.logger, "Setting screen for buffer *testing*"); debug!(self.logger, "Setting screen for buffer *testing*");
Ok(self.fd.set_crtc( Ok(self
self.crtc, .fd
Some(fb), .set_crtc(
(0, 0), self.crtc,
&pending Some(fb),
.connectors (0, 0),
.iter() &pending
.copied() .connectors
.collect::<Vec<connector::Handle>>(), .iter()
Some(*mode), .copied()
).is_ok()) .collect::<Vec<connector::Handle>>(),
Some(*mode),
)
.is_ok())
} }
// we use this function to verify, if a certain connector/mode combination // we use this function to verify, if a certain connector/mode combination
@ -345,13 +354,11 @@ impl<A: AsRawFd + 'static> LegacyDrmSurface<A> {
// Better would be some kind of test commit to ask the driver, // Better would be some kind of test commit to ask the driver,
// but that only exists for the atomic api. // but that only exists for the atomic api.
fn check_connector(&self, conn: connector::Handle, mode: &Mode) -> Result<bool, Error> { fn check_connector(&self, conn: connector::Handle, mode: &Mode) -> Result<bool, Error> {
let info = self.fd let info = self.fd.get_connector(conn).map_err(|source| Error::Access {
.get_connector(conn) errmsg: "Error loading connector info",
.map_err(|source| Error::Access { dev: self.fd.dev_path(),
errmsg: "Error loading connector info", source,
dev: self.fd.dev_path(), })?;
source,
})?;
// check if the connector can handle the current mode // check if the connector can handle the current mode
if info.modes().contains(mode) { if info.modes().contains(mode) {
@ -362,12 +369,11 @@ impl<A: AsRawFd + 'static> LegacyDrmSurface<A> {
.filter(|enc| enc.is_some()) .filter(|enc| enc.is_some())
.map(|enc| enc.unwrap()) .map(|enc| enc.unwrap())
.map(|encoder| { .map(|encoder| {
self.fd.get_encoder(encoder) self.fd.get_encoder(encoder).map_err(|source| Error::Access {
.map_err(|source| Error::Access { errmsg: "Error loading encoder info",
errmsg: "Error loading encoder info", dev: self.fd.dev_path(),
dev: self.fd.dev_path(), source,
source, })
})
}) })
.collect::<Result<Vec<encoder::Info>, _>>()?; .collect::<Result<Vec<encoder::Info>, _>>()?;
@ -406,9 +412,7 @@ impl<A: AsRawFd + 'static> Drop for LegacyDrmSurface<A> {
// disable connectors again // disable connectors again
let current = self.state.read().unwrap(); let current = self.state.read().unwrap();
if set_connector_state(&*self.fd, current.connectors.iter().copied(), false) if set_connector_state(&*self.fd, current.connectors.iter().copied(), false).is_ok() {
.is_ok()
{
// null commit // null commit
let _ = self.fd.set_crtc(self.crtc, None, (0, 0), &[], None); let _ = self.fd.set_crtc(self.crtc, None, (0, 0), &[], None);
} }

View File

@ -2,18 +2,17 @@ use std::collections::HashSet;
use std::os::unix::io::{AsRawFd, RawFd}; use std::os::unix::io::{AsRawFd, RawFd};
use std::sync::Arc; use std::sync::Arc;
use drm::control::{connector, crtc, framebuffer, plane, Device as ControlDevice, Mode};
use drm::Device as BasicDevice; use drm::Device as BasicDevice;
use drm::control::{Device as ControlDevice, Mode, crtc, connector, framebuffer, plane};
pub(super) mod atomic; pub(super) mod atomic;
pub(super) mod legacy; pub(super) mod legacy;
use super::error::Error; use super::error::Error;
use crate::backend::allocator::Format;
use atomic::AtomicDrmSurface; use atomic::AtomicDrmSurface;
use legacy::LegacyDrmSurface; use legacy::LegacyDrmSurface;
use crate::backend::allocator::Format;
pub struct DrmSurface<A: AsRawFd + 'static> pub struct DrmSurface<A: AsRawFd + 'static> {
{
pub(super) crtc: crtc::Handle, pub(super) crtc: crtc::Handle,
pub(super) plane: plane::Handle, pub(super) plane: plane::Handle,
pub(super) internal: Arc<DrmSurfaceInternal<A>>, pub(super) internal: Arc<DrmSurfaceInternal<A>>,
@ -185,12 +184,21 @@ impl<A: AsRawFd + 'static> DrmSurface<A> {
&self.formats &self.formats
} }
pub fn test_buffer(&self, fb: framebuffer::Handle, mode: &Mode, allow_screen_change: bool) -> Result<bool, Error> { pub fn test_buffer(
&self,
fb: framebuffer::Handle,
mode: &Mode,
allow_screen_change: bool,
) -> Result<bool, Error> {
match &*self.internal { match &*self.internal {
DrmSurfaceInternal::Atomic(surf) => surf.test_buffer(fb, mode), DrmSurfaceInternal::Atomic(surf) => surf.test_buffer(fb, mode),
DrmSurfaceInternal::Legacy(surf) => if allow_screen_change { DrmSurfaceInternal::Legacy(surf) => {
surf.test_buffer(fb, mode) if allow_screen_change {
} else { Ok(false) } // There is no test-commiting with the legacy interface surf.test_buffer(fb, mode)
} else {
Ok(false)
}
} // There is no test-commiting with the legacy interface
} }
} }
} }

View File

@ -6,7 +6,6 @@ use super::{ffi, wrap_egl_call, Error, MakeCurrentError};
use crate::backend::egl::display::{EGLDisplay, PixelFormat}; use crate::backend::egl::display::{EGLDisplay, PixelFormat};
use crate::backend::egl::EGLSurface; use crate::backend::egl::EGLSurface;
/// EGL context for rendering /// EGL context for rendering
#[derive(Debug)] #[derive(Debug)]
pub struct EGLContext { pub struct EGLContext {
@ -20,10 +19,7 @@ unsafe impl Send for EGLContext {}
unsafe impl Sync for EGLContext {} unsafe impl Sync for EGLContext {}
impl EGLContext { impl EGLContext {
pub fn new<L>( pub fn new<L>(display: &EGLDisplay, log: L) -> Result<EGLContext, Error>
display: &EGLDisplay,
log: L,
) -> Result<EGLContext, Error>
where where
L: Into<Option<::slog::Logger>>, L: Into<Option<::slog::Logger>>,
{ {
@ -43,11 +39,7 @@ impl EGLContext {
Self::new_internal(display, None, Some((attributes, reqs)), log) Self::new_internal(display, None, Some((attributes, reqs)), log)
} }
pub fn new_shared<L>( pub fn new_shared<L>(display: &EGLDisplay, share: &EGLContext, log: L) -> Result<EGLContext, Error>
display: &EGLDisplay,
share: &EGLContext,
log: L,
) -> Result<EGLContext, Error>
where where
L: Into<Option<::slog::Logger>>, L: Into<Option<::slog::Logger>>,
{ {
@ -82,13 +74,26 @@ impl EGLContext {
Some((attributes, reqs)) => { Some((attributes, reqs)) => {
let (format, config_id) = display.choose_config(attributes, reqs)?; let (format, config_id) = display.choose_config(attributes, reqs)?;
(Some(format), config_id) (Some(format), config_id)
}, }
None => { None => {
if !display.extensions.iter().any(|x| x == "EGL_KHR_no_config_context") && if !display
!display.extensions.iter().any(|x| x == "EGL_MESA_configless_context") && .extensions
!display.extensions.iter().any(|x| x == "EGL_KHR_surfaceless_context") .iter()
.any(|x| x == "EGL_KHR_no_config_context")
&& !display
.extensions
.iter()
.any(|x| x == "EGL_MESA_configless_context")
&& !display
.extensions
.iter()
.any(|x| x == "EGL_KHR_surfaceless_context")
{ {
return Err(Error::EglExtensionNotSupported(&["EGL_KHR_no_config_context", "EGL_MESA_configless_context", "EGL_KHR_surfaceless_context"])); return Err(Error::EglExtensionNotSupported(&[
"EGL_KHR_no_config_context",
"EGL_MESA_configless_context",
"EGL_KHR_surfaceless_context",
]));
} }
(None, ffi::egl::NO_CONFIG_KHR) (None, ffi::egl::NO_CONFIG_KHR)
} }
@ -99,7 +104,9 @@ impl EGLContext {
if let Some((attributes, _)) = config { if let Some((attributes, _)) = config {
let version = attributes.version; let version = attributes.version;
if display.egl_version >= (1, 5) || display.extensions.iter().any(|s| s == "EGL_KHR_create_context") { if display.egl_version >= (1, 5)
|| display.extensions.iter().any(|s| s == "EGL_KHR_create_context")
{
trace!(log, "Setting CONTEXT_MAJOR_VERSION to {}", version.0); trace!(log, "Setting CONTEXT_MAJOR_VERSION to {}", version.0);
context_attributes.push(ffi::egl::CONTEXT_MAJOR_VERSION as i32); context_attributes.push(ffi::egl::CONTEXT_MAJOR_VERSION as i32);
context_attributes.push(version.0 as i32); context_attributes.push(version.0 as i32);
@ -134,7 +141,9 @@ impl EGLContext {
ffi::egl::CreateContext( ffi::egl::CreateContext(
**display.display, **display.display,
config_id, config_id,
shared.map(|context| context.context).unwrap_or(ffi::egl::NO_CONTEXT), shared
.map(|context| context.context)
.unwrap_or(ffi::egl::NO_CONTEXT),
context_attributes.as_ptr(), context_attributes.as_ptr(),
) )
}) })
@ -157,12 +166,13 @@ 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(&self, surface: &EGLSurface) -> Result<(), MakeCurrentError> pub unsafe fn make_current_with_surface(&self, surface: &EGLSurface) -> Result<(), MakeCurrentError> {
{
let surface_ptr = surface.surface.load(Ordering::SeqCst); let surface_ptr = surface.surface.load(Ordering::SeqCst);
wrap_egl_call(|| ffi::egl::MakeCurrent(**self.display.display, surface_ptr, surface_ptr, self.context)) wrap_egl_call(|| {
.map(|_| ()) ffi::egl::MakeCurrent(**self.display.display, surface_ptr, surface_ptr, self.context)
.map_err(Into::into) })
.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.

View File

@ -1,10 +1,10 @@
//! Type safe native types for safe egl initialisation //! Type safe native types for safe egl initialisation
use std::collections::HashSet; use std::collections::HashSet;
use std::sync::Arc;
use std::ffi::CStr; use std::ffi::CStr;
use std::mem::MaybeUninit; use std::mem::MaybeUninit;
use std::ops::Deref; use std::ops::Deref;
use std::sync::Arc;
use nix::libc::c_int; use nix::libc::c_int;
#[cfg(all(feature = "use_system_lib", feature = "wayland_frontend"))] #[cfg(all(feature = "use_system_lib", feature = "wayland_frontend"))]
@ -12,13 +12,13 @@ use wayland_server::{protocol::wl_buffer::WlBuffer, Display};
#[cfg(feature = "use_system_lib")] #[cfg(feature = "use_system_lib")]
use wayland_sys::server::wl_display; use wayland_sys::server::wl_display;
use crate::backend::allocator::{Buffer, dmabuf::Dmabuf, Fourcc, Modifier, Format as DrmFormat}; use crate::backend::allocator::{dmabuf::Dmabuf, Buffer, Format as DrmFormat, Fourcc, Modifier};
use crate::backend::egl::{ use crate::backend::egl::{
ffi::egl::types::EGLImage,
ffi, wrap_egl_call, EGLError, Error,
context::{GlAttributes, PixelFormatRequirements}, context::{GlAttributes, PixelFormatRequirements},
native::{EGLNativeDisplay}, ffi,
BufferAccessError, EGLBuffer, Format, ffi::egl::types::EGLImage,
native::EGLNativeDisplay,
wrap_egl_call, BufferAccessError, EGLBuffer, EGLError, Error, Format,
}; };
/// Wrapper around [`ffi::EGLDisplay`](ffi::egl::types::EGLDisplay) to ensure display is only destroyed /// Wrapper around [`ffi::EGLDisplay`](ffi::egl::types::EGLDisplay) to ensure display is only destroyed
@ -355,22 +355,38 @@ impl EGLDisplay {
/// Imports a dmabuf as an eglimage /// Imports a dmabuf as an eglimage
pub fn create_image_from_dmabuf(&self, dmabuf: &Dmabuf) -> Result<EGLImage, Error> { pub fn create_image_from_dmabuf(&self, dmabuf: &Dmabuf) -> Result<EGLImage, Error> {
if !self.extensions.iter().any(|s| s == "EGL_KHR_image_base") && if !self.extensions.iter().any(|s| s == "EGL_KHR_image_base")
!self.extensions.iter().any(|s| s == "EGL_EXT_image_dma_buf_import") && !self
.extensions
.iter()
.any(|s| s == "EGL_EXT_image_dma_buf_import")
{ {
return Err(Error::EglExtensionNotSupported(&["EGL_KHR_image_base", "EGL_EXT_image_dma_buf_import"])); return Err(Error::EglExtensionNotSupported(&[
"EGL_KHR_image_base",
"EGL_EXT_image_dma_buf_import",
]));
} }
if dmabuf.has_modifier() && !self.extensions.iter().any(|s| s == "EGL_EXT_image_dma_buf_import_modifiers") { if dmabuf.has_modifier()
return Err(Error::EglExtensionNotSupported(&["EGL_EXT_image_dma_buf_import_modifiers"])); && !self
.extensions
.iter()
.any(|s| s == "EGL_EXT_image_dma_buf_import_modifiers")
{
return Err(Error::EglExtensionNotSupported(&[
"EGL_EXT_image_dma_buf_import_modifiers",
]));
}; };
let mut out: Vec<c_int> = Vec::with_capacity(50); let mut out: Vec<c_int> = Vec::with_capacity(50);
out.extend(&[ out.extend(&[
ffi::egl::WIDTH as i32, dmabuf.width() as i32, ffi::egl::WIDTH as i32,
ffi::egl::HEIGHT as i32, dmabuf.height() as i32, dmabuf.width() as i32,
ffi::egl::LINUX_DRM_FOURCC_EXT as i32, dmabuf.format().code as u32 as i32, ffi::egl::HEIGHT as i32,
dmabuf.height() as i32,
ffi::egl::LINUX_DRM_FOURCC_EXT as i32,
dmabuf.format().code as u32 as i32,
]); ]);
let names = [ let names = [
@ -379,38 +395,52 @@ impl EGLDisplay {
ffi::egl::DMA_BUF_PLANE0_OFFSET_EXT, ffi::egl::DMA_BUF_PLANE0_OFFSET_EXT,
ffi::egl::DMA_BUF_PLANE0_PITCH_EXT, ffi::egl::DMA_BUF_PLANE0_PITCH_EXT,
ffi::egl::DMA_BUF_PLANE0_MODIFIER_LO_EXT, ffi::egl::DMA_BUF_PLANE0_MODIFIER_LO_EXT,
ffi::egl::DMA_BUF_PLANE0_MODIFIER_HI_EXT ffi::egl::DMA_BUF_PLANE0_MODIFIER_HI_EXT,
], [ ],
[
ffi::egl::DMA_BUF_PLANE1_FD_EXT, ffi::egl::DMA_BUF_PLANE1_FD_EXT,
ffi::egl::DMA_BUF_PLANE1_OFFSET_EXT, ffi::egl::DMA_BUF_PLANE1_OFFSET_EXT,
ffi::egl::DMA_BUF_PLANE1_PITCH_EXT, ffi::egl::DMA_BUF_PLANE1_PITCH_EXT,
ffi::egl::DMA_BUF_PLANE1_MODIFIER_LO_EXT, ffi::egl::DMA_BUF_PLANE1_MODIFIER_LO_EXT,
ffi::egl::DMA_BUF_PLANE1_MODIFIER_HI_EXT ffi::egl::DMA_BUF_PLANE1_MODIFIER_HI_EXT,
], [ ],
[
ffi::egl::DMA_BUF_PLANE2_FD_EXT, ffi::egl::DMA_BUF_PLANE2_FD_EXT,
ffi::egl::DMA_BUF_PLANE2_OFFSET_EXT, ffi::egl::DMA_BUF_PLANE2_OFFSET_EXT,
ffi::egl::DMA_BUF_PLANE2_PITCH_EXT, ffi::egl::DMA_BUF_PLANE2_PITCH_EXT,
ffi::egl::DMA_BUF_PLANE2_MODIFIER_LO_EXT, ffi::egl::DMA_BUF_PLANE2_MODIFIER_LO_EXT,
ffi::egl::DMA_BUF_PLANE2_MODIFIER_HI_EXT ffi::egl::DMA_BUF_PLANE2_MODIFIER_HI_EXT,
], [ ],
[
ffi::egl::DMA_BUF_PLANE3_FD_EXT, ffi::egl::DMA_BUF_PLANE3_FD_EXT,
ffi::egl::DMA_BUF_PLANE3_OFFSET_EXT, ffi::egl::DMA_BUF_PLANE3_OFFSET_EXT,
ffi::egl::DMA_BUF_PLANE3_PITCH_EXT, ffi::egl::DMA_BUF_PLANE3_PITCH_EXT,
ffi::egl::DMA_BUF_PLANE3_MODIFIER_LO_EXT, ffi::egl::DMA_BUF_PLANE3_MODIFIER_LO_EXT,
ffi::egl::DMA_BUF_PLANE3_MODIFIER_HI_EXT ffi::egl::DMA_BUF_PLANE3_MODIFIER_HI_EXT,
] ],
]; ];
for (i, ((fd, offset), stride)) in dmabuf.handles().iter().zip(dmabuf.offsets()).zip(dmabuf.strides()).enumerate() { for (i, ((fd, offset), stride)) in dmabuf
.handles()
.iter()
.zip(dmabuf.offsets())
.zip(dmabuf.strides())
.enumerate()
{
out.extend(&[ out.extend(&[
names[i][0] as i32, *fd, names[i][0] as i32,
names[i][1] as i32, *offset as i32, *fd,
names[i][2] as i32, *stride as i32, names[i][1] as i32,
*offset as i32,
names[i][2] as i32,
*stride as i32,
]); ]);
if dmabuf.has_modifier() { if dmabuf.has_modifier() {
out.extend(&[ out.extend(&[
names[i][3] as i32, (Into::<u64>::into(dmabuf.format().modifier) & 0xFFFFFFFF) as i32, names[i][3] as i32,
names[i][4] as i32, (Into::<u64>::into(dmabuf.format().modifier) >> 32) as i32, (Into::<u64>::into(dmabuf.format().modifier) & 0xFFFFFFFF) as i32,
names[i][4] as i32,
(Into::<u64>::into(dmabuf.format().modifier) >> 32) as i32,
]) ])
} }
} }
@ -460,8 +490,11 @@ impl EGLDisplay {
} }
} }
fn get_dmabuf_formats(display: &ffi::egl::types::EGLDisplay, extensions: &[String], log: &::slog::Logger) -> Result<(HashSet<DrmFormat>, HashSet<DrmFormat>), EGLError> fn get_dmabuf_formats(
{ display: &ffi::egl::types::EGLDisplay,
extensions: &[String],
log: &::slog::Logger,
) -> Result<(HashSet<DrmFormat>, HashSet<DrmFormat>), EGLError> {
use std::convert::TryFrom; use std::convert::TryFrom;
if !extensions.iter().any(|s| s == "EGL_EXT_image_dma_buf_import") { if !extensions.iter().any(|s| s == "EGL_EXT_image_dma_buf_import") {
@ -475,11 +508,11 @@ fn get_dmabuf_formats(display: &ffi::egl::types::EGLDisplay, extensions: &[Strin
// supported; it's the intended way to just try to create buffers. // supported; it's the intended way to just try to create buffers.
// Just a guess but better than not supporting dmabufs at all, // Just a guess but better than not supporting dmabufs at all,
// given that the modifiers extension isn't supported everywhere. // given that the modifiers extension isn't supported everywhere.
if !extensions.iter().any(|s| s == "EGL_EXT_image_dma_buf_import_modifiers") { if !extensions
vec![ .iter()
Fourcc::Argb8888, .any(|s| s == "EGL_EXT_image_dma_buf_import_modifiers")
Fourcc::Xrgb8888, {
] vec![Fourcc::Argb8888, Fourcc::Xrgb8888]
} else { } else {
let mut num = 0i32; let mut num = 0i32;
wrap_egl_call(|| unsafe { wrap_egl_call(|| unsafe {
@ -490,12 +523,20 @@ fn get_dmabuf_formats(display: &ffi::egl::types::EGLDisplay, extensions: &[Strin
} }
let mut formats: Vec<u32> = Vec::with_capacity(num as usize); let mut formats: Vec<u32> = Vec::with_capacity(num as usize);
wrap_egl_call(|| unsafe { wrap_egl_call(|| unsafe {
ffi::egl::QueryDmaBufFormatsEXT(*display, num, formats.as_mut_ptr() as *mut _, &mut num as *mut _) ffi::egl::QueryDmaBufFormatsEXT(
*display,
num,
formats.as_mut_ptr() as *mut _,
&mut num as *mut _,
)
})?; })?;
unsafe { unsafe {
formats.set_len(num as usize); formats.set_len(num as usize);
} }
formats.into_iter().flat_map(|x| Fourcc::try_from(x).ok()).collect::<Vec<_>>() formats
.into_iter()
.flat_map(|x| Fourcc::try_from(x).ok())
.collect::<Vec<_>>()
} }
}; };
@ -505,24 +546,38 @@ fn get_dmabuf_formats(display: &ffi::egl::types::EGLDisplay, extensions: &[Strin
for fourcc in formats { for fourcc in formats {
let mut num = 0i32; let mut num = 0i32;
wrap_egl_call(|| unsafe { wrap_egl_call(|| unsafe {
ffi::egl::QueryDmaBufModifiersEXT(*display, fourcc as i32, 0, std::ptr::null_mut(), std::ptr::null_mut(), &mut num as *mut _) ffi::egl::QueryDmaBufModifiersEXT(
*display,
fourcc as i32,
0,
std::ptr::null_mut(),
std::ptr::null_mut(),
&mut num as *mut _,
)
})?; })?;
if num == 0 { if num == 0 {
texture_formats.insert(DrmFormat { texture_formats.insert(DrmFormat {
code: fourcc, code: fourcc,
modifier: Modifier::Invalid modifier: Modifier::Invalid,
}); });
render_formats.insert(DrmFormat { render_formats.insert(DrmFormat {
code: fourcc, code: fourcc,
modifier: Modifier::Invalid modifier: Modifier::Invalid,
}); });
} else { } else {
let mut mods: Vec<u64> = Vec::with_capacity(num as usize); let mut mods: Vec<u64> = Vec::with_capacity(num as usize);
let mut external: Vec<ffi::egl::types::EGLBoolean> = Vec::with_capacity(num as usize); let mut external: Vec<ffi::egl::types::EGLBoolean> = Vec::with_capacity(num as usize);
wrap_egl_call(|| unsafe { wrap_egl_call(|| unsafe {
ffi::egl::QueryDmaBufModifiersEXT(*display, fourcc as i32, num, mods.as_mut_ptr(), external.as_mut_ptr(), &mut num as *mut _) ffi::egl::QueryDmaBufModifiersEXT(
*display,
fourcc as i32,
num,
mods.as_mut_ptr(),
external.as_mut_ptr(),
&mut num as *mut _,
)
})?; })?;
unsafe { unsafe {
@ -572,10 +627,7 @@ impl fmt::Debug for EGLBufferReader {
#[cfg(feature = "use_system_lib")] #[cfg(feature = "use_system_lib")]
impl EGLBufferReader { impl EGLBufferReader {
fn new(display: Arc<EGLDisplayHandle>, wayland: *mut wl_display) -> Self { fn new(display: Arc<EGLDisplayHandle>, wayland: *mut wl_display) -> Self {
Self { Self { display, wayland }
display,
wayland,
}
} }
/// Try to receive [`EGLImages`] from a given [`WlBuffer`]. /// Try to receive [`EGLImages`] from a given [`WlBuffer`].
@ -605,9 +657,15 @@ impl EGLBufferReader {
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,
ffi::egl::TEXTURE_EXTERNAL_WL => Format::External, ffi::egl::TEXTURE_EXTERNAL_WL => Format::External,
ffi::egl::TEXTURE_Y_UV_WL => return Err(BufferAccessError::UnsupportedMultiPlanarFormat(Format::Y_UV)), ffi::egl::TEXTURE_Y_UV_WL => {
ffi::egl::TEXTURE_Y_U_V_WL => return Err(BufferAccessError::UnsupportedMultiPlanarFormat(Format::Y_U_V)), return Err(BufferAccessError::UnsupportedMultiPlanarFormat(Format::Y_UV))
ffi::egl::TEXTURE_Y_XUXV_WL => return Err(BufferAccessError::UnsupportedMultiPlanarFormat(Format::Y_XUXV)), }
ffi::egl::TEXTURE_Y_U_V_WL => {
return Err(BufferAccessError::UnsupportedMultiPlanarFormat(Format::Y_U_V))
}
ffi::egl::TEXTURE_Y_XUXV_WL => {
return Err(BufferAccessError::UnsupportedMultiPlanarFormat(Format::Y_XUXV))
}
x => panic!("EGL returned invalid texture type: {}", x), x => panic!("EGL returned invalid texture type: {}", x),
}; };
@ -646,11 +704,7 @@ impl EGLBufferReader {
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() {
let out = [ let out = [ffi::egl::WAYLAND_PLANE_WL as i32, i as i32, ffi::egl::NONE as i32];
ffi::egl::WAYLAND_PLANE_WL as i32,
i as i32,
ffi::egl::NONE as i32,
];
images.push({ images.push({
wrap_egl_call(|| unsafe { wrap_egl_call(|| unsafe {

View File

@ -106,8 +106,11 @@ impl fmt::Debug for BufferAccessError {
write!(formatter, "BufferAccessError::EGLImageCreationFailed") write!(formatter, "BufferAccessError::EGLImageCreationFailed")
} }
BufferAccessError::EglExtensionNotSupported(ref err) => write!(formatter, "{:?}", err), BufferAccessError::EglExtensionNotSupported(ref err) => write!(formatter, "{:?}", err),
BufferAccessError::UnsupportedMultiPlanarFormat(ref fmt) => BufferAccessError::UnsupportedMultiPlanarFormat(ref fmt) => write!(
write!(formatter, "BufferAccessError::UnsupportedMultiPlanerFormat({:?})", fmt), formatter,
"BufferAccessError::UnsupportedMultiPlanerFormat({:?})",
fmt
),
} }
} }
} }
@ -132,9 +135,7 @@ impl std::convert::From<SwapBuffersError> for GraphicsSwapBuffersError {
} }
// the rest is either never happening or are unrecoverable // the rest is either never happening or are unrecoverable
x @ SwapBuffersError::EGLSwapBuffers(_) => GraphicsSwapBuffersError::ContextLost(Box::new(x)), x @ SwapBuffersError::EGLSwapBuffers(_) => GraphicsSwapBuffersError::ContextLost(Box::new(x)),
x @ SwapBuffersError::EGLCreateSurface(_) => { x @ SwapBuffersError::EGLCreateSurface(_) => GraphicsSwapBuffersError::ContextLost(Box::new(x)),
GraphicsSwapBuffersError::ContextLost(Box::new(x))
}
} }
} }
} }

View File

@ -1,12 +1,10 @@
//! Type safe native types for safe context/surface creation //! Type safe native types for safe context/surface creation
use super::{ use super::{display::EGLDisplayHandle, ffi, wrap_egl_call, SwapBuffersError};
display::EGLDisplayHandle, ffi, wrap_egl_call, SwapBuffersError,
};
use nix::libc::{c_int, c_void}; use nix::libc::{c_int, c_void};
use std::sync::Arc;
#[cfg(feature = "backend_gbm")] #[cfg(feature = "backend_gbm")]
use std::os::unix::io::AsRawFd; use std::os::unix::io::AsRawFd;
use std::sync::Arc;
#[cfg(feature = "backend_winit")] #[cfg(feature = "backend_winit")]
use wayland_egl as wegl; use wayland_egl as wegl;
@ -33,7 +31,11 @@ impl<A: AsRawFd + Send + 'static> EGLNativeDisplay for GbmDevice<A> {
&["EGL_MESA_platform_gbm"] &["EGL_MESA_platform_gbm"]
} }
fn platform_display(&self) -> (ffi::egl::types::EGLenum, *mut c_void, Vec<ffi::EGLint>) { fn platform_display(&self) -> (ffi::egl::types::EGLenum, *mut c_void, Vec<ffi::EGLint>) {
(ffi::egl::PLATFORM_GBM_MESA, self.as_raw() as *mut _, vec![ffi::egl::NONE as ffi::EGLint]) (
ffi::egl::PLATFORM_GBM_MESA,
self.as_raw() as *mut _,
vec![ffi::egl::NONE as ffi::EGLint],
)
} }
} }
@ -51,9 +53,17 @@ impl EGLNativeDisplay for WinitWindow {
fn platform_display(&self) -> (ffi::egl::types::EGLenum, *mut c_void, Vec<ffi::EGLint>) { fn platform_display(&self) -> (ffi::egl::types::EGLenum, *mut c_void, Vec<ffi::EGLint>) {
if let Some(display) = self.wayland_display() { if let Some(display) = self.wayland_display() {
(ffi::egl::PLATFORM_WAYLAND_EXT, display as *mut _, vec![ffi::egl::NONE as ffi::EGLint]) (
ffi::egl::PLATFORM_WAYLAND_EXT,
display as *mut _,
vec![ffi::egl::NONE as ffi::EGLint],
)
} else if let Some(display) = self.xlib_display() { } else if let Some(display) = self.xlib_display() {
(ffi::egl::PLATFORM_X11_EXT, display as *mut _, vec![ffi::egl::NONE as ffi::EGLint]) (
ffi::egl::PLATFORM_X11_EXT,
display as *mut _,
vec![ffi::egl::NONE as ffi::EGLint],
)
} else { } else {
unreachable!("No backends for winit other then Wayland and X11 are supported") unreachable!("No backends for winit other then Wayland and X11 are supported")
} }

View File

@ -9,11 +9,11 @@ use nix::libc::c_int;
use crate::backend::egl::{ use crate::backend::egl::{
display::{EGLDisplay, EGLDisplayHandle, PixelFormat}, display::{EGLDisplay, EGLDisplayHandle, PixelFormat},
ffi,
native::EGLNativeSurface, native::EGLNativeSurface,
ffi, EGLError, SwapBuffersError EGLError, SwapBuffersError,
}; };
/// EGL surface of a given EGL context for rendering /// EGL surface of a given EGL context for rendering
pub struct EGLSurface { pub struct EGLSurface {
pub(crate) display: Arc<EGLDisplayHandle>, pub(crate) display: Arc<EGLDisplayHandle>,
@ -98,14 +98,17 @@ impl EGLSurface {
); );
if self.native.needs_recreation() || surface.is_null() || is_bad_surface { if self.native.needs_recreation() || surface.is_null() || is_bad_surface {
let previous = self.surface.compare_exchange( let previous = self
surface, .surface
self.native .compare_exchange(
.create(&self.display, self.config_id, &self.surface_attributes) surface,
.map_err(SwapBuffersError::EGLCreateSurface)? as *mut _, self.native
Ordering::SeqCst, .create(&self.display, self.config_id, &self.surface_attributes)
Ordering::SeqCst, .map_err(SwapBuffersError::EGLCreateSurface)? as *mut _,
).expect("The surface pointer changed in between?"); Ordering::SeqCst,
Ordering::SeqCst,
)
.expect("The surface pointer changed in between?");
if previous == surface && !surface.is_null() { if previous == surface && !surface.is_null() {
let _ = unsafe { ffi::egl::DestroySurface(**self.display, surface as *const _) }; let _ = unsafe { ffi::egl::DestroySurface(**self.display, surface as *const _) };
} }

View File

@ -18,8 +18,8 @@
#![allow(missing_docs)] #![allow(missing_docs)]
//pub mod graphics; //pub mod graphics;
pub mod input;
pub mod allocator; pub mod allocator;
pub mod input;
pub mod renderer; pub mod renderer;
#[cfg(feature = "backend_drm")] #[cfg(feature = "backend_drm")]

View File

@ -6,13 +6,18 @@ use std::rc::Rc;
use cgmath::{prelude::*, Matrix3}; use cgmath::{prelude::*, Matrix3};
mod shaders; mod shaders;
use super::{Bind, Renderer, Texture, Transform, Unbind};
use crate::backend::allocator::{
dmabuf::{Dmabuf, WeakDmabuf},
Format,
};
use crate::backend::egl::{
ffi::egl::types::EGLImage, EGLBuffer, EGLContext, EGLSurface, Format as EGLFormat, MakeCurrentError,
};
use crate::backend::SwapBuffersError; use crate::backend::SwapBuffersError;
use crate::backend::allocator::{dmabuf::{Dmabuf, WeakDmabuf}, Format};
use crate::backend::egl::{EGLContext, EGLSurface, EGLBuffer, Format as EGLFormat, ffi::egl::types::EGLImage, MakeCurrentError};
use super::{Renderer, Bind, Unbind, Transform, Texture};
#[cfg(feature = "wayland_frontend")] #[cfg(feature = "wayland_frontend")]
use wayland_server::protocol::{wl_shm, wl_buffer}; use wayland_server::protocol::{wl_buffer, wl_shm};
#[allow(clippy::all, missing_docs)] #[allow(clippy::all, missing_docs)]
pub mod ffi { pub mod ffi {
@ -109,44 +114,52 @@ impl From<Gles2Error> for SwapBuffersError {
| x @ Gles2Error::ProgramLinkError | x @ Gles2Error::ProgramLinkError
| x @ Gles2Error::GLFunctionLoaderError | x @ Gles2Error::GLFunctionLoaderError
| x @ Gles2Error::GLExtensionNotSupported(_) | x @ Gles2Error::GLExtensionNotSupported(_)
| x @ Gles2Error::UnconstraintRenderingOperation | x @ Gles2Error::UnconstraintRenderingOperation => SwapBuffersError::ContextLost(Box::new(x)),
=> SwapBuffersError::ContextLost(Box::new(x)),
Gles2Error::ContextActivationError(err) => err.into(), Gles2Error::ContextActivationError(err) => err.into(),
x @ Gles2Error::FramebufferBindingError x @ Gles2Error::FramebufferBindingError
| x @ Gles2Error::BindBufferEGLError(_) | x @ Gles2Error::BindBufferEGLError(_)
| x @ Gles2Error::UnsupportedPixelFormat(_) | x @ Gles2Error::UnsupportedPixelFormat(_)
| x @ Gles2Error::BufferAccessError(_) | x @ Gles2Error::BufferAccessError(_) => SwapBuffersError::TemporaryFailure(Box::new(x)),
=> SwapBuffersError::TemporaryFailure(Box::new(x)),
} }
} }
} }
extern "system" fn gl_debug_log(_source: ffi::types::GLenum, extern "system" fn gl_debug_log(
gltype: ffi::types::GLenum, _source: ffi::types::GLenum,
_id: ffi::types::GLuint, gltype: ffi::types::GLenum,
_severity: ffi::types::GLenum, _id: ffi::types::GLuint,
_length: ffi::types::GLsizei, _severity: ffi::types::GLenum,
message: *const ffi::types::GLchar, _length: ffi::types::GLsizei,
user_param: *mut nix::libc::c_void) message: *const ffi::types::GLchar,
{ user_param: *mut nix::libc::c_void,
let _ = std::panic::catch_unwind(move || { ) {
unsafe { let _ = std::panic::catch_unwind(move || unsafe {
let msg = CStr::from_ptr(message); let msg = CStr::from_ptr(message);
let log = Box::from_raw(user_param as *mut ::slog::Logger); let log = Box::from_raw(user_param as *mut ::slog::Logger);
let message_utf8 = msg.to_string_lossy(); let message_utf8 = msg.to_string_lossy();
match gltype { match gltype {
ffi::DEBUG_TYPE_ERROR | ffi::DEBUG_TYPE_UNDEFINED_BEHAVIOR => error!(log, "[GL] {}", message_utf8), ffi::DEBUG_TYPE_ERROR | ffi::DEBUG_TYPE_UNDEFINED_BEHAVIOR => {
ffi::DEBUG_TYPE_DEPRECATED_BEHAVIOR => warn!(log, "[GL] {}", message_utf8), error!(log, "[GL] {}", message_utf8)
_ => debug!(log, "[GL] {}", message_utf8), }
}; ffi::DEBUG_TYPE_DEPRECATED_BEHAVIOR => warn!(log, "[GL] {}", message_utf8),
std::mem::forget(log); _ => debug!(log, "[GL] {}", message_utf8),
} };
std::mem::forget(log);
}); });
} }
unsafe fn compile_shader(gl: &ffi::Gles2, variant: ffi::types::GLuint, src: &'static str) -> Result<ffi::types::GLuint, Gles2Error> { unsafe fn compile_shader(
gl: &ffi::Gles2,
variant: ffi::types::GLuint,
src: &'static str,
) -> Result<ffi::types::GLuint, Gles2Error> {
let shader = gl.CreateShader(variant); let shader = gl.CreateShader(variant);
gl.ShaderSource(shader, 1, &src.as_ptr() as *const *const u8 as *const *const i8, &(src.len() as i32) as *const _); gl.ShaderSource(
shader,
1,
&src.as_ptr() as *const *const u8 as *const *const i8,
&(src.len() as i32) as *const _,
);
gl.CompileShader(shader); gl.CompileShader(shader);
let mut status = ffi::FALSE as i32; let mut status = ffi::FALSE as i32;
@ -159,7 +172,11 @@ unsafe fn compile_shader(gl: &ffi::Gles2, variant: ffi::types::GLuint, src: &'st
Ok(shader) Ok(shader)
} }
unsafe fn link_program(gl: &ffi::Gles2, vert_src: &'static str, frag_src: &'static str) -> Result<ffi::types::GLuint, Gles2Error> { unsafe fn link_program(
gl: &ffi::Gles2,
vert_src: &'static str,
frag_src: &'static str,
) -> Result<ffi::types::GLuint, Gles2Error> {
let vert = compile_shader(gl, ffi::VERTEX_SHADER, vert_src)?; let vert = compile_shader(gl, ffi::VERTEX_SHADER, vert_src)?;
let frag = compile_shader(gl, ffi::FRAGMENT_SHADER, frag_src)?; let frag = compile_shader(gl, ffi::FRAGMENT_SHADER, frag_src)?;
let program = gl.CreateProgram(); let program = gl.CreateProgram();
@ -205,7 +222,7 @@ unsafe fn texture_program(gl: &ffi::Gles2, frag: &'static str) -> Result<Gles2Pr
impl Gles2Renderer { impl Gles2Renderer {
pub unsafe fn new<L>(context: EGLContext, logger: L) -> Result<Gles2Renderer, Gles2Error> pub unsafe fn new<L>(context: EGLContext, logger: L) -> Result<Gles2Renderer, Gles2Error>
where where
L: Into<Option<::slog::Logger>> L: Into<Option<::slog::Logger>>,
{ {
let log = crate::slog_or_fallback(logger).new(o!("smithay_module" => "renderer_gles2")); let log = crate::slog_or_fallback(logger).new(o!("smithay_module" => "renderer_gles2"));
@ -225,14 +242,28 @@ impl Gles2Renderer {
}; };
info!(log, "Initializing OpenGL ES Renderer"); info!(log, "Initializing OpenGL ES Renderer");
info!(log, "GL Version: {:?}", CStr::from_ptr(gl.GetString(ffi::VERSION) as *const i8)); info!(
info!(log, "GL Vendor: {:?}", CStr::from_ptr(gl.GetString(ffi::VENDOR) as *const i8)); log,
info!(log, "GL Renderer: {:?}", CStr::from_ptr(gl.GetString(ffi::RENDERER) as *const i8)); "GL Version: {:?}",
CStr::from_ptr(gl.GetString(ffi::VERSION) as *const i8)
);
info!(
log,
"GL Vendor: {:?}",
CStr::from_ptr(gl.GetString(ffi::VENDOR) as *const i8)
);
info!(
log,
"GL Renderer: {:?}",
CStr::from_ptr(gl.GetString(ffi::RENDERER) as *const i8)
);
info!(log, "Supported GL Extensions: {:?}", exts); info!(log, "Supported GL Extensions: {:?}", exts);
// required for the manditory wl_shm formats // required for the manditory wl_shm formats
if !exts.iter().any(|ext| ext == "GL_EXT_texture_format_BGRA8888") { if !exts.iter().any(|ext| ext == "GL_EXT_texture_format_BGRA8888") {
return Err(Gles2Error::GLExtensionNotSupported(&["GL_EXT_texture_format_BGRA8888"])); return Err(Gles2Error::GLExtensionNotSupported(&[
"GL_EXT_texture_format_BGRA8888",
]));
} }
// required for buffers without linear memory layout // required for buffers without linear memory layout
if !exts.iter().any(|ext| ext == "GL_EXT_unpack_subimage") { if !exts.iter().any(|ext| ext == "GL_EXT_unpack_subimage") {
@ -245,17 +276,19 @@ impl Gles2Renderer {
gl.Enable(ffi::DEBUG_OUTPUT_SYNCHRONOUS); gl.Enable(ffi::DEBUG_OUTPUT_SYNCHRONOUS);
gl.DebugMessageCallback(Some(gl_debug_log), logger as *mut nix::libc::c_void); gl.DebugMessageCallback(Some(gl_debug_log), logger as *mut nix::libc::c_void);
Some(logger) Some(logger)
} else { None }; } else {
None
};
(gl, exts, logger) (gl, exts, logger)
}; };
let programs = [ let programs = [
texture_program(&gl, shaders::FRAGMENT_SHADER_ABGR)?, texture_program(&gl, shaders::FRAGMENT_SHADER_ABGR)?,
texture_program(&gl, shaders::FRAGMENT_SHADER_XBGR)?, texture_program(&gl, shaders::FRAGMENT_SHADER_XBGR)?,
texture_program(&gl, shaders::FRAGMENT_SHADER_BGRA)?, texture_program(&gl, shaders::FRAGMENT_SHADER_BGRA)?,
texture_program(&gl, shaders::FRAGMENT_SHADER_BGRX)?, texture_program(&gl, shaders::FRAGMENT_SHADER_BGRX)?,
texture_program(&gl, shaders::FRAGMENT_SHADER_EXTERNAL)?, texture_program(&gl, shaders::FRAGMENT_SHADER_EXTERNAL)?,
]; ];
let renderer = Gles2Renderer { let renderer = Gles2Renderer {
@ -312,31 +345,45 @@ impl Bind<Dmabuf> for Gles2Renderer {
} }
} }
let buffer = self.buffers let buffer = self
.buffers
.iter() .iter()
.find(|buffer| dmabuf == buffer.dmabuf) .find(|buffer| dmabuf == buffer.dmabuf)
.map(|buf| { .map(|buf| {
let dmabuf = buf.dmabuf.upgrade().expect("Dmabuf equal check succeeded for freed buffer"); let dmabuf = buf
.dmabuf
.upgrade()
.expect("Dmabuf equal check succeeded for freed buffer");
Ok(Gles2Buffer { Ok(Gles2Buffer {
internal: buf.clone(), internal: buf.clone(),
// we keep the dmabuf alive as long as we are bound // we keep the dmabuf alive as long as we are bound
_dmabuf: dmabuf _dmabuf: dmabuf,
}) })
}) })
.unwrap_or_else(|| { .unwrap_or_else(|| {
let image = self.egl.display.create_image_from_dmabuf(&dmabuf).map_err(Gles2Error::BindBufferEGLError)?; let image = self
.egl
.display
.create_image_from_dmabuf(&dmabuf)
.map_err(Gles2Error::BindBufferEGLError)?;
unsafe { unsafe {
let mut rbo = 0; let mut rbo = 0;
self.gl.GenRenderbuffers(1, &mut rbo as *mut _); self.gl.GenRenderbuffers(1, &mut rbo as *mut _);
self.gl.BindRenderbuffer(ffi::RENDERBUFFER, rbo); self.gl.BindRenderbuffer(ffi::RENDERBUFFER, rbo);
self.gl.EGLImageTargetRenderbufferStorageOES(ffi::RENDERBUFFER, image); self.gl
.EGLImageTargetRenderbufferStorageOES(ffi::RENDERBUFFER, image);
self.gl.BindRenderbuffer(ffi::RENDERBUFFER, 0); self.gl.BindRenderbuffer(ffi::RENDERBUFFER, 0);
let mut fbo = 0; let mut fbo = 0;
self.gl.GenFramebuffers(1, &mut fbo as *mut _); self.gl.GenFramebuffers(1, &mut fbo as *mut _);
self.gl.BindFramebuffer(ffi::FRAMEBUFFER, fbo); self.gl.BindFramebuffer(ffi::FRAMEBUFFER, fbo);
self.gl.FramebufferRenderbuffer(ffi::FRAMEBUFFER, ffi::COLOR_ATTACHMENT0, ffi::RENDERBUFFER, rbo); self.gl.FramebufferRenderbuffer(
ffi::FRAMEBUFFER,
ffi::COLOR_ATTACHMENT0,
ffi::RENDERBUFFER,
rbo,
);
let status = self.gl.CheckFramebufferStatus(ffi::FRAMEBUFFER); let status = self.gl.CheckFramebufferStatus(ffi::FRAMEBUFFER);
self.gl.BindFramebuffer(ffi::FRAMEBUFFER, 0); self.gl.BindFramebuffer(ffi::FRAMEBUFFER, 0);
@ -356,7 +403,7 @@ impl Bind<Dmabuf> for Gles2Renderer {
Ok(Gles2Buffer { Ok(Gles2Buffer {
internal: weak, internal: weak,
_dmabuf: dmabuf _dmabuf: dmabuf,
}) })
} }
})?; })?;
@ -439,16 +486,31 @@ impl Renderer for Gles2Renderer {
} }
#[cfg(feature = "image")] #[cfg(feature = "image")]
fn import_bitmap<C: std::ops::Deref<Target=[u8]>>(&mut self, image: &image::ImageBuffer<image::Rgba<u8>, C>) -> Result<Self::TextureId, Self::Error> { fn import_bitmap<C: std::ops::Deref<Target = [u8]>>(
&mut self,
image: &image::ImageBuffer<image::Rgba<u8>, C>,
) -> Result<Self::TextureId, Self::Error> {
self.make_current()?; self.make_current()?;
let mut tex = 0; let mut tex = 0;
unsafe { unsafe {
self.gl.GenTextures(1, &mut tex); self.gl.GenTextures(1, &mut tex);
self.gl.BindTexture(ffi::TEXTURE_2D, tex); self.gl.BindTexture(ffi::TEXTURE_2D, tex);
self.gl.TexParameteri(ffi::TEXTURE_2D, ffi::TEXTURE_WRAP_S, ffi::CLAMP_TO_EDGE as i32); self.gl
self.gl.TexParameteri(ffi::TEXTURE_2D, ffi::TEXTURE_WRAP_T, ffi::CLAMP_TO_EDGE as i32); .TexParameteri(ffi::TEXTURE_2D, ffi::TEXTURE_WRAP_S, ffi::CLAMP_TO_EDGE as i32);
self.gl.TexImage2D(ffi::TEXTURE_2D, 0, ffi::RGBA as i32, image.width() as i32, image.height() as i32, 0, ffi::RGBA, ffi::UNSIGNED_BYTE as u32, image.as_ptr() as *const _); self.gl
.TexParameteri(ffi::TEXTURE_2D, ffi::TEXTURE_WRAP_T, ffi::CLAMP_TO_EDGE as i32);
self.gl.TexImage2D(
ffi::TEXTURE_2D,
0,
ffi::RGBA as i32,
image.width() as i32,
image.height() as i32,
0,
ffi::RGBA,
ffi::UNSIGNED_BYTE as u32,
image.as_ptr() as *const _,
);
self.gl.BindTexture(ffi::TEXTURE_2D, 0); self.gl.BindTexture(ffi::TEXTURE_2D, 0);
} }
@ -465,7 +527,6 @@ impl Renderer for Gles2Renderer {
Ok(texture) Ok(texture)
} }
#[cfg(feature = "wayland_frontend")] #[cfg(feature = "wayland_frontend")]
fn import_shm(&mut self, buffer: &wl_buffer::WlBuffer) -> Result<Self::TextureId, Self::Error> { fn import_shm(&mut self, buffer: &wl_buffer::WlBuffer) -> Result<Self::TextureId, Self::Error> {
use crate::wayland::shm::with_buffer_contents; use crate::wayland::shm::with_buffer_contents;
@ -498,10 +559,22 @@ impl Renderer for Gles2Renderer {
self.gl.GenTextures(1, &mut tex); self.gl.GenTextures(1, &mut tex);
self.gl.BindTexture(ffi::TEXTURE_2D, tex); self.gl.BindTexture(ffi::TEXTURE_2D, tex);
self.gl.TexParameteri(ffi::TEXTURE_2D, ffi::TEXTURE_WRAP_S, ffi::CLAMP_TO_EDGE as i32); self.gl
self.gl.TexParameteri(ffi::TEXTURE_2D, ffi::TEXTURE_WRAP_T, ffi::CLAMP_TO_EDGE as i32); .TexParameteri(ffi::TEXTURE_2D, ffi::TEXTURE_WRAP_S, ffi::CLAMP_TO_EDGE as i32);
self.gl
.TexParameteri(ffi::TEXTURE_2D, ffi::TEXTURE_WRAP_T, ffi::CLAMP_TO_EDGE as i32);
self.gl.PixelStorei(ffi::UNPACK_ROW_LENGTH, stride / pixelsize); self.gl.PixelStorei(ffi::UNPACK_ROW_LENGTH, stride / pixelsize);
self.gl.TexImage2D(ffi::TEXTURE_2D, 0, gl_format as i32, width, height, 0, gl_format, ffi::UNSIGNED_BYTE as u32, slice.as_ptr() as *const _); self.gl.TexImage2D(
ffi::TEXTURE_2D,
0,
gl_format as i32,
width,
height,
0,
gl_format,
ffi::UNSIGNED_BYTE as u32,
slice.as_ptr() as *const _,
);
self.gl.PixelStorei(ffi::UNPACK_ROW_LENGTH, 0); self.gl.PixelStorei(ffi::UNPACK_ROW_LENGTH, 0);
self.gl.BindTexture(ffi::TEXTURE_2D, 0); self.gl.BindTexture(ffi::TEXTURE_2D, 0);
@ -518,7 +591,8 @@ impl Renderer for Gles2Renderer {
self.egl.unbind()?; self.egl.unbind()?;
Ok(texture) Ok(texture)
}).map_err(Gles2Error::BufferAccessError)? })
.map_err(Gles2Error::BufferAccessError)?
} }
#[cfg(feature = "wayland_frontend")] #[cfg(feature = "wayland_frontend")]
@ -530,21 +604,23 @@ impl Renderer for Gles2Renderer {
self.make_current()?; self.make_current()?;
let mut tex = 0; let mut tex = 0;
let target = if buffer.format == EGLFormat::External { ffi::TEXTURE_EXTERNAL_OES } else { ffi::TEXTURE_2D }; let target = if buffer.format == EGLFormat::External {
ffi::TEXTURE_EXTERNAL_OES
} else {
ffi::TEXTURE_2D
};
unsafe { unsafe {
self.gl.GenTextures(1, &mut tex); self.gl.GenTextures(1, &mut tex);
self.gl.BindTexture(target, tex); self.gl.BindTexture(target, tex);
self.gl.EGLImageTargetTexture2DOES( self.gl
target, .EGLImageTargetTexture2DOES(target, buffer.image(0).unwrap());
buffer.image(0).unwrap(),
);
} }
let texture = Gles2Texture { let texture = Gles2Texture {
texture: tex, texture: tex,
texture_kind: match buffer.format { texture_kind: match buffer.format {
EGLFormat::RGB => 3, EGLFormat::RGB => 3,
EGLFormat::RGBA => 2, EGLFormat::RGBA => 2,
EGLFormat::External => 4, EGLFormat::External => 4,
_ => unreachable!("EGLBuffer currenly does not expose multi-planar buffers to us"), _ => unreachable!("EGLBuffer currenly does not expose multi-planar buffers to us"),
@ -570,7 +646,6 @@ impl Renderer for Gles2Renderer {
Ok(()) Ok(())
} }
fn begin(&mut self, width: u32, height: u32, transform: Transform) -> Result<(), Gles2Error> { fn begin(&mut self, width: u32, height: u32, transform: Transform) -> Result<(), Gles2Error> {
self.make_current()?; self.make_current()?;
unsafe { unsafe {
@ -612,7 +687,12 @@ impl Renderer for Gles2Renderer {
Ok(()) Ok(())
} }
fn render_texture(&mut self, tex: &Self::TextureId, mut matrix: Matrix3<f32>, alpha: f32) -> Result<(), Self::Error> { fn render_texture(
&mut self,
tex: &Self::TextureId,
mut matrix: Matrix3<f32>,
alpha: f32,
) -> Result<(), Self::Error> {
self.make_current()?; self.make_current()?;
if self.current_projection.is_none() { if self.current_projection.is_none() {
return Err(Gles2Error::UnconstraintRenderingOperation); return Err(Gles2Error::UnconstraintRenderingOperation);
@ -621,30 +701,62 @@ impl Renderer for Gles2Renderer {
//apply output transformation //apply output transformation
matrix = self.current_projection.as_ref().unwrap() * matrix; matrix = self.current_projection.as_ref().unwrap() * matrix;
let target = if tex.is_external { ffi::TEXTURE_EXTERNAL_OES } else { ffi::TEXTURE_2D }; let target = if tex.is_external {
ffi::TEXTURE_EXTERNAL_OES
} else {
ffi::TEXTURE_2D
};
// render // render
unsafe { unsafe {
self.gl.ActiveTexture(ffi::TEXTURE0); self.gl.ActiveTexture(ffi::TEXTURE0);
self.gl.BindTexture(target, tex.texture); self.gl.BindTexture(target, tex.texture);
self.gl.TexParameteri(target, ffi::TEXTURE_MIN_FILTER, ffi::LINEAR as i32); self.gl
.TexParameteri(target, ffi::TEXTURE_MIN_FILTER, ffi::LINEAR as i32);
self.gl.UseProgram(self.programs[tex.texture_kind].program); self.gl.UseProgram(self.programs[tex.texture_kind].program);
self.gl.Uniform1i(self.programs[tex.texture_kind].uniform_tex, 0); self.gl.Uniform1i(self.programs[tex.texture_kind].uniform_tex, 0);
self.gl.UniformMatrix3fv(self.programs[tex.texture_kind].uniform_matrix, 1, ffi::FALSE, matrix.as_ptr()); self.gl.UniformMatrix3fv(
self.gl.Uniform1i(self.programs[tex.texture_kind].uniform_invert_y, if tex.y_inverted { 1 } else { 0 }); self.programs[tex.texture_kind].uniform_matrix,
self.gl.Uniform1f(self.programs[tex.texture_kind].uniform_alpha, alpha); 1,
ffi::FALSE,
matrix.as_ptr(),
);
self.gl.Uniform1i(
self.programs[tex.texture_kind].uniform_invert_y,
if tex.y_inverted { 1 } else { 0 },
);
self.gl
.Uniform1f(self.programs[tex.texture_kind].uniform_alpha, alpha);
self.gl.VertexAttribPointer(self.programs[tex.texture_kind].attrib_position as u32, 2, ffi::FLOAT, ffi::FALSE, 0, VERTS.as_ptr() as *const _); self.gl.VertexAttribPointer(
self.gl.VertexAttribPointer(self.programs[tex.texture_kind].attrib_tex_coords as u32, 2, ffi::FLOAT, ffi::FALSE, 0, TEX_COORDS.as_ptr() as *const _); self.programs[tex.texture_kind].attrib_position as u32,
2,
ffi::FLOAT,
ffi::FALSE,
0,
VERTS.as_ptr() as *const _,
);
self.gl.VertexAttribPointer(
self.programs[tex.texture_kind].attrib_tex_coords as u32,
2,
ffi::FLOAT,
ffi::FALSE,
0,
TEX_COORDS.as_ptr() as *const _,
);
self.gl.EnableVertexAttribArray(self.programs[tex.texture_kind].attrib_position as u32); self.gl
self.gl.EnableVertexAttribArray(self.programs[tex.texture_kind].attrib_tex_coords as u32); .EnableVertexAttribArray(self.programs[tex.texture_kind].attrib_position as u32);
self.gl
.EnableVertexAttribArray(self.programs[tex.texture_kind].attrib_tex_coords as u32);
self.gl.DrawArrays(ffi::TRIANGLE_STRIP, 0, 4); self.gl.DrawArrays(ffi::TRIANGLE_STRIP, 0, 4);
self.gl.DisableVertexAttribArray(self.programs[tex.texture_kind].attrib_position as u32); self.gl
self.gl.DisableVertexAttribArray(self.programs[tex.texture_kind].attrib_tex_coords as u32); .DisableVertexAttribArray(self.programs[tex.texture_kind].attrib_position as u32);
self.gl
.DisableVertexAttribArray(self.programs[tex.texture_kind].attrib_tex_coords as u32);
self.gl.BindTexture(target, 0); self.gl.BindTexture(target, 0);
} }

View File

@ -3,7 +3,7 @@ use std::error::Error;
use cgmath::{prelude::*, Matrix3, Vector2}; use cgmath::{prelude::*, Matrix3, Vector2};
#[cfg(feature = "wayland_frontend")] #[cfg(feature = "wayland_frontend")]
use wayland_server::protocol::{wl_shm, wl_buffer}; use wayland_server::protocol::{wl_buffer, wl_shm};
use crate::backend::SwapBuffersError; use crate::backend::SwapBuffersError;
#[cfg(feature = "renderer_gl")] #[cfg(feature = "renderer_gl")]
@ -26,46 +26,14 @@ pub enum Transform {
impl Transform { impl Transform {
pub fn matrix(&self) -> Matrix3<f32> { pub fn matrix(&self) -> Matrix3<f32> {
match self { match self {
Transform::Normal => Matrix3::new( Transform::Normal => Matrix3::new(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0),
1.0, 0.0, 0.0, Transform::_90 => Matrix3::new(0.0, -1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0),
0.0, 1.0, 0.0, Transform::_180 => Matrix3::new(-1.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0, 0.0, 1.0),
0.0, 0.0, 1.0, Transform::_270 => Matrix3::new(0.0, 1.0, 0.0, -1.0, 0.0, 0.0, 0.0, 0.0, 1.0),
), Transform::Flipped => Matrix3::new(-1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0),
Transform::_90 => Matrix3::new( Transform::Flipped90 => Matrix3::new(0.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0),
0.0, -1.0, 0.0, Transform::Flipped180 => Matrix3::new(1.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0, 0.0, 1.0),
1.0, 0.0, 0.0, Transform::Flipped270 => Matrix3::new(0.0, -1.0, 0.0, -1.0, 0.0, 0.0, 0.0, 0.0, 1.0),
0.0, 0.0, 1.0,
),
Transform::_180 => Matrix3::new(
-1.0, 0.0, 0.0,
0.0, -1.0, 0.0,
0.0, 0.0, 1.0,
),
Transform::_270 => Matrix3::new(
0.0, 1.0, 0.0,
-1.0, 0.0, 0.0,
0.0, 0.0, 1.0,
),
Transform::Flipped => Matrix3::new(
-1.0, 0.0, 0.0,
0.0, 1.0, 0.0,
0.0, 0.0, 1.0,
),
Transform::Flipped90 => Matrix3::new(
0.0, 1.0, 0.0,
1.0, 0.0, 0.0,
0.0, 0.0, 1.0,
),
Transform::Flipped180 => Matrix3::new(
1.0, 0.0, 0.0,
0.0, -1.0, 0.0,
0.0, 0.0, 1.0,
),
Transform::Flipped270 => Matrix3::new(
0.0, -1.0, 0.0,
-1.0, 0.0, 0.0,
0.0, 0.0, 1.0,
),
} }
} }
@ -137,7 +105,10 @@ pub trait Renderer {
type TextureId: Texture; type TextureId: Texture;
#[cfg(feature = "image")] #[cfg(feature = "image")]
fn import_bitmap<C: std::ops::Deref<Target=[u8]>>(&mut self, image: &image::ImageBuffer<image::Rgba<u8>, C>) -> Result<Self::TextureId, Self::Error>; fn import_bitmap<C: std::ops::Deref<Target = [u8]>>(
&mut self,
image: &image::ImageBuffer<image::Rgba<u8>, C>,
) -> Result<Self::TextureId, Self::Error>;
#[cfg(feature = "wayland_frontend")] #[cfg(feature = "wayland_frontend")]
fn shm_formats(&self) -> &[wl_shm::Format] { fn shm_formats(&self) -> &[wl_shm::Format] {
// Mandatory // Mandatory
@ -149,12 +120,28 @@ pub trait Renderer {
fn import_egl(&mut self, buffer: &EGLBuffer) -> Result<Self::TextureId, Self::Error>; fn import_egl(&mut self, buffer: &EGLBuffer) -> Result<Self::TextureId, Self::Error>;
fn destroy_texture(&mut self, texture: Self::TextureId) -> Result<(), Self::Error>; fn destroy_texture(&mut self, texture: Self::TextureId) -> Result<(), Self::Error>;
fn begin(&mut self, width: u32, height: u32, transform: Transform) -> Result<(), <Self as Renderer>::Error>; fn begin(
&mut self,
width: u32,
height: u32,
transform: Transform,
) -> Result<(), <Self as Renderer>::Error>;
fn finish(&mut self) -> Result<(), SwapBuffersError>; fn finish(&mut self) -> Result<(), SwapBuffersError>;
fn clear(&mut self, color: [f32; 4]) -> Result<(), Self::Error>; fn clear(&mut self, color: [f32; 4]) -> Result<(), Self::Error>;
fn render_texture(&mut self, texture: &Self::TextureId, matrix: Matrix3<f32>, alpha: f32) -> Result<(), Self::Error>; fn render_texture(
fn render_texture_at(&mut self, texture: &Self::TextureId, pos: (i32, i32), transform: Transform, alpha: f32) -> Result<(), Self::Error> { &mut self,
texture: &Self::TextureId,
matrix: Matrix3<f32>,
alpha: f32,
) -> Result<(), Self::Error>;
fn render_texture_at(
&mut self,
texture: &Self::TextureId,
pos: (i32, i32),
transform: Transform,
alpha: f32,
) -> Result<(), Self::Error> {
let mut mat = Matrix3::<f32>::identity(); let mut mat = Matrix3::<f32>::identity();
// position and scale // position and scale
@ -173,5 +160,4 @@ pub trait Renderer {
self.render_texture(texture, mat, alpha) self.render_texture(texture, mat, alpha)
} }
} }

View File

@ -2,28 +2,24 @@
use crate::backend::egl::display::EGLDisplay; use crate::backend::egl::display::EGLDisplay;
use crate::backend::{ use crate::backend::{
egl::{context::GlAttributes, native, EGLContext, EGLSurface, EGLBuffer, Error as EGLError}, egl::{context::GlAttributes, native, EGLBuffer, EGLContext, EGLSurface, Error as EGLError},
renderer::{
Renderer, Bind, Transform,
gles2::{Gles2Renderer, Gles2Error, Gles2Texture},
},
input::{ input::{
Axis, AxisSource, Event as BackendEvent, InputBackend, InputEvent, KeyState, KeyboardKeyEvent, Axis, AxisSource, Event as BackendEvent, InputBackend, InputEvent, KeyState, KeyboardKeyEvent,
MouseButton, MouseButtonState, PointerAxisEvent, PointerButtonEvent, PointerMotionAbsoluteEvent, MouseButton, MouseButtonState, PointerAxisEvent, PointerButtonEvent, PointerMotionAbsoluteEvent,
Seat, SeatCapabilities, TouchCancelEvent, TouchDownEvent, TouchMotionEvent, TouchSlot, TouchUpEvent, Seat, SeatCapabilities, TouchCancelEvent, TouchDownEvent, TouchMotionEvent, TouchSlot, TouchUpEvent,
UnusedEvent, UnusedEvent,
}, },
}; renderer::{
use std::{ gles2::{Gles2Error, Gles2Renderer, Gles2Texture},
cell::RefCell, Bind, Renderer, Transform,
rc::Rc, },
time::Instant,
}; };
use cgmath::Matrix3; use cgmath::Matrix3;
use std::{cell::RefCell, rc::Rc, time::Instant};
use wayland_egl as wegl; use wayland_egl as wegl;
use wayland_server::Display;
#[cfg(feature = "wayland_frontend")] #[cfg(feature = "wayland_frontend")]
use wayland_server::protocol::{wl_shm, wl_buffer}; use wayland_server::protocol::{wl_buffer, wl_shm};
use wayland_server::Display;
use winit::{ use winit::{
dpi::{LogicalPosition, LogicalSize, PhysicalSize}, dpi::{LogicalPosition, LogicalSize, PhysicalSize},
event::{ event::{
@ -37,7 +33,7 @@ use winit::{
}; };
#[cfg(feature = "use_system_lib")] #[cfg(feature = "use_system_lib")]
use crate::backend::egl::{display::EGLBufferReader}; use crate::backend::egl::display::EGLBufferReader;
/// Errors thrown by the `winit` backends /// Errors thrown by the `winit` backends
#[derive(thiserror::Error, Debug)] #[derive(thiserror::Error, Debug)]
@ -158,23 +154,33 @@ where
let surface = unsafe { let surface = unsafe {
wegl::WlEglSurface::new_from_raw(wl_surface as *mut _, size.width as i32, size.height as i32) wegl::WlEglSurface::new_from_raw(wl_surface as *mut _, size.width as i32, size.height as i32)
}; };
EGLSurface::new(&display, context.pixel_format().unwrap(), reqs.double_buffer, context.config_id(), surface, log.clone()) EGLSurface::new(
.map_err(EGLError::CreationFailed)? &display,
context.pixel_format().unwrap(),
reqs.double_buffer,
context.config_id(),
surface,
log.clone(),
)
.map_err(EGLError::CreationFailed)?
} else if let Some(xlib_window) = winit_window.xlib_window().map(native::XlibWindow) { } else if let Some(xlib_window) = winit_window.xlib_window().map(native::XlibWindow) {
debug!(log, "Winit backend: X11"); debug!(log, "Winit backend: X11");
EGLSurface::new(&display, context.pixel_format().unwrap(), reqs.double_buffer, context.config_id(), xlib_window, log.clone()) EGLSurface::new(
.map_err(EGLError::CreationFailed)? &display,
context.pixel_format().unwrap(),
reqs.double_buffer,
context.config_id(),
xlib_window,
log.clone(),
)
.map_err(EGLError::CreationFailed)?
} else { } else {
unreachable!("No backends for winit other then Wayland and X11 are supported") unreachable!("No backends for winit other then Wayland and X11 are supported")
}; };
let _ = context.unbind(); let _ = context.unbind();
( (display, context, surface)
display,
context,
surface,
)
}; };
let size = Rc::new(RefCell::new(WindowSize { let size = Rc::new(RefCell::new(WindowSize {
@ -261,7 +267,10 @@ impl Renderer for WinitGraphicsBackend {
type TextureId = Gles2Texture; type TextureId = Gles2Texture;
#[cfg(feature = "image")] #[cfg(feature = "image")]
fn import_bitmap<C: std::ops::Deref<Target=[u8]>>(&mut self, image: &image::ImageBuffer<image::Rgba<u8>, C>) -> Result<Self::TextureId, Self::Error> { fn import_bitmap<C: std::ops::Deref<Target = [u8]>>(
&mut self,
image: &image::ImageBuffer<image::Rgba<u8>, C>,
) -> Result<Self::TextureId, Self::Error> {
self.renderer.import_bitmap(image) self.renderer.import_bitmap(image)
} }
@ -284,7 +293,12 @@ impl Renderer for WinitGraphicsBackend {
self.renderer.destroy_texture(texture) self.renderer.destroy_texture(texture)
} }
fn begin(&mut self, width: u32, height: u32, transform: Transform) -> Result<(), <Self as Renderer>::Error> { fn begin(
&mut self,
width: u32,
height: u32,
transform: Transform,
) -> Result<(), <Self as Renderer>::Error> {
self.renderer.bind(self.egl.clone())?; self.renderer.bind(self.egl.clone())?;
self.renderer.begin(width, height, transform) self.renderer.begin(width, height, transform)
} }
@ -293,7 +307,12 @@ impl Renderer for WinitGraphicsBackend {
self.renderer.clear(color) self.renderer.clear(color)
} }
fn render_texture(&mut self, texture: &Self::TextureId, matrix: Matrix3<f32>, alpha: f32) -> Result<(), Self::Error> { fn render_texture(
&mut self,
texture: &Self::TextureId,
matrix: Matrix3<f32>,
alpha: f32,
) -> Result<(), Self::Error> {
self.renderer.render_texture(texture, matrix, alpha) self.renderer.render_texture(texture, matrix, alpha)
} }

View File

@ -255,7 +255,11 @@ where
for f in &*formats { for f in &*formats {
dmabuf.format(f.format as u32); dmabuf.format(f.format as u32);
if version >= 3 { if version >= 3 {
dmabuf.modifier(f.format as u32, (Into::<u64>::into(f.modifier) >> 32) as u32, Into::<u64>::into(f.modifier) as u32); dmabuf.modifier(
f.format as u32,
(Into::<u64>::into(f.modifier) >> 32) as u32,
Into::<u64>::into(f.modifier) as u32,
);
} }
} }
}, },