rustfmt
This commit is contained in:
parent
36bf5618ed
commit
52c01535d0
|
@ -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,7 +147,7 @@ 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,
|
||||
|
|
|
@ -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,40 +173,38 @@ 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 {
|
||||
|
|
|
@ -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,34 +419,36 @@ 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;
|
||||
}
|
||||
};
|
||||
|
@ -470,15 +461,17 @@ 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;
|
||||
}
|
||||
};
|
||||
|
@ -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");
|
||||
|
@ -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,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -141,7 +163,17 @@ pub fn run_winit(
|
|||
// 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()
|
||||
|
|
|
@ -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,7 +96,15 @@ 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);
|
||||
|
@ -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>>,
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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,7 +119,11 @@ 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
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
@ -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,7 +214,8 @@ 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(),
|
||||
|
|
|
@ -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,8 +18,12 @@ 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,
|
||||
|
@ -27,12 +34,11 @@ impl<A: AsRawFd + 'static> LegacyDrmDevice<A> {
|
|||
// 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
|
||||
|
|
|
@ -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,
|
||||
|
@ -92,9 +95,7 @@ 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"
|
||||
|
@ -152,12 +165,14 @@ impl<A: AsRawFd + 'static> DrmDevice<A> {
|
|||
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) {
|
||||
|
@ -224,9 +239,15 @@ impl<A: AsRawFd + 'static> DrmDevice<A> {
|
|||
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
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -262,7 +287,13 @@ 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));
|
||||
}
|
||||
|
@ -270,7 +301,7 @@ impl<A: AsRawFd + 'static> DrmDevice<A> {
|
|||
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) {
|
||||
|
@ -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,
|
||||
|
|
|
@ -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 }))
|
||||
|
|
|
@ -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 session::DrmDeviceObserver;
|
||||
pub use render::{DrmRenderSurface, Error as DrmRenderError};
|
||||
pub use session::DrmDeviceObserver;
|
||||
pub use surface::DrmSurface;
|
||||
|
|
|
@ -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,13 +62,28 @@ 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);
|
||||
|
@ -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,9 +190,12 @@ 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)
|
||||
}
|
||||
}
|
||||
|
@ -159,7 +204,7 @@ where
|
|||
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> {
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -405,26 +475,23 @@ where
|
|||
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)),
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
@ -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,19 +488,20 @@ 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(())
|
||||
}
|
||||
|
@ -502,7 +511,8 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
|
|||
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",
|
||||
|
@ -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")
|
||||
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
@ -324,17 +330,20 @@ impl<A: AsRawFd + 'static> LegacyDrmSurface<A> {
|
|||
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);
|
||||
}
|
||||
|
|
|
@ -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>>,
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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,11 +39,7 @@ 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>>,
|
||||
{
|
||||
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
@ -355,22 +355,38 @@ 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 = [
|
||||
|
@ -379,38 +395,52 @@ impl EGLDisplay {
|
|||
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 {
|
||||
|
|
|
@ -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)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
|
|
|
@ -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 _) };
|
||||
}
|
||||
|
|
|
@ -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")]
|
||||
|
|
|
@ -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();
|
||||
|
@ -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,
|
||||
})
|
||||
}
|
||||
})?;
|
||||
|
@ -439,16 +486,31 @@ impl Renderer for Gles2Renderer {
|
|||
}
|
||||
|
||||
#[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);
|
||||
}
|
||||
|
||||
|
@ -465,7 +527,6 @@ impl Renderer for Gles2Renderer {
|
|||
Ok(texture)
|
||||
}
|
||||
|
||||
|
||||
#[cfg(feature = "wayland_frontend")]
|
||||
fn import_shm(&mut self, buffer: &wl_buffer::WlBuffer) -> Result<Self::TextureId, Self::Error> {
|
||||
use crate::wayland::shm::with_buffer_contents;
|
||||
|
@ -498,10 +559,22 @@ impl Renderer for Gles2Renderer {
|
|||
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);
|
||||
|
@ -518,7 +591,8 @@ impl Renderer for Gles2Renderer {
|
|||
self.egl.unbind()?;
|
||||
|
||||
Ok(texture)
|
||||
}).map_err(Gles2Error::BufferAccessError)?
|
||||
})
|
||||
.map_err(Gles2Error::BufferAccessError)?
|
||||
}
|
||||
|
||||
#[cfg(feature = "wayland_frontend")]
|
||||
|
@ -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"),
|
||||
|
@ -570,7 +646,6 @@ impl Renderer for Gles2Renderer {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
fn begin(&mut self, width: u32, height: u32, transform: Transform) -> Result<(), Gles2Error> {
|
||||
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,30 +701,62 @@ 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.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.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
|
||||
.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);
|
||||
}
|
||||
|
|
|
@ -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,12 +120,28 @@ 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
|
||||
|
@ -173,5 +160,4 @@ pub trait Renderer {
|
|||
|
||||
self.render_texture(texture, mat, alpha)
|
||||
}
|
||||
|
||||
}
|
|
@ -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 {
|
||||
|
@ -261,7 +267,10 @@ impl Renderer for WinitGraphicsBackend {
|
|||
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)
|
||||
}
|
||||
|
||||
|
@ -284,7 +293,12 @@ impl Renderer for WinitGraphicsBackend {
|
|||
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)
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
Loading…
Reference in New Issue