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;
#[cfg(feature = "egl")]
use smithay::backend::egl::{
display::EGLBufferReader, BufferAccessError as EGLBufferAccessError, EGLBuffer,
};
use smithay::backend::egl::{display::EGLBufferReader, BufferAccessError as EGLBufferAccessError, EGLBuffer};
use smithay::{
reexports::wayland_server::protocol::wl_buffer::WlBuffer,
wayland::shm::{with_buffer_contents as shm_buffer_contents, BufferAccessError},
@ -76,7 +74,7 @@ impl BufferUtils {
let egl_buffer = match result {
Ok(egl) => Some(egl),
Err(EGLBufferAccessError::NotManaged(_)) => { None },
Err(EGLBufferAccessError::NotManaged(_)) => None,
Err(err) => {
error!(self.log, "EGL error"; "err" => format!("{:?}", err));
return Err(buffer);
@ -112,7 +110,7 @@ pub struct BufferTextures<T> {
#[cfg(feature = "udev")]
impl<T: Texture> BufferTextures<T> {
#[cfg(feature = "egl")]
pub fn load_texture<'a, R: Renderer<TextureId=T>>(
pub fn load_texture<'a, R: Renderer<TextureId = T>>(
&'a mut self,
id: u64,
renderer: &mut R,
@ -136,7 +134,7 @@ impl<T: Texture> BufferTextures<T> {
}
#[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,
id: u64,
renderer: &mut R,
@ -149,14 +147,14 @@ impl<T: Texture> BufferTextures<T> {
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,
id: u64,
renderer: &mut R,
texture_destruction_callback: &Sender<T>,
) -> Result<&'a T, R::Error> {
let texture = renderer.import_shm(&self.buffer)?;
if let Some(old_texture) = self.textures.insert(id, 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();
}
}
}
}

View File

@ -1,19 +1,12 @@
#![allow(clippy::too_many_arguments)]
use std::{
cell::RefCell,
rc::Rc,
sync::mpsc::Sender,
};
use std::{cell::RefCell, rc::Rc, sync::mpsc::Sender};
use slog::Logger;
use smithay::{
backend::renderer::{Renderer, Texture, Transform},
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,
wayland::{
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::buffer_utils::{BufferUtils, BufferTextures};
pub fn draw_cursor<R, E, T>(
renderer: &mut R,
@ -35,10 +28,10 @@ pub fn draw_cursor<R, E, T>(
token: MyCompositorToken,
log: &Logger,
) -> Result<(), SwapBuffersError>
where
R: Renderer<Error=E, TextureId=T>,
E: std::error::Error + Into<SwapBuffersError>,
T: Texture + 'static,
where
R: Renderer<Error = E, TextureId = T>,
E: std::error::Error + Into<SwapBuffersError>,
T: Texture + 'static,
{
let (dx, dy) = match token.with_role_data::<CursorImageRole, _, _>(surface, |data| data.hotspot) {
Ok(h) => h,
@ -50,7 +43,16 @@ pub fn draw_cursor<R, E, T>(
(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>(
@ -63,10 +65,10 @@ fn draw_surface_tree<R, E, T>(
compositor_token: MyCompositorToken,
log: &Logger,
) -> Result<(), SwapBuffersError>
where
R: Renderer<Error=E, TextureId=T>,
E: std::error::Error + Into<SwapBuffersError>,
T: Texture + 'static,
where
R: Renderer<Error = E, TextureId = T>,
E: std::error::Error + Into<SwapBuffersError>,
T: Texture + 'static,
{
let mut result = Ok(());
@ -85,7 +87,7 @@ fn draw_surface_tree<R, E, T>(
// already logged the error
Err(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>>() {
let mut data = data.borrow_mut();
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
// only passes it to our children
if Role::<SubsurfaceRole>::has(role) {
x += sub_x;
y += sub_y;
}
let texture = buffer_textures.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) {
let texture = buffer_textures
.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());
}
}
@ -163,41 +173,39 @@ pub fn draw_windows<R, E, T>(
compositor_token: MyCompositorToken,
log: &::slog::Logger,
) -> Result<(), SwapBuffersError>
where
R: Renderer<Error=E, TextureId=T>,
E: std::error::Error + Into<SwapBuffersError>,
T: Texture + 'static,
where
R: Renderer<Error = E, TextureId = T>,
E: std::error::Error + Into<SwapBuffersError>,
T: Texture + 'static,
{
let mut result = Ok(());
// redraw the frame, in a simple but inneficient way
window_map.with_windows_from_bottom_to_top(
|toplevel_surface, mut initial_place, bounding_box| {
// skip windows that do not overlap with a given output
if let Some(output) = output_rect {
if !output.overlaps(bounding_box) {
return;
}
initial_place.0 -= output.x;
window_map.with_windows_from_bottom_to_top(|toplevel_surface, mut initial_place, bounding_box| {
// skip windows that do not overlap with a given output
if let Some(output) = output_rect {
if !output.overlaps(bounding_box) {
return;
}
if let Some(wl_surface) = toplevel_surface.get_surface() {
// this surface is a root of a subsurface tree that needs to be drawn
if let Err(err) = draw_surface_tree(
renderer,
renderer_id,
texture_destruction_callback,
buffer_utils,
&wl_surface,
initial_place,
compositor_token,
log,
) {
result = Err(err);
}
initial_place.0 -= output.x;
}
if let Some(wl_surface) = toplevel_surface.get_surface() {
// this surface is a root of a subsurface tree that needs to be drawn
if let Err(err) = draw_surface_tree(
renderer,
renderer_id,
texture_destruction_callback,
buffer_utils,
&wl_surface,
initial_place,
compositor_token,
log,
) {
result = Err(err);
}
},
);
}
});
result
}
@ -211,10 +219,10 @@ pub fn draw_dnd_icon<R, E, T>(
token: MyCompositorToken,
log: &::slog::Logger,
) -> Result<(), SwapBuffersError>
where
R: Renderer<Error=E, TextureId=T>,
E: std::error::Error + Into<SwapBuffersError>,
T: Texture + 'static,
where
R: Renderer<Error = E, TextureId = T>,
E: std::error::Error + Into<SwapBuffersError>,
T: Texture + 'static,
{
if !token.has_role::<DnDIconRole>(surface) {
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."
);
}
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>(
renderer: Rc<RefCell<R>>,
evt_handle: &LoopHandle<Data>,
logger: ::slog::Logger,
)
where
<R as Renderer>::Error: Into<SwapBuffersError>
) where
<R as Renderer>::Error: Into<SwapBuffersError>,
{
let result = {
let mut renderer = renderer.borrow_mut();
// Does not matter if we render an empty frame
renderer.begin(1, 1, Transform::Normal).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())
renderer
.begin(1, 1, Transform::Normal)
.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 {
match err {

View File

@ -5,7 +5,7 @@ use std::{
os::unix::io::{AsRawFd, RawFd},
path::PathBuf,
rc::Rc,
sync::{atomic::Ordering, Arc, Mutex, mpsc},
sync::{atomic::Ordering, mpsc, Arc, Mutex},
time::Duration,
};
@ -14,27 +14,16 @@ use slog::Logger;
use smithay::{
backend::{
SwapBuffersError,
drm::{
DrmDevice,
DeviceHandler,
device_bind,
DrmRenderSurface,
DrmError,
DevPath,
},
egl::{EGLDisplay, EGLContext, display::EGLBufferReader},
renderer::{
Transform,
Renderer,
gles2::{
Gles2Renderer,
Gles2Texture,
},
},
drm::{device_bind, DevPath, DeviceHandler, DrmDevice, DrmError, DrmRenderSurface},
egl::{display::EGLBufferReader, EGLContext, EGLDisplay},
libinput::{LibinputInputBackend, LibinputSessionInterface},
renderer::{
gles2::{Gles2Renderer, Gles2Texture},
Renderer, Transform,
},
session::{auto::AutoSession, Session, Signal as SessionSignal},
udev::{primary_gpu, UdevBackend, UdevEvent},
SwapBuffersError,
},
reexports::{
calloop::{
@ -45,16 +34,13 @@ use smithay::{
drm::{
self,
control::{
Device as ControlDevice,
connector::{Info as ConnectorInfo, State as ConnectorState},
crtc,
encoder::Info as EncoderInfo,
Device as ControlDevice,
},
},
gbm::{
BufferObject as GbmBuffer,
Device as GbmDevice,
},
gbm::{BufferObject as GbmBuffer, Device as GbmDevice},
input::Libinput,
nix::{fcntl::OFlag, sys::stat::dev_t},
wayland_server::{
@ -72,9 +58,9 @@ use smithay::{
};
use crate::buffer_utils::BufferUtils;
use crate::drawing::*;
use crate::shell::{MyWindowMap, Roles};
use crate::state::AnvilState;
use crate::drawing::*;
#[derive(Clone)]
pub struct SessionFd(RawFd);
@ -358,7 +344,9 @@ impl<Data: 'static> UdevHandlerImpl<Data> {
};
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_id(),
crtc,
@ -377,25 +365,26 @@ impl<Data: 'static> UdevHandlerImpl<Data> {
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,
Err(err) => {
warn!(logger, "Failed to create drm surface: {}", err);
continue;
}
};
let renderer = match DrmRenderSurface::new(
surface,
gbm.clone(),
renderer,
logger.clone()
) {
Ok(renderer) => renderer,
Err(err) => {
warn!(logger, "Failed to create rendering surface: {}", err);
continue;
}
};
let renderer =
match DrmRenderSurface::new(surface, gbm.clone(), renderer, logger.clone()) {
Ok(renderer) => renderer,
Err(err) => {
warn!(logger, "Failed to create rendering surface: {}", err);
continue;
}
};
output_map.push(MyOutput::new(
display,
@ -430,38 +419,40 @@ impl<Data: 'static> UdevHandlerImpl<Data> {
match {
let fd = SessionFd(fd);
(
DrmDevice::new(
fd.clone(),
true,
self.logger.clone(),
),
GbmDevice::new(
fd
),
DrmDevice::new(fd.clone(), true, self.logger.clone()),
GbmDevice::new(fd),
)
}
{
} {
(Ok(drm), Ok(gbm)) => Some((drm, gbm)),
(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
},
}
(_, Err(err)) => {
// 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
},
}
}
})
{
let egl = match EGLDisplay::new(&gbm, self.logger.clone()) {
Ok(display) => display,
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;
}
};
// init hardware acceleration on the primary gpu.
#[cfg(feature = "egl")]
{
@ -470,19 +461,21 @@ impl<Data: 'static> UdevHandlerImpl<Data> {
self.logger,
"Initializing EGL Hardware Acceleration via {:?}", path
);
*self.egl_buffer_reader.borrow_mut() =
egl.bind_wl_display(&*self.display.borrow()).ok();
*self.egl_buffer_reader.borrow_mut() = egl.bind_wl_display(&*self.display.borrow()).ok();
}
}
let context = match EGLContext::new(&egl, self.logger.clone()) {
Ok(context) => context,
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;
}
};
let backends = Rc::new(RefCell::new(UdevHandlerImpl::<Data>::scan_connectors(
&mut device,
&gbm,
@ -498,7 +491,9 @@ impl<Data: 'static> UdevHandlerImpl<Data> {
let pointer_image = {
let context = EGLContext::new_shared(&egl, &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.
@ -674,35 +669,34 @@ impl DrmRenderer {
) {
if let Some(surface) = self.backends.borrow().get(&crtc) {
let result = DrmRenderer::render_surface(
&mut *surface.borrow_mut(),
&self.texture_destruction_callback.0,
&self.buffer_utils,
self.device_id,
crtc,
&mut *self.window_map.borrow_mut(),
&mut *self.output_map.borrow_mut(),
&self.compositor_token,
&*self.pointer_location.borrow(),
&self.pointer_image,
&*self.dnd_icon.lock().unwrap(),
&mut *self.cursor_status.lock().unwrap(),
&self.logger
&mut *surface.borrow_mut(),
&self.texture_destruction_callback.0,
&self.buffer_utils,
self.device_id,
crtc,
&mut *self.window_map.borrow_mut(),
&mut *self.output_map.borrow_mut(),
&self.compositor_token,
&*self.pointer_location.borrow(),
&self.pointer_image,
&*self.dnd_icon.lock().unwrap(),
&mut *self.cursor_status.lock().unwrap(),
&self.logger,
);
if let Err(err) = result {
warn!(self.logger, "Error during rendering: {:?}", err);
let reschedule =
match err {
SwapBuffersError::AlreadySwapped => false,
SwapBuffersError::TemporaryFailure(err) => {
!matches!(err.downcast_ref::<DrmError>(),
Some(&DrmError::DeviceInactive) |
Some(&DrmError::Access {
source: drm::SystemError::PermissionDenied,
..
}))
}
SwapBuffersError::ContextLost(err) => panic!("Rendering loop lost: {}", err),
};
let reschedule = match err {
SwapBuffersError::AlreadySwapped => false,
SwapBuffersError::TemporaryFailure(err) => !matches!(
err.downcast_ref::<DrmError>(),
Some(&DrmError::DeviceInactive)
| Some(&DrmError::Access {
source: drm::SystemError::PermissionDenied,
..
})
),
SwapBuffersError::ContextLost(err) => panic!("Rendering loop lost: {}", err),
};
if reschedule {
debug!(self.logger, "Rescheduling");
@ -741,7 +735,7 @@ impl DrmRenderer {
self.window_map
.borrow()
.send_frames(self.start_time.elapsed().as_millis() as u32);
while let Ok(texture) = self.texture_destruction_callback.1.try_recv() {
let _ = surface.borrow_mut().destroy_texture(texture);
}
@ -809,7 +803,16 @@ impl DrmRenderer {
{
if let Some(ref wl_surface) = dnd_icon.as_ref() {
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()
}
}
}

View File

@ -3,7 +3,7 @@ use std::{cell::RefCell, rc::Rc, sync::atomic::Ordering, time::Duration};
//#[cfg(feature = "egl")]
//use smithay::backend::egl::EGLGraphicsBackend;
use smithay::{
backend::{renderer::Renderer, input::InputBackend, winit, SwapBuffersError},
backend::{input::InputBackend, renderer::Renderer, winit, SwapBuffersError},
reexports::{
calloop::EventLoop,
wayland_server::{protocol::wl_output, Display},
@ -16,9 +16,9 @@ use smithay::{
use slog::Logger;
use crate::state::AnvilState;
use crate::buffer_utils::BufferUtils;
use crate::drawing::*;
use crate::state::AnvilState;
pub fn run_winit(
display: Rc<RefCell<Display>>,
@ -111,10 +111,22 @@ pub fn run_winit(
// drawing logic
{
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_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();
// draw the dnd icon if any
@ -122,7 +134,17 @@ pub fn run_winit(
let guard = state.dnd_icon.lock().unwrap();
if let Some(ref surface) = *guard {
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 {
*guard = CursorImageStatus::Default;
}
// draw as relevant
if let CursorImageStatus::Image(ref surface) = *guard {
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 {
renderer.window().set_cursor_visible(true);
}
@ -153,7 +185,6 @@ pub fn run_winit(
}
}
if event_loop
.dispatch(Some(Duration::from_millis(16)), &mut state)
.is_err()

View File

@ -6,28 +6,18 @@ extern crate slog;
use slog::Drain;
use smithay::{
backend::{
allocator::{Format, Fourcc, Modifier, Swapchain, Slot, dumb::DumbBuffer},
drm::{
DrmError,
DrmDevice, DrmSurface,
DeviceHandler,
device_bind,
}
allocator::{dumb::DumbBuffer, Format, Fourcc, Modifier, Slot, Swapchain},
drm::{device_bind, DeviceHandler, DrmDevice, DrmError, DrmSurface},
},
reexports::{
calloop::EventLoop,
drm::{
control::{
connector::State as ConnectorState, crtc, framebuffer,
Device as ControlDevice,
},
},
drm::control::{connector::State as ConnectorState, crtc, framebuffer, Device as ControlDevice},
},
};
use std::{
fs::{File, OpenOptions},
os::unix::io::{AsRawFd, RawFd},
io::Error as IoError,
os::unix::io::{AsRawFd, RawFd},
rc::Rc,
sync::Mutex,
};
@ -54,10 +44,11 @@ fn main() {
let mut options = OpenOptions::new();
options.read(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 =
DrmDevice::new(fd.clone(), true, log.clone()).unwrap();
let mut device = DrmDevice::new(fd.clone(), true, log.clone()).unwrap();
// Get a set of all modesetting resource handles (excluding planes):
let res_handles = ControlDevice::resource_handles(&device).unwrap();
@ -105,12 +96,20 @@ fn main() {
*/
let (w, h) = mode.size();
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 framebuffer = surface.add_framebuffer(&first_buffer.handle, 32, 32).unwrap();
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 {
swapchain,
current: first_buffer,
@ -133,7 +132,8 @@ fn main() {
}
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>,
surface: Rc<DrmSurface<FdWrapper>>,
}

View File

@ -1,6 +1,6 @@
use super::{Buffer, Format, Modifier};
use std::sync::{Arc, Weak};
use std::os::unix::io::RawFd;
use std::sync::{Arc, Weak};
const MAX_PLANES: usize = 4;
@ -68,9 +68,11 @@ impl Dmabuf {
fds: &[RawFd],
) -> Option<Dmabuf> {
if offsets.len() < planes
|| strides.len() < planes
|| fds.len() < planes
|| planes == 0 || planes > MAX_PLANES {
|| strides.len() < planes
|| fds.len() < planes
|| planes == 0
|| planes > MAX_PLANES
{
return None;
}
@ -82,9 +84,24 @@ impl Dmabuf {
Some(Dmabuf(Arc::new(DmabufInternal {
num_planes: planes,
offsets: [*offsets.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()],
offsets: [
*offsets.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(),
height: src.height(),
@ -105,8 +122,7 @@ impl Dmabuf {
}
pub fn has_modifier(&self) -> bool {
self.0.format.modifier != Modifier::Invalid &&
self.0.format.modifier != Modifier::Linear
self.0.format.modifier != Modifier::Invalid && self.0.format.modifier != Modifier::Linear
}
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 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 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> {
type Error = drm::SystemError;
fn create_buffer(&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 */)?;
fn create_buffer(
&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 {
fd: match &*self.internal {
@ -38,7 +43,7 @@ impl<A: AsRawFd + 'static> Buffer for DumbBuffer<A> {
fn height(&self) -> u32 {
self.handle.size().1
}
fn format(&self) -> Format {
self.format
}
@ -48,4 +53,4 @@ impl<A: AsRawFd + 'static> Drop for DumbBuffer<A> {
fn drop(&mut self) {
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 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> {
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)
} 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);
}
let offsets = (0i32..planes).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>>()?;
let offsets = (0i32..planes)
.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())
}
}
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;
if self.has_modifier() || buf.num_planes > 1 || buf.offsets[0] != 0 {
gbm.import_buffer_object_from_dma_buf_with_modifiers(
@ -106,8 +119,12 @@ impl Dmabuf {
buf.height,
buf.strides[0],
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 gbm;
pub mod dmabuf;
#[cfg(feature = "backend_drm")]
pub mod dumb;
pub mod dmabuf;
#[cfg(feature = "backend_gbm")]
pub mod gbm;
mod swapchain;
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 {
fn width(&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;
}
@ -20,4 +25,4 @@ pub trait Allocator<B: Buffer> {
type Error: std::error::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::sync::{Arc, Mutex, MutexGuard, atomic::{AtomicBool, Ordering}};
use std::ops::Deref;
use std::sync::{
atomic::{AtomicBool, Ordering},
Arc, Mutex, MutexGuard,
};
use crate::backend::allocator::{Allocator, Buffer, Format};
@ -84,12 +87,12 @@ where
impl<A, B, D, U, E1, E2> Swapchain<A, B, U, D>
where
A: Allocator<B, Error=E1>,
B: Buffer + TryInto<D, Error=E2>,
A: Allocator<B, Error = E1>,
B: Buffer + TryInto<D, Error = E2>,
D: Buffer,
E1: 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> {
Swapchain {
@ -107,8 +110,10 @@ where
if free_slot.buffer.is_none() {
free_slot.buffer = Arc::new(Some(
self.allocator
.create_buffer(self.width, self.height, self.format).map_err(SwapchainError::AllocationError)?
.try_into().map_err(SwapchainError::ConversionError)?
.create_buffer(self.width, self.height, self.format)
.map_err(SwapchainError::AllocationError)?
.try_into()
.map_err(SwapchainError::ConversionError)?,
));
}
assert!(free_slot.buffer.is_some());
@ -116,7 +121,6 @@ where
if !free_slot.acquired.swap(true, Ordering::SeqCst) {
return Ok(Some(free_slot.clone()));
}
}
// no free slots
@ -132,4 +136,4 @@ where
self.height = height;
self.slots = Default::default();
}
}
}

View File

@ -1,9 +1,15 @@
use std::collections::HashMap;
use std::sync::{Arc, atomic::{AtomicBool, Ordering}};
use std::os::unix::io::AsRawFd;
use std::sync::{
atomic::{AtomicBool, Ordering},
Arc,
};
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 crate::backend::drm::error::Error;
@ -31,8 +37,12 @@ pub struct AtomicDrmDevice<A: AsRawFd + 'static> {
}
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 {
fd,
active,
@ -42,17 +52,16 @@ impl<A: AsRawFd + 'static> AtomicDrmDevice<A> {
};
// Enumerate (and save) the current device state.
let res_handles = dev.fd.resource_handles()
.map_err(|source| Error::Access {
errmsg: "Error loading drm resources",
dev: dev.fd.dev_path(),
source,
})?;
let res_handles = dev.fd.resource_handles().map_err(|source| Error::Access {
errmsg: "Error loading drm resources",
dev: dev.fd.dev_path(),
source,
})?;
let plane_handles = dev.fd.plane_handles().map_err(|source| Error::Access {
errmsg: "Error loading planes",
dev: dev.fd.dev_path(),
source
source,
})?;
let planes = plane_handles.planes();
@ -77,7 +86,7 @@ impl<A: AsRawFd + 'static> AtomicDrmDevice<A> {
dev.old_state = old_state;
dev.prop_mapping = mapping;
trace!(dev.logger, "Mapping: {:#?}", dev.prop_mapping);
// If the user does not explicitly requests us to skip this,
// 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.
// This is because we do commits per surface and not per device, so we do a global
// commit here, to fix any conflicts.
let res_handles = self.fd.resource_handles()
.map_err(|source| Error::Access {
errmsg: "Error loading drm resources",
dev: self.fd.dev_path(),
source,
})?;
let res_handles = self.fd.resource_handles().map_err(|source| Error::Access {
errmsg: "Error loading drm resources",
dev: self.fd.dev_path(),
source,
})?;
// Disable all connectors (otherwise we might run into conflicting commits when restarting the rendering loop)
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, *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 {
errmsg: "Failed to disable connectors",
dev: self.fd.dev_path(),
source,
})?;
Ok(())
}
}

View File

@ -1,8 +1,11 @@
use std::collections::HashMap;
use std::sync::{Arc, atomic::{AtomicBool, Ordering}};
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 crate::backend::drm::error::Error;
@ -15,24 +18,27 @@ pub struct LegacyDrmDevice<A: AsRawFd + 'static> {
}
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 {
fd,
active,
old_state: HashMap::new(),
logger: logger.new(o!("smithay_module" => "backend_drm_legacy", "drm_module" => "device")),
};
// Enumerate (and save) the current device state.
// We need to keep the previous device configuration to restore the state later,
// so we query everything, that we can set.
let res_handles = dev.fd.resource_handles()
.map_err(|source| Error::Access {
errmsg: "Error loading drm resources",
dev: dev.fd.dev_path(),
source,
})?;
let res_handles = dev.fd.resource_handles().map_err(|source| Error::Access {
errmsg: "Error loading drm resources",
dev: dev.fd.dev_path(),
source,
})?;
for &con in res_handles.connectors() {
let con_info = dev.fd.get_connector(con).map_err(|source| Error::Access {
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,
// 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)?;
for crtc in res_handles.crtcs() {
// null commit (necessary to trigger removal on the kernel side with the legacy api.)
self.fd.set_crtc(*crtc, None, (0, 0), &[], None)
.map_err(|source| Error::Access {
errmsg: "Error setting crtc",
dev: self.fd.dev_path(),
source,
})?;
}
for crtc in res_handles.crtcs() {
// null commit (necessary to trigger removal on the kernel side with the legacy api.)
self.fd
.set_crtc(*crtc, None, (0, 0), &[], None)
.map_err(|source| Error::Access {
errmsg: "Error setting crtc",
dev: self.fd.dev_path(),
source,
})?;
}
Ok(())
Ok(())
}
}
@ -127,38 +133,32 @@ pub fn set_connector_state<D>(
enabled: bool,
) -> Result<(), Error>
where
D: ControlDevice
D: ControlDevice,
{
// for every connector...
for conn in connectors {
let info = dev
.get_connector(conn)
.map_err(|source| Error::Access {
errmsg: "Failed to get connector infos",
dev: dev.dev_path(),
source,
})?;
let info = dev.get_connector(conn).map_err(|source| Error::Access {
errmsg: "Failed to get connector infos",
dev: dev.dev_path(),
source,
})?;
// that is currently connected ...
if info.state() == connector::State::Connected {
// get a list of it's properties.
let props = dev
.get_properties(conn)
.map_err(|source| Error::Access {
errmsg: "Failed to get properties for connector",
dev: dev.dev_path(),
source,
})?;
let props = dev.get_properties(conn).map_err(|source| Error::Access {
errmsg: "Failed to get properties for connector",
dev: dev.dev_path(),
source,
})?;
let (handles, _) = props.as_props_and_values();
// for every handle ...
for handle in handles {
// get information of that property
let info = dev
.get_property(*handle)
.map_err(|source| Error::Access {
errmsg: "Failed to get property of connector",
dev: dev.dev_path(),
source,
})?;
let info = dev.get_property(*handle).map_err(|source| Error::Access {
errmsg: "Failed to get property of connector",
dev: dev.dev_path(),
source,
})?;
// to find out, if we got the handle of the "DPMS" property ...
if info.name().to_str().map(|x| x == "DPMS").unwrap_or(false) {
// so we can use that to turn on / off the connector
@ -181,4 +181,4 @@ where
}
}
Ok(())
}
}

View File

@ -1,24 +1,27 @@
use std::rc::Rc;
use std::cell::RefCell;
use std::collections::HashSet;
use std::convert::TryFrom;
use std::sync::{Arc, atomic::AtomicBool};
use std::path::PathBuf;
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 drm::{Device as BasicDevice, ClientCapability, DriverCapability};
use drm::control::{ResourceHandles, PlaneResourceHandles, Device as ControlDevice, Event, Mode, PlaneType, crtc, plane, connector, property};
use drm::control::{
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::sys::stat::fstat;
pub(super) mod atomic;
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 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(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"));
info!(log, "DrmDevice initializing");
let dev_id = fstat(fd.as_raw_fd())
.map_err(Error::UnableToGetDeviceId)?
.st_rdev;
let dev_id = fstat(fd.as_raw_fd()).map_err(Error::UnableToGetDeviceId)?.st_rdev;
let active = Arc::new(AtomicBool::new(true));
let dev = Arc::new({
let mut dev = FdWrapper {
@ -115,7 +116,9 @@ impl<A: AsRawFd + 'static> DrmDevice<A> {
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 {
errmsg: "Error loading resource handles",
dev: dev.dev_path(),
@ -126,7 +129,12 @@ impl<A: AsRawFd + 'static> DrmDevice<A> {
dev: dev.dev_path(),
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 {
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")
.map(|x| {
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 {
info!(log, "SMITHAY_USE_LEGACY is set. Forcing LegacyDrmDevice.");
};
Ok(if dev.set_client_capability(ClientCapability::Atomic, true).is_ok() && !force_legacy {
DrmDeviceInternal::Atomic(AtomicDrmDevice::new(dev, active, disable_connectors, log)?)
} else {
info!(log, "Falling back to LegacyDrmDevice");
DrmDeviceInternal::Legacy(LegacyDrmDevice::new(dev, active, disable_connectors, log)?)
})
Ok(
if dev.set_client_capability(ClientCapability::Atomic, true).is_ok() && !force_legacy {
DrmDeviceInternal::Atomic(AtomicDrmDevice::new(dev, active, disable_connectors, log)?)
} else {
info!(log, "Falling back to LegacyDrmDevice");
DrmDeviceInternal::Legacy(LegacyDrmDevice::new(dev, active, disable_connectors, log)?)
},
)
}
pub fn process_events(&mut self) {
@ -196,7 +211,7 @@ impl<A: AsRawFd + 'static> DrmDevice<A> {
DrmDeviceInternal::Legacy(_) => false,
}
}
pub fn set_handler(&mut self, handler: impl DeviceHandler + 'static) {
let handler = Some(Box::new(handler) as Box<dyn DeviceHandler + 'static>);
*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 {
errmsg: "Failed to get plane information",
dev: self.dev_path(),
source,
source,
})?;
let filter = info.possible_crtcs();
if self.resources.filter_crtcs(filter).contains(crtc) {
match self.plane_type(*plane)? {
PlaneType::Primary => { primary = Some(*plane); },
PlaneType::Cursor => { cursor = Some(*plane); },
PlaneType::Overlay => { overlay.push(*plane); },
PlaneType::Primary => {
primary = Some(*plane);
}
PlaneType::Cursor => {
cursor = Some(*plane);
}
PlaneType::Overlay => {
overlay.push(*plane);
}
};
}
}
@ -234,7 +255,11 @@ impl<A: AsRawFd + 'static> DrmDevice<A> {
Ok(Planes {
primary: primary.expect("Crtc has no primary plane"),
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 {
errmsg: "Failed to get properties of plane",
dev: self.dev_path(),
source,
source,
})?;
let (ids, vals) = props.as_props_and_values();
for (&id, &val) in ids.iter().zip(vals.iter()) {
let info = self.get_property(id).map_err(|source| Error::Access {
errmsg: "Failed to get property info",
dev: self.dev_path(),
source,
source,
})?;
if info.name().to_str().map(|x| x == "type").unwrap_or(false) {
return Ok(match val {
@ -262,21 +287,27 @@ impl<A: AsRawFd + 'static> DrmDevice<A> {
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() {
return Err(Error::SurfaceWithoutConnectors(crtc));
}
let info = self.get_plane(plane).map_err(|source| Error::Access {
errmsg: "Failed to get plane info",
dev: self.dev_path(),
source
source,
})?;
let filter = info.possible_crtcs();
if !self.resources.filter_crtcs(filter).contains(&crtc) {
return Err(Error::PlaneNotCompatible(crtc, plane));
}
let active = match &*self.internal {
DrmDeviceInternal::Atomic(dev) => dev.active.clone(),
DrmDeviceInternal::Legacy(dev) => dev.active.clone(),
@ -288,13 +319,29 @@ impl<A: AsRawFd + 'static> DrmDevice<A> {
_ => 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 {
if self.plane_type(plane)? != PlaneType::Primary {
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
@ -304,18 +351,25 @@ impl<A: AsRawFd + 'static> DrmDevice<A> {
source,
})?;
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 {
code,
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 {
errmsg: "Failed to query properties",
dev: self.dev_path(),
source
source,
})?;
if let Ok(prop) = surf.plane_prop_handle(plane, "IN_FORMATS") {
let prop_info = self.get_property(prop).map_err(|source| Error::Access {
@ -324,7 +378,11 @@ impl<A: AsRawFd + 'static> DrmDevice<A> {
source,
})?;
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) {
let data = self.get_property_blob(blob).map_err(|source| Error::Access {
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 = &*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 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: *const u32 = fmt_mod_blob_ptr
.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 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();
for j in 0..64 {
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);
if let Some(code) = code {
formats.insert(Format {
code,
modifier,
});
formats.insert(Format { 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 {
crtc,

View File

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

View File

@ -1,11 +1,11 @@
pub(crate) mod device;
pub(self) mod surface;
pub(self) mod error;
pub(self) mod session;
mod render;
pub(self) mod session;
pub(self) mod surface;
pub use device::{DrmDevice, DrmSource, DeviceHandler, device_bind, Planes, DevPath};
pub use surface::DrmSurface;
pub use device::{device_bind, DevPath, DeviceHandler, DrmDevice, DrmSource, Planes};
pub use error::Error as DrmError;
pub use render::{DrmRenderSurface, Error as DrmRenderError};
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::convert::TryInto;
use std::os::unix::io::AsRawFd;
use std::sync::Arc;
use cgmath::Matrix3;
use drm::buffer::PlanarBuffer;
use drm::control::{Device, Mode, crtc, connector, framebuffer, plane};
use gbm::{Device as GbmDevice, BufferObject, BufferObjectFlags};
use drm::control::{connector, crtc, framebuffer, plane, Device, Mode};
use gbm::{BufferObject, BufferObjectFlags, Device as GbmDevice};
#[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::allocator::{Allocator, Format, Fourcc, Modifier, Swapchain, SwapchainError, Slot, Buffer, dmabuf::Dmabuf};
use crate::backend::renderer::{Renderer, Bind, Transform, Texture};
use super::{device::DevPath, surface::DrmSurfaceInternal, DrmError, DrmSurface};
use crate::backend::allocator::{
dmabuf::Dmabuf, Allocator, Buffer, Format, Fourcc, Modifier, Slot, Swapchain, SwapchainError,
};
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<
D: AsRawFd + 'static,
@ -33,16 +35,20 @@ pub struct DrmRenderSurface<
impl<D, A, B, R, E1, E2, E3> DrmRenderSurface<D, A, R, B>
where
D: AsRawFd + 'static,
A: Allocator<B, Error=E1>,
B: Buffer + TryInto<Dmabuf, Error=E2>,
R: Bind<Dmabuf> + Renderer<Error=E3>,
A: Allocator<B, Error = E1>,
B: Buffer + TryInto<Dmabuf, Error = E2>,
R: Bind<Dmabuf> + Renderer<Error = E3>,
E1: std::error::Error + 'static,
E2: std::error::Error + 'static,
E3: std::error::Error + 'static,
{
#[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 do not want something like Abgr4444, which looses color information
// - some formats might perform terribly
@ -56,14 +62,29 @@ where
let logger = crate::slog_or_fallback(log).new(o!("backend" => "drm_render"));
// select a format
let plane_formats = drm.supported_formats().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<_>>();
let plane_formats = drm
.supported_formats()
.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 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() {
return Err(Error::NoSupportedPlaneFormat);
} else if renderer_formats.is_empty() {
@ -74,38 +95,48 @@ where
// 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
// create a buffer with a LINEAR layout instead of an implicit modifier.
if
(plane_formats.len() == 1 &&
plane_formats.iter().next().unwrap().modifier == Modifier::Invalid
&& renderer_formats.iter().all(|x| x.modifier != Modifier::Invalid)
&& renderer_formats.iter().any(|x| x.modifier == Modifier::Linear)
) || (renderer_formats.len() == 1 &&
renderer_formats.iter().next().unwrap().modifier == Modifier::Invalid
if (plane_formats.len() == 1
&& plane_formats.iter().next().unwrap().modifier == Modifier::Invalid
&& renderer_formats.iter().all(|x| x.modifier != Modifier::Invalid)
&& renderer_formats.iter().any(|x| x.modifier == Modifier::Linear))
|| (renderer_formats.len() == 1
&& renderer_formats.iter().next().unwrap().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 {
code,
modifier: Modifier::Linear,
}]
} else {
plane_formats.intersection(&renderer_formats).cloned().collect::<Vec<_>>()
plane_formats
.intersection(&renderer_formats)
.cloned()
.collect::<Vec<_>>()
}
};
debug!(logger, "Testing Formats: {:?}", formats);
// Test explicit formats first
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::Invalid)).cloned();
.chain(formats.iter().find(|x| x.modifier == Modifier::Invalid))
.cloned();
DrmRenderSurface::new_internal(drm, allocator, renderer, iter, logger)
}
#[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 mode = drm.pending_mode();
@ -117,16 +148,28 @@ where
{
let dmabuf: Dmabuf = (*buffer).clone();
match renderer.bind(dmabuf).map_err(Error::<E1, E2, E3>::RenderError)
.and_then(|_| 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))
match renderer
.bind(dmabuf)
.map_err(Error::<E1, E2, E3>::RenderError)
.and_then(|_| {
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) => {
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;
buffer.set_userdata(bo);
match drm.test_buffer(fb, &mode, true)
{
match drm.test_buffer(fb, &mode, true) {
Ok(_) => {
debug!(logger, "Success, choosen format: {:?}", format);
let buffers = Buffers::new(drm.clone(), gbm, buffer);
@ -148,18 +190,21 @@ where
buffers,
current_buffer: None,
})
},
}
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)
}
}
}
pub fn queue_frame(&mut self) -> Result<(), Error<E1, E2, E3>> {
let mode = self.drm.pending_mode();
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> {
@ -177,11 +222,11 @@ where
pub fn frame_submitted(&mut self) -> Result<(), Error<E1, E2, E3>> {
self.buffers.submitted()
}
pub fn crtc(&self) -> crtc::Handle {
self.drm.crtc()
}
pub fn plane(&self) -> plane::Handle {
self.drm.plane()
}
@ -219,13 +264,12 @@ where
}
}
impl<D, A, B, T, R, E1, E2, E3> Renderer for DrmRenderSurface<D, A, R, B>
where
D: AsRawFd + 'static,
A: Allocator<B, Error=E1>,
B: Buffer + TryInto<Dmabuf, Error=E2>,
R: Bind<Dmabuf> + Renderer<Error=E3, TextureId=T>,
A: Allocator<B, Error = E1>,
B: Buffer + TryInto<Dmabuf, Error = E2>,
R: Bind<Dmabuf> + Renderer<Error = E3, TextureId = T>,
T: Texture,
E1: std::error::Error + 'static,
E2: std::error::Error + 'static,
@ -235,7 +279,10 @@ where
type TextureId = T;
#[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)
}
@ -248,16 +295,16 @@ where
fn import_shm(&mut self, buffer: &wl_buffer::WlBuffer) -> Result<Self::TextureId, Self::Error> {
self.renderer.import_shm(buffer).map_err(Error::RenderError)
}
#[cfg(feature = "wayland_frontend")]
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> {
self.renderer.destroy_texture(texture).map_err(Error::RenderError)
}
fn begin(&mut self, width: u32, height: u32, transform: Transform) -> Result<(), Error<E1, E2, E3>> {
if self.current_buffer.is_some() {
return Ok(());
@ -266,15 +313,24 @@ where
let slot = self.swapchain.acquire()?.ok_or(Error::NoFreeSlotsError)?;
self.renderer.bind((*slot).clone()).map_err(Error::RenderError)?;
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)
}
fn render_texture(&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 render_texture(
&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> {
@ -284,7 +340,10 @@ where
let result = self.renderer.finish();
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(()) => {}
Err(Error::DrmError(drm)) => return Err(drm.into()),
Err(Error::GbmError(err)) => return Err(SwapBuffersError::ContextLost(Box::new(err))),
@ -318,7 +377,11 @@ impl<D> Buffers<D>
where
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 {
drm,
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
E1: 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
E1: 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
E1: 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
A: AsRawFd + 'static,
E1: std::error::Error + 'static,
@ -399,32 +469,29 @@ where
Modifier::Invalid => None,
x => Some(x),
};
let logger = match &*(*drm).internal {
DrmSurfaceInternal::Atomic(surf) => surf.logger.clone(),
DrmSurfaceInternal::Legacy(surf) => surf.logger.clone(),
};
let fb = match
if modifier.is_some() {
let num = bo.plane_count().unwrap();
let modifiers = [
modifier,
if num > 1 { modifier } else { None },
if num > 2 { modifier } else { None },
if num > 3 { modifier } else { None },
];
drm.add_planar_framebuffer(&bo, &modifiers, drm_ffi::DRM_MODE_FB_MODIFIERS)
} else {
drm.add_planar_framebuffer(&bo, &[None, None, None, None], 0)
}
{
let fb = match if modifier.is_some() {
let num = bo.plane_count().unwrap();
let modifiers = [
modifier,
if num > 1 { modifier } else { None },
if num > 2 { modifier } else { None },
if num > 3 { modifier } else { None },
];
drm.add_planar_framebuffer(&bo, &modifiers, drm_ffi::DRM_MODE_FB_MODIFIERS)
} else {
drm.add_planar_framebuffer(&bo, &[None, None, None, None], 0)
} {
Ok(fb) => fb,
Err(source) => {
// We only support this as a fallback of last resort for ARGB8888 visuals,
// like xf86-video-modesetting does.
if drm::buffer::Buffer::format(&bo) != Fourcc::Argb8888
|| bo.handles()[1].is_some() {
if drm::buffer::Buffer::format(&bo) != Fourcc::Argb8888 || bo.handles()[1].is_some() {
return Err(Error::DrmError(DrmError::Access {
errmsg: "Failed to add framebuffer",
dev: drm.dev_path(),
@ -432,17 +499,15 @@ where
}));
}
debug!(logger, "Failed to add framebuffer, trying legacy method");
drm.add_framebuffer(&bo, 32, 32).map_err(|source| DrmError::Access {
errmsg: "Failed to add framebuffer",
dev: drm.dev_path(),
source,
})?
drm.add_framebuffer(&bo, 32, 32)
.map_err(|source| DrmError::Access {
errmsg: "Failed to add framebuffer",
dev: drm.dev_path(),
source,
})?
}
};
bo.set_userdata(FbHandle {
drm: drm.clone(),
fb,
}).unwrap();
bo.set_userdata(FbHandle { drm: drm.clone(), fb }).unwrap();
Ok(bo)
}
@ -471,21 +536,21 @@ where
#[error("The swapchain encounted an error: {0}")]
SwapchainError(#[from] SwapchainError<E1, E2>),
#[error("The renderer encounted an error: {0}")]
RenderError(#[source] E3)
RenderError(#[source] E3),
}
impl<
E1: std::error::Error + 'static,
E2: std::error::Error + 'static,
E3: std::error::Error + Into<SwapBuffersError> + 'static,
> From<Error<E1, E2, E3>> for SwapBuffersError {
E1: std::error::Error + 'static,
E2: std::error::Error + 'static,
E3: std::error::Error + Into<SwapBuffersError> + 'static,
> From<Error<E1, E2, E3>> for SwapBuffersError
{
fn from(err: Error<E1, E2, E3>) -> SwapBuffersError {
match err {
x @ Error::NoSupportedPlaneFormat
| x @ Error::NoSupportedRendererFormat
| x @ Error::FormatsNotCompatible
| x @ Error::InitialRenderingError
=> SwapBuffersError::ContextLost(Box::new(x)),
| x @ Error::InitialRenderingError => SwapBuffersError::ContextLost(Box::new(x)),
x @ Error::NoFreeSlotsError => SwapBuffersError::TemporaryFailure(Box::new(x)),
Error::DrmError(err) => err.into(),
Error::GbmError(err) => SwapBuffersError::ContextLost(Box::new(err)),
@ -493,4 +558,4 @@ impl<
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::sync::{
atomic::{AtomicBool, Ordering},
Arc, Weak,
};
use drm::Device as BasicDevice;
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...
// lets fix that
if let Err(err) = self.reset_state() {
warn!(self.logger, "Unable to reset state after tty switch: {}", err);
// TODO call drm-handler::error
}
self.active.store(true, Ordering::SeqCst);
}
fn reset_state(&mut self) -> Result<(), Error> {
if let Some(dev) = self.dev.upgrade() {
dev.reset_state()
@ -110,4 +113,4 @@ impl<A: AsRawFd + 'static> DrmDeviceObserver<A> {
Ok(())
}
}
}
}

View File

@ -6,11 +6,14 @@ use drm::control::{
use std::collections::HashSet;
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::{
device::{DevPath, DrmDeviceInternal},
device::atomic::Mapping,
device::{DevPath, DrmDeviceInternal},
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"));
info!(
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 {
@ -63,30 +70,25 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
// 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_blob = match crtc_info.mode() {
Some(mode) => fd
.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 {
Some(mode) => fd.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 res_handles = fd.resource_handles()
.map_err(|source| Error::Access {
errmsg: "Error loading drm resources",
dev: fd.dev_path(),
source,
})?;
let blob = fd.create_property_blob(&mode).map_err(|source| Error::Access {
errmsg: "Failed to create Property Blob for mode",
dev: fd.dev_path(),
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.
// 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`.
let mut current_connectors = HashSet::new();
for conn in res_handles.connectors() {
let crtc_prop =
prop_mapping
let crtc_prop = prop_mapping
.0
.get(&conn)
.expect("Unknown handle")
@ -105,8 +106,7 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
name: "CRTC_ID",
})
.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();
for (&id, &val) in ids.iter().zip(vals.iter()) {
if id == crtc_prop {
@ -152,14 +152,20 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
// here we create a dumbbuffer for that purpose.
fn create_test_buffer(&self, mode: &Mode) -> Result<framebuffer::Handle, Error> {
let (w, h) = mode.size();
let db = self.fd
.create_dumb_buffer((w as u32, h as u32), crate::backend::allocator::Fourcc::Argb8888, 32)
let db = self
.fd
.create_dumb_buffer(
(w as u32, h as u32),
crate::backend::allocator::Fourcc::Argb8888,
32,
)
.map_err(|source| Error::Access {
errmsg: "Failed to create dumb buffer",
dev: self.fd.dev_path(),
source,
})?;
let fb = self.fd
let fb = self
.fd
.add_framebuffer(&db, 32, 32)
.map_err(|source| Error::Access {
errmsg: "Failed to create framebuffer",
@ -198,13 +204,11 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
return Err(Error::DeviceInactive);
}
let info = self.fd
.get_connector(conn)
.map_err(|source| Error::Access {
errmsg: "Error loading connector info",
dev: self.fd.dev_path(),
source,
})?;
let info = self.fd.get_connector(conn).map_err(|source| Error::Access {
errmsg: "Error loading connector info",
dev: self.fd.dev_path(),
source,
})?;
let mut pending = self.pending.write().unwrap();
@ -219,11 +223,12 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
Some(pending.mode),
Some(pending.blob),
)?;
self.fd.atomic_commit(
&[AtomicCommitFlags::AllowModeset, AtomicCommitFlags::TestOnly],
req,
)
.map_err(|_| Error::TestFailed(self.crtc))?;
self.fd
.atomic_commit(
&[AtomicCommitFlags::AllowModeset, AtomicCommitFlags::TestOnly],
req,
)
.map_err(|_| Error::TestFailed(self.crtc))?;
// seems to be, lets add the connector
pending.connectors.insert(conn);
@ -255,11 +260,12 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
Some(pending.mode),
Some(pending.blob),
)?;
self.fd.atomic_commit(
&[AtomicCommitFlags::AllowModeset, AtomicCommitFlags::TestOnly],
req,
)
.map_err(|_| Error::TestFailed(self.crtc))?;
self.fd
.atomic_commit(
&[AtomicCommitFlags::AllowModeset, AtomicCommitFlags::TestOnly],
req,
)
.map_err(|_| Error::TestFailed(self.crtc))?;
// seems to be, lets remove the connector
pending.connectors.remove(&conn);
@ -293,11 +299,12 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
Some(pending.blob),
)?;
self.fd.atomic_commit(
&[AtomicCommitFlags::AllowModeset, AtomicCommitFlags::TestOnly],
req,
)
.map_err(|_| Error::TestFailed(self.crtc))?;
self.fd
.atomic_commit(
&[AtomicCommitFlags::AllowModeset, AtomicCommitFlags::TestOnly],
req,
)
.map_err(|_| Error::TestFailed(self.crtc))?;
pending.connectors = conns;
@ -312,7 +319,8 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
let mut pending = self.pending.write().unwrap();
// check if new config is supported
let new_blob = self.fd
let new_blob = self
.fd
.create_property_blob(&mode)
.map_err(|source| Error::Access {
errmsg: "Failed to create Property Blob for mode",
@ -329,7 +337,8 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
Some(mode),
Some(new_blob),
)?;
if let Err(err) = self.fd
if let Err(err) = self
.fd
.atomic_commit(
&[AtomicCommitFlags::AllowModeset, AtomicCommitFlags::TestOnly],
req,
@ -346,7 +355,7 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
Ok(())
}
pub fn commit_pending(&self) -> bool {
*self.pending.read().unwrap() != *self.state.read().unwrap()
}
@ -403,7 +412,8 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
Some(pending.blob),
)?;
if let Err(err) = self.fd
if let Err(err) = self
.fd
.atomic_commit(
&[AtomicCommitFlags::AllowModeset, AtomicCommitFlags::TestOnly],
req.clone(),
@ -429,7 +439,8 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
};
debug!(self.logger, "Setting screen: {:?}", req);
let result = self.fd
let result = self
.fd
.atomic_commit(
if event {
&[
@ -441,10 +452,7 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
AtomicCommitFlags::Nonblock,
]
} else {
&[
AtomicCommitFlags::AllowModeset,
AtomicCommitFlags::Nonblock,
]
&[AtomicCommitFlags::AllowModeset, AtomicCommitFlags::Nonblock]
},
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,
// indicating a problem in our assumptions.
trace!(self.logger, "Queueing page flip: {:?}", req);
self.fd.atomic_commit(
if event {
&[AtomicCommitFlags::PageFlipEvent, AtomicCommitFlags::Nonblock]
} else {
&[AtomicCommitFlags::Nonblock]
},
req,
)
.map_err(|source| Error::Access {
errmsg: "Page flip commit failed",
dev: self.fd.dev_path(),
source,
})?;
self.fd
.atomic_commit(
if event {
&[AtomicCommitFlags::PageFlipEvent, AtomicCommitFlags::Nonblock]
} else {
&[AtomicCommitFlags::Nonblock]
},
req,
)
.map_err(|source| Error::Access {
errmsg: "Page flip commit failed",
dev: self.fd.dev_path(),
source,
})?;
Ok(())
}
pub fn test_buffer(&self, fb: framebuffer::Handle, mode: &Mode) -> Result<bool, Error> {
if !self.active.load(Ordering::SeqCst) {
return Err(Error::DeviceInactive);
}
let blob = self.fd
let blob = self
.fd
.create_property_blob(&mode)
.map_err(|source| Error::Access {
errmsg: "Failed to create Property Blob for mode",
dev: self.fd.dev_path(),
source,
})?;
let current = self.state.read().unwrap();
let pending = self.pending.read().unwrap();
@ -524,10 +534,16 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
self.plane,
Some(fb),
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)
}
@ -536,8 +552,7 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
handle: connector::Handle,
name: &'static str,
) -> Result<property::Handle, Error> {
self
.prop_mapping
self.prop_mapping
.0
.get(&handle)
.expect("Unknown handle")
@ -549,9 +564,12 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
.map(|x| *x)
}
pub(crate) fn crtc_prop_handle(&self, handle: crtc::Handle, name: &'static str) -> Result<property::Handle, Error> {
self
.prop_mapping
pub(crate) fn crtc_prop_handle(
&self,
handle: crtc::Handle,
name: &'static str,
) -> Result<property::Handle, Error> {
self.prop_mapping
.1
.get(&handle)
.expect("Unknown handle")
@ -569,8 +587,7 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
handle: framebuffer::Handle,
name: &'static str,
) -> Result<property::Handle, Error> {
self
.prop_mapping
self.prop_mapping
.2
.get(&handle)
.expect("Unknown handle")
@ -587,8 +604,7 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
handle: plane::Handle,
name: &'static str,
) -> Result<property::Handle, Error> {
self
.prop_mapping
self.prop_mapping
.3
.get(&handle)
.expect("Unknown handle")
@ -657,7 +673,7 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
property::Value::Framebuffer(Some(fb)),
);
}
// we also need to connect the plane
req.add_property(
plane,
@ -733,10 +749,12 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
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))?;
self.fd.atomic_commit(&[AtomicCommitFlags::Nonblock], req)
self.fd
.atomic_commit(&[AtomicCommitFlags::Nonblock], req)
.map_err(|source| Error::Access {
errmsg: "Failed to commit on clear_plane",
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.
// This makes sure our cursor won't stay visible.
if let Err(err) = self.clear_plane() {
warn!(
self.logger,
"Failed to clear plane on {:?}: {}", self.crtc, err
);
warn!(self.logger, "Failed to clear plane on {:?}: {}", self.crtc, err);
}
// disable connectors again

View File

@ -1,15 +1,15 @@
use drm::control::{
connector, crtc, encoder, framebuffer, Device as ControlDevice, Mode,
PageFlipFlags,
};
use drm::control::{connector, crtc, encoder, framebuffer, Device as ControlDevice, Mode, PageFlipFlags};
use std::collections::HashSet;
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::{
device::{DevPath, DrmDeviceInternal},
device::legacy::set_connector_state,
device::{DevPath, DrmDeviceInternal},
error::Error,
};
@ -54,12 +54,11 @@ impl<A: AsRawFd + 'static> LegacyDrmSurface<A> {
let current_mode = crtc_info.mode();
let mut current_connectors = HashSet::new();
let res_handles = fd.resource_handles()
.map_err(|source| Error::Access {
errmsg: "Error loading drm resources",
dev: fd.dev_path(),
source,
})?;
let res_handles = fd.resource_handles().map_err(|source| Error::Access {
errmsg: "Error loading drm resources",
dev: fd.dev_path(),
source,
})?;
for &con in res_handles.connectors() {
let con_info = fd.get_connector(con).map_err(|source| Error::Access {
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
for connector in &pending.connectors {
if !self.fd
if !self
.fd
.get_connector(*connector)
.map_err(|source| Error::Access {
errmsg: "Error loading connector info",
@ -229,7 +229,8 @@ impl<A: AsRawFd + 'static> LegacyDrmSurface<A> {
if conn_removed {
// 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 {
errmsg: "Error setting crtc",
dev: self.fd.dev_path(),
@ -253,22 +254,23 @@ impl<A: AsRawFd + 'static> LegacyDrmSurface<A> {
debug!(self.logger, "Setting screen");
// do a modeset and attach the given framebuffer
self.fd.set_crtc(
self.crtc,
Some(framebuffer),
(0, 0),
&pending
.connectors
.iter()
.copied()
.collect::<Vec<connector::Handle>>(),
Some(pending.mode),
)
.map_err(|source| Error::Access {
errmsg: "Error setting crtc",
dev: self.fd.dev_path(),
source,
})?;
self.fd
.set_crtc(
self.crtc,
Some(framebuffer),
(0, 0),
&pending
.connectors
.iter()
.copied()
.collect::<Vec<connector::Handle>>(),
Some(pending.mode),
)
.map_err(|source| Error::Access {
errmsg: "Error setting crtc",
dev: self.fd.dev_path(),
source,
})?;
*current = pending.clone();
@ -306,7 +308,11 @@ impl<A: AsRawFd + 'static> LegacyDrmSurface<A> {
&*self.fd,
self.crtc,
framebuffer,
if event { &[PageFlipFlags::PageFlipEvent] } else { &[] },
if event {
&[PageFlipFlags::PageFlipEvent]
} else {
&[]
},
None,
)
.map_err(|source| Error::Access {
@ -320,21 +326,24 @@ impl<A: AsRawFd + 'static> LegacyDrmSurface<A> {
if !self.active.load(Ordering::SeqCst) {
return Err(Error::DeviceInactive);
}
let pending = self.pending.read().unwrap();
debug!(self.logger, "Setting screen for buffer *testing*");
Ok(self.fd.set_crtc(
self.crtc,
Some(fb),
(0, 0),
&pending
.connectors
.iter()
.copied()
.collect::<Vec<connector::Handle>>(),
Some(*mode),
).is_ok())
Ok(self
.fd
.set_crtc(
self.crtc,
Some(fb),
(0, 0),
&pending
.connectors
.iter()
.copied()
.collect::<Vec<connector::Handle>>(),
Some(*mode),
)
.is_ok())
}
// 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,
// but that only exists for the atomic api.
fn check_connector(&self, conn: connector::Handle, mode: &Mode) -> Result<bool, Error> {
let info = self.fd
.get_connector(conn)
.map_err(|source| Error::Access {
errmsg: "Error loading connector info",
dev: self.fd.dev_path(),
source,
})?;
let info = self.fd.get_connector(conn).map_err(|source| Error::Access {
errmsg: "Error loading connector info",
dev: self.fd.dev_path(),
source,
})?;
// check if the connector can handle the current mode
if info.modes().contains(mode) {
@ -362,12 +369,11 @@ impl<A: AsRawFd + 'static> LegacyDrmSurface<A> {
.filter(|enc| enc.is_some())
.map(|enc| enc.unwrap())
.map(|encoder| {
self.fd.get_encoder(encoder)
.map_err(|source| Error::Access {
errmsg: "Error loading encoder info",
dev: self.fd.dev_path(),
source,
})
self.fd.get_encoder(encoder).map_err(|source| Error::Access {
errmsg: "Error loading encoder info",
dev: self.fd.dev_path(),
source,
})
})
.collect::<Result<Vec<encoder::Info>, _>>()?;
@ -406,9 +412,7 @@ impl<A: AsRawFd + 'static> Drop for LegacyDrmSurface<A> {
// disable connectors again
let current = self.state.read().unwrap();
if set_connector_state(&*self.fd, current.connectors.iter().copied(), false)
.is_ok()
{
if set_connector_state(&*self.fd, current.connectors.iter().copied(), false).is_ok() {
// null commit
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::sync::Arc;
use drm::control::{connector, crtc, framebuffer, plane, Device as ControlDevice, Mode};
use drm::Device as BasicDevice;
use drm::control::{Device as ControlDevice, Mode, crtc, connector, framebuffer, plane};
pub(super) mod atomic;
pub(super) mod legacy;
use super::error::Error;
use crate::backend::allocator::Format;
use atomic::AtomicDrmSurface;
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) plane: plane::Handle,
pub(super) internal: Arc<DrmSurfaceInternal<A>>,
@ -46,7 +45,7 @@ impl<A: AsRawFd + 'static> DrmSurface<A> {
pub fn plane(&self) -> plane::Handle {
self.plane
}
/// Currently used [`connector`](drm::control::connector)s of this `Surface`
pub fn current_connectors(&self) -> impl IntoIterator<Item = connector::Handle> {
match &*self.internal {
@ -185,12 +184,21 @@ impl<A: AsRawFd + 'static> DrmSurface<A> {
&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 {
DrmSurfaceInternal::Atomic(surf) => surf.test_buffer(fb, mode),
DrmSurfaceInternal::Legacy(surf) => if allow_screen_change {
surf.test_buffer(fb, mode)
} else { Ok(false) } // There is no test-commiting with the legacy interface
DrmSurfaceInternal::Legacy(surf) => {
if allow_screen_change {
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::EGLSurface;
/// EGL context for rendering
#[derive(Debug)]
pub struct EGLContext {
@ -20,10 +19,7 @@ unsafe impl Send for EGLContext {}
unsafe impl Sync for EGLContext {}
impl EGLContext {
pub fn new<L>(
display: &EGLDisplay,
log: L,
) -> Result<EGLContext, Error>
pub fn new<L>(display: &EGLDisplay, log: L) -> Result<EGLContext, Error>
where
L: Into<Option<::slog::Logger>>,
{
@ -43,17 +39,13 @@ impl EGLContext {
Self::new_internal(display, None, Some((attributes, reqs)), log)
}
pub fn new_shared<L>(
display: &EGLDisplay,
share: &EGLContext,
log: L,
) -> Result<EGLContext, Error>
pub fn new_shared<L>(display: &EGLDisplay, share: &EGLContext, log: L) -> Result<EGLContext, Error>
where
L: Into<Option<::slog::Logger>>,
{
Self::new_internal(display, Some(share), None, log)
}
pub fn new_shared_with_config<L>(
display: &EGLDisplay,
share: &EGLContext,
@ -82,13 +74,26 @@ impl EGLContext {
Some((attributes, reqs)) => {
let (format, config_id) = display.choose_config(attributes, reqs)?;
(Some(format), config_id)
},
}
None => {
if !display.extensions.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")
if !display
.extensions
.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)
}
@ -99,7 +104,9 @@ impl EGLContext {
if let Some((attributes, _)) = config {
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);
context_attributes.push(ffi::egl::CONTEXT_MAJOR_VERSION as i32);
context_attributes.push(version.0 as i32);
@ -134,7 +141,9 @@ impl EGLContext {
ffi::egl::CreateContext(
**display.display,
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(),
)
})
@ -157,12 +166,13 @@ impl EGLContext {
///
/// This function is marked unsafe, because the context cannot be made current
/// 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);
wrap_egl_call(|| ffi::egl::MakeCurrent(**self.display.display, surface_ptr, surface_ptr, self.context))
.map(|_| ())
.map_err(Into::into)
wrap_egl_call(|| {
ffi::egl::MakeCurrent(**self.display.display, surface_ptr, surface_ptr, self.context)
})
.map(|_| ())
.map_err(Into::into)
}
/// Makes the OpenGL context the current context in the current thread with no surface bound.

View File

@ -1,10 +1,10 @@
//! Type safe native types for safe egl initialisation
use std::collections::HashSet;
use std::sync::Arc;
use std::ffi::CStr;
use std::mem::MaybeUninit;
use std::ops::Deref;
use std::sync::Arc;
use nix::libc::c_int;
#[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")]
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::{
ffi::egl::types::EGLImage,
ffi, wrap_egl_call, EGLError, Error,
context::{GlAttributes, PixelFormatRequirements},
native::{EGLNativeDisplay},
BufferAccessError, EGLBuffer, Format,
ffi,
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
@ -94,7 +94,7 @@ impl EGLDisplay {
return Err(Error::EglExtensionNotSupported(native.required_extensions()));
}
}
let (platform, native_ptr, attributes) = native.platform_display();
// we create an EGLDisplay
let display = unsafe {
@ -355,62 +355,92 @@ impl EGLDisplay {
/// Imports a dmabuf as an eglimage
pub fn create_image_from_dmabuf(&self, dmabuf: &Dmabuf) -> Result<EGLImage, Error> {
if !self.extensions.iter().any(|s| s == "EGL_KHR_image_base") &&
!self.extensions.iter().any(|s| s == "EGL_EXT_image_dma_buf_import")
if !self.extensions.iter().any(|s| s == "EGL_KHR_image_base")
&& !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") {
return Err(Error::EglExtensionNotSupported(&["EGL_EXT_image_dma_buf_import_modifiers"]));
if dmabuf.has_modifier()
&& !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);
out.extend(&[
ffi::egl::WIDTH as i32, dmabuf.width() 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,
ffi::egl::WIDTH as i32,
dmabuf.width() 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 = [
[
ffi::egl::DMA_BUF_PLANE0_FD_EXT,
ffi::egl::DMA_BUF_PLANE0_OFFSET_EXT,
ffi::egl::DMA_BUF_PLANE0_PITCH_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_OFFSET_EXT,
ffi::egl::DMA_BUF_PLANE1_PITCH_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_OFFSET_EXT,
ffi::egl::DMA_BUF_PLANE2_PITCH_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_OFFSET_EXT,
ffi::egl::DMA_BUF_PLANE3_PITCH_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(&[
names[i][0] as i32, *fd,
names[i][1] as i32, *offset as i32,
names[i][2] as i32, *stride as i32,
names[i][0] as i32,
*fd,
names[i][1] as i32,
*offset as i32,
names[i][2] as i32,
*stride as i32,
]);
if dmabuf.has_modifier() {
out.extend(&[
names[i][3] 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,
names[i][3] 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;
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.
// Just a guess but better than not supporting dmabufs at all,
// given that the modifiers extension isn't supported everywhere.
if !extensions.iter().any(|s| s == "EGL_EXT_image_dma_buf_import_modifiers") {
vec![
Fourcc::Argb8888,
Fourcc::Xrgb8888,
]
if !extensions
.iter()
.any(|s| s == "EGL_EXT_image_dma_buf_import_modifiers")
{
vec![Fourcc::Argb8888, Fourcc::Xrgb8888]
} else {
let mut num = 0i32;
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);
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 {
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 {
let mut num = 0i32;
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 {
texture_formats.insert(DrmFormat {
code: fourcc,
modifier: Modifier::Invalid
modifier: Modifier::Invalid,
});
render_formats.insert(DrmFormat {
code: fourcc,
modifier: Modifier::Invalid
modifier: Modifier::Invalid,
});
} else {
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);
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 {
@ -572,10 +627,7 @@ impl fmt::Debug for EGLBufferReader {
#[cfg(feature = "use_system_lib")]
impl EGLBufferReader {
fn new(display: Arc<EGLDisplayHandle>, wayland: *mut wl_display) -> Self {
Self {
display,
wayland,
}
Self { display, wayland }
}
/// 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_RGBA as i32 => Format::RGBA,
ffi::egl::TEXTURE_EXTERNAL_WL => Format::External,
ffi::egl::TEXTURE_Y_UV_WL => return Err(BufferAccessError::UnsupportedMultiPlanarFormat(Format::Y_UV)),
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)),
ffi::egl::TEXTURE_Y_UV_WL => {
return Err(BufferAccessError::UnsupportedMultiPlanarFormat(Format::Y_UV))
}
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),
};
@ -646,11 +704,7 @@ impl EGLBufferReader {
let mut images = Vec::with_capacity(format.num_planes());
for i in 0..format.num_planes() {
let out = [
ffi::egl::WAYLAND_PLANE_WL as i32,
i as i32,
ffi::egl::NONE as i32,
];
let out = [ffi::egl::WAYLAND_PLANE_WL as i32, i as i32, ffi::egl::NONE as i32];
images.push({
wrap_egl_call(|| unsafe {
@ -740,4 +794,4 @@ pub struct PixelFormat {
pub multisampling: Option<u16>,
/// is srgb enabled
pub srgb: bool,
}
}

View File

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

View File

@ -1,12 +1,10 @@
//! Type safe native types for safe context/surface creation
use super::{
display::EGLDisplayHandle, ffi, wrap_egl_call, SwapBuffersError,
};
use super::{display::EGLDisplayHandle, ffi, wrap_egl_call, SwapBuffersError};
use nix::libc::{c_int, c_void};
use std::sync::Arc;
#[cfg(feature = "backend_gbm")]
use std::os::unix::io::AsRawFd;
use std::sync::Arc;
#[cfg(feature = "backend_winit")]
use wayland_egl as wegl;
@ -33,7 +31,11 @@ impl<A: AsRawFd + Send + 'static> EGLNativeDisplay for GbmDevice<A> {
&["EGL_MESA_platform_gbm"]
}
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>) {
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() {
(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 {
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.
///
///
/// 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.
/// It allows you to control the direction of the resizing if necessary.
///
///
/// Implementations may ignore the dx and dy arguments.
///
///
/// Returns true if the resize was successful.
fn resize(&self, _width: i32, _height: i32, _dx: i32, _dy: i32) -> bool {
false
@ -160,7 +170,7 @@ unsafe impl EGLNativeSurface for wegl::WlEglSurface {
)
})
}
fn resize(&self, width: i32, height: i32, dx: i32, dy: i32) -> bool {
wegl::WlEglSurface::resize(self, width, height, dx, dy);
true

View File

@ -9,11 +9,11 @@ use nix::libc::c_int;
use crate::backend::egl::{
display::{EGLDisplay, EGLDisplayHandle, PixelFormat},
ffi,
native::EGLNativeSurface,
ffi, EGLError, SwapBuffersError
EGLError, SwapBuffersError,
};
/// EGL surface of a given EGL context for rendering
pub struct EGLSurface {
pub(crate) display: Arc<EGLDisplayHandle>,
@ -98,14 +98,17 @@ impl EGLSurface {
);
if self.native.needs_recreation() || surface.is_null() || is_bad_surface {
let previous = self.surface.compare_exchange(
surface,
self.native
.create(&self.display, self.config_id, &self.surface_attributes)
.map_err(SwapBuffersError::EGLCreateSurface)? as *mut _,
Ordering::SeqCst,
Ordering::SeqCst,
).expect("The surface pointer changed in between?");
let previous = self
.surface
.compare_exchange(
surface,
self.native
.create(&self.display, self.config_id, &self.surface_attributes)
.map_err(SwapBuffersError::EGLCreateSurface)? as *mut _,
Ordering::SeqCst,
Ordering::SeqCst,
)
.expect("The surface pointer changed in between?");
if previous == surface && !surface.is_null() {
let _ = unsafe { ffi::egl::DestroySurface(**self.display, surface as *const _) };
}
@ -139,15 +142,15 @@ impl EGLSurface {
pub fn pixel_format(&self) -> PixelFormat {
self.pixel_format
}
/// Tries to resize the underlying native 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.
/// It allows you to control the direction of the resizing if necessary.
///
///
/// Implementations may ignore the dx and dy arguments.
///
///
/// Returns true if the resize was successful.
pub fn resize(&self, width: i32, height: i32, dx: i32, dy: i32) -> bool {
self.native.resize(width, height, dx, dy)

View File

@ -18,8 +18,8 @@
#![allow(missing_docs)]
//pub mod graphics;
pub mod input;
pub mod allocator;
pub mod input;
pub mod renderer;
#[cfg(feature = "backend_drm")]
@ -66,4 +66,4 @@ pub enum SwapBuffersError {
/// recreation.
#[error("A temporary condition caused the page flip to fail: {0}")]
TemporaryFailure(Box<dyn std::error::Error>),
}
}

View File

@ -6,13 +6,18 @@ use std::rc::Rc;
use cgmath::{prelude::*, Matrix3};
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::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")]
use wayland_server::protocol::{wl_shm, wl_buffer};
use wayland_server::protocol::{wl_buffer, wl_shm};
#[allow(clippy::all, missing_docs)]
pub mod ffi {
@ -109,44 +114,52 @@ impl From<Gles2Error> for SwapBuffersError {
| x @ Gles2Error::ProgramLinkError
| x @ Gles2Error::GLFunctionLoaderError
| x @ Gles2Error::GLExtensionNotSupported(_)
| x @ Gles2Error::UnconstraintRenderingOperation
=> SwapBuffersError::ContextLost(Box::new(x)),
| x @ Gles2Error::UnconstraintRenderingOperation => SwapBuffersError::ContextLost(Box::new(x)),
Gles2Error::ContextActivationError(err) => err.into(),
x @ Gles2Error::FramebufferBindingError
| x @ Gles2Error::BindBufferEGLError(_)
| x @ Gles2Error::UnsupportedPixelFormat(_)
| x @ Gles2Error::BufferAccessError(_)
=> SwapBuffersError::TemporaryFailure(Box::new(x)),
| x @ Gles2Error::BufferAccessError(_) => SwapBuffersError::TemporaryFailure(Box::new(x)),
}
}
}
extern "system" fn gl_debug_log(_source: ffi::types::GLenum,
gltype: ffi::types::GLenum,
_id: ffi::types::GLuint,
_severity: ffi::types::GLenum,
_length: ffi::types::GLsizei,
message: *const ffi::types::GLchar,
user_param: *mut nix::libc::c_void)
{
let _ = std::panic::catch_unwind(move || {
unsafe {
let msg = CStr::from_ptr(message);
let log = Box::from_raw(user_param as *mut ::slog::Logger);
let message_utf8 = msg.to_string_lossy();
match gltype {
ffi::DEBUG_TYPE_ERROR | ffi::DEBUG_TYPE_UNDEFINED_BEHAVIOR => error!(log, "[GL] {}", message_utf8),
ffi::DEBUG_TYPE_DEPRECATED_BEHAVIOR => warn!(log, "[GL] {}", message_utf8),
_ => debug!(log, "[GL] {}", message_utf8),
};
std::mem::forget(log);
}
extern "system" fn gl_debug_log(
_source: ffi::types::GLenum,
gltype: ffi::types::GLenum,
_id: ffi::types::GLuint,
_severity: ffi::types::GLenum,
_length: ffi::types::GLsizei,
message: *const ffi::types::GLchar,
user_param: *mut nix::libc::c_void,
) {
let _ = std::panic::catch_unwind(move || unsafe {
let msg = CStr::from_ptr(message);
let log = Box::from_raw(user_param as *mut ::slog::Logger);
let message_utf8 = msg.to_string_lossy();
match gltype {
ffi::DEBUG_TYPE_ERROR | ffi::DEBUG_TYPE_UNDEFINED_BEHAVIOR => {
error!(log, "[GL] {}", message_utf8)
}
ffi::DEBUG_TYPE_DEPRECATED_BEHAVIOR => warn!(log, "[GL] {}", message_utf8),
_ => 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);
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);
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)
}
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 frag = compile_shader(gl, ffi::FRAGMENT_SHADER, frag_src)?;
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> {
let program = link_program(&gl, shaders::VERTEX_SHADER, frag)?;
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 = 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 {
pub unsafe fn new<L>(context: EGLContext, logger: L) -> Result<Gles2Renderer, Gles2Error>
where
L: Into<Option<::slog::Logger>>
L: Into<Option<::slog::Logger>>,
{
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, "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,
"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);
// required for the manditory wl_shm formats
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
if !exts.iter().any(|ext| ext == "GL_EXT_unpack_subimage") {
@ -245,17 +276,19 @@ impl Gles2Renderer {
gl.Enable(ffi::DEBUG_OUTPUT_SYNCHRONOUS);
gl.DebugMessageCallback(Some(gl_debug_log), logger as *mut nix::libc::c_void);
Some(logger)
} else { None };
} else {
None
};
(gl, exts, logger)
};
let programs = [
texture_program(&gl, shaders::FRAGMENT_SHADER_ABGR)?,
texture_program(&gl, shaders::FRAGMENT_SHADER_XBGR)?,
texture_program(&gl, shaders::FRAGMENT_SHADER_BGRA)?,
texture_program(&gl, shaders::FRAGMENT_SHADER_BGRX)?,
texture_program(&gl, shaders::FRAGMENT_SHADER_EXTERNAL)?,
texture_program(&gl, shaders::FRAGMENT_SHADER_ABGR)?,
texture_program(&gl, shaders::FRAGMENT_SHADER_XBGR)?,
texture_program(&gl, shaders::FRAGMENT_SHADER_BGRA)?,
texture_program(&gl, shaders::FRAGMENT_SHADER_BGRX)?,
texture_program(&gl, shaders::FRAGMENT_SHADER_EXTERNAL)?,
];
let renderer = Gles2Renderer {
@ -312,31 +345,45 @@ impl Bind<Dmabuf> for Gles2Renderer {
}
}
let buffer = self.buffers
let buffer = self
.buffers
.iter()
.find(|buffer| dmabuf == buffer.dmabuf)
.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 {
internal: buf.clone(),
// we keep the dmabuf alive as long as we are bound
_dmabuf: dmabuf
_dmabuf: dmabuf,
})
})
.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 {
let mut rbo = 0;
self.gl.GenRenderbuffers(1, &mut rbo as *mut _);
self.gl.BindRenderbuffer(ffi::RENDERBUFFER, rbo);
self.gl.EGLImageTargetRenderbufferStorageOES(ffi::RENDERBUFFER, image);
self.gl
.EGLImageTargetRenderbufferStorageOES(ffi::RENDERBUFFER, image);
self.gl.BindRenderbuffer(ffi::RENDERBUFFER, 0);
let mut fbo = 0;
self.gl.GenFramebuffers(1, &mut fbo as *mut _);
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);
self.gl.BindFramebuffer(ffi::FRAMEBUFFER, 0);
@ -356,7 +403,7 @@ impl Bind<Dmabuf> for Gles2Renderer {
Ok(Gles2Buffer {
internal: weak,
_dmabuf: dmabuf
_dmabuf: dmabuf,
})
}
})?;
@ -364,7 +411,7 @@ impl Bind<Dmabuf> for Gles2Renderer {
unsafe {
self.gl.BindFramebuffer(ffi::FRAMEBUFFER, buffer.internal.fbo);
}
self.target_buffer = Some(buffer);
Ok(())
}
@ -437,21 +484,36 @@ impl Renderer for Gles2Renderer {
wl_shm::Format::Xrgb8888,
]
}
#[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()?;
let mut tex = 0;
unsafe {
self.gl.GenTextures(1, &mut 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.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
.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.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);
}
let texture = Gles2Texture {
texture: tex,
texture_kind: 2,
@ -461,10 +523,9 @@ impl Renderer for Gles2Renderer {
height: image.height(),
};
self.egl.unbind()?;
Ok(texture)
}
#[cfg(feature = "wayland_frontend")]
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| {
self.make_current()?;
let offset = data.offset as i32;
let width = data.width as i32;
let height = data.height as i32;
@ -492,16 +553,28 @@ impl Renderer for Gles2Renderer {
wl_shm::Format::Xrgb8888 => (ffi::BGRA_EXT, 3),
format => return Err(Gles2Error::UnsupportedPixelFormat(format)),
};
let mut tex = 0;
unsafe {
self.gl.GenTextures(1, &mut 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.TexParameteri(ffi::TEXTURE_2D, ffi::TEXTURE_WRAP_T, ffi::CLAMP_TO_EDGE as i32);
self.gl
.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.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.BindTexture(ffi::TEXTURE_2D, 0);
@ -516,11 +589,12 @@ impl Renderer for Gles2Renderer {
height: height as u32,
};
self.egl.unbind()?;
Ok(texture)
}).map_err(Gles2Error::BufferAccessError)?
})
.map_err(Gles2Error::BufferAccessError)?
}
#[cfg(feature = "wayland_frontend")]
fn import_egl(&mut self, buffer: &EGLBuffer) -> Result<Self::TextureId, Self::Error> {
if !self.extensions.iter().any(|ext| ext == "GL_OES_EGL_image") {
@ -530,21 +604,23 @@ impl Renderer for Gles2Renderer {
self.make_current()?;
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 {
self.gl.GenTextures(1, &mut tex);
self.gl.BindTexture(target, tex);
self.gl.EGLImageTargetTexture2DOES(
target,
buffer.image(0).unwrap(),
);
self.gl
.EGLImageTargetTexture2DOES(target, buffer.image(0).unwrap());
}
let texture = Gles2Texture {
texture: tex,
texture_kind: match buffer.format {
EGLFormat::RGB => 3,
EGLFormat::RGB => 3,
EGLFormat::RGBA => 2,
EGLFormat::External => 4,
_ => unreachable!("EGLBuffer currenly does not expose multi-planar buffers to us"),
@ -555,10 +631,10 @@ impl Renderer for Gles2Renderer {
height: buffer.height,
};
self.egl.unbind()?;
Ok(texture)
}
fn destroy_texture(&mut self, texture: Self::TextureId) -> Result<(), Self::Error> {
self.make_current()?;
@ -570,12 +646,11 @@ impl Renderer for Gles2Renderer {
Ok(())
}
fn begin(&mut self, width: u32, height: u32, transform: Transform) -> Result<(), Gles2Error> {
self.make_current()?;
unsafe {
self.gl.Viewport(0, 0, width as i32, height as i32);
self.gl.Enable(ffi::BLEND);
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);
Ok(())
}
fn clear(&mut self, color: [f32; 4]) -> Result<(), Self::Error> {
self.make_current()?;
unsafe {
@ -612,7 +687,12 @@ impl Renderer for Gles2Renderer {
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()?;
if self.current_projection.is_none() {
return Err(Gles2Error::UnconstraintRenderingOperation);
@ -621,31 +701,63 @@ impl Renderer for Gles2Renderer {
//apply output transformation
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
unsafe {
self.gl.ActiveTexture(ffi::TEXTURE0);
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.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.Uniform1i(self.programs[tex.texture_kind].uniform_invert_y, if tex.y_inverted { 1 } else { 0 });
self.gl.Uniform1f(self.programs[tex.texture_kind].uniform_alpha, alpha);
self.gl.VertexAttribPointer(self.programs[tex.texture_kind].attrib_position as u32, 2, ffi::FLOAT, ffi::FALSE, 0, VERTS.as_ptr() as *const _);
self.gl.VertexAttribPointer(self.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.UniformMatrix3fv(
self.programs[tex.texture_kind].uniform_matrix,
1,
ffi::FALSE,
matrix.as_ptr(),
);
self.gl.Uniform1i(
self.programs[tex.texture_kind].uniform_invert_y,
if tex.y_inverted { 1 } else { 0 },
);
self.gl
.Uniform1f(self.programs[tex.texture_kind].uniform_alpha, alpha);
self.gl.VertexAttribPointer(
self.programs[tex.texture_kind].attrib_position as u32,
2,
ffi::FLOAT,
ffi::FALSE,
0,
VERTS.as_ptr() as *const _,
);
self.gl.VertexAttribPointer(
self.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.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
.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);
}

View File

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

View File

@ -3,7 +3,7 @@ use std::error::Error;
use cgmath::{prelude::*, Matrix3, Vector2};
#[cfg(feature = "wayland_frontend")]
use wayland_server::protocol::{wl_shm, wl_buffer};
use wayland_server::protocol::{wl_buffer, wl_shm};
use crate::backend::SwapBuffersError;
#[cfg(feature = "renderer_gl")]
@ -26,46 +26,14 @@ pub enum Transform {
impl Transform {
pub fn matrix(&self) -> Matrix3<f32> {
match self {
Transform::Normal => Matrix3::new(
1.0, 0.0, 0.0,
0.0, 1.0, 0.0,
0.0, 0.0, 1.0,
),
Transform::_90 => Matrix3::new(
0.0, -1.0, 0.0,
1.0, 0.0, 0.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,
),
Transform::Normal => Matrix3::new(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0),
Transform::_90 => Matrix3::new(0.0, -1.0, 0.0, 1.0, 0.0, 0.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;
#[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")]
fn shm_formats(&self) -> &[wl_shm::Format] {
// Mandatory
@ -149,14 +120,30 @@ pub trait Renderer {
fn import_egl(&mut self, buffer: &EGLBuffer) -> Result<Self::TextureId, 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 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_at(&mut self, texture: &Self::TextureId, pos: (i32, i32), transform: Transform, alpha: f32) -> Result<(), Self::Error> {
fn render_texture(
&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();
// position and scale
let size = texture.size();
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)
}
}
}

View File

@ -2,28 +2,24 @@
use crate::backend::egl::display::EGLDisplay;
use crate::backend::{
egl::{context::GlAttributes, native, EGLContext, EGLSurface, EGLBuffer, Error as EGLError},
renderer::{
Renderer, Bind, Transform,
gles2::{Gles2Renderer, Gles2Error, Gles2Texture},
},
egl::{context::GlAttributes, native, EGLBuffer, EGLContext, EGLSurface, Error as EGLError},
input::{
Axis, AxisSource, Event as BackendEvent, InputBackend, InputEvent, KeyState, KeyboardKeyEvent,
MouseButton, MouseButtonState, PointerAxisEvent, PointerButtonEvent, PointerMotionAbsoluteEvent,
Seat, SeatCapabilities, TouchCancelEvent, TouchDownEvent, TouchMotionEvent, TouchSlot, TouchUpEvent,
UnusedEvent,
},
};
use std::{
cell::RefCell,
rc::Rc,
time::Instant,
renderer::{
gles2::{Gles2Error, Gles2Renderer, Gles2Texture},
Bind, Renderer, Transform,
},
};
use cgmath::Matrix3;
use std::{cell::RefCell, rc::Rc, time::Instant};
use wayland_egl as wegl;
use wayland_server::Display;
#[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::{
dpi::{LogicalPosition, LogicalSize, PhysicalSize},
event::{
@ -37,7 +33,7 @@ use winit::{
};
#[cfg(feature = "use_system_lib")]
use crate::backend::egl::{display::EGLBufferReader};
use crate::backend::egl::display::EGLBufferReader;
/// Errors thrown by the `winit` backends
#[derive(thiserror::Error, Debug)]
@ -158,23 +154,33 @@ where
let surface = unsafe {
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())
.map_err(EGLError::CreationFailed)?
EGLSurface::new(
&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) {
debug!(log, "Winit backend: X11");
EGLSurface::new(&display, context.pixel_format().unwrap(), reqs.double_buffer, context.config_id(), xlib_window, log.clone())
.map_err(EGLError::CreationFailed)?
EGLSurface::new(
&display,
context.pixel_format().unwrap(),
reqs.double_buffer,
context.config_id(),
xlib_window,
log.clone(),
)
.map_err(EGLError::CreationFailed)?
} else {
unreachable!("No backends for winit other then Wayland and X11 are supported")
};
let _ = context.unbind();
(
display,
context,
surface,
)
(display, context, surface)
};
let size = Rc::new(RefCell::new(WindowSize {
@ -250,7 +256,7 @@ impl WinitGraphicsBackend {
let size = self.size.borrow();
size.physical_size.into()
};
self.renderer.bind(self.egl.clone())?;
self.renderer.begin(width, height, Transform::Normal)
}
@ -259,12 +265,15 @@ impl WinitGraphicsBackend {
impl Renderer for WinitGraphicsBackend {
type Error = Gles2Error;
type TextureId = Gles2Texture;
#[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)
}
#[cfg(feature = "wayland_frontend")]
fn shm_formats(&self) -> &[wl_shm::Format] {
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> {
self.renderer.import_shm(buffer)
}
#[cfg(feature = "wayland_frontend")]
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> {
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.begin(width, height, transform)
}
@ -293,7 +307,12 @@ impl Renderer for WinitGraphicsBackend {
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)
}

View File

@ -255,7 +255,11 @@ where
for f in &*formats {
dmabuf.format(f.format as u32);
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,
);
}
}
},