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,14 +147,14 @@ 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,
texture_destruction_callback: &Sender<T>, texture_destruction_callback: &Sender<T>,
) -> Result<&'a T, R::Error> { ) -> Result<&'a T, R::Error> {
let texture = renderer.import_shm(&self.buffer)?; let texture = renderer.import_shm(&self.buffer)?;
if let Some(old_texture) = self.textures.insert(id, texture) { if let Some(old_texture) = self.textures.insert(id, texture) {
let _ = renderer.destroy_texture(old_texture)?; let _ = renderer.destroy_texture(old_texture)?;
} }
@ -173,4 +171,4 @@ impl<T> Drop for BufferTextures<T> {
self.callbacks.get(&id).unwrap().send(texture).unwrap(); self.callbacks.get(&id).unwrap().send(texture).unwrap();
} }
} }
} }

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,41 +173,39 @@ 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,38 +419,40 @@ 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;
} }
}; };
// init hardware acceleration on the primary gpu. // init hardware acceleration on the primary gpu.
#[cfg(feature = "egl")] #[cfg(feature = "egl")]
{ {
@ -470,19 +461,21 @@ 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;
} }
}; };
let backends = Rc::new(RefCell::new(UdevHandlerImpl::<Data>::scan_connectors( let backends = Rc::new(RefCell::new(UdevHandlerImpl::<Data>::scan_connectors(
&mut device, &mut device,
&gbm, &gbm,
@ -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");
@ -741,7 +735,7 @@ impl DrmRenderer {
self.window_map self.window_map
.borrow() .borrow()
.send_frames(self.start_time.elapsed().as_millis() as u32); .send_frames(self.start_time.elapsed().as_millis() as u32);
while let Ok(texture) = self.texture_destruction_callback.1.try_recv() { while let Ok(texture) = self.texture_destruction_callback.1.try_recv() {
let _ = surface.borrow_mut().destroy_texture(texture); let _ = surface.borrow_mut().destroy_texture(texture);
} }
@ -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,
)?;
} }
} }
} }
@ -842,4 +845,4 @@ impl DrmRenderer {
} }
surface.finish() surface.finish()
} }
} }

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");
} }
} }
} }
@ -137,11 +159,21 @@ pub fn run_winit(
if reset { if reset {
*guard = CursorImageStatus::Default; *guard = CursorImageStatus::Default;
} }
// 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,12 +96,20 @@ 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);
// Get the device as an allocator into the // Get the device as an allocator into the
device.set_handler(DrmHandlerImpl { device.set_handler(DrmHandlerImpl {
swapchain, swapchain,
current: first_buffer, current: first_buffer,
@ -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 {
@ -128,4 +144,4 @@ impl Drop for DmabufInternal {
} }
} }
} }
} }

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 {
@ -38,7 +43,7 @@ impl<A: AsRawFd + 'static> Buffer for DumbBuffer<A> {
fn height(&self) -> u32 { fn height(&self) -> u32 {
self.handle.size().1 self.handle.size().1
} }
fn format(&self) -> Format { fn format(&self) -> Format {
self.format self.format
} }
@ -48,4 +53,4 @@ impl<A: AsRawFd + 'static> Drop for DumbBuffer<A> {
fn drop(&mut self) { fn drop(&mut self) {
let _ = self.fd.destroy_dumb_buffer(self.handle); let _ = self.fd.destroy_dumb_buffer(self.handle);
} }
} }

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,8 +119,12 @@ 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;
} }
@ -20,4 +25,4 @@ pub trait Allocator<B: Buffer> {
type Error: std::error::Error; type Error: std::error::Error;
fn create_buffer(&mut self, width: u32, height: u32, format: Format) -> Result<B, Self::Error>; fn create_buffer(&mut self, width: u32, height: u32, format: Format) -> Result<B, Self::Error>;
} }

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
@ -132,4 +136,4 @@ where
self.height = height; self.height = height;
self.slots = Default::default(); self.slots = Default::default();
} }
} }

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();
@ -77,7 +86,7 @@ impl<A: AsRawFd + 'static> AtomicDrmDevice<A> {
dev.old_state = old_state; dev.old_state = old_state;
dev.prop_mapping = mapping; dev.prop_mapping = mapping;
trace!(dev.logger, "Mapping: {:#?}", dev.prop_mapping); trace!(dev.logger, "Mapping: {:#?}", dev.prop_mapping);
// 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.
// //
@ -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,13 +214,14 @@ 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(),
source, source,
})?; })?;
Ok(()) Ok(())
} }
} }

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,24 +18,27 @@ 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,
old_state: HashMap::new(), old_state: HashMap::new(),
logger: logger.new(o!("smithay_module" => "backend_drm_legacy", "drm_module" => "device")), logger: logger.new(o!("smithay_module" => "backend_drm_legacy", "drm_module" => "device")),
}; };
// 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
@ -181,4 +181,4 @@ where
} }
} }
Ok(()) Ok(())
} }

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,
@ -91,10 +94,8 @@ 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"
@ -151,13 +164,15 @@ impl<A: AsRawFd + 'static> DrmDevice<A> {
if force_legacy { if force_legacy {
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) {
@ -196,7 +211,7 @@ impl<A: AsRawFd + 'static> DrmDevice<A> {
DrmDeviceInternal::Legacy(_) => false, DrmDeviceInternal::Legacy(_) => false,
} }
} }
pub fn set_handler(&mut self, handler: impl DeviceHandler + 'static) { pub fn set_handler(&mut self, handler: impl DeviceHandler + 'static) {
let handler = Some(Box::new(handler) as Box<dyn DeviceHandler + 'static>); let handler = Some(Box::new(handler) as Box<dyn DeviceHandler + 'static>);
*self.handler.borrow_mut() = handler; *self.handler.borrow_mut() = handler;
@ -219,14 +234,20 @@ 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 information", errmsg: "Failed to get plane information",
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) {
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
},
}) })
} }
@ -242,14 +267,14 @@ impl<A: AsRawFd + 'static> DrmDevice<A> {
let props = self.get_properties(plane).map_err(|source| Error::Access { let props = self.get_properties(plane).map_err(|source| Error::Access {
errmsg: "Failed to get properties of plane", errmsg: "Failed to get properties of plane",
dev: self.dev_path(), dev: self.dev_path(),
source, source,
})?; })?;
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()) {
let info = self.get_property(id).map_err(|source| Error::Access { let info = self.get_property(id).map_err(|source| Error::Access {
errmsg: "Failed to get property info", errmsg: "Failed to get property info",
dev: self.dev_path(), dev: self.dev_path(),
source, source,
})?; })?;
if info.name().to_str().map(|x| x == "type").unwrap_or(false) { if info.name().to_str().map(|x| x == "type").unwrap_or(false) {
return Ok(match val { return Ok(match val {
@ -262,21 +287,27 @@ 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));
} }
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) {
return Err(Error::PlaneNotCompatible(crtc, plane)); return Err(Error::PlaneNotCompatible(crtc, plane));
} }
let active = match &*self.internal { let active = match &*self.internal {
DrmDeviceInternal::Atomic(dev) => dev.active.clone(), DrmDeviceInternal::Atomic(dev) => dev.active.clone(),
DrmDeviceInternal::Legacy(dev) => dev.active.clone(), DrmDeviceInternal::Legacy(dev) => dev.active.clone(),
@ -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 }))
@ -81,4 +82,4 @@ impl From<Error> for SwapBuffersError {
x => SwapBuffersError::ContextLost(Box::new(x)), x => SwapBuffersError::ContextLost(Box::new(x)),
} }
} }
} }

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 render::{DrmRenderSurface, Error as DrmRenderError};
pub use session::DrmDeviceObserver; pub use session::DrmDeviceObserver;
pub use render::{DrmRenderSurface, Error as DrmRenderError}; 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,14 +62,29 @@ 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);
} else if renderer_formats.is_empty() { } else if renderer_formats.is_empty() {
@ -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,18 +190,21 @@ 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)
} }
} }
} }
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> {
@ -177,11 +222,11 @@ where
pub fn frame_submitted(&mut self) -> Result<(), Error<E1, E2, E3>> { pub fn frame_submitted(&mut self) -> Result<(), Error<E1, E2, E3>> {
self.buffers.submitted() self.buffers.submitted()
} }
pub fn crtc(&self) -> crtc::Handle { pub fn crtc(&self) -> crtc::Handle {
self.drm.crtc() self.drm.crtc()
} }
pub fn plane(&self) -> plane::Handle { pub fn plane(&self) -> plane::Handle {
self.drm.plane() self.drm.plane()
} }
@ -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)
} }
@ -248,16 +295,16 @@ where
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> {
self.renderer.import_shm(buffer).map_err(Error::RenderError) self.renderer.import_shm(buffer).map_err(Error::RenderError)
} }
#[cfg(feature = "wayland_frontend")] #[cfg(feature = "wayland_frontend")]
fn import_egl(&mut self, buffer: &EGLBuffer) -> Result<Self::TextureId, Self::Error> { fn import_egl(&mut self, buffer: &EGLBuffer) -> Result<Self::TextureId, Self::Error> {
self.renderer.import_egl(buffer).map_err(Error::RenderError) self.renderer.import_egl(buffer).map_err(Error::RenderError)
} }
fn destroy_texture(&mut self, texture: Self::TextureId) -> Result<(), Self::Error> { fn destroy_texture(&mut self, texture: Self::TextureId) -> Result<(), Self::Error> {
self.renderer.destroy_texture(texture).map_err(Error::RenderError) self.renderer.destroy_texture(texture).map_err(Error::RenderError)
} }
fn begin(&mut self, width: u32, height: u32, transform: Transform) -> Result<(), Error<E1, E2, E3>> { fn begin(&mut self, width: u32, height: u32, transform: Transform) -> Result<(), Error<E1, E2, E3>> {
if self.current_buffer.is_some() { if self.current_buffer.is_some() {
return Ok(()); return Ok(());
@ -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,
@ -347,7 +413,7 @@ where
} }
} }
pub fn submitted<E1, E2, E3>(&mut self) -> Result<(), Error<E1, E2, E3>> pub fn submitted<E1, E2, E3>(&mut self) -> 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,
@ -364,7 +430,7 @@ where
} }
} }
fn submit<E1, E2, E3>(&mut self) -> Result<(), Error<E1, E2, E3>> fn submit<E1, E2, E3>(&mut self) -> 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,
@ -399,32 +469,29 @@ where
Modifier::Invalid => None, Modifier::Invalid => None,
x => Some(x), x => Some(x),
}; };
let logger = match &*(*drm).internal { let logger = match &*(*drm).internal {
DrmSurfaceInternal::Atomic(surf) => surf.logger.clone(), DrmSurfaceInternal::Atomic(surf) => surf.logger.clone(),
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)),
@ -493,4 +558,4 @@ impl<
Error::RenderError(err) => err.into(), Error::RenderError(err) => err.into(),
} }
} }
} }

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;
@ -92,17 +95,17 @@ impl<A: AsRawFd + 'static> DrmDeviceObserver<A> {
} }
} }
} }
// okay, the previous session/whatever might left the drm devices in any state... // okay, the previous session/whatever might left the drm devices in any state...
// lets fix that // lets fix that
if let Err(err) = self.reset_state() { if let Err(err) = self.reset_state() {
warn!(self.logger, "Unable to reset state after tty switch: {}", err); warn!(self.logger, "Unable to reset state after tty switch: {}", err);
// TODO call drm-handler::error // TODO call drm-handler::error
} }
self.active.store(true, Ordering::SeqCst); self.active.store(true, Ordering::SeqCst);
} }
fn reset_state(&mut self) -> Result<(), Error> { fn reset_state(&mut self) -> Result<(), Error> {
if let Some(dev) = self.dev.upgrade() { if let Some(dev) = self.dev.upgrade() {
dev.reset_state() dev.reset_state()
@ -110,4 +113,4 @@ impl<A: AsRawFd + 'static> DrmDeviceObserver<A> {
Ok(()) Ok(())
} }
} }
} }

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,
@ -346,7 +355,7 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
Ok(()) Ok(())
} }
pub fn commit_pending(&self) -> bool { pub fn commit_pending(&self) -> bool {
*self.pending.read().unwrap() != *self.state.read().unwrap() *self.pending.read().unwrap() != *self.state.read().unwrap()
} }
@ -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,36 +488,38 @@ 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(())
} }
pub fn test_buffer(&self, fb: framebuffer::Handle, mode: &Mode) -> Result<bool, Error> { pub fn test_buffer(&self, fb: framebuffer::Handle, mode: &Mode) -> Result<bool, Error> {
if !self.active.load(Ordering::SeqCst) { if !self.active.load(Ordering::SeqCst) {
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",
dev: self.fd.dev_path(), dev: self.fd.dev_path(),
source, source,
})?; })?;
let current = self.state.read().unwrap(); let current = self.state.read().unwrap();
let pending = self.pending.read().unwrap(); let pending = self.pending.read().unwrap();
@ -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")
@ -657,7 +673,7 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
property::Value::Framebuffer(Some(fb)), property::Value::Framebuffer(Some(fb)),
); );
} }
// we also need to connect the plane // we also need to connect the plane
req.add_property( req.add_property(
plane, plane,
@ -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 {
@ -320,21 +326,24 @@ impl<A: AsRawFd + 'static> LegacyDrmSurface<A> {
if !self.active.load(Ordering::SeqCst) { if !self.active.load(Ordering::SeqCst) {
return Err(Error::DeviceInactive); return Err(Error::DeviceInactive);
} }
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>>,
@ -46,7 +45,7 @@ impl<A: AsRawFd + 'static> DrmSurface<A> {
pub fn plane(&self) -> plane::Handle { pub fn plane(&self) -> plane::Handle {
self.plane self.plane
} }
/// Currently used [`connector`](drm::control::connector)s of this `Surface` /// Currently used [`connector`](drm::control::connector)s of this `Surface`
pub fn current_connectors(&self) -> impl IntoIterator<Item = connector::Handle> { pub fn current_connectors(&self) -> impl IntoIterator<Item = connector::Handle> {
match &*self.internal { match &*self.internal {
@ -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,17 +39,13 @@ 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>>,
{ {
Self::new_internal(display, Some(share), None, log) Self::new_internal(display, Some(share), None, log)
} }
pub fn new_shared_with_config<L>( pub fn new_shared_with_config<L>(
display: &EGLDisplay, display: &EGLDisplay,
share: &EGLContext, share: &EGLContext,
@ -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
@ -94,7 +94,7 @@ impl EGLDisplay {
return Err(Error::EglExtensionNotSupported(native.required_extensions())); return Err(Error::EglExtensionNotSupported(native.required_extensions()));
} }
} }
let (platform, native_ptr, attributes) = native.platform_display(); let (platform, native_ptr, attributes) = native.platform_display();
// we create an EGLDisplay // we create an EGLDisplay
let display = unsafe { let display = unsafe {
@ -355,62 +355,92 @@ 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 = [
[ [
ffi::egl::DMA_BUF_PLANE0_FD_EXT, ffi::egl::DMA_BUF_PLANE0_FD_EXT,
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 {
@ -740,4 +794,4 @@ pub struct PixelFormat {
pub multisampling: Option<u16>, pub multisampling: Option<u16>,
/// is srgb enabled /// is srgb enabled
pub srgb: bool, pub srgb: bool,
} }

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")
} }
@ -91,13 +101,13 @@ pub unsafe trait EGLNativeSurface: Send + Sync {
} }
/// If the surface supports resizing you may implement and use this function. /// If the surface supports resizing you may implement and use this function.
/// ///
/// The two first arguments (width, height) are the new size of the surface, /// The two first arguments (width, height) are the new size of the surface,
/// the two others (dx, dy) represent the displacement of the top-left corner of the surface. /// the two others (dx, dy) represent the displacement of the top-left corner of the surface.
/// It allows you to control the direction of the resizing if necessary. /// It allows you to control the direction of the resizing if necessary.
/// ///
/// Implementations may ignore the dx and dy arguments. /// Implementations may ignore the dx and dy arguments.
/// ///
/// Returns true if the resize was successful. /// Returns true if the resize was successful.
fn resize(&self, _width: i32, _height: i32, _dx: i32, _dy: i32) -> bool { fn resize(&self, _width: i32, _height: i32, _dx: i32, _dy: i32) -> bool {
false false
@ -160,7 +170,7 @@ unsafe impl EGLNativeSurface for wegl::WlEglSurface {
) )
}) })
} }
fn resize(&self, width: i32, height: i32, dx: i32, dy: i32) -> bool { fn resize(&self, width: i32, height: i32, dx: i32, dy: i32) -> bool {
wegl::WlEglSurface::resize(self, width, height, dx, dy); wegl::WlEglSurface::resize(self, width, height, dx, dy);
true true

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 _) };
} }
@ -139,15 +142,15 @@ impl EGLSurface {
pub fn pixel_format(&self) -> PixelFormat { pub fn pixel_format(&self) -> PixelFormat {
self.pixel_format self.pixel_format
} }
/// Tries to resize the underlying native surface. /// Tries to resize the underlying native surface.
/// ///
/// The two first arguments (width, height) are the new size of the surface, /// The two first arguments (width, height) are the new size of the surface,
/// the two others (dx, dy) represent the displacement of the top-left corner of the surface. /// the two others (dx, dy) represent the displacement of the top-left corner of the surface.
/// It allows you to control the direction of the resizing if necessary. /// It allows you to control the direction of the resizing if necessary.
/// ///
/// Implementations may ignore the dx and dy arguments. /// Implementations may ignore the dx and dy arguments.
/// ///
/// Returns true if the resize was successful. /// Returns true if the resize was successful.
pub fn resize(&self, width: i32, height: i32, dx: i32, dy: i32) -> bool { pub fn resize(&self, width: i32, height: i32, dx: i32, dy: i32) -> bool {
self.native.resize(width, height, dx, dy) self.native.resize(width, height, dx, dy)

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")]
@ -66,4 +66,4 @@ pub enum SwapBuffersError {
/// recreation. /// recreation.
#[error("A temporary condition caused the page flip to fail: {0}")] #[error("A temporary condition caused the page flip to fail: {0}")]
TemporaryFailure(Box<dyn std::error::Error>), TemporaryFailure(Box<dyn std::error::Error>),
} }

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();
@ -183,7 +200,7 @@ unsafe fn link_program(gl: &ffi::Gles2, vert_src: &'static str, frag_src: &'stat
unsafe fn texture_program(gl: &ffi::Gles2, frag: &'static str) -> Result<Gles2Program, Gles2Error> { unsafe fn texture_program(gl: &ffi::Gles2, frag: &'static str) -> Result<Gles2Program, Gles2Error> {
let program = link_program(&gl, shaders::VERTEX_SHADER, frag)?; let program = link_program(&gl, shaders::VERTEX_SHADER, frag)?;
let position = CStr::from_bytes_with_nul(b"position\0").expect("NULL terminated"); let position = CStr::from_bytes_with_nul(b"position\0").expect("NULL terminated");
let tex_coords = CStr::from_bytes_with_nul(b"tex_coords\0").expect("NULL terminated"); let tex_coords = CStr::from_bytes_with_nul(b"tex_coords\0").expect("NULL terminated");
let tex = CStr::from_bytes_with_nul(b"tex\0").expect("NULL terminated"); let tex = CStr::from_bytes_with_nul(b"tex\0").expect("NULL terminated");
@ -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,
}) })
} }
})?; })?;
@ -364,7 +411,7 @@ impl Bind<Dmabuf> for Gles2Renderer {
unsafe { unsafe {
self.gl.BindFramebuffer(ffi::FRAMEBUFFER, buffer.internal.fbo); self.gl.BindFramebuffer(ffi::FRAMEBUFFER, buffer.internal.fbo);
} }
self.target_buffer = Some(buffer); self.target_buffer = Some(buffer);
Ok(()) Ok(())
} }
@ -437,21 +484,36 @@ impl Renderer for Gles2Renderer {
wl_shm::Format::Xrgb8888, wl_shm::Format::Xrgb8888,
] ]
} }
#[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);
} }
let texture = Gles2Texture { let texture = Gles2Texture {
texture: tex, texture: tex,
texture_kind: 2, texture_kind: 2,
@ -461,10 +523,9 @@ impl Renderer for Gles2Renderer {
height: image.height(), height: image.height(),
}; };
self.egl.unbind()?; self.egl.unbind()?;
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> {
@ -472,7 +533,7 @@ impl Renderer for Gles2Renderer {
with_buffer_contents(&buffer, |slice, data| { with_buffer_contents(&buffer, |slice, data| {
self.make_current()?; self.make_current()?;
let offset = data.offset as i32; let offset = data.offset as i32;
let width = data.width as i32; let width = data.width as i32;
let height = data.height as i32; let height = data.height as i32;
@ -492,16 +553,28 @@ impl Renderer for Gles2Renderer {
wl_shm::Format::Xrgb8888 => (ffi::BGRA_EXT, 3), wl_shm::Format::Xrgb8888 => (ffi::BGRA_EXT, 3),
format => return Err(Gles2Error::UnsupportedPixelFormat(format)), format => return Err(Gles2Error::UnsupportedPixelFormat(format)),
}; };
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
.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);
@ -516,11 +589,12 @@ impl Renderer for Gles2Renderer {
height: height as u32, height: height as u32,
}; };
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")]
fn import_egl(&mut self, buffer: &EGLBuffer) -> Result<Self::TextureId, Self::Error> { fn import_egl(&mut self, buffer: &EGLBuffer) -> Result<Self::TextureId, Self::Error> {
if !self.extensions.iter().any(|ext| ext == "GL_OES_EGL_image") { if !self.extensions.iter().any(|ext| ext == "GL_OES_EGL_image") {
@ -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"),
@ -555,10 +631,10 @@ impl Renderer for Gles2Renderer {
height: buffer.height, height: buffer.height,
}; };
self.egl.unbind()?; self.egl.unbind()?;
Ok(texture) Ok(texture)
} }
fn destroy_texture(&mut self, texture: Self::TextureId) -> Result<(), Self::Error> { fn destroy_texture(&mut self, texture: Self::TextureId) -> Result<(), Self::Error> {
self.make_current()?; self.make_current()?;
@ -570,12 +646,11 @@ 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 {
self.gl.Viewport(0, 0, width as i32, height as i32); self.gl.Viewport(0, 0, width as i32, height as i32);
self.gl.Enable(ffi::BLEND); self.gl.Enable(ffi::BLEND);
self.gl.BlendFunc(ffi::ONE, ffi::ONE_MINUS_SRC_ALPHA); self.gl.BlendFunc(ffi::ONE, ffi::ONE_MINUS_SRC_ALPHA);
} }
@ -601,7 +676,7 @@ impl Renderer for Gles2Renderer {
self.current_projection = Some(transform.matrix() * renderer); self.current_projection = Some(transform.matrix() * renderer);
Ok(()) Ok(())
} }
fn clear(&mut self, color: [f32; 4]) -> Result<(), Self::Error> { fn clear(&mut self, color: [f32; 4]) -> Result<(), Self::Error> {
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,31 +701,63 @@ 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,
self.gl.VertexAttribPointer(self.programs[tex.texture_kind].attrib_position as u32, 2, ffi::FLOAT, ffi::FALSE, 0, VERTS.as_ptr() as *const _); matrix.as_ptr(),
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.Uniform1i(
self.gl.EnableVertexAttribArray(self.programs[tex.texture_kind].attrib_position as u32); self.programs[tex.texture_kind].uniform_invert_y,
self.gl.EnableVertexAttribArray(self.programs[tex.texture_kind].attrib_tex_coords as u32); 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.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
.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

@ -89,4 +89,4 @@ varying vec2 v_tex_coords;
void main() { void main() {
gl_FragColor = texture2D(tex, v_tex_coords) * alpha; gl_FragColor = texture2D(tex, v_tex_coords) * alpha;
} }
"#; "#;

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,14 +120,30 @@ 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
let size = texture.size(); let size = texture.size();
mat = mat * Matrix3::from_translation(Vector2::new(pos.0 as f32, pos.1 as f32)); mat = mat * Matrix3::from_translation(Vector2::new(pos.0 as f32, pos.1 as f32));
@ -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 {
@ -250,7 +256,7 @@ impl WinitGraphicsBackend {
let size = self.size.borrow(); let size = self.size.borrow();
size.physical_size.into() size.physical_size.into()
}; };
self.renderer.bind(self.egl.clone())?; self.renderer.bind(self.egl.clone())?;
self.renderer.begin(width, height, Transform::Normal) self.renderer.begin(width, height, Transform::Normal)
} }
@ -259,12 +265,15 @@ impl WinitGraphicsBackend {
impl Renderer for WinitGraphicsBackend { impl Renderer for WinitGraphicsBackend {
type Error = Gles2Error; type Error = Gles2Error;
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)
} }
#[cfg(feature = "wayland_frontend")] #[cfg(feature = "wayland_frontend")]
fn shm_formats(&self) -> &[wl_shm::Format] { fn shm_formats(&self) -> &[wl_shm::Format] {
Renderer::shm_formats(&self.renderer) Renderer::shm_formats(&self.renderer)
@ -274,17 +283,22 @@ impl Renderer for WinitGraphicsBackend {
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> {
self.renderer.import_shm(buffer) self.renderer.import_shm(buffer)
} }
#[cfg(feature = "wayland_frontend")] #[cfg(feature = "wayland_frontend")]
fn import_egl(&mut self, buffer: &EGLBuffer) -> Result<Self::TextureId, Self::Error> { fn import_egl(&mut self, buffer: &EGLBuffer) -> Result<Self::TextureId, Self::Error> {
self.renderer.import_egl(buffer) self.renderer.import_egl(buffer)
} }
fn destroy_texture(&mut self, texture: Self::TextureId) -> Result<(), Self::Error> { fn destroy_texture(&mut self, texture: Self::TextureId) -> Result<(), Self::Error> {
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,
);
} }
} }
}, },