cargo fmt
This commit is contained in:
parent
890a17189b
commit
12e80ca2c6
|
@ -15,7 +15,7 @@ use smithay::{
|
||||||
},
|
},
|
||||||
utils::Rectangle,
|
utils::Rectangle,
|
||||||
wayland::{
|
wayland::{
|
||||||
compositor::{roles::Role, SubsurfaceRole, TraversalAction, Damage},
|
compositor::{roles::Role, Damage, SubsurfaceRole, TraversalAction},
|
||||||
data_device::DnDIconRole,
|
data_device::DnDIconRole,
|
||||||
seat::CursorImageRole,
|
seat::CursorImageRole,
|
||||||
},
|
},
|
||||||
|
@ -46,7 +46,7 @@ pub fn draw_cursor<R, E, F, T>(
|
||||||
log: &Logger,
|
log: &Logger,
|
||||||
) -> Result<(), SwapBuffersError>
|
) -> Result<(), SwapBuffersError>
|
||||||
where
|
where
|
||||||
R: Renderer<Error = E, TextureId = T, Frame=F>,
|
R: Renderer<Error = E, TextureId = T, Frame = F>,
|
||||||
F: Frame<Error = E, TextureId = T>,
|
F: Frame<Error = E, TextureId = T>,
|
||||||
E: std::error::Error + Into<SwapBuffersError>,
|
E: std::error::Error + Into<SwapBuffersError>,
|
||||||
T: Texture + 'static,
|
T: Texture + 'static,
|
||||||
|
@ -61,7 +61,15 @@ where
|
||||||
(0, 0)
|
(0, 0)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
draw_surface_tree(renderer, frame, surface, egl_buffer_reader, (x - dx, y - dy), token, log)
|
draw_surface_tree(
|
||||||
|
renderer,
|
||||||
|
frame,
|
||||||
|
surface,
|
||||||
|
egl_buffer_reader,
|
||||||
|
(x - dx, y - dy),
|
||||||
|
token,
|
||||||
|
log,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_surface_tree<R, E, F, T>(
|
fn draw_surface_tree<R, E, F, T>(
|
||||||
|
@ -74,7 +82,7 @@ fn draw_surface_tree<R, E, F, T>(
|
||||||
log: &Logger,
|
log: &Logger,
|
||||||
) -> Result<(), SwapBuffersError>
|
) -> Result<(), SwapBuffersError>
|
||||||
where
|
where
|
||||||
R: Renderer<Error = E, TextureId = T, Frame=F>,
|
R: Renderer<Error = E, TextureId = T, Frame = F>,
|
||||||
F: Frame<Error = E, TextureId = T>,
|
F: Frame<Error = E, TextureId = T>,
|
||||||
E: std::error::Error + Into<SwapBuffersError>,
|
E: std::error::Error + Into<SwapBuffersError>,
|
||||||
T: Texture + 'static,
|
T: Texture + 'static,
|
||||||
|
@ -92,7 +100,12 @@ where
|
||||||
if let Some(buffer) = data.current_state.buffer.take() {
|
if let Some(buffer) = data.current_state.buffer.take() {
|
||||||
match renderer.import_buffer(&buffer, &attributes, egl_buffer_reader) {
|
match renderer.import_buffer(&buffer, &attributes, egl_buffer_reader) {
|
||||||
Ok(m) => {
|
Ok(m) => {
|
||||||
let buffer = if smithay::wayland::shm::with_buffer_contents(&buffer, |_,_| ()).is_ok() {
|
let buffer = if smithay::wayland::shm::with_buffer_contents(
|
||||||
|
&buffer,
|
||||||
|
|_, _| (),
|
||||||
|
)
|
||||||
|
.is_ok()
|
||||||
|
{
|
||||||
buffer.release();
|
buffer.release();
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
|
@ -111,7 +124,8 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Now, should we be drawn ?
|
// Now, should we be drawn ?
|
||||||
if data.texture.is_some() {// if yes, also process the children
|
if data.texture.is_some() {
|
||||||
|
// if yes, also process the children
|
||||||
if Role::<SubsurfaceRole>::has(role) {
|
if Role::<SubsurfaceRole>::has(role) {
|
||||||
x += data.current_state.sub_location.0;
|
x += data.current_state.sub_location.0;
|
||||||
y += data.current_state.sub_location.1;
|
y += data.current_state.sub_location.1;
|
||||||
|
@ -168,7 +182,7 @@ pub fn draw_windows<R, E, F, T>(
|
||||||
log: &::slog::Logger,
|
log: &::slog::Logger,
|
||||||
) -> Result<(), SwapBuffersError>
|
) -> Result<(), SwapBuffersError>
|
||||||
where
|
where
|
||||||
R: Renderer<Error = E, TextureId = T, Frame=F>,
|
R: Renderer<Error = E, TextureId = T, Frame = F>,
|
||||||
F: Frame<Error = E, TextureId = T>,
|
F: Frame<Error = E, TextureId = T>,
|
||||||
E: std::error::Error + Into<SwapBuffersError>,
|
E: std::error::Error + Into<SwapBuffersError>,
|
||||||
T: Texture + 'static,
|
T: Texture + 'static,
|
||||||
|
@ -213,7 +227,7 @@ pub fn draw_dnd_icon<R, E, F, T>(
|
||||||
log: &::slog::Logger,
|
log: &::slog::Logger,
|
||||||
) -> Result<(), SwapBuffersError>
|
) -> Result<(), SwapBuffersError>
|
||||||
where
|
where
|
||||||
R: Renderer<Error = E, TextureId = T, Frame=F>,
|
R: Renderer<Error = E, TextureId = T, Frame = F>,
|
||||||
F: Frame<Error = E, TextureId = T>,
|
F: Frame<Error = E, TextureId = T>,
|
||||||
E: std::error::Error + Into<SwapBuffersError>,
|
E: std::error::Error + Into<SwapBuffersError>,
|
||||||
T: Texture + 'static,
|
T: Texture + 'static,
|
||||||
|
|
|
@ -0,0 +1,664 @@
|
||||||
|
use std::{
|
||||||
|
cell::RefCell,
|
||||||
|
collections::hash_map::{Entry, HashMap},
|
||||||
|
io::Error as IoError,
|
||||||
|
fs::{File, OpenOptions},
|
||||||
|
rc::Rc,
|
||||||
|
os::unix::io::{AsRawFd, RawFd},
|
||||||
|
sync::{atomic::Ordering, Arc, Mutex},
|
||||||
|
time::Duration,
|
||||||
|
};
|
||||||
|
|
||||||
|
use image::ImageBuffer;
|
||||||
|
use slog::Logger;
|
||||||
|
|
||||||
|
#[cfg(feature = "egl")]
|
||||||
|
use smithay::{
|
||||||
|
backend::egl::display::EGLBufferReader,
|
||||||
|
};
|
||||||
|
use smithay::{
|
||||||
|
backend::{
|
||||||
|
drm::{device_bind, DeviceHandler, DrmDevice, DrmError, DrmRenderSurface},
|
||||||
|
egl::{EGLContext, EGLDisplay},
|
||||||
|
renderer::{
|
||||||
|
gles2::{Gles2Renderer, Gles2Texture},
|
||||||
|
Frame, Renderer, Transform,
|
||||||
|
},
|
||||||
|
SwapBuffersError,
|
||||||
|
},
|
||||||
|
reexports::{
|
||||||
|
calloop::{
|
||||||
|
generic::Generic,
|
||||||
|
timer::{Timer, TimerHandle},
|
||||||
|
EventLoop, LoopHandle, Source,
|
||||||
|
},
|
||||||
|
drm::{
|
||||||
|
self,
|
||||||
|
control::{
|
||||||
|
connector::{Info as ConnectorInfo, State as ConnectorState},
|
||||||
|
crtc,
|
||||||
|
encoder::Info as EncoderInfo,
|
||||||
|
Device as ControlDevice,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
gbm::{BufferObject as GbmBuffer, Device as GbmDevice},
|
||||||
|
nix::sys::stat::dev_t,
|
||||||
|
wayland_server::{
|
||||||
|
protocol::{wl_output, wl_surface, wl_buffer},
|
||||||
|
Display, Global,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
utils::Rectangle,
|
||||||
|
wayland::{
|
||||||
|
compositor::CompositorToken,
|
||||||
|
output::{Mode, Output, PhysicalProperties},
|
||||||
|
seat::CursorImageStatus,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::drawing::*;
|
||||||
|
use crate::shell::{MyWindowMap, Roles};
|
||||||
|
use crate::state::AnvilState;
|
||||||
|
|
||||||
|
pub struct FileWrapper(File);
|
||||||
|
impl AsRawFd for FileWrapper {
|
||||||
|
fn as_raw_fd(&self) -> RawFd {
|
||||||
|
self.0.as_raw_fd()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Clone for FileWrapper {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
FileWrapper(self.0.try_clone().unwrap())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run_raw(
|
||||||
|
display: Rc<RefCell<Display>>,
|
||||||
|
event_loop: &mut EventLoop<AnvilState>,
|
||||||
|
path: impl AsRef<str>,
|
||||||
|
log: Logger,
|
||||||
|
) -> Result<(), ()> {
|
||||||
|
let name = display
|
||||||
|
.borrow_mut()
|
||||||
|
.add_socket_auto()
|
||||||
|
.unwrap()
|
||||||
|
.into_string()
|
||||||
|
.unwrap();
|
||||||
|
info!(log, "Listening on wayland socket"; "name" => name.clone());
|
||||||
|
::std::env::set_var("WAYLAND_DISPLAY", name);
|
||||||
|
|
||||||
|
#[cfg(feature = "egl")]
|
||||||
|
let egl_buffer_reader = Rc::new(RefCell::new(None));
|
||||||
|
|
||||||
|
let output_map = Rc::new(RefCell::new(Vec::new()));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize the compositor
|
||||||
|
*/
|
||||||
|
let mut state = AnvilState::init(
|
||||||
|
display.clone(),
|
||||||
|
event_loop.handle(),
|
||||||
|
#[cfg(feature = "egl")]
|
||||||
|
egl_buffer_reader.clone(),
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
log.clone(),
|
||||||
|
);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize the backend
|
||||||
|
*/
|
||||||
|
// Try to open the device
|
||||||
|
let mut options = OpenOptions::new();
|
||||||
|
options.read(true);
|
||||||
|
options.write(true);
|
||||||
|
let _backend = if let Some((mut device, gbm)) = options.open(path.as_ref())
|
||||||
|
.ok()
|
||||||
|
.and_then(|fd| {
|
||||||
|
let file = FileWrapper(fd);
|
||||||
|
match {
|
||||||
|
(
|
||||||
|
DrmDevice::new(file.clone(), true, log.clone()),
|
||||||
|
GbmDevice::new(file),
|
||||||
|
)
|
||||||
|
} {
|
||||||
|
(Ok(drm), Ok(gbm)) => Some((drm, gbm)),
|
||||||
|
(Err(err), _) => {
|
||||||
|
error!(
|
||||||
|
log,
|
||||||
|
"Aborting initializing {:?}, because of drm error: {}", path.as_ref(), err
|
||||||
|
);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
(_, Err(err)) => {
|
||||||
|
// TODO try DumbBuffer allocator in this case
|
||||||
|
error!(
|
||||||
|
log,
|
||||||
|
"Aborting initializing {:?}, because of gbm error: {}", path.as_ref(), err
|
||||||
|
);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
{
|
||||||
|
let egl = match EGLDisplay::new(&gbm, log.clone()) {
|
||||||
|
Ok(display) => display,
|
||||||
|
Err(err) => {
|
||||||
|
warn!(
|
||||||
|
log,
|
||||||
|
"Skipping device {:?}, because of egl display error: {}", path.as_ref(), err
|
||||||
|
);
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let context = match EGLContext::new(&egl, log.clone()) {
|
||||||
|
Ok(context) => context,
|
||||||
|
Err(err) => {
|
||||||
|
warn!(
|
||||||
|
log,
|
||||||
|
"Skipping device {:?}, because of egl context error: {}", path.as_ref(), err
|
||||||
|
);
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#[cfg(feature = "egl")]
|
||||||
|
{
|
||||||
|
info!(
|
||||||
|
log,
|
||||||
|
"Initializing EGL Hardware Acceleration via {:?}", path.as_ref()
|
||||||
|
);
|
||||||
|
*egl_buffer_reader.borrow_mut() = egl.bind_wl_display(&*display.borrow()).ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
let backends = Rc::new(RefCell::new(scan_connectors(
|
||||||
|
&mut device,
|
||||||
|
&gbm,
|
||||||
|
&egl,
|
||||||
|
&context,
|
||||||
|
&mut *display.borrow_mut(),
|
||||||
|
&mut *output_map.borrow_mut(),
|
||||||
|
&log,
|
||||||
|
)));
|
||||||
|
|
||||||
|
let bytes = include_bytes!("../resources/cursor2.rgba");
|
||||||
|
let pointer_image = {
|
||||||
|
let context = EGLContext::new_shared(&egl, &context, log.clone()).unwrap();
|
||||||
|
let mut renderer = unsafe { Gles2Renderer::new(context, log.clone()).unwrap() };
|
||||||
|
let image = ImageBuffer::from_raw(64, 64, bytes.to_vec()).unwrap();
|
||||||
|
renderer
|
||||||
|
.import_bitmap(&image)
|
||||||
|
.expect("Failed to load pointer")
|
||||||
|
};
|
||||||
|
|
||||||
|
// Set the handler.
|
||||||
|
// Note: if you replicate this (very simple) structure, it is rather easy
|
||||||
|
// to introduce reference cycles with Rc. Be sure about your drop order
|
||||||
|
let renderer = Rc::new(DrmRenderer {
|
||||||
|
#[cfg(feature = "egl")]
|
||||||
|
egl_buffer_reader:egl_buffer_reader.borrow().clone(),
|
||||||
|
compositor_token: state.ctoken,
|
||||||
|
backends: backends.clone(),
|
||||||
|
window_map: state.window_map.clone(),
|
||||||
|
output_map: output_map.clone(),
|
||||||
|
pointer_location: state.pointer_location.clone(),
|
||||||
|
pointer_image,
|
||||||
|
cursor_status: state.cursor_status.clone(),
|
||||||
|
dnd_icon: state.dnd_icon.clone(),
|
||||||
|
logger: log.clone(),
|
||||||
|
start_time: std::time::Instant::now(),
|
||||||
|
});
|
||||||
|
device.set_handler(DrmHandlerImpl {
|
||||||
|
renderer,
|
||||||
|
loop_handle: event_loop.handle(),
|
||||||
|
});
|
||||||
|
|
||||||
|
let event_source = device_bind(&event_loop.handle(), device)
|
||||||
|
.map_err(|e| -> IoError { e.into() })
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
trace!(log, "Backends: {:?}", backends.borrow().keys());
|
||||||
|
for renderer in backends.borrow_mut().values() {
|
||||||
|
// render first frame
|
||||||
|
trace!(log, "Scheduling frame");
|
||||||
|
schedule_initial_render(renderer.clone(), &event_loop.handle(), log.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
BackendData {
|
||||||
|
event_source,
|
||||||
|
surfaces: backends,
|
||||||
|
egl,
|
||||||
|
context,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Err(());
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* And run our loop
|
||||||
|
*/
|
||||||
|
|
||||||
|
while state.running.load(Ordering::SeqCst) {
|
||||||
|
if event_loop
|
||||||
|
.dispatch(Some(Duration::from_millis(16)), &mut state)
|
||||||
|
.is_err()
|
||||||
|
{
|
||||||
|
state.running.store(false, Ordering::SeqCst);
|
||||||
|
} else {
|
||||||
|
display.borrow_mut().flush_clients(&mut state);
|
||||||
|
state.window_map.borrow_mut().refresh();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cleanup stuff
|
||||||
|
state.window_map.borrow_mut().clear();
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn scan_connectors(
|
||||||
|
device: &mut DrmDevice<FileWrapper>,
|
||||||
|
gbm: &GbmDevice<FileWrapper>,
|
||||||
|
egl: &EGLDisplay,
|
||||||
|
context: &EGLContext,
|
||||||
|
display: &mut Display,
|
||||||
|
output_map: &mut Vec<MyOutput>,
|
||||||
|
logger: &::slog::Logger,
|
||||||
|
) -> HashMap<crtc::Handle, Rc<RefCell<RenderSurface>>> {
|
||||||
|
// Get a set of all modesetting resource handles (excluding planes):
|
||||||
|
let res_handles = device.resource_handles().unwrap();
|
||||||
|
|
||||||
|
// Use first connected connector
|
||||||
|
let connector_infos: Vec<ConnectorInfo> = res_handles
|
||||||
|
.connectors()
|
||||||
|
.iter()
|
||||||
|
.map(|conn| device.get_connector(*conn).unwrap())
|
||||||
|
.filter(|conn| conn.state() == ConnectorState::Connected)
|
||||||
|
.inspect(|conn| info!(logger, "Connected: {:?}", conn.interface()))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let mut backends = HashMap::new();
|
||||||
|
|
||||||
|
// very naive way of finding good crtc/encoder/connector combinations. This problem is np-complete
|
||||||
|
for connector_info in connector_infos {
|
||||||
|
let encoder_infos = connector_info
|
||||||
|
.encoders()
|
||||||
|
.iter()
|
||||||
|
.filter_map(|e| *e)
|
||||||
|
.flat_map(|encoder_handle| device.get_encoder(encoder_handle))
|
||||||
|
.collect::<Vec<EncoderInfo>>();
|
||||||
|
'outer: for encoder_info in encoder_infos {
|
||||||
|
for crtc in res_handles.filter_crtcs(encoder_info.possible_crtcs()) {
|
||||||
|
if let Entry::Vacant(entry) = backends.entry(crtc) {
|
||||||
|
info!(
|
||||||
|
logger,
|
||||||
|
"Trying to setup connector {:?}-{} with crtc {:?}",
|
||||||
|
connector_info.interface(),
|
||||||
|
connector_info.interface_id(),
|
||||||
|
crtc,
|
||||||
|
);
|
||||||
|
let context = match EGLContext::new_shared(egl, context, logger.clone()) {
|
||||||
|
Ok(context) => context,
|
||||||
|
Err(err) => {
|
||||||
|
warn!(logger, "Failed to create EGLContext: {}", err);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let renderer = match unsafe { Gles2Renderer::new(context, logger.clone()) } {
|
||||||
|
Ok(renderer) => renderer,
|
||||||
|
Err(err) => {
|
||||||
|
warn!(logger, "Failed to create Gles2 Renderer: {}", err);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let surface = match device.create_surface(
|
||||||
|
crtc,
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
output_map.push(MyOutput::new(
|
||||||
|
display,
|
||||||
|
device.device_id(),
|
||||||
|
crtc,
|
||||||
|
connector_info,
|
||||||
|
logger.clone(),
|
||||||
|
));
|
||||||
|
|
||||||
|
entry.insert(Rc::new(RefCell::new(renderer)));
|
||||||
|
break 'outer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
backends
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct MyOutput {
|
||||||
|
pub device_id: dev_t,
|
||||||
|
pub crtc: crtc::Handle,
|
||||||
|
pub size: (u32, u32),
|
||||||
|
_wl: Output,
|
||||||
|
global: Option<Global<wl_output::WlOutput>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MyOutput {
|
||||||
|
fn new(
|
||||||
|
display: &mut Display,
|
||||||
|
device_id: dev_t,
|
||||||
|
crtc: crtc::Handle,
|
||||||
|
conn: ConnectorInfo,
|
||||||
|
logger: ::slog::Logger,
|
||||||
|
) -> MyOutput {
|
||||||
|
let (output, global) = Output::new(
|
||||||
|
display,
|
||||||
|
format!("{:?}", conn.interface()),
|
||||||
|
PhysicalProperties {
|
||||||
|
width: conn.size().unwrap_or((0, 0)).0 as i32,
|
||||||
|
height: conn.size().unwrap_or((0, 0)).1 as i32,
|
||||||
|
subpixel: wl_output::Subpixel::Unknown,
|
||||||
|
make: "Smithay".into(),
|
||||||
|
model: "Generic DRM".into(),
|
||||||
|
},
|
||||||
|
logger,
|
||||||
|
);
|
||||||
|
|
||||||
|
let mode = conn.modes()[0];
|
||||||
|
let (w, h) = mode.size();
|
||||||
|
output.change_current_state(
|
||||||
|
Some(Mode {
|
||||||
|
width: w as i32,
|
||||||
|
height: h as i32,
|
||||||
|
refresh: (mode.vrefresh() * 1000) as i32,
|
||||||
|
}),
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
output.set_preferred(Mode {
|
||||||
|
width: w as i32,
|
||||||
|
height: h as i32,
|
||||||
|
refresh: (mode.vrefresh() * 1000) as i32,
|
||||||
|
});
|
||||||
|
|
||||||
|
MyOutput {
|
||||||
|
device_id,
|
||||||
|
crtc,
|
||||||
|
size: (w as u32, h as u32),
|
||||||
|
_wl: output,
|
||||||
|
global: Some(global),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for MyOutput {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.global.take().unwrap().destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type RenderSurface = DrmRenderSurface<FileWrapper, GbmDevice<FileWrapper>, Gles2Renderer, GbmBuffer<()>>;
|
||||||
|
|
||||||
|
struct BackendData {
|
||||||
|
surfaces: Rc<RefCell<HashMap<crtc::Handle, Rc<RefCell<RenderSurface>>>>>,
|
||||||
|
context: EGLContext,
|
||||||
|
egl: EGLDisplay,
|
||||||
|
event_source: Source<Generic<DrmDevice<FileWrapper>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct DrmHandlerImpl<Data: 'static> {
|
||||||
|
renderer: Rc<DrmRenderer>,
|
||||||
|
loop_handle: LoopHandle<Data>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Data: 'static> DeviceHandler for DrmHandlerImpl<Data> {
|
||||||
|
fn vblank(&mut self, crtc: crtc::Handle) {
|
||||||
|
self.renderer.clone().render(crtc, None, Some(&self.loop_handle))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn error(&mut self, error: DrmError) {
|
||||||
|
error!(self.renderer.logger, "{:?}", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct DrmRenderer {
|
||||||
|
#[cfg(feature = "egl")]
|
||||||
|
egl_buffer_reader: Option<EGLBufferReader>,
|
||||||
|
compositor_token: CompositorToken<Roles>,
|
||||||
|
backends: Rc<RefCell<HashMap<crtc::Handle, Rc<RefCell<RenderSurface>>>>>,
|
||||||
|
window_map: Rc<RefCell<MyWindowMap>>,
|
||||||
|
output_map: Rc<RefCell<Vec<MyOutput>>>,
|
||||||
|
pointer_location: Rc<RefCell<(f64, f64)>>,
|
||||||
|
pointer_image: Gles2Texture,
|
||||||
|
cursor_status: Arc<Mutex<CursorImageStatus>>,
|
||||||
|
dnd_icon: Arc<Mutex<Option<wl_surface::WlSurface>>>,
|
||||||
|
logger: ::slog::Logger,
|
||||||
|
start_time: std::time::Instant,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DrmRenderer {
|
||||||
|
fn render<Data: 'static>(
|
||||||
|
self: Rc<Self>,
|
||||||
|
crtc: crtc::Handle,
|
||||||
|
timer: Option<TimerHandle<(std::rc::Weak<DrmRenderer>, crtc::Handle)>>,
|
||||||
|
evt_handle: Option<&LoopHandle<Data>>,
|
||||||
|
) {
|
||||||
|
if let Some(surface) = self.backends.borrow().get(&crtc) {
|
||||||
|
let result = DrmRenderer::render_surface(
|
||||||
|
&mut *surface.borrow_mut(),
|
||||||
|
#[cfg(feature = "egl")]
|
||||||
|
self.egl_buffer_reader.as_ref(),
|
||||||
|
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),
|
||||||
|
};
|
||||||
|
|
||||||
|
if reschedule {
|
||||||
|
debug!(self.logger, "Rescheduling");
|
||||||
|
match (timer, evt_handle) {
|
||||||
|
(Some(handle), _) => {
|
||||||
|
let _ = handle.add_timeout(
|
||||||
|
Duration::from_millis(1000 /*a seconds*/ / 60 /*refresh rate*/),
|
||||||
|
(Rc::downgrade(&self), crtc),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
(None, Some(evt_handle)) => {
|
||||||
|
let timer = Timer::new().unwrap();
|
||||||
|
let handle = timer.handle();
|
||||||
|
let _ = handle.add_timeout(
|
||||||
|
Duration::from_millis(1000 /*a seconds*/ / 60 /*refresh rate*/),
|
||||||
|
(Rc::downgrade(&self), crtc),
|
||||||
|
);
|
||||||
|
evt_handle
|
||||||
|
.insert_source(timer, |(renderer, crtc), handle, _data| {
|
||||||
|
if let Some(renderer) = renderer.upgrade() {
|
||||||
|
renderer.render(
|
||||||
|
crtc,
|
||||||
|
Some(handle.clone()),
|
||||||
|
Option::<&LoopHandle<Data>>::None,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// TODO: only send drawn windows the frames callback
|
||||||
|
// Send frame events so that client start drawing their next frame
|
||||||
|
self.window_map
|
||||||
|
.borrow()
|
||||||
|
.send_frames(self.start_time.elapsed().as_millis() as u32);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
|
fn render_surface(
|
||||||
|
surface: &mut RenderSurface,
|
||||||
|
#[cfg(feature = "egl")] egl_buffer_reader: Option<&EGLBufferReader>,
|
||||||
|
crtc: crtc::Handle,
|
||||||
|
window_map: &mut MyWindowMap,
|
||||||
|
output_map: &mut Vec<MyOutput>,
|
||||||
|
compositor_token: &CompositorToken<Roles>,
|
||||||
|
pointer_location: &(f64, f64),
|
||||||
|
pointer_image: &Gles2Texture,
|
||||||
|
dnd_icon: &Option<wl_surface::WlSurface>,
|
||||||
|
cursor_status: &mut CursorImageStatus,
|
||||||
|
logger: &slog::Logger,
|
||||||
|
) -> Result<(), SwapBuffersError> {
|
||||||
|
#[cfg(not(feature = "egl"))]
|
||||||
|
let egl_buffer_reader = None;
|
||||||
|
|
||||||
|
surface.frame_submitted()?;
|
||||||
|
|
||||||
|
// get output coordinates
|
||||||
|
let (x, y) = output_map
|
||||||
|
.iter()
|
||||||
|
.take_while(|output| output.crtc != crtc)
|
||||||
|
.fold((0u32, 0u32), |pos, output| (pos.0 + output.size.0, pos.1));
|
||||||
|
let (width, height) = output_map
|
||||||
|
.iter()
|
||||||
|
.find(|output| output.crtc == crtc)
|
||||||
|
.map(|output| output.size)
|
||||||
|
.unwrap_or((0, 0)); // in this case the output will be removed.
|
||||||
|
|
||||||
|
// and draw in sync with our monitor
|
||||||
|
surface.render(|renderer, frame| -> Result<(), SwapBuffersError> {
|
||||||
|
frame.clear([0.8, 0.8, 0.9, 1.0])?;
|
||||||
|
// draw the surfaces
|
||||||
|
draw_windows(
|
||||||
|
renderer,
|
||||||
|
frame,
|
||||||
|
egl_buffer_reader,
|
||||||
|
window_map,
|
||||||
|
Some(Rectangle {
|
||||||
|
x: x as i32,
|
||||||
|
y: y as i32,
|
||||||
|
width: width as i32,
|
||||||
|
height: height as i32,
|
||||||
|
}),
|
||||||
|
*compositor_token,
|
||||||
|
logger,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
// get pointer coordinates
|
||||||
|
let (ptr_x, ptr_y) = *pointer_location;
|
||||||
|
let ptr_x = ptr_x.trunc().abs() as i32 - x as i32;
|
||||||
|
let ptr_y = ptr_y.trunc().abs() as i32 - y as i32;
|
||||||
|
|
||||||
|
// set cursor
|
||||||
|
if ptr_x >= 0 && ptr_x < width as i32 && ptr_y >= 0 && ptr_y < height as i32 {
|
||||||
|
// draw the dnd icon if applicable
|
||||||
|
{
|
||||||
|
if let Some(ref wl_surface) = dnd_icon.as_ref() {
|
||||||
|
if wl_surface.as_ref().is_alive() {
|
||||||
|
draw_dnd_icon(
|
||||||
|
renderer,
|
||||||
|
frame,
|
||||||
|
wl_surface,
|
||||||
|
egl_buffer_reader,
|
||||||
|
(ptr_x, ptr_y),
|
||||||
|
*compositor_token,
|
||||||
|
logger,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// draw the cursor as relevant
|
||||||
|
{
|
||||||
|
// reset the cursor if the surface is no longer alive
|
||||||
|
let mut reset = false;
|
||||||
|
if let CursorImageStatus::Image(ref surface) = *cursor_status {
|
||||||
|
reset = !surface.as_ref().is_alive();
|
||||||
|
}
|
||||||
|
if reset {
|
||||||
|
*cursor_status = CursorImageStatus::Default;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let CursorImageStatus::Image(ref wl_surface) = *cursor_status {
|
||||||
|
draw_cursor(
|
||||||
|
renderer,
|
||||||
|
frame,
|
||||||
|
wl_surface,
|
||||||
|
egl_buffer_reader,
|
||||||
|
(ptr_x, ptr_y),
|
||||||
|
*compositor_token,
|
||||||
|
logger,
|
||||||
|
)?;
|
||||||
|
} else {
|
||||||
|
frame.render_texture_at(pointer_image, (ptr_x, ptr_y), Transform::Normal, 1.0)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}).map_err(Into::<SwapBuffersError>::into).and_then(|x| x)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn schedule_initial_render<Data: 'static>(
|
||||||
|
renderer: Rc<RefCell<RenderSurface>>,
|
||||||
|
evt_handle: &LoopHandle<Data>,
|
||||||
|
logger: ::slog::Logger,
|
||||||
|
) {
|
||||||
|
let result = {
|
||||||
|
let mut renderer = renderer.borrow_mut();
|
||||||
|
// Does not matter if we render an empty frame
|
||||||
|
renderer
|
||||||
|
.render(|_, frame| {
|
||||||
|
frame
|
||||||
|
.clear([0.8, 0.8, 0.9, 1.0])
|
||||||
|
.map_err(Into::<SwapBuffersError>::into)
|
||||||
|
})
|
||||||
|
.map_err(Into::<SwapBuffersError>::into)
|
||||||
|
.and_then(|x| x.map_err(Into::<SwapBuffersError>::into))
|
||||||
|
};
|
||||||
|
if let Err(err) = result {
|
||||||
|
match err {
|
||||||
|
SwapBuffersError::AlreadySwapped => {}
|
||||||
|
SwapBuffersError::TemporaryFailure(err) => {
|
||||||
|
// TODO dont reschedule after 3(?) retries
|
||||||
|
warn!(logger, "Failed to submit page_flip: {}", err);
|
||||||
|
let handle = evt_handle.clone();
|
||||||
|
evt_handle.insert_idle(move |_| schedule_initial_render(renderer, &handle, logger));
|
||||||
|
}
|
||||||
|
SwapBuffersError::ContextLost(err) => panic!("Rendering loop lost: {}", err),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -767,36 +767,61 @@ impl DrmRenderer {
|
||||||
.unwrap_or((0, 0)); // in this case the output will be removed.
|
.unwrap_or((0, 0)); // in this case the output will be removed.
|
||||||
|
|
||||||
// and draw in sync with our monitor
|
// and draw in sync with our monitor
|
||||||
surface.render(|renderer, frame| {
|
surface
|
||||||
frame.clear([0.8, 0.8, 0.9, 1.0])?;
|
.render(|renderer, frame| {
|
||||||
// draw the surfaces
|
frame.clear([0.8, 0.8, 0.9, 1.0])?;
|
||||||
draw_windows(
|
// draw the surfaces
|
||||||
renderer,
|
draw_windows(
|
||||||
frame,
|
renderer,
|
||||||
egl_buffer_reader,
|
frame,
|
||||||
window_map,
|
egl_buffer_reader,
|
||||||
Some(Rectangle {
|
window_map,
|
||||||
x: x as i32,
|
Some(Rectangle {
|
||||||
y: y as i32,
|
x: x as i32,
|
||||||
width: width as i32,
|
y: y as i32,
|
||||||
height: height as i32,
|
width: width as i32,
|
||||||
}),
|
height: height as i32,
|
||||||
*compositor_token,
|
}),
|
||||||
logger,
|
*compositor_token,
|
||||||
)?;
|
logger,
|
||||||
|
)?;
|
||||||
|
|
||||||
// get pointer coordinates
|
// get pointer coordinates
|
||||||
let (ptr_x, ptr_y) = *pointer_location;
|
let (ptr_x, ptr_y) = *pointer_location;
|
||||||
let ptr_x = ptr_x.trunc().abs() as i32 - x as i32;
|
let ptr_x = ptr_x.trunc().abs() as i32 - x as i32;
|
||||||
let ptr_y = ptr_y.trunc().abs() as i32 - y as i32;
|
let ptr_y = ptr_y.trunc().abs() as i32 - y as i32;
|
||||||
|
|
||||||
// set cursor
|
// set cursor
|
||||||
if ptr_x >= 0 && ptr_x < width as i32 && ptr_y >= 0 && ptr_y < height as i32 {
|
if ptr_x >= 0 && ptr_x < width as i32 && ptr_y >= 0 && ptr_y < height as i32 {
|
||||||
// draw the dnd icon if applicable
|
// draw the dnd icon if applicable
|
||||||
{
|
{
|
||||||
if let Some(ref wl_surface) = dnd_icon.as_ref() {
|
if let Some(ref wl_surface) = dnd_icon.as_ref() {
|
||||||
if wl_surface.as_ref().is_alive() {
|
if wl_surface.as_ref().is_alive() {
|
||||||
draw_dnd_icon(
|
draw_dnd_icon(
|
||||||
|
renderer,
|
||||||
|
frame,
|
||||||
|
wl_surface,
|
||||||
|
egl_buffer_reader,
|
||||||
|
(ptr_x, ptr_y),
|
||||||
|
*compositor_token,
|
||||||
|
logger,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// draw the cursor as relevant
|
||||||
|
{
|
||||||
|
// reset the cursor if the surface is no longer alive
|
||||||
|
let mut reset = false;
|
||||||
|
if let CursorImageStatus::Image(ref surface) = *cursor_status {
|
||||||
|
reset = !surface.as_ref().is_alive();
|
||||||
|
}
|
||||||
|
if reset {
|
||||||
|
*cursor_status = CursorImageStatus::Default;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let CursorImageStatus::Image(ref wl_surface) = *cursor_status {
|
||||||
|
draw_cursor(
|
||||||
renderer,
|
renderer,
|
||||||
frame,
|
frame,
|
||||||
wl_surface,
|
wl_surface,
|
||||||
|
@ -805,40 +830,17 @@ impl DrmRenderer {
|
||||||
*compositor_token,
|
*compositor_token,
|
||||||
logger,
|
logger,
|
||||||
)?;
|
)?;
|
||||||
|
} else {
|
||||||
|
frame.render_texture_at(pointer_image, (ptr_x, ptr_y), Transform::Normal, 1.0)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// draw the cursor as relevant
|
|
||||||
{
|
|
||||||
// reset the cursor if the surface is no longer alive
|
|
||||||
let mut reset = false;
|
|
||||||
if let CursorImageStatus::Image(ref surface) = *cursor_status {
|
|
||||||
reset = !surface.as_ref().is_alive();
|
|
||||||
}
|
|
||||||
if reset {
|
|
||||||
*cursor_status = CursorImageStatus::Default;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let CursorImageStatus::Image(ref wl_surface) = *cursor_status {
|
Ok(())
|
||||||
draw_cursor(
|
})
|
||||||
renderer,
|
.map_err(Into::<SwapBuffersError>::into)
|
||||||
frame,
|
.and_then(|x| x)
|
||||||
wl_surface,
|
.map_err(Into::<SwapBuffersError>::into)
|
||||||
egl_buffer_reader,
|
|
||||||
(ptr_x, ptr_y),
|
|
||||||
*compositor_token,
|
|
||||||
logger,
|
|
||||||
)?;
|
|
||||||
} else {
|
|
||||||
frame.render_texture_at(pointer_image, (ptr_x, ptr_y), Transform::Normal, 1.0)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}).map_err(Into::<SwapBuffersError>::into)
|
|
||||||
.and_then(|x| x)
|
|
||||||
.map_err(Into::<SwapBuffersError>::into)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -871,4 +873,4 @@ fn schedule_initial_render<Data: 'static>(
|
||||||
SwapBuffersError::ContextLost(err) => panic!("Rendering loop lost: {}", err),
|
SwapBuffersError::ContextLost(err) => panic!("Rendering loop lost: {}", err),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -99,28 +99,55 @@ pub fn run_winit(
|
||||||
{
|
{
|
||||||
let mut renderer = renderer.borrow_mut();
|
let mut renderer = renderer.borrow_mut();
|
||||||
|
|
||||||
|
let result = renderer
|
||||||
|
.render(|renderer, frame| {
|
||||||
|
frame.clear([0.8, 0.8, 0.9, 1.0])?;
|
||||||
|
|
||||||
let result = renderer.render(|renderer, frame| {
|
// draw the windows
|
||||||
frame.clear([0.8, 0.8, 0.9, 1.0])?;
|
draw_windows(
|
||||||
|
renderer,
|
||||||
|
frame,
|
||||||
|
reader.as_ref(),
|
||||||
|
&*state.window_map.borrow(),
|
||||||
|
None,
|
||||||
|
state.ctoken,
|
||||||
|
&log,
|
||||||
|
)?;
|
||||||
|
|
||||||
// draw the windows
|
let (x, y) = *state.pointer_location.borrow();
|
||||||
draw_windows(
|
// draw the dnd icon if any
|
||||||
renderer,
|
{
|
||||||
frame,
|
let guard = state.dnd_icon.lock().unwrap();
|
||||||
reader.as_ref(),
|
if let Some(ref surface) = *guard {
|
||||||
&*state.window_map.borrow(),
|
if surface.as_ref().is_alive() {
|
||||||
None,
|
draw_dnd_icon(
|
||||||
state.ctoken,
|
renderer,
|
||||||
&log,
|
frame,
|
||||||
)?;
|
surface,
|
||||||
|
reader.as_ref(),
|
||||||
|
(x as i32, y as i32),
|
||||||
|
state.ctoken,
|
||||||
|
&log,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// draw the cursor as relevant
|
||||||
|
{
|
||||||
|
let mut guard = state.cursor_status.lock().unwrap();
|
||||||
|
// reset the cursor if the surface is no longer alive
|
||||||
|
let mut reset = false;
|
||||||
|
if let CursorImageStatus::Image(ref surface) = *guard {
|
||||||
|
reset = !surface.as_ref().is_alive();
|
||||||
|
}
|
||||||
|
if reset {
|
||||||
|
*guard = CursorImageStatus::Default;
|
||||||
|
}
|
||||||
|
|
||||||
let (x, y) = *state.pointer_location.borrow();
|
// draw as relevant
|
||||||
// draw the dnd icon if any
|
if let CursorImageStatus::Image(ref surface) = *guard {
|
||||||
{
|
cursor_visible = false;
|
||||||
let guard = state.dnd_icon.lock().unwrap();
|
draw_cursor(
|
||||||
if let Some(ref surface) = *guard {
|
|
||||||
if surface.as_ref().is_alive() {
|
|
||||||
draw_dnd_icon(
|
|
||||||
renderer,
|
renderer,
|
||||||
frame,
|
frame,
|
||||||
surface,
|
surface,
|
||||||
|
@ -129,42 +156,16 @@ pub fn run_winit(
|
||||||
state.ctoken,
|
state.ctoken,
|
||||||
&log,
|
&log,
|
||||||
)?;
|
)?;
|
||||||
|
} else {
|
||||||
|
cursor_visible = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
// draw the cursor as relevant
|
|
||||||
{
|
|
||||||
let mut guard = state.cursor_status.lock().unwrap();
|
|
||||||
// reset the cursor if the surface is no longer alive
|
|
||||||
let mut reset = false;
|
|
||||||
if let CursorImageStatus::Image(ref surface) = *guard {
|
|
||||||
reset = !surface.as_ref().is_alive();
|
|
||||||
}
|
|
||||||
if reset {
|
|
||||||
*guard = CursorImageStatus::Default;
|
|
||||||
}
|
|
||||||
|
|
||||||
// draw as relevant
|
Ok(())
|
||||||
if let CursorImageStatus::Image(ref surface) = *guard {
|
})
|
||||||
cursor_visible = false;
|
.map_err(Into::<SwapBuffersError>::into)
|
||||||
draw_cursor(
|
.and_then(|x| x.into());
|
||||||
renderer,
|
|
||||||
frame,
|
|
||||||
surface,
|
|
||||||
reader.as_ref(),
|
|
||||||
(x as i32, y as i32),
|
|
||||||
state.ctoken,
|
|
||||||
&log,
|
|
||||||
)?;
|
|
||||||
} else {
|
|
||||||
cursor_visible = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}).map_err(Into::<SwapBuffersError>::into)
|
|
||||||
.and_then(|x| x.into());
|
|
||||||
|
|
||||||
renderer.window().set_cursor_visible(cursor_visible);
|
renderer.window().set_cursor_visible(cursor_visible);
|
||||||
|
|
||||||
if let Err(SwapBuffersError::ContextLost(err)) = result {
|
if let Err(SwapBuffersError::ContextLost(err)) = result {
|
||||||
|
|
|
@ -122,7 +122,9 @@ fn main() {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// Start rendering
|
// Start rendering
|
||||||
surface.commit([(framebuffer, surface.plane())].iter(), true).unwrap();
|
surface
|
||||||
|
.commit([(framebuffer, surface.plane())].iter(), true)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
// Run
|
// Run
|
||||||
event_loop.run(None, &mut (), |_| {}).unwrap();
|
event_loop.run(None, &mut (), |_| {}).unwrap();
|
||||||
|
@ -158,7 +160,9 @@ impl DeviceHandler for DrmHandlerImpl {
|
||||||
}
|
}
|
||||||
|
|
||||||
let fb = self.current.userdata().unwrap();
|
let fb = self.current.userdata().unwrap();
|
||||||
self.surface.page_flip([(fb, self.surface.plane())].iter(), true).unwrap();
|
self.surface
|
||||||
|
.page_flip([(fb, self.surface.plane())].iter(), true)
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn error(&mut self, error: DrmError) {
|
fn error(&mut self, error: DrmError) {
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
//! Module for [dmabuf](https://01.org/linuxgraphics/gfx-docs/drm/driver-api/dma-buf.html) buffers.
|
//! Module for [dmabuf](https://01.org/linuxgraphics/gfx-docs/drm/driver-api/dma-buf.html) buffers.
|
||||||
//!
|
//!
|
||||||
//! `Dmabuf`s act alike to smart pointers and can be freely cloned and passed around.
|
//! `Dmabuf`s act alike to smart pointers and can be freely cloned and passed around.
|
||||||
//! Once the last `Dmabuf` reference is dropped, its file descriptor is closed and
|
//! Once the last `Dmabuf` reference is dropped, its file descriptor is closed and
|
||||||
//! underlying resources are freed.
|
//! underlying resources are freed.
|
||||||
//!
|
//!
|
||||||
//! If you want to hold on to a potentially alive dmabuf without blocking the free up
|
//! If you want to hold on to a potentially alive dmabuf without blocking the free up
|
||||||
//! of the underlying resouces, you may `downgrade` a `Dmabuf` reference to a `WeakDmabuf`.
|
//! of the underlying resouces, you may `downgrade` a `Dmabuf` reference to a `WeakDmabuf`.
|
||||||
//!
|
//!
|
||||||
//! This can be especially useful in resources where other parts of the stack should decide upon
|
//! This can be especially useful in resources where other parts of the stack should decide upon
|
||||||
//! the lifetime of the buffer. E.g. when you are only caching associated resources for a dmabuf.
|
//! the lifetime of the buffer. E.g. when you are only caching associated resources for a dmabuf.
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
//! Module for Buffers created using [libgbm](gbm).
|
//! Module for Buffers created using [libgbm](gbm).
|
||||||
//!
|
//!
|
||||||
//! The re-exported [`GbmDevice`](gbm::Device) implements the [`Allocator`](super::Allocator) trait
|
//! The re-exported [`GbmDevice`](gbm::Device) implements the [`Allocator`](super::Allocator) trait
|
||||||
//! and [`GbmBuffer`](gbm::BufferObject) satisfies the [`Buffer`](super::Buffer) trait while also allowing
|
//! and [`GbmBuffer`](gbm::BufferObject) satisfies the [`Buffer`](super::Buffer) trait while also allowing
|
||||||
//! conversions to and from [dmabufs](super::dmabuf).
|
//! conversions to and from [dmabufs](super::dmabuf).
|
||||||
|
|
|
@ -111,9 +111,14 @@ where
|
||||||
/// The swapchain has an internal maximum of four re-usable buffers.
|
/// The swapchain has an internal maximum of four re-usable buffers.
|
||||||
/// This function returns the first free one.
|
/// This function returns the first free one.
|
||||||
pub fn acquire(&mut self) -> Result<Option<Slot<B, U>>, A::Error> {
|
pub fn acquire(&mut self) -> Result<Option<Slot<B, U>>, A::Error> {
|
||||||
if let Some(free_slot) = self.slots.iter_mut().find(|s| !s.acquired.swap(true, Ordering::SeqCst)) {
|
if let Some(free_slot) = self
|
||||||
|
.slots
|
||||||
|
.iter_mut()
|
||||||
|
.find(|s| !s.acquired.swap(true, Ordering::SeqCst))
|
||||||
|
{
|
||||||
if free_slot.buffer.is_none() {
|
if free_slot.buffer.is_none() {
|
||||||
let mut free_slot = Arc::get_mut(free_slot).expect("Acquired was false, but Arc is not unique?");
|
let mut free_slot =
|
||||||
|
Arc::get_mut(free_slot).expect("Acquired was false, but Arc is not unique?");
|
||||||
free_slot.buffer = Some(self.allocator.create_buffer(
|
free_slot.buffer = Some(self.allocator.create_buffer(
|
||||||
self.width,
|
self.width,
|
||||||
self.height,
|
self.height,
|
||||||
|
|
|
@ -90,7 +90,9 @@ impl<A: AsRawFd + 'static> LegacyDrmDevice<A> {
|
||||||
|
|
||||||
for crtc in res_handles.crtcs() {
|
for crtc in res_handles.crtcs() {
|
||||||
#[allow(deprecated)]
|
#[allow(deprecated)]
|
||||||
let _ = self.fd.set_cursor(*crtc, Option::<&drm::control::dumbbuffer::DumbBuffer>::None);
|
let _ = self
|
||||||
|
.fd
|
||||||
|
.set_cursor(*crtc, Option::<&drm::control::dumbbuffer::DumbBuffer>::None);
|
||||||
// null commit (necessary to trigger removal on the kernel side with the legacy api.)
|
// null commit (necessary to trigger removal on the kernel side with the legacy api.)
|
||||||
self.fd
|
self.fd
|
||||||
.set_crtc(*crtc, None, (0, 0), &[], None)
|
.set_crtc(*crtc, None, (0, 0), &[], None)
|
||||||
|
|
|
@ -5,18 +5,15 @@ use std::rc::Rc;
|
||||||
use std::sync::{atomic::AtomicBool, Arc};
|
use std::sync::{atomic::AtomicBool, Arc};
|
||||||
|
|
||||||
use calloop::{generic::Generic, InsertError, LoopHandle, Source};
|
use calloop::{generic::Generic, InsertError, LoopHandle, Source};
|
||||||
use drm::control::{
|
use drm::control::{connector, crtc, Device as ControlDevice, Event, Mode, ResourceHandles};
|
||||||
connector, crtc, Device as ControlDevice, Event, Mode,
|
|
||||||
ResourceHandles,
|
|
||||||
};
|
|
||||||
use drm::{ClientCapability, Device as BasicDevice};
|
use drm::{ClientCapability, Device as BasicDevice};
|
||||||
use nix::libc::dev_t;
|
use nix::libc::dev_t;
|
||||||
use nix::sys::stat::fstat;
|
use nix::sys::stat::fstat;
|
||||||
|
|
||||||
pub(super) mod atomic;
|
pub(super) mod atomic;
|
||||||
pub(super) mod legacy;
|
pub(super) mod legacy;
|
||||||
use super::{error::Error, Planes, planes};
|
|
||||||
use super::surface::{atomic::AtomicDrmSurface, legacy::LegacyDrmSurface, DrmSurface, DrmSurfaceInternal};
|
use super::surface::{atomic::AtomicDrmSurface, legacy::LegacyDrmSurface, DrmSurface, DrmSurfaceInternal};
|
||||||
|
use super::{error::Error, planes, Planes};
|
||||||
use atomic::AtomicDrmDevice;
|
use atomic::AtomicDrmDevice;
|
||||||
use legacy::LegacyDrmDevice;
|
use legacy::LegacyDrmDevice;
|
||||||
|
|
||||||
|
@ -337,8 +334,6 @@ impl<A: AsRawFd + 'static> DrmDevice<A> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// Trait to receive events of a bound [`DrmDevice`]
|
/// Trait to receive events of a bound [`DrmDevice`]
|
||||||
///
|
///
|
||||||
/// See [`device_bind`]
|
/// See [`device_bind`]
|
||||||
|
|
|
@ -74,7 +74,7 @@ pub use error::Error as DrmError;
|
||||||
pub use render::{DrmRenderSurface, Error as DrmRenderError};
|
pub use render::{DrmRenderSurface, Error as DrmRenderError};
|
||||||
pub use surface::DrmSurface;
|
pub use surface::DrmSurface;
|
||||||
|
|
||||||
use drm::control::{plane, crtc, Device as ControlDevice, PlaneType};
|
use drm::control::{crtc, plane, Device as ControlDevice, PlaneType};
|
||||||
|
|
||||||
/// A set of planes as supported by a crtc
|
/// A set of planes as supported by a crtc
|
||||||
pub struct Planes {
|
pub struct Planes {
|
||||||
|
@ -86,11 +86,15 @@ pub struct Planes {
|
||||||
pub overlay: Vec<plane::Handle>,
|
pub overlay: Vec<plane::Handle>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn planes(dev: &impl ControlDevice, crtc: &crtc::Handle, has_universal_planes: bool) -> Result<Planes, DrmError> {
|
fn planes(
|
||||||
|
dev: &impl ControlDevice,
|
||||||
|
crtc: &crtc::Handle,
|
||||||
|
has_universal_planes: bool,
|
||||||
|
) -> Result<Planes, DrmError> {
|
||||||
let mut primary = None;
|
let mut primary = None;
|
||||||
let mut cursor = None;
|
let mut cursor = None;
|
||||||
let mut overlay = Vec::new();
|
let mut overlay = Vec::new();
|
||||||
|
|
||||||
let planes = dev.plane_handles().map_err(|source| DrmError::Access {
|
let planes = dev.plane_handles().map_err(|source| DrmError::Access {
|
||||||
errmsg: "Error loading plane handles",
|
errmsg: "Error loading plane handles",
|
||||||
dev: dev.dev_path(),
|
dev: dev.dev_path(),
|
||||||
|
@ -101,7 +105,7 @@ fn planes(dev: &impl ControlDevice, crtc: &crtc::Handle, has_universal_planes: b
|
||||||
errmsg: "Error loading resource handles",
|
errmsg: "Error loading resource handles",
|
||||||
dev: dev.dev_path(),
|
dev: dev.dev_path(),
|
||||||
source,
|
source,
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
for plane in planes.planes() {
|
for plane in planes.planes() {
|
||||||
let info = dev.get_plane(*plane).map_err(|source| DrmError::Access {
|
let info = dev.get_plane(*plane).map_err(|source| DrmError::Access {
|
||||||
|
@ -127,16 +131,8 @@ fn planes(dev: &impl ControlDevice, crtc: &crtc::Handle, has_universal_planes: b
|
||||||
|
|
||||||
Ok(Planes {
|
Ok(Planes {
|
||||||
primary: primary.expect("Crtc has no primary plane"),
|
primary: primary.expect("Crtc has no primary plane"),
|
||||||
cursor: if has_universal_planes {
|
cursor: if has_universal_planes { cursor } else { None },
|
||||||
cursor
|
overlay: if has_universal_planes { overlay } else { Vec::new() },
|
||||||
} else {
|
|
||||||
None
|
|
||||||
},
|
|
||||||
overlay: if has_universal_planes {
|
|
||||||
overlay
|
|
||||||
} else {
|
|
||||||
Vec::new()
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -162,4 +158,4 @@ fn plane_type(dev: &impl ControlDevice, plane: plane::Handle) -> Result<PlaneTyp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,14 +7,12 @@ use drm::control::{connector, crtc, framebuffer, plane, Device, Mode};
|
||||||
use gbm::{BufferObject, BufferObjectFlags, Device as GbmDevice};
|
use gbm::{BufferObject, BufferObjectFlags, Device as GbmDevice};
|
||||||
|
|
||||||
use super::{device::DevPath, surface::DrmSurfaceInternal, DrmError, DrmSurface};
|
use super::{device::DevPath, surface::DrmSurfaceInternal, DrmError, DrmSurface};
|
||||||
|
use crate::backend::allocator::{
|
||||||
|
dmabuf::{AsDmabuf, Dmabuf},
|
||||||
|
Allocator, Buffer, Format, Fourcc, Modifier, Slot, Swapchain,
|
||||||
|
};
|
||||||
use crate::backend::renderer::{Bind, Frame, Renderer, Texture, Transform};
|
use crate::backend::renderer::{Bind, Frame, Renderer, Texture, Transform};
|
||||||
use crate::backend::SwapBuffersError;
|
use crate::backend::SwapBuffersError;
|
||||||
use crate::backend::{
|
|
||||||
allocator::{
|
|
||||||
dmabuf::{AsDmabuf, Dmabuf},
|
|
||||||
Allocator, Buffer, Format, Fourcc, Modifier, Slot, Swapchain,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Simplified by limited abstraction to link single [`DrmSurface`]s to renderers.
|
/// Simplified by limited abstraction to link single [`DrmSurface`]s to renderers.
|
||||||
///
|
///
|
||||||
|
@ -161,9 +159,12 @@ where
|
||||||
.map_err(Error::<E1, E2, E3>::RenderError)
|
.map_err(Error::<E1, E2, E3>::RenderError)
|
||||||
.and_then(|_| {
|
.and_then(|_| {
|
||||||
renderer
|
renderer
|
||||||
.render(mode.size().0 as u32, mode.size().1 as u32, Transform::Normal, |_, frame| {
|
.render(
|
||||||
frame.clear([0.0, 0.0, 0.0, 1.0])
|
mode.size().0 as u32,
|
||||||
})
|
mode.size().1 as u32,
|
||||||
|
Transform::Normal,
|
||||||
|
|_, frame| frame.clear([0.0, 0.0, 0.0, 1.0]),
|
||||||
|
)
|
||||||
.map_err(Error::RenderError)
|
.map_err(Error::RenderError)
|
||||||
})
|
})
|
||||||
.and_then(|_| renderer.unbind().map_err(Error::RenderError))
|
.and_then(|_| renderer.unbind().map_err(Error::RenderError))
|
||||||
|
@ -217,7 +218,7 @@ where
|
||||||
/// and this surface set a the rendering target.
|
/// and this surface set a the rendering target.
|
||||||
pub fn render<F, S>(&mut self, rendering: F) -> Result<S, Error<E1, E2, E3>>
|
pub fn render<F, S>(&mut self, rendering: F) -> Result<S, Error<E1, E2, E3>>
|
||||||
where
|
where
|
||||||
F: FnOnce(&mut R, &mut <R as Renderer>::Frame) -> S
|
F: FnOnce(&mut R, &mut <R as Renderer>::Frame) -> S,
|
||||||
{
|
{
|
||||||
let mode = self.drm.pending_mode();
|
let mode = self.drm.pending_mode();
|
||||||
let (width, height) = (mode.size().0 as u32, mode.size().1 as u32);
|
let (width, height) = (mode.size().0 as u32, mode.size().1 as u32);
|
||||||
|
@ -239,7 +240,7 @@ where
|
||||||
rendering,
|
rendering,
|
||||||
)
|
)
|
||||||
.map_err(Error::RenderError)?;
|
.map_err(Error::RenderError)?;
|
||||||
|
|
||||||
match self.buffers.queue::<E1, E2, E3>(slot, dmabuf) {
|
match self.buffers.queue::<E1, E2, E3>(slot, dmabuf) {
|
||||||
Ok(()) => {}
|
Ok(()) => {}
|
||||||
Err(Error::DrmError(drm)) => return Err(drm.into()),
|
Err(Error::DrmError(drm)) => return Err(drm.into()),
|
||||||
|
|
|
@ -379,8 +379,13 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn use_plane(&self, plane: plane::Handle, position: (i32, i32), size: (u32, u32)) -> Result<(), Error> {
|
pub fn use_plane(
|
||||||
|
&self,
|
||||||
|
plane: plane::Handle,
|
||||||
|
position: (i32, i32),
|
||||||
|
size: (u32, u32),
|
||||||
|
) -> Result<(), Error> {
|
||||||
let info = PlaneInfo {
|
let info = PlaneInfo {
|
||||||
handle: plane,
|
handle: plane,
|
||||||
x: position.0,
|
x: position.0,
|
||||||
|
@ -399,20 +404,26 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
|
||||||
&mut [].iter(),
|
&mut [].iter(),
|
||||||
self.plane,
|
self.plane,
|
||||||
&new_planes,
|
&new_planes,
|
||||||
Some([(self.create_test_buffer(pending.mode.size())?, self.plane)]
|
Some(
|
||||||
.iter()
|
[(self.create_test_buffer(pending.mode.size())?, self.plane)]
|
||||||
.chain(new_planes.iter().map(|info| {
|
.iter()
|
||||||
match self.create_test_buffer((info.w as u16, info.h as u16)) {
|
.chain(
|
||||||
Ok(test_buff) => Ok((test_buff, info.handle)),
|
new_planes
|
||||||
Err(err) => Err(err),
|
.iter()
|
||||||
}
|
.map(
|
||||||
}).collect::<Result<Vec<_>, _>>()?.iter())
|
|info| match self.create_test_buffer((info.w as u16, info.h as u16)) {
|
||||||
|
Ok(test_buff) => Ok((test_buff, info.handle)),
|
||||||
|
Err(err) => Err(err),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.collect::<Result<Vec<_>, _>>()?
|
||||||
|
.iter(),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
Some(pending.mode),
|
Some(pending.mode),
|
||||||
Some(pending.blob),
|
Some(pending.blob),
|
||||||
)?;
|
)?;
|
||||||
self
|
self.fd
|
||||||
.fd
|
|
||||||
.atomic_commit(
|
.atomic_commit(
|
||||||
&[AtomicCommitFlags::AllowModeset, AtomicCommitFlags::TestOnly],
|
&[AtomicCommitFlags::AllowModeset, AtomicCommitFlags::TestOnly],
|
||||||
req,
|
req,
|
||||||
|
@ -428,7 +439,11 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
|
||||||
*self.pending.read().unwrap() != *self.state.read().unwrap()
|
*self.pending.read().unwrap() != *self.state.read().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn commit<'a>(&self, framebuffers: impl Iterator<Item=&'a (framebuffer::Handle, plane::Handle)>, event: bool) -> Result<(), Error> {
|
pub fn commit<'a>(
|
||||||
|
&self,
|
||||||
|
framebuffers: impl Iterator<Item = &'a (framebuffer::Handle, plane::Handle)>,
|
||||||
|
event: bool,
|
||||||
|
) -> Result<(), Error> {
|
||||||
if !self.active.load(Ordering::SeqCst) {
|
if !self.active.load(Ordering::SeqCst) {
|
||||||
return Err(Error::DeviceInactive);
|
return Err(Error::DeviceInactive);
|
||||||
}
|
}
|
||||||
|
@ -538,7 +553,11 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn page_flip<'a>(&self, framebuffers: impl Iterator<Item=&'a (framebuffer::Handle, plane::Handle)>, event: bool) -> Result<(), Error> {
|
pub fn page_flip<'a>(
|
||||||
|
&self,
|
||||||
|
framebuffers: impl Iterator<Item = &'a (framebuffer::Handle, plane::Handle)>,
|
||||||
|
event: bool,
|
||||||
|
) -> Result<(), Error> {
|
||||||
if !self.active.load(Ordering::SeqCst) {
|
if !self.active.load(Ordering::SeqCst) {
|
||||||
return Err(Error::DeviceInactive);
|
return Err(Error::DeviceInactive);
|
||||||
}
|
}
|
||||||
|
@ -618,7 +637,13 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn test_plane_buffer(&self, fb: framebuffer::Handle, plane: plane::Handle, position: (i32, i32), size: (u32, u32)) -> Result<bool, Error> {
|
pub fn test_plane_buffer(
|
||||||
|
&self,
|
||||||
|
fb: framebuffer::Handle,
|
||||||
|
plane: plane::Handle,
|
||||||
|
position: (i32, i32),
|
||||||
|
size: (u32, u32),
|
||||||
|
) -> Result<bool, Error> {
|
||||||
if !self.active.load(Ordering::SeqCst) {
|
if !self.active.load(Ordering::SeqCst) {
|
||||||
return Err(Error::DeviceInactive);
|
return Err(Error::DeviceInactive);
|
||||||
}
|
}
|
||||||
|
@ -726,7 +751,7 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
|
||||||
removed_connectors: &mut dyn Iterator<Item = &connector::Handle>,
|
removed_connectors: &mut dyn Iterator<Item = &connector::Handle>,
|
||||||
primary: plane::Handle,
|
primary: plane::Handle,
|
||||||
planes: &[PlaneInfo],
|
planes: &[PlaneInfo],
|
||||||
framebuffers: Option<impl Iterator<Item=&'a (framebuffer::Handle, plane::Handle)>>,
|
framebuffers: Option<impl Iterator<Item = &'a (framebuffer::Handle, plane::Handle)>>,
|
||||||
mode: Option<Mode>,
|
mode: Option<Mode>,
|
||||||
blob: Option<property::Value<'static>>,
|
blob: Option<property::Value<'static>>,
|
||||||
) -> Result<AtomicModeReq, Error> {
|
) -> Result<AtomicModeReq, Error> {
|
||||||
|
@ -832,7 +857,7 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
|
||||||
property::Value::UnsignedRange(mode.size().1 as u64),
|
property::Value::UnsignedRange(mode.size().1 as u64),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// and finally the others
|
// and finally the others
|
||||||
for plane_info in planes {
|
for plane_info in planes {
|
||||||
req.add_property(
|
req.add_property(
|
||||||
|
@ -901,7 +926,8 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
|
||||||
property::Value::Framebuffer(None),
|
property::Value::Framebuffer(None),
|
||||||
);
|
);
|
||||||
|
|
||||||
let result = self.fd
|
let result = self
|
||||||
|
.fd
|
||||||
.atomic_commit(&[AtomicCommitFlags::Nonblock], req)
|
.atomic_commit(&[AtomicCommitFlags::Nonblock], req)
|
||||||
.map_err(|source| Error::Access {
|
.map_err(|source| Error::Access {
|
||||||
errmsg: "Failed to commit on clear_plane",
|
errmsg: "Failed to commit on clear_plane",
|
||||||
|
@ -910,7 +936,10 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
|
||||||
});
|
});
|
||||||
|
|
||||||
if result.is_ok() {
|
if result.is_ok() {
|
||||||
self.additional_planes.lock().unwrap().retain(|info| info.handle != plane);
|
self.additional_planes
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.retain(|info| info.handle != plane);
|
||||||
}
|
}
|
||||||
|
|
||||||
result
|
result
|
||||||
|
@ -947,11 +976,17 @@ impl<A: AsRawFd + 'static> Drop for AtomicDrmSurface<A> {
|
||||||
// other ttys that use no cursor, might not clear it themselves.
|
// other ttys that use no cursor, might not clear it themselves.
|
||||||
// This makes sure our cursor won't stay visible.
|
// This makes sure our cursor won't stay visible.
|
||||||
if let Err(err) = self.clear_plane(self.plane) {
|
if let Err(err) = self.clear_plane(self.plane) {
|
||||||
warn!(self.logger, "Failed to clear plane {:?} on {:?}: {}", self.plane, self.crtc, err);
|
warn!(
|
||||||
|
self.logger,
|
||||||
|
"Failed to clear plane {:?} on {:?}: {}", self.plane, self.crtc, err
|
||||||
|
);
|
||||||
}
|
}
|
||||||
for plane_info in self.additional_planes.lock().unwrap().iter() {
|
for plane_info in self.additional_planes.lock().unwrap().iter() {
|
||||||
if let Err(err) = self.clear_plane(plane_info.handle) {
|
if let Err(err) = self.clear_plane(plane_info.handle) {
|
||||||
warn!(self.logger, "Failed to clear plane {:?} on {:?}: {}", plane_info.handle, self.crtc, err);
|
warn!(
|
||||||
|
self.logger,
|
||||||
|
"Failed to clear plane {:?} on {:?}: {}", plane_info.handle, self.crtc, err
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,12 +11,7 @@ use nix::libc::dev_t;
|
||||||
|
|
||||||
pub(super) mod atomic;
|
pub(super) mod atomic;
|
||||||
pub(super) mod legacy;
|
pub(super) mod legacy;
|
||||||
use super::{
|
use super::{device::DevPath, error::Error, plane_type, planes, PlaneType, Planes};
|
||||||
error::Error,
|
|
||||||
Planes, PlaneType,
|
|
||||||
plane_type, planes,
|
|
||||||
device::DevPath,
|
|
||||||
};
|
|
||||||
use crate::backend::allocator::{Format, Fourcc, Modifier};
|
use crate::backend::allocator::{Format, Fourcc, Modifier};
|
||||||
use atomic::AtomicDrmSurface;
|
use atomic::AtomicDrmSurface;
|
||||||
use legacy::LegacyDrmSurface;
|
use legacy::LegacyDrmSurface;
|
||||||
|
@ -150,16 +145,21 @@ impl<A: AsRawFd + 'static> DrmSurface<A> {
|
||||||
|
|
||||||
/// Tries to setup a cursor or overlay [`Plane`](drm::control::plane)
|
/// Tries to setup a cursor or overlay [`Plane`](drm::control::plane)
|
||||||
/// to be set at the next commit/page_flip with the given position and size.
|
/// to be set at the next commit/page_flip with the given position and size.
|
||||||
///
|
///
|
||||||
/// Planes can have arbitrary hardware constraints, that cannot be expressed in the api,
|
/// Planes can have arbitrary hardware constraints, that cannot be expressed in the api,
|
||||||
/// like supporting only positions at even or odd values, allowing only certain sizes or disallowing overlapping planes.
|
/// like supporting only positions at even or odd values, allowing only certain sizes or disallowing overlapping planes.
|
||||||
/// Using planes should therefor be done in a best-efford manner. Failures on `page_flip` or `commit`
|
/// Using planes should therefor be done in a best-efford manner. Failures on `page_flip` or `commit`
|
||||||
/// should be expected and alternative code paths without the usage of planes prepared.
|
/// should be expected and alternative code paths without the usage of planes prepared.
|
||||||
///
|
///
|
||||||
/// Fails if tests for the given plane fail, if the underlying
|
/// Fails if tests for the given plane fail, if the underlying
|
||||||
/// implementation does not support the use of planes or if the plane
|
/// implementation does not support the use of planes or if the plane
|
||||||
/// is not supported by this crtc.
|
/// is not supported by this crtc.
|
||||||
pub fn use_plane(&self, plane: plane::Handle, position: (i32, i32), size: (u32, u32)) -> Result<(), Error> {
|
pub fn use_plane(
|
||||||
|
&self,
|
||||||
|
plane: plane::Handle,
|
||||||
|
position: (i32, i32),
|
||||||
|
size: (u32, u32),
|
||||||
|
) -> Result<(), Error> {
|
||||||
match &*self.internal {
|
match &*self.internal {
|
||||||
DrmSurfaceInternal::Atomic(surf) => surf.use_plane(plane, position, size),
|
DrmSurfaceInternal::Atomic(surf) => surf.use_plane(plane, position, size),
|
||||||
DrmSurfaceInternal::Legacy(_) => Err(Error::NonPrimaryPlane(plane)),
|
DrmSurfaceInternal::Legacy(_) => Err(Error::NonPrimaryPlane(plane)),
|
||||||
|
@ -167,7 +167,7 @@ impl<A: AsRawFd + 'static> DrmSurface<A> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Disables the given plane.
|
/// Disables the given plane.
|
||||||
///
|
///
|
||||||
/// Errors if the plane is not supported by this crtc or if the underlying
|
/// Errors if the plane is not supported by this crtc or if the underlying
|
||||||
/// implementation does not support the use of planes.
|
/// implementation does not support the use of planes.
|
||||||
pub fn clear_plane(&self, plane: plane::Handle) -> Result<(), Error> {
|
pub fn clear_plane(&self, plane: plane::Handle) -> Result<(), Error> {
|
||||||
|
@ -200,17 +200,23 @@ impl<A: AsRawFd + 'static> DrmSurface<A> {
|
||||||
/// but will trigger a `vblank` event once done.
|
/// but will trigger a `vblank` event once done.
|
||||||
/// Make sure to [set a `DeviceHandler`](crate::backend::drm::DrmDevice::set_handler) and
|
/// Make sure to [set a `DeviceHandler`](crate::backend::drm::DrmDevice::set_handler) and
|
||||||
/// [register the belonging `Device`](crate::backend::drm::device_bind) before to receive the event in time.
|
/// [register the belonging `Device`](crate::backend::drm::device_bind) before to receive the event in time.
|
||||||
pub fn commit<'a>(&self, mut framebuffers: impl Iterator<Item=&'a (framebuffer::Handle, plane::Handle)>, event: bool) -> Result<(), Error> {
|
pub fn commit<'a>(
|
||||||
|
&self,
|
||||||
|
mut framebuffers: impl Iterator<Item = &'a (framebuffer::Handle, plane::Handle)>,
|
||||||
|
event: bool,
|
||||||
|
) -> Result<(), Error> {
|
||||||
match &*self.internal {
|
match &*self.internal {
|
||||||
DrmSurfaceInternal::Atomic(surf) => surf.commit(framebuffers, event),
|
DrmSurfaceInternal::Atomic(surf) => surf.commit(framebuffers, event),
|
||||||
DrmSurfaceInternal::Legacy(surf) => if let Some((fb, plane)) = framebuffers.next() {
|
DrmSurfaceInternal::Legacy(surf) => {
|
||||||
if plane_type(self, *plane)? != PlaneType::Primary {
|
if let Some((fb, plane)) = framebuffers.next() {
|
||||||
return Err(Error::NonPrimaryPlane(*plane));
|
if plane_type(self, *plane)? != PlaneType::Primary {
|
||||||
|
return Err(Error::NonPrimaryPlane(*plane));
|
||||||
|
}
|
||||||
|
surf.commit(*fb, event)
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
surf.commit(*fb, event)
|
}
|
||||||
} else {
|
|
||||||
Ok(())
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -222,17 +228,23 @@ impl<A: AsRawFd + 'static> DrmSurface<A> {
|
||||||
/// This operation is not blocking and will produce a `vblank` event once swapping is done.
|
/// This operation is not blocking and will produce a `vblank` event once swapping is done.
|
||||||
/// Make sure to [set a `DeviceHandler`](crate::backend::drm::DrmDevice::set_handler) and
|
/// Make sure to [set a `DeviceHandler`](crate::backend::drm::DrmDevice::set_handler) and
|
||||||
/// [register the belonging `DrmDevice`](crate::backend::drm::device_bind) before to receive the event in time.
|
/// [register the belonging `DrmDevice`](crate::backend::drm::device_bind) before to receive the event in time.
|
||||||
pub fn page_flip<'a>(&self, mut framebuffers: impl Iterator<Item=&'a (framebuffer::Handle, plane::Handle)>, event: bool) -> Result<(), Error> {
|
pub fn page_flip<'a>(
|
||||||
|
&self,
|
||||||
|
mut framebuffers: impl Iterator<Item = &'a (framebuffer::Handle, plane::Handle)>,
|
||||||
|
event: bool,
|
||||||
|
) -> Result<(), Error> {
|
||||||
match &*self.internal {
|
match &*self.internal {
|
||||||
DrmSurfaceInternal::Atomic(surf) => surf.page_flip(framebuffers, event),
|
DrmSurfaceInternal::Atomic(surf) => surf.page_flip(framebuffers, event),
|
||||||
DrmSurfaceInternal::Legacy(surf) => if let Some((fb, plane)) = framebuffers.next() {
|
DrmSurfaceInternal::Legacy(surf) => {
|
||||||
if plane_type(self, *plane)? != PlaneType::Primary {
|
if let Some((fb, plane)) = framebuffers.next() {
|
||||||
return Err(Error::NonPrimaryPlane(*plane));
|
if plane_type(self, *plane)? != PlaneType::Primary {
|
||||||
|
return Err(Error::NonPrimaryPlane(*plane));
|
||||||
|
}
|
||||||
|
surf.page_flip(*fb, event)
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
surf.page_flip(*fb, event)
|
}
|
||||||
} else {
|
|
||||||
Ok(())
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -394,7 +406,7 @@ impl<A: AsRawFd + 'static> DrmSurface<A> {
|
||||||
} // There is no test-commiting with the legacy interface
|
} // There is no test-commiting with the legacy interface
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tests is a framebuffer can be used with this surface and a given plane.
|
/// Tests is a framebuffer can be used with this surface and a given plane.
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
|
@ -404,7 +416,7 @@ impl<A: AsRawFd + 'static> DrmSurface<A> {
|
||||||
/// (only works for *cursor* and *overlay* planes - for primary planes use `test_buffer`)
|
/// (only works for *cursor* and *overlay* planes - for primary planes use `test_buffer`)
|
||||||
/// - `position` - The position of the plane
|
/// - `position` - The position of the plane
|
||||||
/// - `size` - The size of the plane
|
/// - `size` - The size of the plane
|
||||||
///
|
///
|
||||||
/// If the test cannot be performed, this function returns false.
|
/// If the test cannot be performed, this function returns false.
|
||||||
/// This is always the case for non-atomic surfaces.
|
/// This is always the case for non-atomic surfaces.
|
||||||
pub fn test_plane_buffer(
|
pub fn test_plane_buffer(
|
||||||
|
@ -416,8 +428,7 @@ impl<A: AsRawFd + 'static> DrmSurface<A> {
|
||||||
) -> Result<bool, Error> {
|
) -> Result<bool, Error> {
|
||||||
match &*self.internal {
|
match &*self.internal {
|
||||||
DrmSurfaceInternal::Atomic(surf) => surf.test_plane_buffer(fb, plane, position, size),
|
DrmSurfaceInternal::Atomic(surf) => surf.test_plane_buffer(fb, plane, position, size),
|
||||||
DrmSurfaceInternal::Legacy(_) => { Ok(false) }
|
DrmSurfaceInternal::Legacy(_) => Ok(false), // There is no test-commiting with the legacy interface
|
||||||
// There is no test-commiting with the legacy interface
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,7 @@ use crate::backend::egl::{
|
||||||
ffi::egl::{self as ffi_egl, types::EGLImage},
|
ffi::egl::{self as ffi_egl, types::EGLImage},
|
||||||
EGLContext, EGLSurface, Format as EGLFormat, MakeCurrentError,
|
EGLContext, EGLSurface, Format as EGLFormat, MakeCurrentError,
|
||||||
};
|
};
|
||||||
use crate::{backend::SwapBuffersError};
|
use crate::backend::SwapBuffersError;
|
||||||
|
|
||||||
#[cfg(feature = "wayland_frontend")]
|
#[cfg(feature = "wayland_frontend")]
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -534,28 +534,32 @@ impl Gles2Renderer {
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut upload_full = false;
|
let mut upload_full = false;
|
||||||
|
|
||||||
let texture = Gles2Texture(
|
let texture = Gles2Texture(
|
||||||
// why not store a `Gles2Texture`? because the user might do so.
|
// why not store a `Gles2Texture`? because the user might do so.
|
||||||
// this is guaranteed a non-public internal type, so we are good.
|
// this is guaranteed a non-public internal type, so we are good.
|
||||||
surface.user_data.get::<Rc<Gles2TextureInternal>>().cloned().unwrap_or_else(|| {
|
surface
|
||||||
let mut tex = 0;
|
.user_data
|
||||||
unsafe { self.gl.GenTextures(1, &mut tex) };
|
.get::<Rc<Gles2TextureInternal>>()
|
||||||
// new texture, upload in full
|
.cloned()
|
||||||
upload_full = true;
|
.unwrap_or_else(|| {
|
||||||
let texture = Rc::new(Gles2TextureInternal {
|
let mut tex = 0;
|
||||||
texture: tex,
|
unsafe { self.gl.GenTextures(1, &mut tex) };
|
||||||
texture_kind: shader_idx,
|
// new texture, upload in full
|
||||||
is_external: false,
|
upload_full = true;
|
||||||
y_inverted: false,
|
let texture = Rc::new(Gles2TextureInternal {
|
||||||
width: width as u32,
|
texture: tex,
|
||||||
height: height as u32,
|
texture_kind: shader_idx,
|
||||||
buffer: Some(buffer.clone()),
|
is_external: false,
|
||||||
egl_images: None,
|
y_inverted: false,
|
||||||
destruction_callback_sender: self.destruction_callback_sender.clone(),
|
width: width as u32,
|
||||||
});
|
height: height as u32,
|
||||||
texture
|
buffer: Some(buffer.clone()),
|
||||||
})
|
egl_images: None,
|
||||||
|
destruction_callback_sender: self.destruction_callback_sender.clone(),
|
||||||
|
});
|
||||||
|
texture
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -566,8 +570,7 @@ impl Gles2Renderer {
|
||||||
self.gl
|
self.gl
|
||||||
.TexParameteri(ffi::TEXTURE_2D, ffi::TEXTURE_WRAP_T, ffi::CLAMP_TO_EDGE as i32);
|
.TexParameteri(ffi::TEXTURE_2D, ffi::TEXTURE_WRAP_T, ffi::CLAMP_TO_EDGE as i32);
|
||||||
self.gl.PixelStorei(ffi::UNPACK_ROW_LENGTH, stride / pixelsize);
|
self.gl.PixelStorei(ffi::UNPACK_ROW_LENGTH, stride / pixelsize);
|
||||||
|
|
||||||
|
|
||||||
if upload_full {
|
if upload_full {
|
||||||
trace!(self.logger, "Uploading shm texture for {:?}", buffer);
|
trace!(self.logger, "Uploading shm texture for {:?}", buffer);
|
||||||
self.gl.TexImage2D(
|
self.gl.TexImage2D(
|
||||||
|
@ -659,7 +662,10 @@ impl Gles2Renderer {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "wayland_frontend")]
|
#[cfg(feature = "wayland_frontend")]
|
||||||
fn existing_dmabuf_texture(&self, buffer: &wl_buffer::WlBuffer) -> Result<Option<Gles2Texture>, Gles2Error> {
|
fn existing_dmabuf_texture(
|
||||||
|
&self,
|
||||||
|
buffer: &wl_buffer::WlBuffer,
|
||||||
|
) -> Result<Option<Gles2Texture>, Gles2Error> {
|
||||||
let existing_texture = self
|
let existing_texture = self
|
||||||
.dmabuf_cache
|
.dmabuf_cache
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -945,10 +951,7 @@ impl Renderer for Gles2Renderer {
|
||||||
let texture = if egl.and_then(|egl| egl.egl_buffer_dimensions(&buffer)).is_some() {
|
let texture = if egl.and_then(|egl| egl.egl_buffer_dimensions(&buffer)).is_some() {
|
||||||
self.import_egl(&buffer, egl.unwrap())
|
self.import_egl(&buffer, egl.unwrap())
|
||||||
} else if crate::wayland::shm::with_buffer_contents(&buffer, |_, _| ()).is_ok() {
|
} else if crate::wayland::shm::with_buffer_contents(&buffer, |_, _| ()).is_ok() {
|
||||||
self.import_shm(
|
self.import_shm(&buffer, surface)
|
||||||
&buffer,
|
|
||||||
surface,
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
Err(Gles2Error::UnknownBufferType)
|
Err(Gles2Error::UnknownBufferType)
|
||||||
}?;
|
}?;
|
||||||
|
@ -973,12 +976,13 @@ impl Renderer for Gles2Renderer {
|
||||||
|
|
||||||
fn render<F, R>(
|
fn render<F, R>(
|
||||||
&mut self,
|
&mut self,
|
||||||
width: u32, height: u32,
|
width: u32,
|
||||||
|
height: u32,
|
||||||
transform: Transform,
|
transform: Transform,
|
||||||
rendering: F,
|
rendering: F,
|
||||||
) -> Result<R, Self::Error>
|
) -> Result<R, Self::Error>
|
||||||
where
|
where
|
||||||
F: FnOnce(&mut Self, &mut Self::Frame) -> R
|
F: FnOnce(&mut Self, &mut Self::Frame) -> R,
|
||||||
{
|
{
|
||||||
self.make_current()?;
|
self.make_current()?;
|
||||||
// delayed destruction until the next frame rendering.
|
// delayed destruction until the next frame rendering.
|
||||||
|
@ -1016,7 +1020,7 @@ impl Renderer for Gles2Renderer {
|
||||||
};
|
};
|
||||||
|
|
||||||
let result = rendering(self, &mut frame);
|
let result = rendering(self, &mut frame);
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
self.gl.Flush();
|
self.gl.Flush();
|
||||||
// We need to wait for the previously submitted GL commands to complete
|
// We need to wait for the previously submitted GL commands to complete
|
||||||
|
@ -1027,7 +1031,7 @@ impl Renderer for Gles2Renderer {
|
||||||
// In case of a drm atomic backend the fence could be supplied by using the
|
// In case of a drm atomic backend the fence could be supplied by using the
|
||||||
// IN_FENCE_FD property.
|
// IN_FENCE_FD property.
|
||||||
// See https://01.org/linuxgraphics/gfx-docs/drm/gpu/drm-kms.html#explicit-fencing-properties for
|
// See https://01.org/linuxgraphics/gfx-docs/drm/gpu/drm-kms.html#explicit-fencing-properties for
|
||||||
// the topic on submitting a IN_FENCE_FD and the mesa kmskube example
|
// the topic on submitting a IN_FENCE_FD and the mesa kmskube example
|
||||||
// https://gitlab.freedesktop.org/mesa/kmscube/-/blob/9f63f359fab1b5d8e862508e4e51c9dfe339ccb0/drm-atomic.c
|
// https://gitlab.freedesktop.org/mesa/kmscube/-/blob/9f63f359fab1b5d8e862508e4e51c9dfe339ccb0/drm-atomic.c
|
||||||
// especially here
|
// especially here
|
||||||
// https://gitlab.freedesktop.org/mesa/kmscube/-/blob/9f63f359fab1b5d8e862508e4e51c9dfe339ccb0/drm-atomic.c#L147
|
// https://gitlab.freedesktop.org/mesa/kmscube/-/blob/9f63f359fab1b5d8e862508e4e51c9dfe339ccb0/drm-atomic.c#L147
|
||||||
|
|
|
@ -10,11 +10,11 @@
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
|
|
||||||
|
#[cfg(feature = "wayland_frontend")]
|
||||||
|
use crate::wayland::compositor::SurfaceAttributes;
|
||||||
use cgmath::{prelude::*, Matrix3, Vector2};
|
use cgmath::{prelude::*, Matrix3, Vector2};
|
||||||
#[cfg(feature = "wayland_frontend")]
|
#[cfg(feature = "wayland_frontend")]
|
||||||
use wayland_server::protocol::{wl_buffer, wl_shm};
|
use wayland_server::protocol::{wl_buffer, wl_shm};
|
||||||
#[cfg(feature = "wayland_frontend")]
|
|
||||||
use crate::wayland::compositor::SurfaceAttributes;
|
|
||||||
|
|
||||||
use crate::{backend::SwapBuffersError, utils::Rectangle};
|
use crate::{backend::SwapBuffersError, utils::Rectangle};
|
||||||
#[cfg(feature = "renderer_gl")]
|
#[cfg(feature = "renderer_gl")]
|
||||||
|
@ -108,7 +108,7 @@ impl From<wayland_server::protocol::wl_output::Transform> for Transform {
|
||||||
/// Abstraction for Renderers, that can render into different targets
|
/// Abstraction for Renderers, that can render into different targets
|
||||||
pub trait Bind<Target>: Unbind {
|
pub trait Bind<Target>: Unbind {
|
||||||
/// Bind a given rendering target, which will contain the rendering results until `unbind` is called.
|
/// Bind a given rendering target, which will contain the rendering results until `unbind` is called.
|
||||||
///
|
///
|
||||||
/// Binding to target, while another one is already bound, is rendering defined.
|
/// Binding to target, while another one is already bound, is rendering defined.
|
||||||
/// Some renderers might happily replace the current target, while other might drop the call
|
/// Some renderers might happily replace the current target, while other might drop the call
|
||||||
/// or throw an error.
|
/// or throw an error.
|
||||||
|
@ -199,8 +199,8 @@ pub trait Renderer {
|
||||||
type Error: Error;
|
type Error: Error;
|
||||||
/// Texture Handle type used by this renderer.
|
/// Texture Handle type used by this renderer.
|
||||||
type TextureId: Texture;
|
type TextureId: Texture;
|
||||||
|
|
||||||
type Frame: Frame<Error=Self::Error, TextureId=Self::TextureId>;
|
type Frame: Frame<Error = Self::Error, TextureId = Self::TextureId>;
|
||||||
|
|
||||||
/// Import a given bitmap into the renderer.
|
/// Import a given bitmap into the renderer.
|
||||||
///
|
///
|
||||||
|
@ -261,9 +261,8 @@ pub trait Renderer {
|
||||||
transform: Transform,
|
transform: Transform,
|
||||||
rendering: F,
|
rendering: F,
|
||||||
) -> Result<R, Self::Error>
|
) -> Result<R, Self::Error>
|
||||||
where
|
where
|
||||||
F: FnOnce(&mut Self, &mut Self::Frame) -> R
|
F: FnOnce(&mut Self, &mut Self::Frame) -> R;
|
||||||
;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the dimensions of a wl_buffer
|
/// Returns the dimensions of a wl_buffer
|
||||||
|
|
|
@ -10,10 +10,11 @@ use crate::backend::{
|
||||||
UnusedEvent,
|
UnusedEvent,
|
||||||
},
|
},
|
||||||
renderer::{
|
renderer::{
|
||||||
gles2::{Gles2Error, Gles2Renderer, Gles2Frame, Gles2Texture},
|
gles2::{Gles2Error, Gles2Frame, Gles2Renderer, Gles2Texture},
|
||||||
Bind, Unbind, Frame, Renderer, Transform,
|
Bind, Frame, Renderer, Transform, Unbind,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
use crate::utils::Rectangle;
|
||||||
use std::{cell::RefCell, rc::Rc, time::Instant};
|
use std::{cell::RefCell, rc::Rc, time::Instant};
|
||||||
use wayland_egl as wegl;
|
use wayland_egl as wegl;
|
||||||
use wayland_server::Display;
|
use wayland_server::Display;
|
||||||
|
@ -28,7 +29,6 @@ use winit::{
|
||||||
platform::unix::WindowExtUnix,
|
platform::unix::WindowExtUnix,
|
||||||
window::{Window as WinitWindow, WindowBuilder},
|
window::{Window as WinitWindow, WindowBuilder},
|
||||||
};
|
};
|
||||||
use crate::utils::Rectangle;
|
|
||||||
|
|
||||||
#[cfg(feature = "use_system_lib")]
|
#[cfg(feature = "use_system_lib")]
|
||||||
use crate::backend::egl::display::EGLBufferReader;
|
use crate::backend::egl::display::EGLBufferReader;
|
||||||
|
@ -264,7 +264,7 @@ impl WinitGraphicsBackend {
|
||||||
/// and this window set as the rendering target.
|
/// and this window set as the rendering target.
|
||||||
pub fn render<F, R>(&mut self, rendering: F) -> Result<R, crate::backend::SwapBuffersError>
|
pub fn render<F, R>(&mut self, rendering: F) -> Result<R, crate::backend::SwapBuffersError>
|
||||||
where
|
where
|
||||||
F: FnOnce(&mut Gles2Renderer, &mut Gles2Frame) -> R
|
F: FnOnce(&mut Gles2Renderer, &mut Gles2Frame) -> R,
|
||||||
{
|
{
|
||||||
let (width, height) = {
|
let (width, height) = {
|
||||||
let size = self.size.borrow();
|
let size = self.size.borrow();
|
||||||
|
@ -272,7 +272,9 @@ impl WinitGraphicsBackend {
|
||||||
};
|
};
|
||||||
|
|
||||||
self.renderer.bind(self.egl.clone())?;
|
self.renderer.bind(self.egl.clone())?;
|
||||||
let result = self.renderer.render(width, height, Transform::Normal, rendering)?;
|
let result = self
|
||||||
|
.renderer
|
||||||
|
.render(width, height, Transform::Normal, rendering)?;
|
||||||
self.egl.swap_buffers()?;
|
self.egl.swap_buffers()?;
|
||||||
self.renderer.unbind()?;
|
self.renderer.unbind()?;
|
||||||
Ok(result)
|
Ok(result)
|
||||||
|
|
Loading…
Reference in New Issue