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;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
#[cfg(feature = "egl")]
|
#[cfg(feature = "egl")]
|
||||||
use smithay::backend::egl::{
|
use smithay::backend::egl::{display::EGLBufferReader, BufferAccessError as EGLBufferAccessError, EGLBuffer};
|
||||||
display::EGLBufferReader, BufferAccessError as EGLBufferAccessError, EGLBuffer,
|
|
||||||
};
|
|
||||||
use smithay::{
|
use smithay::{
|
||||||
reexports::wayland_server::protocol::wl_buffer::WlBuffer,
|
reexports::wayland_server::protocol::wl_buffer::WlBuffer,
|
||||||
wayland::shm::{with_buffer_contents as shm_buffer_contents, BufferAccessError},
|
wayland::shm::{with_buffer_contents as shm_buffer_contents, BufferAccessError},
|
||||||
|
@ -76,7 +74,7 @@ impl BufferUtils {
|
||||||
|
|
||||||
let egl_buffer = match result {
|
let egl_buffer = match result {
|
||||||
Ok(egl) => Some(egl),
|
Ok(egl) => Some(egl),
|
||||||
Err(EGLBufferAccessError::NotManaged(_)) => { None },
|
Err(EGLBufferAccessError::NotManaged(_)) => None,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
error!(self.log, "EGL error"; "err" => format!("{:?}", err));
|
error!(self.log, "EGL error"; "err" => format!("{:?}", err));
|
||||||
return Err(buffer);
|
return Err(buffer);
|
||||||
|
@ -112,7 +110,7 @@ pub struct BufferTextures<T> {
|
||||||
#[cfg(feature = "udev")]
|
#[cfg(feature = "udev")]
|
||||||
impl<T: Texture> BufferTextures<T> {
|
impl<T: Texture> BufferTextures<T> {
|
||||||
#[cfg(feature = "egl")]
|
#[cfg(feature = "egl")]
|
||||||
pub fn load_texture<'a, R: Renderer<TextureId=T>>(
|
pub fn load_texture<'a, R: Renderer<TextureId = T>>(
|
||||||
&'a mut self,
|
&'a mut self,
|
||||||
id: u64,
|
id: u64,
|
||||||
renderer: &mut R,
|
renderer: &mut R,
|
||||||
|
@ -136,7 +134,7 @@ impl<T: Texture> BufferTextures<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "egl"))]
|
#[cfg(not(feature = "egl"))]
|
||||||
pub fn load_texture<'a, R: Renderer<Texture=T>>(
|
pub fn load_texture<'a, R: Renderer<Texture = T>>(
|
||||||
&'a mut self,
|
&'a mut self,
|
||||||
id: u64,
|
id: u64,
|
||||||
renderer: &mut R,
|
renderer: &mut R,
|
||||||
|
@ -149,14 +147,14 @@ impl<T: Texture> BufferTextures<T> {
|
||||||
self.load_shm_texture(id, renderer, texture_destruction_callback)
|
self.load_shm_texture(id, renderer, texture_destruction_callback)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_shm_texture<'a, R: Renderer<TextureId=T>>(
|
fn load_shm_texture<'a, R: Renderer<TextureId = T>>(
|
||||||
&'a mut self,
|
&'a mut self,
|
||||||
id: u64,
|
id: u64,
|
||||||
renderer: &mut R,
|
renderer: &mut R,
|
||||||
texture_destruction_callback: &Sender<T>,
|
texture_destruction_callback: &Sender<T>,
|
||||||
) -> Result<&'a T, R::Error> {
|
) -> Result<&'a T, R::Error> {
|
||||||
let texture = renderer.import_shm(&self.buffer)?;
|
let texture = renderer.import_shm(&self.buffer)?;
|
||||||
|
|
||||||
if let Some(old_texture) = self.textures.insert(id, texture) {
|
if let Some(old_texture) = self.textures.insert(id, texture) {
|
||||||
let _ = renderer.destroy_texture(old_texture)?;
|
let _ = renderer.destroy_texture(old_texture)?;
|
||||||
}
|
}
|
||||||
|
@ -173,4 +171,4 @@ impl<T> Drop for BufferTextures<T> {
|
||||||
self.callbacks.get(&id).unwrap().send(texture).unwrap();
|
self.callbacks.get(&id).unwrap().send(texture).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,19 +1,12 @@
|
||||||
#![allow(clippy::too_many_arguments)]
|
#![allow(clippy::too_many_arguments)]
|
||||||
|
|
||||||
use std::{
|
use std::{cell::RefCell, rc::Rc, sync::mpsc::Sender};
|
||||||
cell::RefCell,
|
|
||||||
rc::Rc,
|
|
||||||
sync::mpsc::Sender,
|
|
||||||
};
|
|
||||||
|
|
||||||
use slog::Logger;
|
use slog::Logger;
|
||||||
use smithay::{
|
use smithay::{
|
||||||
|
backend::renderer::{Renderer, Texture, Transform},
|
||||||
backend::SwapBuffersError,
|
backend::SwapBuffersError,
|
||||||
backend::renderer::{Renderer, Transform, Texture},
|
reexports::{calloop::LoopHandle, wayland_server::protocol::wl_surface},
|
||||||
reexports::{
|
|
||||||
calloop::LoopHandle,
|
|
||||||
wayland_server::protocol::wl_surface,
|
|
||||||
},
|
|
||||||
utils::Rectangle,
|
utils::Rectangle,
|
||||||
wayland::{
|
wayland::{
|
||||||
compositor::{roles::Role, SubsurfaceRole, TraversalAction},
|
compositor::{roles::Role, SubsurfaceRole, TraversalAction},
|
||||||
|
@ -22,8 +15,8 @@ use smithay::{
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use crate::buffer_utils::{BufferTextures, BufferUtils};
|
||||||
use crate::shell::{MyCompositorToken, MyWindowMap, SurfaceData};
|
use crate::shell::{MyCompositorToken, MyWindowMap, SurfaceData};
|
||||||
use crate::buffer_utils::{BufferUtils, BufferTextures};
|
|
||||||
|
|
||||||
pub fn draw_cursor<R, E, T>(
|
pub fn draw_cursor<R, E, T>(
|
||||||
renderer: &mut R,
|
renderer: &mut R,
|
||||||
|
@ -35,10 +28,10 @@ pub fn draw_cursor<R, E, T>(
|
||||||
token: MyCompositorToken,
|
token: MyCompositorToken,
|
||||||
log: &Logger,
|
log: &Logger,
|
||||||
) -> Result<(), SwapBuffersError>
|
) -> Result<(), SwapBuffersError>
|
||||||
where
|
where
|
||||||
R: Renderer<Error=E, TextureId=T>,
|
R: Renderer<Error = E, TextureId = T>,
|
||||||
E: std::error::Error + Into<SwapBuffersError>,
|
E: std::error::Error + Into<SwapBuffersError>,
|
||||||
T: Texture + 'static,
|
T: Texture + 'static,
|
||||||
{
|
{
|
||||||
let (dx, dy) = match token.with_role_data::<CursorImageRole, _, _>(surface, |data| data.hotspot) {
|
let (dx, dy) = match token.with_role_data::<CursorImageRole, _, _>(surface, |data| data.hotspot) {
|
||||||
Ok(h) => h,
|
Ok(h) => h,
|
||||||
|
@ -50,7 +43,16 @@ pub fn draw_cursor<R, E, T>(
|
||||||
(0, 0)
|
(0, 0)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
draw_surface_tree(renderer, renderer_id, texture_destruction_callback, buffer_utils, surface, (x - dx, y - dy), token, log)
|
draw_surface_tree(
|
||||||
|
renderer,
|
||||||
|
renderer_id,
|
||||||
|
texture_destruction_callback,
|
||||||
|
buffer_utils,
|
||||||
|
surface,
|
||||||
|
(x - dx, y - dy),
|
||||||
|
token,
|
||||||
|
log,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_surface_tree<R, E, T>(
|
fn draw_surface_tree<R, E, T>(
|
||||||
|
@ -63,10 +65,10 @@ fn draw_surface_tree<R, E, T>(
|
||||||
compositor_token: MyCompositorToken,
|
compositor_token: MyCompositorToken,
|
||||||
log: &Logger,
|
log: &Logger,
|
||||||
) -> Result<(), SwapBuffersError>
|
) -> Result<(), SwapBuffersError>
|
||||||
where
|
where
|
||||||
R: Renderer<Error=E, TextureId=T>,
|
R: Renderer<Error = E, TextureId = T>,
|
||||||
E: std::error::Error + Into<SwapBuffersError>,
|
E: std::error::Error + Into<SwapBuffersError>,
|
||||||
T: Texture + 'static,
|
T: Texture + 'static,
|
||||||
{
|
{
|
||||||
let mut result = Ok(());
|
let mut result = Ok(());
|
||||||
|
|
||||||
|
@ -85,7 +87,7 @@ fn draw_surface_tree<R, E, T>(
|
||||||
// already logged the error
|
// already logged the error
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
warn!(log, "Error loading buffer: {:?}", err);
|
warn!(log, "Error loading buffer: {:?}", err);
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -133,15 +135,23 @@ fn draw_surface_tree<R, E, T>(
|
||||||
if let Some(ref data) = attributes.user_data.get::<RefCell<SurfaceData>>() {
|
if let Some(ref data) = attributes.user_data.get::<RefCell<SurfaceData>>() {
|
||||||
let mut data = data.borrow_mut();
|
let mut data = data.borrow_mut();
|
||||||
let (sub_x, sub_y) = data.current_state.sub_location;
|
let (sub_x, sub_y) = data.current_state.sub_location;
|
||||||
if let Some(buffer_textures) = data.texture.as_mut().and_then(|x| x.downcast_mut::<BufferTextures<T>>()) {
|
if let Some(buffer_textures) = data
|
||||||
|
.texture
|
||||||
|
.as_mut()
|
||||||
|
.and_then(|x| x.downcast_mut::<BufferTextures<T>>())
|
||||||
|
{
|
||||||
// we need to re-extract the subsurface offset, as the previous closure
|
// we need to re-extract the subsurface offset, as the previous closure
|
||||||
// only passes it to our children
|
// only passes it to our children
|
||||||
if Role::<SubsurfaceRole>::has(role) {
|
if Role::<SubsurfaceRole>::has(role) {
|
||||||
x += sub_x;
|
x += sub_x;
|
||||||
y += sub_y;
|
y += sub_y;
|
||||||
}
|
}
|
||||||
let texture = buffer_textures.load_texture(renderer_id, renderer, texture_destruction_callback).unwrap();
|
let texture = buffer_textures
|
||||||
if let Err(err) = renderer.render_texture_at(texture, (x, y), Transform::Normal /* TODO */, 1.0) {
|
.load_texture(renderer_id, renderer, texture_destruction_callback)
|
||||||
|
.unwrap();
|
||||||
|
if let Err(err) =
|
||||||
|
renderer.render_texture_at(texture, (x, y), Transform::Normal /* TODO */, 1.0)
|
||||||
|
{
|
||||||
result = Err(err.into());
|
result = Err(err.into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -163,41 +173,39 @@ pub fn draw_windows<R, E, T>(
|
||||||
compositor_token: MyCompositorToken,
|
compositor_token: MyCompositorToken,
|
||||||
log: &::slog::Logger,
|
log: &::slog::Logger,
|
||||||
) -> Result<(), SwapBuffersError>
|
) -> Result<(), SwapBuffersError>
|
||||||
where
|
where
|
||||||
R: Renderer<Error=E, TextureId=T>,
|
R: Renderer<Error = E, TextureId = T>,
|
||||||
E: std::error::Error + Into<SwapBuffersError>,
|
E: std::error::Error + Into<SwapBuffersError>,
|
||||||
T: Texture + 'static,
|
T: Texture + 'static,
|
||||||
{
|
{
|
||||||
let mut result = Ok(());
|
let mut result = Ok(());
|
||||||
|
|
||||||
// redraw the frame, in a simple but inneficient way
|
// redraw the frame, in a simple but inneficient way
|
||||||
window_map.with_windows_from_bottom_to_top(
|
window_map.with_windows_from_bottom_to_top(|toplevel_surface, mut initial_place, bounding_box| {
|
||||||
|toplevel_surface, mut initial_place, bounding_box| {
|
// skip windows that do not overlap with a given output
|
||||||
// skip windows that do not overlap with a given output
|
if let Some(output) = output_rect {
|
||||||
if let Some(output) = output_rect {
|
if !output.overlaps(bounding_box) {
|
||||||
if !output.overlaps(bounding_box) {
|
return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
initial_place.0 -= output.x;
|
|
||||||
}
|
}
|
||||||
if let Some(wl_surface) = toplevel_surface.get_surface() {
|
initial_place.0 -= output.x;
|
||||||
// this surface is a root of a subsurface tree that needs to be drawn
|
}
|
||||||
if let Err(err) = draw_surface_tree(
|
if let Some(wl_surface) = toplevel_surface.get_surface() {
|
||||||
renderer,
|
// this surface is a root of a subsurface tree that needs to be drawn
|
||||||
renderer_id,
|
if let Err(err) = draw_surface_tree(
|
||||||
texture_destruction_callback,
|
renderer,
|
||||||
buffer_utils,
|
renderer_id,
|
||||||
&wl_surface,
|
texture_destruction_callback,
|
||||||
initial_place,
|
buffer_utils,
|
||||||
compositor_token,
|
&wl_surface,
|
||||||
log,
|
initial_place,
|
||||||
) {
|
compositor_token,
|
||||||
result = Err(err);
|
log,
|
||||||
}
|
) {
|
||||||
|
result = Err(err);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
);
|
});
|
||||||
|
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -211,10 +219,10 @@ pub fn draw_dnd_icon<R, E, T>(
|
||||||
token: MyCompositorToken,
|
token: MyCompositorToken,
|
||||||
log: &::slog::Logger,
|
log: &::slog::Logger,
|
||||||
) -> Result<(), SwapBuffersError>
|
) -> Result<(), SwapBuffersError>
|
||||||
where
|
where
|
||||||
R: Renderer<Error=E, TextureId=T>,
|
R: Renderer<Error = E, TextureId = T>,
|
||||||
E: std::error::Error + Into<SwapBuffersError>,
|
E: std::error::Error + Into<SwapBuffersError>,
|
||||||
T: Texture + 'static,
|
T: Texture + 'static,
|
||||||
{
|
{
|
||||||
if !token.has_role::<DnDIconRole>(surface) {
|
if !token.has_role::<DnDIconRole>(surface) {
|
||||||
warn!(
|
warn!(
|
||||||
|
@ -222,23 +230,37 @@ pub fn draw_dnd_icon<R, E, T>(
|
||||||
"Trying to display as a dnd icon a surface that does not have the DndIcon role."
|
"Trying to display as a dnd icon a surface that does not have the DndIcon role."
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
draw_surface_tree(renderer, renderer_id, texture_destruction_callback, buffer_utils, surface, (x, y), token, log)
|
draw_surface_tree(
|
||||||
|
renderer,
|
||||||
|
renderer_id,
|
||||||
|
texture_destruction_callback,
|
||||||
|
buffer_utils,
|
||||||
|
surface,
|
||||||
|
(x, y),
|
||||||
|
token,
|
||||||
|
log,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn schedule_initial_render<R: Renderer + 'static, Data: 'static>(
|
pub fn schedule_initial_render<R: Renderer + 'static, Data: 'static>(
|
||||||
renderer: Rc<RefCell<R>>,
|
renderer: Rc<RefCell<R>>,
|
||||||
evt_handle: &LoopHandle<Data>,
|
evt_handle: &LoopHandle<Data>,
|
||||||
logger: ::slog::Logger,
|
logger: ::slog::Logger,
|
||||||
)
|
) where
|
||||||
where
|
<R as Renderer>::Error: Into<SwapBuffersError>,
|
||||||
<R as Renderer>::Error: Into<SwapBuffersError>
|
|
||||||
{
|
{
|
||||||
let result = {
|
let result = {
|
||||||
let mut renderer = renderer.borrow_mut();
|
let mut renderer = renderer.borrow_mut();
|
||||||
// Does not matter if we render an empty frame
|
// Does not matter if we render an empty frame
|
||||||
renderer.begin(1, 1, Transform::Normal).map_err(Into::<SwapBuffersError>::into)
|
renderer
|
||||||
.and_then(|_| renderer.clear([0.8, 0.8, 0.9, 1.0]).map_err(Into::<SwapBuffersError>::into))
|
.begin(1, 1, Transform::Normal)
|
||||||
.and_then(|_| renderer.finish())
|
.map_err(Into::<SwapBuffersError>::into)
|
||||||
|
.and_then(|_| {
|
||||||
|
renderer
|
||||||
|
.clear([0.8, 0.8, 0.9, 1.0])
|
||||||
|
.map_err(Into::<SwapBuffersError>::into)
|
||||||
|
})
|
||||||
|
.and_then(|_| renderer.finish())
|
||||||
};
|
};
|
||||||
if let Err(err) = result {
|
if let Err(err) = result {
|
||||||
match err {
|
match err {
|
||||||
|
|
|
@ -5,7 +5,7 @@ use std::{
|
||||||
os::unix::io::{AsRawFd, RawFd},
|
os::unix::io::{AsRawFd, RawFd},
|
||||||
path::PathBuf,
|
path::PathBuf,
|
||||||
rc::Rc,
|
rc::Rc,
|
||||||
sync::{atomic::Ordering, Arc, Mutex, mpsc},
|
sync::{atomic::Ordering, mpsc, Arc, Mutex},
|
||||||
time::Duration,
|
time::Duration,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -14,27 +14,16 @@ use slog::Logger;
|
||||||
|
|
||||||
use smithay::{
|
use smithay::{
|
||||||
backend::{
|
backend::{
|
||||||
SwapBuffersError,
|
drm::{device_bind, DevPath, DeviceHandler, DrmDevice, DrmError, DrmRenderSurface},
|
||||||
drm::{
|
egl::{display::EGLBufferReader, EGLContext, EGLDisplay},
|
||||||
DrmDevice,
|
|
||||||
DeviceHandler,
|
|
||||||
device_bind,
|
|
||||||
DrmRenderSurface,
|
|
||||||
DrmError,
|
|
||||||
DevPath,
|
|
||||||
},
|
|
||||||
egl::{EGLDisplay, EGLContext, display::EGLBufferReader},
|
|
||||||
renderer::{
|
|
||||||
Transform,
|
|
||||||
Renderer,
|
|
||||||
gles2::{
|
|
||||||
Gles2Renderer,
|
|
||||||
Gles2Texture,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
libinput::{LibinputInputBackend, LibinputSessionInterface},
|
libinput::{LibinputInputBackend, LibinputSessionInterface},
|
||||||
|
renderer::{
|
||||||
|
gles2::{Gles2Renderer, Gles2Texture},
|
||||||
|
Renderer, Transform,
|
||||||
|
},
|
||||||
session::{auto::AutoSession, Session, Signal as SessionSignal},
|
session::{auto::AutoSession, Session, Signal as SessionSignal},
|
||||||
udev::{primary_gpu, UdevBackend, UdevEvent},
|
udev::{primary_gpu, UdevBackend, UdevEvent},
|
||||||
|
SwapBuffersError,
|
||||||
},
|
},
|
||||||
reexports::{
|
reexports::{
|
||||||
calloop::{
|
calloop::{
|
||||||
|
@ -45,16 +34,13 @@ use smithay::{
|
||||||
drm::{
|
drm::{
|
||||||
self,
|
self,
|
||||||
control::{
|
control::{
|
||||||
Device as ControlDevice,
|
|
||||||
connector::{Info as ConnectorInfo, State as ConnectorState},
|
connector::{Info as ConnectorInfo, State as ConnectorState},
|
||||||
crtc,
|
crtc,
|
||||||
encoder::Info as EncoderInfo,
|
encoder::Info as EncoderInfo,
|
||||||
|
Device as ControlDevice,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
gbm::{
|
gbm::{BufferObject as GbmBuffer, Device as GbmDevice},
|
||||||
BufferObject as GbmBuffer,
|
|
||||||
Device as GbmDevice,
|
|
||||||
},
|
|
||||||
input::Libinput,
|
input::Libinput,
|
||||||
nix::{fcntl::OFlag, sys::stat::dev_t},
|
nix::{fcntl::OFlag, sys::stat::dev_t},
|
||||||
wayland_server::{
|
wayland_server::{
|
||||||
|
@ -72,9 +58,9 @@ use smithay::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::buffer_utils::BufferUtils;
|
use crate::buffer_utils::BufferUtils;
|
||||||
|
use crate::drawing::*;
|
||||||
use crate::shell::{MyWindowMap, Roles};
|
use crate::shell::{MyWindowMap, Roles};
|
||||||
use crate::state::AnvilState;
|
use crate::state::AnvilState;
|
||||||
use crate::drawing::*;
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct SessionFd(RawFd);
|
pub struct SessionFd(RawFd);
|
||||||
|
@ -358,7 +344,9 @@ impl<Data: 'static> UdevHandlerImpl<Data> {
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Entry::Vacant(entry) = backends.entry(crtc) {
|
if let Entry::Vacant(entry) = backends.entry(crtc) {
|
||||||
info!(logger, "Trying to setup connector {:?}-{} with crtc {:?}",
|
info!(
|
||||||
|
logger,
|
||||||
|
"Trying to setup connector {:?}-{} with crtc {:?}",
|
||||||
connector_info.interface(),
|
connector_info.interface(),
|
||||||
connector_info.interface_id(),
|
connector_info.interface_id(),
|
||||||
crtc,
|
crtc,
|
||||||
|
@ -377,25 +365,26 @@ impl<Data: 'static> UdevHandlerImpl<Data> {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let surface = match device.create_surface(crtc, primary, connector_info.modes()[0], &[connector_info.handle()]) {
|
let surface = match device.create_surface(
|
||||||
|
crtc,
|
||||||
|
primary,
|
||||||
|
connector_info.modes()[0],
|
||||||
|
&[connector_info.handle()],
|
||||||
|
) {
|
||||||
Ok(surface) => surface,
|
Ok(surface) => surface,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
warn!(logger, "Failed to create drm surface: {}", err);
|
warn!(logger, "Failed to create drm surface: {}", err);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let renderer = match DrmRenderSurface::new(
|
let renderer =
|
||||||
surface,
|
match DrmRenderSurface::new(surface, gbm.clone(), renderer, logger.clone()) {
|
||||||
gbm.clone(),
|
Ok(renderer) => renderer,
|
||||||
renderer,
|
Err(err) => {
|
||||||
logger.clone()
|
warn!(logger, "Failed to create rendering surface: {}", err);
|
||||||
) {
|
continue;
|
||||||
Ok(renderer) => renderer,
|
}
|
||||||
Err(err) => {
|
};
|
||||||
warn!(logger, "Failed to create rendering surface: {}", err);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
output_map.push(MyOutput::new(
|
output_map.push(MyOutput::new(
|
||||||
display,
|
display,
|
||||||
|
@ -430,38 +419,40 @@ impl<Data: 'static> UdevHandlerImpl<Data> {
|
||||||
match {
|
match {
|
||||||
let fd = SessionFd(fd);
|
let fd = SessionFd(fd);
|
||||||
(
|
(
|
||||||
DrmDevice::new(
|
DrmDevice::new(fd.clone(), true, self.logger.clone()),
|
||||||
fd.clone(),
|
GbmDevice::new(fd),
|
||||||
true,
|
|
||||||
self.logger.clone(),
|
|
||||||
),
|
|
||||||
GbmDevice::new(
|
|
||||||
fd
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
}
|
} {
|
||||||
{
|
|
||||||
(Ok(drm), Ok(gbm)) => Some((drm, gbm)),
|
(Ok(drm), Ok(gbm)) => Some((drm, gbm)),
|
||||||
(Err(err), _) => {
|
(Err(err), _) => {
|
||||||
warn!(self.logger, "Skipping device {:?}, because of drm error: {}", device_id, err);
|
warn!(
|
||||||
|
self.logger,
|
||||||
|
"Skipping device {:?}, because of drm error: {}", device_id, err
|
||||||
|
);
|
||||||
None
|
None
|
||||||
},
|
}
|
||||||
(_, Err(err)) => {
|
(_, Err(err)) => {
|
||||||
// TODO try DumbBuffer allocator in this case
|
// TODO try DumbBuffer allocator in this case
|
||||||
warn!(self.logger, "Skipping device {:?}, because of gbm error: {}", device_id, err);
|
warn!(
|
||||||
|
self.logger,
|
||||||
|
"Skipping device {:?}, because of gbm error: {}", device_id, err
|
||||||
|
);
|
||||||
None
|
None
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
{
|
{
|
||||||
let egl = match EGLDisplay::new(&gbm, self.logger.clone()) {
|
let egl = match EGLDisplay::new(&gbm, self.logger.clone()) {
|
||||||
Ok(display) => display,
|
Ok(display) => display,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
warn!(self.logger, "Skipping device {:?}, because of egl display error: {}", device_id, err);
|
warn!(
|
||||||
|
self.logger,
|
||||||
|
"Skipping device {:?}, because of egl display error: {}", device_id, err
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// init hardware acceleration on the primary gpu.
|
// init hardware acceleration on the primary gpu.
|
||||||
#[cfg(feature = "egl")]
|
#[cfg(feature = "egl")]
|
||||||
{
|
{
|
||||||
|
@ -470,19 +461,21 @@ impl<Data: 'static> UdevHandlerImpl<Data> {
|
||||||
self.logger,
|
self.logger,
|
||||||
"Initializing EGL Hardware Acceleration via {:?}", path
|
"Initializing EGL Hardware Acceleration via {:?}", path
|
||||||
);
|
);
|
||||||
*self.egl_buffer_reader.borrow_mut() =
|
*self.egl_buffer_reader.borrow_mut() = egl.bind_wl_display(&*self.display.borrow()).ok();
|
||||||
egl.bind_wl_display(&*self.display.borrow()).ok();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let context = match EGLContext::new(&egl, self.logger.clone()) {
|
let context = match EGLContext::new(&egl, self.logger.clone()) {
|
||||||
Ok(context) => context,
|
Ok(context) => context,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
warn!(self.logger, "Skipping device {:?}, because of egl context error: {}", device_id, err);
|
warn!(
|
||||||
|
self.logger,
|
||||||
|
"Skipping device {:?}, because of egl context error: {}", device_id, err
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let backends = Rc::new(RefCell::new(UdevHandlerImpl::<Data>::scan_connectors(
|
let backends = Rc::new(RefCell::new(UdevHandlerImpl::<Data>::scan_connectors(
|
||||||
&mut device,
|
&mut device,
|
||||||
&gbm,
|
&gbm,
|
||||||
|
@ -498,7 +491,9 @@ impl<Data: 'static> UdevHandlerImpl<Data> {
|
||||||
let pointer_image = {
|
let pointer_image = {
|
||||||
let context = EGLContext::new_shared(&egl, &context, self.logger.clone()).unwrap();
|
let context = EGLContext::new_shared(&egl, &context, self.logger.clone()).unwrap();
|
||||||
let mut renderer = unsafe { Gles2Renderer::new(context, self.logger.clone()).unwrap() };
|
let mut renderer = unsafe { Gles2Renderer::new(context, self.logger.clone()).unwrap() };
|
||||||
renderer.import_bitmap(&self.pointer_image).expect("Failed to load pointer")
|
renderer
|
||||||
|
.import_bitmap(&self.pointer_image)
|
||||||
|
.expect("Failed to load pointer")
|
||||||
};
|
};
|
||||||
|
|
||||||
// Set the handler.
|
// Set the handler.
|
||||||
|
@ -674,35 +669,34 @@ impl DrmRenderer {
|
||||||
) {
|
) {
|
||||||
if let Some(surface) = self.backends.borrow().get(&crtc) {
|
if let Some(surface) = self.backends.borrow().get(&crtc) {
|
||||||
let result = DrmRenderer::render_surface(
|
let result = DrmRenderer::render_surface(
|
||||||
&mut *surface.borrow_mut(),
|
&mut *surface.borrow_mut(),
|
||||||
&self.texture_destruction_callback.0,
|
&self.texture_destruction_callback.0,
|
||||||
&self.buffer_utils,
|
&self.buffer_utils,
|
||||||
self.device_id,
|
self.device_id,
|
||||||
crtc,
|
crtc,
|
||||||
&mut *self.window_map.borrow_mut(),
|
&mut *self.window_map.borrow_mut(),
|
||||||
&mut *self.output_map.borrow_mut(),
|
&mut *self.output_map.borrow_mut(),
|
||||||
&self.compositor_token,
|
&self.compositor_token,
|
||||||
&*self.pointer_location.borrow(),
|
&*self.pointer_location.borrow(),
|
||||||
&self.pointer_image,
|
&self.pointer_image,
|
||||||
&*self.dnd_icon.lock().unwrap(),
|
&*self.dnd_icon.lock().unwrap(),
|
||||||
&mut *self.cursor_status.lock().unwrap(),
|
&mut *self.cursor_status.lock().unwrap(),
|
||||||
&self.logger
|
&self.logger,
|
||||||
);
|
);
|
||||||
if let Err(err) = result {
|
if let Err(err) = result {
|
||||||
warn!(self.logger, "Error during rendering: {:?}", err);
|
warn!(self.logger, "Error during rendering: {:?}", err);
|
||||||
let reschedule =
|
let reschedule = match err {
|
||||||
match err {
|
SwapBuffersError::AlreadySwapped => false,
|
||||||
SwapBuffersError::AlreadySwapped => false,
|
SwapBuffersError::TemporaryFailure(err) => !matches!(
|
||||||
SwapBuffersError::TemporaryFailure(err) => {
|
err.downcast_ref::<DrmError>(),
|
||||||
!matches!(err.downcast_ref::<DrmError>(),
|
Some(&DrmError::DeviceInactive)
|
||||||
Some(&DrmError::DeviceInactive) |
|
| Some(&DrmError::Access {
|
||||||
Some(&DrmError::Access {
|
source: drm::SystemError::PermissionDenied,
|
||||||
source: drm::SystemError::PermissionDenied,
|
..
|
||||||
..
|
})
|
||||||
}))
|
),
|
||||||
}
|
SwapBuffersError::ContextLost(err) => panic!("Rendering loop lost: {}", err),
|
||||||
SwapBuffersError::ContextLost(err) => panic!("Rendering loop lost: {}", err),
|
};
|
||||||
};
|
|
||||||
|
|
||||||
if reschedule {
|
if reschedule {
|
||||||
debug!(self.logger, "Rescheduling");
|
debug!(self.logger, "Rescheduling");
|
||||||
|
@ -741,7 +735,7 @@ impl DrmRenderer {
|
||||||
self.window_map
|
self.window_map
|
||||||
.borrow()
|
.borrow()
|
||||||
.send_frames(self.start_time.elapsed().as_millis() as u32);
|
.send_frames(self.start_time.elapsed().as_millis() as u32);
|
||||||
|
|
||||||
while let Ok(texture) = self.texture_destruction_callback.1.try_recv() {
|
while let Ok(texture) = self.texture_destruction_callback.1.try_recv() {
|
||||||
let _ = surface.borrow_mut().destroy_texture(texture);
|
let _ = surface.borrow_mut().destroy_texture(texture);
|
||||||
}
|
}
|
||||||
|
@ -809,7 +803,16 @@ impl DrmRenderer {
|
||||||
{
|
{
|
||||||
if let Some(ref wl_surface) = dnd_icon.as_ref() {
|
if let Some(ref wl_surface) = dnd_icon.as_ref() {
|
||||||
if wl_surface.as_ref().is_alive() {
|
if wl_surface.as_ref().is_alive() {
|
||||||
draw_dnd_icon(surface, device_id, texture_destruction_callback, buffer_utils, wl_surface, (ptr_x, ptr_y), *compositor_token, logger)?;
|
draw_dnd_icon(
|
||||||
|
surface,
|
||||||
|
device_id,
|
||||||
|
texture_destruction_callback,
|
||||||
|
buffer_utils,
|
||||||
|
wl_surface,
|
||||||
|
(ptr_x, ptr_y),
|
||||||
|
*compositor_token,
|
||||||
|
logger,
|
||||||
|
)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -842,4 +845,4 @@ impl DrmRenderer {
|
||||||
}
|
}
|
||||||
surface.finish()
|
surface.finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ use std::{cell::RefCell, rc::Rc, sync::atomic::Ordering, time::Duration};
|
||||||
//#[cfg(feature = "egl")]
|
//#[cfg(feature = "egl")]
|
||||||
//use smithay::backend::egl::EGLGraphicsBackend;
|
//use smithay::backend::egl::EGLGraphicsBackend;
|
||||||
use smithay::{
|
use smithay::{
|
||||||
backend::{renderer::Renderer, input::InputBackend, winit, SwapBuffersError},
|
backend::{input::InputBackend, renderer::Renderer, winit, SwapBuffersError},
|
||||||
reexports::{
|
reexports::{
|
||||||
calloop::EventLoop,
|
calloop::EventLoop,
|
||||||
wayland_server::{protocol::wl_output, Display},
|
wayland_server::{protocol::wl_output, Display},
|
||||||
|
@ -16,9 +16,9 @@ use smithay::{
|
||||||
|
|
||||||
use slog::Logger;
|
use slog::Logger;
|
||||||
|
|
||||||
use crate::state::AnvilState;
|
|
||||||
use crate::buffer_utils::BufferUtils;
|
use crate::buffer_utils::BufferUtils;
|
||||||
use crate::drawing::*;
|
use crate::drawing::*;
|
||||||
|
use crate::state::AnvilState;
|
||||||
|
|
||||||
pub fn run_winit(
|
pub fn run_winit(
|
||||||
display: Rc<RefCell<Display>>,
|
display: Rc<RefCell<Display>>,
|
||||||
|
@ -111,10 +111,22 @@ pub fn run_winit(
|
||||||
// drawing logic
|
// drawing logic
|
||||||
{
|
{
|
||||||
renderer.begin().expect("Failed to render frame");
|
renderer.begin().expect("Failed to render frame");
|
||||||
renderer.clear([0.8, 0.8, 0.9, 1.0]).expect("Failed to clear frame");
|
renderer
|
||||||
|
.clear([0.8, 0.8, 0.9, 1.0])
|
||||||
|
.expect("Failed to clear frame");
|
||||||
|
|
||||||
// draw the windows
|
// draw the windows
|
||||||
draw_windows(&mut renderer, 0, &texture_send, &buffer_utils, &*state.window_map.borrow(), None, state.ctoken, &log).expect("Failed to renderer windows");
|
draw_windows(
|
||||||
|
&mut renderer,
|
||||||
|
0,
|
||||||
|
&texture_send,
|
||||||
|
&buffer_utils,
|
||||||
|
&*state.window_map.borrow(),
|
||||||
|
None,
|
||||||
|
state.ctoken,
|
||||||
|
&log,
|
||||||
|
)
|
||||||
|
.expect("Failed to renderer windows");
|
||||||
|
|
||||||
let (x, y) = *state.pointer_location.borrow();
|
let (x, y) = *state.pointer_location.borrow();
|
||||||
// draw the dnd icon if any
|
// draw the dnd icon if any
|
||||||
|
@ -122,7 +134,17 @@ pub fn run_winit(
|
||||||
let guard = state.dnd_icon.lock().unwrap();
|
let guard = state.dnd_icon.lock().unwrap();
|
||||||
if let Some(ref surface) = *guard {
|
if let Some(ref surface) = *guard {
|
||||||
if surface.as_ref().is_alive() {
|
if surface.as_ref().is_alive() {
|
||||||
draw_dnd_icon(&mut renderer, 0, &texture_send, &buffer_utils, surface, (x as i32, y as i32), state.ctoken, &log).expect("Failed to render dnd icon");
|
draw_dnd_icon(
|
||||||
|
&mut renderer,
|
||||||
|
0,
|
||||||
|
&texture_send,
|
||||||
|
&buffer_utils,
|
||||||
|
surface,
|
||||||
|
(x as i32, y as i32),
|
||||||
|
state.ctoken,
|
||||||
|
&log,
|
||||||
|
)
|
||||||
|
.expect("Failed to render dnd icon");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -137,11 +159,21 @@ pub fn run_winit(
|
||||||
if reset {
|
if reset {
|
||||||
*guard = CursorImageStatus::Default;
|
*guard = CursorImageStatus::Default;
|
||||||
}
|
}
|
||||||
|
|
||||||
// draw as relevant
|
// draw as relevant
|
||||||
if let CursorImageStatus::Image(ref surface) = *guard {
|
if let CursorImageStatus::Image(ref surface) = *guard {
|
||||||
renderer.window().set_cursor_visible(false);
|
renderer.window().set_cursor_visible(false);
|
||||||
draw_cursor(&mut renderer, 0, &texture_send, &buffer_utils, surface, (x as i32, y as i32), state.ctoken, &log).expect("Failed to render cursor");
|
draw_cursor(
|
||||||
|
&mut renderer,
|
||||||
|
0,
|
||||||
|
&texture_send,
|
||||||
|
&buffer_utils,
|
||||||
|
surface,
|
||||||
|
(x as i32, y as i32),
|
||||||
|
state.ctoken,
|
||||||
|
&log,
|
||||||
|
)
|
||||||
|
.expect("Failed to render cursor");
|
||||||
} else {
|
} else {
|
||||||
renderer.window().set_cursor_visible(true);
|
renderer.window().set_cursor_visible(true);
|
||||||
}
|
}
|
||||||
|
@ -153,7 +185,6 @@ pub fn run_winit(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if event_loop
|
if event_loop
|
||||||
.dispatch(Some(Duration::from_millis(16)), &mut state)
|
.dispatch(Some(Duration::from_millis(16)), &mut state)
|
||||||
.is_err()
|
.is_err()
|
||||||
|
|
|
@ -6,28 +6,18 @@ extern crate slog;
|
||||||
use slog::Drain;
|
use slog::Drain;
|
||||||
use smithay::{
|
use smithay::{
|
||||||
backend::{
|
backend::{
|
||||||
allocator::{Format, Fourcc, Modifier, Swapchain, Slot, dumb::DumbBuffer},
|
allocator::{dumb::DumbBuffer, Format, Fourcc, Modifier, Slot, Swapchain},
|
||||||
drm::{
|
drm::{device_bind, DeviceHandler, DrmDevice, DrmError, DrmSurface},
|
||||||
DrmError,
|
|
||||||
DrmDevice, DrmSurface,
|
|
||||||
DeviceHandler,
|
|
||||||
device_bind,
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
reexports::{
|
reexports::{
|
||||||
calloop::EventLoop,
|
calloop::EventLoop,
|
||||||
drm::{
|
drm::control::{connector::State as ConnectorState, crtc, framebuffer, Device as ControlDevice},
|
||||||
control::{
|
|
||||||
connector::State as ConnectorState, crtc, framebuffer,
|
|
||||||
Device as ControlDevice,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use std::{
|
use std::{
|
||||||
fs::{File, OpenOptions},
|
fs::{File, OpenOptions},
|
||||||
os::unix::io::{AsRawFd, RawFd},
|
|
||||||
io::Error as IoError,
|
io::Error as IoError,
|
||||||
|
os::unix::io::{AsRawFd, RawFd},
|
||||||
rc::Rc,
|
rc::Rc,
|
||||||
sync::Mutex,
|
sync::Mutex,
|
||||||
};
|
};
|
||||||
|
@ -54,10 +44,11 @@ fn main() {
|
||||||
let mut options = OpenOptions::new();
|
let mut options = OpenOptions::new();
|
||||||
options.read(true);
|
options.read(true);
|
||||||
options.write(true);
|
options.write(true);
|
||||||
let fd = FdWrapper { file: Rc::new(options.open("/dev/dri/card0").unwrap()) };
|
let fd = FdWrapper {
|
||||||
|
file: Rc::new(options.open("/dev/dri/card0").unwrap()),
|
||||||
|
};
|
||||||
|
|
||||||
let mut device =
|
let mut device = DrmDevice::new(fd.clone(), true, log.clone()).unwrap();
|
||||||
DrmDevice::new(fd.clone(), true, log.clone()).unwrap();
|
|
||||||
|
|
||||||
// Get a set of all modesetting resource handles (excluding planes):
|
// Get a set of all modesetting resource handles (excluding planes):
|
||||||
let res_handles = ControlDevice::resource_handles(&device).unwrap();
|
let res_handles = ControlDevice::resource_handles(&device).unwrap();
|
||||||
|
@ -105,12 +96,20 @@ fn main() {
|
||||||
*/
|
*/
|
||||||
let (w, h) = mode.size();
|
let (w, h) = mode.size();
|
||||||
let allocator = DrmDevice::new(fd, false, log.clone()).unwrap();
|
let allocator = DrmDevice::new(fd, false, log.clone()).unwrap();
|
||||||
let mut swapchain = Swapchain::new(allocator, w.into(), h.into(), Format { code: Fourcc::Argb8888, modifier: Modifier::Invalid });
|
let mut swapchain = Swapchain::new(
|
||||||
|
allocator,
|
||||||
|
w.into(),
|
||||||
|
h.into(),
|
||||||
|
Format {
|
||||||
|
code: Fourcc::Argb8888,
|
||||||
|
modifier: Modifier::Invalid,
|
||||||
|
},
|
||||||
|
);
|
||||||
let first_buffer: Slot<DumbBuffer<FdWrapper>, _> = swapchain.acquire().unwrap().unwrap();
|
let first_buffer: Slot<DumbBuffer<FdWrapper>, _> = swapchain.acquire().unwrap().unwrap();
|
||||||
let framebuffer = surface.add_framebuffer(&first_buffer.handle, 32, 32).unwrap();
|
let framebuffer = surface.add_framebuffer(&first_buffer.handle, 32, 32).unwrap();
|
||||||
first_buffer.set_userdata(framebuffer);
|
first_buffer.set_userdata(framebuffer);
|
||||||
|
|
||||||
// Get the device as an allocator into the
|
// Get the device as an allocator into the
|
||||||
device.set_handler(DrmHandlerImpl {
|
device.set_handler(DrmHandlerImpl {
|
||||||
swapchain,
|
swapchain,
|
||||||
current: first_buffer,
|
current: first_buffer,
|
||||||
|
@ -133,7 +132,8 @@ fn main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct DrmHandlerImpl {
|
pub struct DrmHandlerImpl {
|
||||||
swapchain: Swapchain<DrmDevice<FdWrapper>, DumbBuffer<FdWrapper>, framebuffer::Handle, DumbBuffer<FdWrapper>>,
|
swapchain:
|
||||||
|
Swapchain<DrmDevice<FdWrapper>, DumbBuffer<FdWrapper>, framebuffer::Handle, DumbBuffer<FdWrapper>>,
|
||||||
current: Slot<DumbBuffer<FdWrapper>, framebuffer::Handle>,
|
current: Slot<DumbBuffer<FdWrapper>, framebuffer::Handle>,
|
||||||
surface: Rc<DrmSurface<FdWrapper>>,
|
surface: Rc<DrmSurface<FdWrapper>>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use super::{Buffer, Format, Modifier};
|
use super::{Buffer, Format, Modifier};
|
||||||
use std::sync::{Arc, Weak};
|
|
||||||
use std::os::unix::io::RawFd;
|
use std::os::unix::io::RawFd;
|
||||||
|
use std::sync::{Arc, Weak};
|
||||||
|
|
||||||
const MAX_PLANES: usize = 4;
|
const MAX_PLANES: usize = 4;
|
||||||
|
|
||||||
|
@ -68,9 +68,11 @@ impl Dmabuf {
|
||||||
fds: &[RawFd],
|
fds: &[RawFd],
|
||||||
) -> Option<Dmabuf> {
|
) -> Option<Dmabuf> {
|
||||||
if offsets.len() < planes
|
if offsets.len() < planes
|
||||||
|| strides.len() < planes
|
|| strides.len() < planes
|
||||||
|| fds.len() < planes
|
|| fds.len() < planes
|
||||||
|| planes == 0 || planes > MAX_PLANES {
|
|| planes == 0
|
||||||
|
|| planes > MAX_PLANES
|
||||||
|
{
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,9 +84,24 @@ impl Dmabuf {
|
||||||
|
|
||||||
Some(Dmabuf(Arc::new(DmabufInternal {
|
Some(Dmabuf(Arc::new(DmabufInternal {
|
||||||
num_planes: planes,
|
num_planes: planes,
|
||||||
offsets: [*offsets.next().unwrap(), *offsets.next().unwrap(), *offsets.next().unwrap(), *offsets.next().unwrap()],
|
offsets: [
|
||||||
strides: [*strides.next().unwrap(), *strides.next().unwrap(), *strides.next().unwrap(), *strides.next().unwrap()],
|
*offsets.next().unwrap(),
|
||||||
fds: [*fds.next().unwrap(), *fds.next().unwrap(), *fds.next().unwrap(), *fds.next().unwrap()],
|
*offsets.next().unwrap(),
|
||||||
|
*offsets.next().unwrap(),
|
||||||
|
*offsets.next().unwrap(),
|
||||||
|
],
|
||||||
|
strides: [
|
||||||
|
*strides.next().unwrap(),
|
||||||
|
*strides.next().unwrap(),
|
||||||
|
*strides.next().unwrap(),
|
||||||
|
*strides.next().unwrap(),
|
||||||
|
],
|
||||||
|
fds: [
|
||||||
|
*fds.next().unwrap(),
|
||||||
|
*fds.next().unwrap(),
|
||||||
|
*fds.next().unwrap(),
|
||||||
|
*fds.next().unwrap(),
|
||||||
|
],
|
||||||
|
|
||||||
width: src.width(),
|
width: src.width(),
|
||||||
height: src.height(),
|
height: src.height(),
|
||||||
|
@ -105,8 +122,7 @@ impl Dmabuf {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn has_modifier(&self) -> bool {
|
pub fn has_modifier(&self) -> bool {
|
||||||
self.0.format.modifier != Modifier::Invalid &&
|
self.0.format.modifier != Modifier::Invalid && self.0.format.modifier != Modifier::Linear
|
||||||
self.0.format.modifier != Modifier::Linear
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn weak(&self) -> WeakDmabuf {
|
pub fn weak(&self) -> WeakDmabuf {
|
||||||
|
@ -128,4 +144,4 @@ impl Drop for DmabufInternal {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ use std::os::unix::io::AsRawFd;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use drm::buffer::Buffer as DrmBuffer;
|
use drm::buffer::Buffer as DrmBuffer;
|
||||||
use drm::control::{Device as ControlDevice, dumbbuffer::DumbBuffer as Handle};
|
use drm::control::{dumbbuffer::DumbBuffer as Handle, Device as ControlDevice};
|
||||||
|
|
||||||
use super::{Allocator, Buffer, Format};
|
use super::{Allocator, Buffer, Format};
|
||||||
use crate::backend::drm::device::{DrmDevice, DrmDeviceInternal, FdWrapper};
|
use crate::backend::drm::device::{DrmDevice, DrmDeviceInternal, FdWrapper};
|
||||||
|
@ -16,8 +16,13 @@ pub struct DumbBuffer<A: AsRawFd + 'static> {
|
||||||
impl<A: AsRawFd + 'static> Allocator<DumbBuffer<A>> for DrmDevice<A> {
|
impl<A: AsRawFd + 'static> Allocator<DumbBuffer<A>> for DrmDevice<A> {
|
||||||
type Error = drm::SystemError;
|
type Error = drm::SystemError;
|
||||||
|
|
||||||
fn create_buffer(&mut self, width: u32, height: u32, format: Format) -> Result<DumbBuffer<A>, Self::Error> {
|
fn create_buffer(
|
||||||
let handle = self.create_dumb_buffer((width, height), format.code, 32/* TODO */)?;
|
&mut self,
|
||||||
|
width: u32,
|
||||||
|
height: u32,
|
||||||
|
format: Format,
|
||||||
|
) -> Result<DumbBuffer<A>, Self::Error> {
|
||||||
|
let handle = self.create_dumb_buffer((width, height), format.code, 32 /* TODO */)?;
|
||||||
|
|
||||||
Ok(DumbBuffer {
|
Ok(DumbBuffer {
|
||||||
fd: match &*self.internal {
|
fd: match &*self.internal {
|
||||||
|
@ -38,7 +43,7 @@ impl<A: AsRawFd + 'static> Buffer for DumbBuffer<A> {
|
||||||
fn height(&self) -> u32 {
|
fn height(&self) -> u32 {
|
||||||
self.handle.size().1
|
self.handle.size().1
|
||||||
}
|
}
|
||||||
|
|
||||||
fn format(&self) -> Format {
|
fn format(&self) -> Format {
|
||||||
self.format
|
self.format
|
||||||
}
|
}
|
||||||
|
@ -48,4 +53,4 @@ impl<A: AsRawFd + 'static> Drop for DumbBuffer<A> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
let _ = self.fd.destroy_dumb_buffer(self.handle);
|
let _ = self.fd.destroy_dumb_buffer(self.handle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
|
use super::{dmabuf::Dmabuf, Allocator, Buffer, Format, Fourcc, Modifier};
|
||||||
|
use gbm::{BufferObject as GbmBuffer, BufferObjectFlags, Device as GbmDevice};
|
||||||
use std::os::unix::io::AsRawFd;
|
use std::os::unix::io::AsRawFd;
|
||||||
use gbm::{BufferObject as GbmBuffer, Device as GbmDevice, BufferObjectFlags};
|
|
||||||
use super::{Allocator, Buffer, Format, Fourcc, Modifier, dmabuf::Dmabuf};
|
|
||||||
|
|
||||||
impl<A: AsRawFd + 'static, T> Allocator<GbmBuffer<T>> for GbmDevice<A> {
|
impl<A: AsRawFd + 'static, T> Allocator<GbmBuffer<T>> for GbmDevice<A> {
|
||||||
type Error = std::io::Error;
|
type Error = std::io::Error;
|
||||||
|
@ -13,7 +13,12 @@ impl<A: AsRawFd + 'static, T> Allocator<GbmBuffer<T>> for GbmDevice<A> {
|
||||||
}
|
}
|
||||||
self.create_buffer_object(width, height, format.code, usage)
|
self.create_buffer_object(width, height, format.code, usage)
|
||||||
} else {
|
} else {
|
||||||
self.create_buffer_object_with_modifiers(width, height, format.code, Some(format.modifier).into_iter())
|
self.create_buffer_object_with_modifiers(
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
format.code,
|
||||||
|
Some(format.modifier).into_iter(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -77,15 +82,23 @@ impl<T> std::convert::TryFrom<GbmBuffer<T>> for Dmabuf {
|
||||||
return Err(GbmConvertError::InvalidFD);
|
return Err(GbmConvertError::InvalidFD);
|
||||||
}
|
}
|
||||||
|
|
||||||
let offsets = (0i32..planes).map(|i| buf.offset(i)).collect::<Result<Vec<u32>, gbm::DeviceDestroyedError>>()?;
|
let offsets = (0i32..planes)
|
||||||
let strides = (0i32..planes).map(|i| buf.stride_for_plane(i)).collect::<Result<Vec<u32>, gbm::DeviceDestroyedError>>()?;
|
.map(|i| buf.offset(i))
|
||||||
|
.collect::<Result<Vec<u32>, gbm::DeviceDestroyedError>>()?;
|
||||||
|
let strides = (0i32..planes)
|
||||||
|
.map(|i| buf.stride_for_plane(i))
|
||||||
|
.collect::<Result<Vec<u32>, gbm::DeviceDestroyedError>>()?;
|
||||||
|
|
||||||
Ok(Dmabuf::new(buf, planes as usize, &offsets, &strides, &fds).unwrap())
|
Ok(Dmabuf::new(buf, planes as usize, &offsets, &strides, &fds).unwrap())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Dmabuf {
|
impl Dmabuf {
|
||||||
pub fn import<A: AsRawFd + 'static, T>(&self, gbm: &GbmDevice<A>, usage: BufferObjectFlags) -> std::io::Result<GbmBuffer<T>> {
|
pub fn import<A: AsRawFd + 'static, T>(
|
||||||
|
&self,
|
||||||
|
gbm: &GbmDevice<A>,
|
||||||
|
usage: BufferObjectFlags,
|
||||||
|
) -> std::io::Result<GbmBuffer<T>> {
|
||||||
let buf = &*self.0;
|
let buf = &*self.0;
|
||||||
if self.has_modifier() || buf.num_planes > 1 || buf.offsets[0] != 0 {
|
if self.has_modifier() || buf.num_planes > 1 || buf.offsets[0] != 0 {
|
||||||
gbm.import_buffer_object_from_dma_buf_with_modifiers(
|
gbm.import_buffer_object_from_dma_buf_with_modifiers(
|
||||||
|
@ -106,8 +119,12 @@ impl Dmabuf {
|
||||||
buf.height,
|
buf.height,
|
||||||
buf.strides[0],
|
buf.strides[0],
|
||||||
buf.format.code,
|
buf.format.code,
|
||||||
if buf.format.modifier == Modifier::Linear { usage | BufferObjectFlags::LINEAR } else { usage },
|
if buf.format.modifier == Modifier::Linear {
|
||||||
|
usage | BufferObjectFlags::LINEAR
|
||||||
|
} else {
|
||||||
|
usage
|
||||||
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,18 +1,23 @@
|
||||||
#[cfg(feature = "backend_gbm")]
|
pub mod dmabuf;
|
||||||
pub mod gbm;
|
|
||||||
#[cfg(feature = "backend_drm")]
|
#[cfg(feature = "backend_drm")]
|
||||||
pub mod dumb;
|
pub mod dumb;
|
||||||
pub mod dmabuf;
|
#[cfg(feature = "backend_gbm")]
|
||||||
|
pub mod gbm;
|
||||||
|
|
||||||
mod swapchain;
|
mod swapchain;
|
||||||
pub use swapchain::{Slot, Swapchain, SwapchainError};
|
pub use swapchain::{Slot, Swapchain, SwapchainError};
|
||||||
|
|
||||||
pub use drm_fourcc::{DrmFormat as Format, DrmFourcc as Fourcc, DrmModifier as Modifier, DrmVendor as Vendor, UnrecognizedFourcc, UnrecognizedVendor};
|
pub use drm_fourcc::{
|
||||||
|
DrmFormat as Format, DrmFourcc as Fourcc, DrmModifier as Modifier, DrmVendor as Vendor,
|
||||||
|
UnrecognizedFourcc, UnrecognizedVendor,
|
||||||
|
};
|
||||||
|
|
||||||
pub trait Buffer {
|
pub trait Buffer {
|
||||||
fn width(&self) -> u32;
|
fn width(&self) -> u32;
|
||||||
fn height(&self) -> u32;
|
fn height(&self) -> u32;
|
||||||
fn size(&self) -> (u32, u32) { (self.width(), self.height()) }
|
fn size(&self) -> (u32, u32) {
|
||||||
|
(self.width(), self.height())
|
||||||
|
}
|
||||||
fn format(&self) -> Format;
|
fn format(&self) -> Format;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,4 +25,4 @@ pub trait Allocator<B: Buffer> {
|
||||||
type Error: std::error::Error;
|
type Error: std::error::Error;
|
||||||
|
|
||||||
fn create_buffer(&mut self, width: u32, height: u32, format: Format) -> Result<B, Self::Error>;
|
fn create_buffer(&mut self, width: u32, height: u32, format: Format) -> Result<B, Self::Error>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
use std::sync::{Arc, Mutex, MutexGuard, atomic::{AtomicBool, Ordering}};
|
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
use std::sync::{
|
||||||
|
atomic::{AtomicBool, Ordering},
|
||||||
|
Arc, Mutex, MutexGuard,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::backend::allocator::{Allocator, Buffer, Format};
|
use crate::backend::allocator::{Allocator, Buffer, Format};
|
||||||
|
|
||||||
|
@ -84,12 +87,12 @@ where
|
||||||
|
|
||||||
impl<A, B, D, U, E1, E2> Swapchain<A, B, U, D>
|
impl<A, B, D, U, E1, E2> Swapchain<A, B, U, D>
|
||||||
where
|
where
|
||||||
A: Allocator<B, Error=E1>,
|
A: Allocator<B, Error = E1>,
|
||||||
B: Buffer + TryInto<D, Error=E2>,
|
B: Buffer + TryInto<D, Error = E2>,
|
||||||
D: Buffer,
|
D: Buffer,
|
||||||
E1: std::error::Error + 'static,
|
E1: std::error::Error + 'static,
|
||||||
E2: std::error::Error + 'static,
|
E2: std::error::Error + 'static,
|
||||||
U: 'static
|
U: 'static,
|
||||||
{
|
{
|
||||||
pub fn new(allocator: A, width: u32, height: u32, format: Format) -> Swapchain<A, B, U, D> {
|
pub fn new(allocator: A, width: u32, height: u32, format: Format) -> Swapchain<A, B, U, D> {
|
||||||
Swapchain {
|
Swapchain {
|
||||||
|
@ -107,8 +110,10 @@ where
|
||||||
if free_slot.buffer.is_none() {
|
if free_slot.buffer.is_none() {
|
||||||
free_slot.buffer = Arc::new(Some(
|
free_slot.buffer = Arc::new(Some(
|
||||||
self.allocator
|
self.allocator
|
||||||
.create_buffer(self.width, self.height, self.format).map_err(SwapchainError::AllocationError)?
|
.create_buffer(self.width, self.height, self.format)
|
||||||
.try_into().map_err(SwapchainError::ConversionError)?
|
.map_err(SwapchainError::AllocationError)?
|
||||||
|
.try_into()
|
||||||
|
.map_err(SwapchainError::ConversionError)?,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
assert!(free_slot.buffer.is_some());
|
assert!(free_slot.buffer.is_some());
|
||||||
|
@ -116,7 +121,6 @@ where
|
||||||
if !free_slot.acquired.swap(true, Ordering::SeqCst) {
|
if !free_slot.acquired.swap(true, Ordering::SeqCst) {
|
||||||
return Ok(Some(free_slot.clone()));
|
return Ok(Some(free_slot.clone()));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// no free slots
|
// no free slots
|
||||||
|
@ -132,4 +136,4 @@ where
|
||||||
self.height = height;
|
self.height = height;
|
||||||
self.slots = Default::default();
|
self.slots = Default::default();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,15 @@
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::sync::{Arc, atomic::{AtomicBool, Ordering}};
|
|
||||||
use std::os::unix::io::AsRawFd;
|
use std::os::unix::io::AsRawFd;
|
||||||
|
use std::sync::{
|
||||||
|
atomic::{AtomicBool, Ordering},
|
||||||
|
Arc,
|
||||||
|
};
|
||||||
|
|
||||||
use drm::control::atomic::AtomicModeReq;
|
use drm::control::atomic::AtomicModeReq;
|
||||||
use drm::control::{Device as ControlDevice, AtomicCommitFlags, PropertyValueSet, ResourceHandle, crtc, connector, framebuffer, plane, property};
|
use drm::control::{
|
||||||
|
connector, crtc, framebuffer, plane, property, AtomicCommitFlags, Device as ControlDevice,
|
||||||
|
PropertyValueSet, ResourceHandle,
|
||||||
|
};
|
||||||
|
|
||||||
use super::{DevPath, FdWrapper};
|
use super::{DevPath, FdWrapper};
|
||||||
use crate::backend::drm::error::Error;
|
use crate::backend::drm::error::Error;
|
||||||
|
@ -31,8 +37,12 @@ pub struct AtomicDrmDevice<A: AsRawFd + 'static> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<A: AsRawFd + 'static> AtomicDrmDevice<A> {
|
impl<A: AsRawFd + 'static> AtomicDrmDevice<A> {
|
||||||
pub fn new(fd: Arc<FdWrapper<A>>, active: Arc<AtomicBool>, disable_connectors: bool, logger: ::slog::Logger) -> Result<Self, Error>
|
pub fn new(
|
||||||
{
|
fd: Arc<FdWrapper<A>>,
|
||||||
|
active: Arc<AtomicBool>,
|
||||||
|
disable_connectors: bool,
|
||||||
|
logger: ::slog::Logger,
|
||||||
|
) -> Result<Self, Error> {
|
||||||
let mut dev = AtomicDrmDevice {
|
let mut dev = AtomicDrmDevice {
|
||||||
fd,
|
fd,
|
||||||
active,
|
active,
|
||||||
|
@ -42,17 +52,16 @@ impl<A: AsRawFd + 'static> AtomicDrmDevice<A> {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Enumerate (and save) the current device state.
|
// Enumerate (and save) the current device state.
|
||||||
let res_handles = dev.fd.resource_handles()
|
let res_handles = dev.fd.resource_handles().map_err(|source| Error::Access {
|
||||||
.map_err(|source| Error::Access {
|
errmsg: "Error loading drm resources",
|
||||||
errmsg: "Error loading drm resources",
|
dev: dev.fd.dev_path(),
|
||||||
dev: dev.fd.dev_path(),
|
source,
|
||||||
source,
|
})?;
|
||||||
})?;
|
|
||||||
|
|
||||||
let plane_handles = dev.fd.plane_handles().map_err(|source| Error::Access {
|
let plane_handles = dev.fd.plane_handles().map_err(|source| Error::Access {
|
||||||
errmsg: "Error loading planes",
|
errmsg: "Error loading planes",
|
||||||
dev: dev.fd.dev_path(),
|
dev: dev.fd.dev_path(),
|
||||||
source
|
source,
|
||||||
})?;
|
})?;
|
||||||
let planes = plane_handles.planes();
|
let planes = plane_handles.planes();
|
||||||
|
|
||||||
|
@ -77,7 +86,7 @@ impl<A: AsRawFd + 'static> AtomicDrmDevice<A> {
|
||||||
dev.old_state = old_state;
|
dev.old_state = old_state;
|
||||||
dev.prop_mapping = mapping;
|
dev.prop_mapping = mapping;
|
||||||
trace!(dev.logger, "Mapping: {:#?}", dev.prop_mapping);
|
trace!(dev.logger, "Mapping: {:#?}", dev.prop_mapping);
|
||||||
|
|
||||||
// If the user does not explicitly requests us to skip this,
|
// If the user does not explicitly requests us to skip this,
|
||||||
// we clear out the complete connector<->crtc mapping on device creation.
|
// we clear out the complete connector<->crtc mapping on device creation.
|
||||||
//
|
//
|
||||||
|
@ -167,12 +176,11 @@ impl<A: AsRawFd + 'static> AtomicDrmDevice<A> {
|
||||||
// on top of the state the previous compositor left the device in.
|
// on top of the state the previous compositor left the device in.
|
||||||
// This is because we do commits per surface and not per device, so we do a global
|
// This is because we do commits per surface and not per device, so we do a global
|
||||||
// commit here, to fix any conflicts.
|
// commit here, to fix any conflicts.
|
||||||
let res_handles = self.fd.resource_handles()
|
let res_handles = self.fd.resource_handles().map_err(|source| Error::Access {
|
||||||
.map_err(|source| Error::Access {
|
errmsg: "Error loading drm resources",
|
||||||
errmsg: "Error loading drm resources",
|
dev: self.fd.dev_path(),
|
||||||
dev: self.fd.dev_path(),
|
source,
|
||||||
source,
|
})?;
|
||||||
})?;
|
|
||||||
|
|
||||||
// Disable all connectors (otherwise we might run into conflicting commits when restarting the rendering loop)
|
// Disable all connectors (otherwise we might run into conflicting commits when restarting the rendering loop)
|
||||||
let mut req = AtomicModeReq::new();
|
let mut req = AtomicModeReq::new();
|
||||||
|
@ -206,13 +214,14 @@ impl<A: AsRawFd + 'static> AtomicDrmDevice<A> {
|
||||||
req.add_property(*crtc, *active_prop, property::Value::Boolean(false));
|
req.add_property(*crtc, *active_prop, property::Value::Boolean(false));
|
||||||
req.add_property(*crtc, *mode_prop, property::Value::Unknown(0));
|
req.add_property(*crtc, *mode_prop, property::Value::Unknown(0));
|
||||||
}
|
}
|
||||||
self.fd.atomic_commit(&[AtomicCommitFlags::AllowModeset], req)
|
self.fd
|
||||||
|
.atomic_commit(&[AtomicCommitFlags::AllowModeset], req)
|
||||||
.map_err(|source| Error::Access {
|
.map_err(|source| Error::Access {
|
||||||
errmsg: "Failed to disable connectors",
|
errmsg: "Failed to disable connectors",
|
||||||
dev: self.fd.dev_path(),
|
dev: self.fd.dev_path(),
|
||||||
source,
|
source,
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::sync::{Arc, atomic::{AtomicBool, Ordering}};
|
|
||||||
use std::os::unix::io::AsRawFd;
|
use std::os::unix::io::AsRawFd;
|
||||||
|
use std::sync::{
|
||||||
|
atomic::{AtomicBool, Ordering},
|
||||||
|
Arc,
|
||||||
|
};
|
||||||
|
|
||||||
use drm::control::{Device as ControlDevice, crtc, connector};
|
use drm::control::{connector, crtc, Device as ControlDevice};
|
||||||
|
|
||||||
use super::{DevPath, FdWrapper};
|
use super::{DevPath, FdWrapper};
|
||||||
use crate::backend::drm::error::Error;
|
use crate::backend::drm::error::Error;
|
||||||
|
@ -15,24 +18,27 @@ pub struct LegacyDrmDevice<A: AsRawFd + 'static> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<A: AsRawFd + 'static> LegacyDrmDevice<A> {
|
impl<A: AsRawFd + 'static> LegacyDrmDevice<A> {
|
||||||
pub fn new(fd: Arc<FdWrapper<A>>, active: Arc<AtomicBool>, disable_connectors: bool, logger: slog::Logger) -> Result<Self, Error>
|
pub fn new(
|
||||||
{
|
fd: Arc<FdWrapper<A>>,
|
||||||
|
active: Arc<AtomicBool>,
|
||||||
|
disable_connectors: bool,
|
||||||
|
logger: slog::Logger,
|
||||||
|
) -> Result<Self, Error> {
|
||||||
let mut dev = LegacyDrmDevice {
|
let mut dev = LegacyDrmDevice {
|
||||||
fd,
|
fd,
|
||||||
active,
|
active,
|
||||||
old_state: HashMap::new(),
|
old_state: HashMap::new(),
|
||||||
logger: logger.new(o!("smithay_module" => "backend_drm_legacy", "drm_module" => "device")),
|
logger: logger.new(o!("smithay_module" => "backend_drm_legacy", "drm_module" => "device")),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Enumerate (and save) the current device state.
|
// Enumerate (and save) the current device state.
|
||||||
// We need to keep the previous device configuration to restore the state later,
|
// We need to keep the previous device configuration to restore the state later,
|
||||||
// so we query everything, that we can set.
|
// so we query everything, that we can set.
|
||||||
let res_handles = dev.fd.resource_handles()
|
let res_handles = dev.fd.resource_handles().map_err(|source| Error::Access {
|
||||||
.map_err(|source| Error::Access {
|
errmsg: "Error loading drm resources",
|
||||||
errmsg: "Error loading drm resources",
|
dev: dev.fd.dev_path(),
|
||||||
dev: dev.fd.dev_path(),
|
source,
|
||||||
source,
|
})?;
|
||||||
})?;
|
|
||||||
for &con in res_handles.connectors() {
|
for &con in res_handles.connectors() {
|
||||||
let con_info = dev.fd.get_connector(con).map_err(|source| Error::Access {
|
let con_info = dev.fd.get_connector(con).map_err(|source| Error::Access {
|
||||||
errmsg: "Error loading connector info",
|
errmsg: "Error loading connector info",
|
||||||
|
@ -60,7 +66,6 @@ impl<A: AsRawFd + 'static> LegacyDrmDevice<A> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// If the user does not explicitly requests us to skip this,
|
// If the user does not explicitly requests us to skip this,
|
||||||
// we clear out the complete connector<->crtc mapping on device creation.
|
// we clear out the complete connector<->crtc mapping on device creation.
|
||||||
//
|
//
|
||||||
|
@ -83,17 +88,18 @@ impl<A: AsRawFd + 'static> LegacyDrmDevice<A> {
|
||||||
})?;
|
})?;
|
||||||
set_connector_state(&*self.fd, res_handles.connectors().iter().copied(), false)?;
|
set_connector_state(&*self.fd, res_handles.connectors().iter().copied(), false)?;
|
||||||
|
|
||||||
for crtc in res_handles.crtcs() {
|
for crtc in res_handles.crtcs() {
|
||||||
// null commit (necessary to trigger removal on the kernel side with the legacy api.)
|
// null commit (necessary to trigger removal on the kernel side with the legacy api.)
|
||||||
self.fd.set_crtc(*crtc, None, (0, 0), &[], None)
|
self.fd
|
||||||
.map_err(|source| Error::Access {
|
.set_crtc(*crtc, None, (0, 0), &[], None)
|
||||||
errmsg: "Error setting crtc",
|
.map_err(|source| Error::Access {
|
||||||
dev: self.fd.dev_path(),
|
errmsg: "Error setting crtc",
|
||||||
source,
|
dev: self.fd.dev_path(),
|
||||||
})?;
|
source,
|
||||||
}
|
})?;
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,38 +133,32 @@ pub fn set_connector_state<D>(
|
||||||
enabled: bool,
|
enabled: bool,
|
||||||
) -> Result<(), Error>
|
) -> Result<(), Error>
|
||||||
where
|
where
|
||||||
D: ControlDevice
|
D: ControlDevice,
|
||||||
{
|
{
|
||||||
// for every connector...
|
// for every connector...
|
||||||
for conn in connectors {
|
for conn in connectors {
|
||||||
let info = dev
|
let info = dev.get_connector(conn).map_err(|source| Error::Access {
|
||||||
.get_connector(conn)
|
errmsg: "Failed to get connector infos",
|
||||||
.map_err(|source| Error::Access {
|
dev: dev.dev_path(),
|
||||||
errmsg: "Failed to get connector infos",
|
source,
|
||||||
dev: dev.dev_path(),
|
})?;
|
||||||
source,
|
|
||||||
})?;
|
|
||||||
// that is currently connected ...
|
// that is currently connected ...
|
||||||
if info.state() == connector::State::Connected {
|
if info.state() == connector::State::Connected {
|
||||||
// get a list of it's properties.
|
// get a list of it's properties.
|
||||||
let props = dev
|
let props = dev.get_properties(conn).map_err(|source| Error::Access {
|
||||||
.get_properties(conn)
|
errmsg: "Failed to get properties for connector",
|
||||||
.map_err(|source| Error::Access {
|
dev: dev.dev_path(),
|
||||||
errmsg: "Failed to get properties for connector",
|
source,
|
||||||
dev: dev.dev_path(),
|
})?;
|
||||||
source,
|
|
||||||
})?;
|
|
||||||
let (handles, _) = props.as_props_and_values();
|
let (handles, _) = props.as_props_and_values();
|
||||||
// for every handle ...
|
// for every handle ...
|
||||||
for handle in handles {
|
for handle in handles {
|
||||||
// get information of that property
|
// get information of that property
|
||||||
let info = dev
|
let info = dev.get_property(*handle).map_err(|source| Error::Access {
|
||||||
.get_property(*handle)
|
errmsg: "Failed to get property of connector",
|
||||||
.map_err(|source| Error::Access {
|
dev: dev.dev_path(),
|
||||||
errmsg: "Failed to get property of connector",
|
source,
|
||||||
dev: dev.dev_path(),
|
})?;
|
||||||
source,
|
|
||||||
})?;
|
|
||||||
// to find out, if we got the handle of the "DPMS" property ...
|
// to find out, if we got the handle of the "DPMS" property ...
|
||||||
if info.name().to_str().map(|x| x == "DPMS").unwrap_or(false) {
|
if info.name().to_str().map(|x| x == "DPMS").unwrap_or(false) {
|
||||||
// so we can use that to turn on / off the connector
|
// so we can use that to turn on / off the connector
|
||||||
|
@ -181,4 +181,4 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,24 +1,27 @@
|
||||||
use std::rc::Rc;
|
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::sync::{Arc, atomic::AtomicBool};
|
|
||||||
use std::path::PathBuf;
|
|
||||||
use std::os::unix::io::{AsRawFd, RawFd};
|
use std::os::unix::io::{AsRawFd, RawFd};
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use std::rc::Rc;
|
||||||
|
use std::sync::{atomic::AtomicBool, Arc};
|
||||||
|
|
||||||
use calloop::{generic::Generic, InsertError, LoopHandle, Source};
|
use calloop::{generic::Generic, InsertError, LoopHandle, Source};
|
||||||
use drm::{Device as BasicDevice, ClientCapability, DriverCapability};
|
use drm::control::{
|
||||||
use drm::control::{ResourceHandles, PlaneResourceHandles, Device as ControlDevice, Event, Mode, PlaneType, crtc, plane, connector, property};
|
connector, crtc, plane, property, Device as ControlDevice, Event, Mode, PlaneResourceHandles, PlaneType,
|
||||||
|
ResourceHandles,
|
||||||
|
};
|
||||||
|
use drm::{ClientCapability, Device as BasicDevice, DriverCapability};
|
||||||
use nix::libc::dev_t;
|
use nix::libc::dev_t;
|
||||||
use nix::sys::stat::fstat;
|
use nix::sys::stat::fstat;
|
||||||
|
|
||||||
pub(super) mod atomic;
|
pub(super) mod atomic;
|
||||||
pub(super) mod legacy;
|
pub(super) mod legacy;
|
||||||
|
use super::error::Error;
|
||||||
|
use super::surface::{atomic::AtomicDrmSurface, legacy::LegacyDrmSurface, DrmSurface, DrmSurfaceInternal};
|
||||||
|
use crate::backend::allocator::{Format, Fourcc, Modifier};
|
||||||
use atomic::AtomicDrmDevice;
|
use atomic::AtomicDrmDevice;
|
||||||
use legacy::LegacyDrmDevice;
|
use legacy::LegacyDrmDevice;
|
||||||
use super::surface::{DrmSurface, DrmSurfaceInternal, atomic::AtomicDrmSurface, legacy::LegacyDrmSurface};
|
|
||||||
use super::error::Error;
|
|
||||||
use crate::backend::allocator::{Fourcc, Format, Modifier};
|
|
||||||
|
|
||||||
pub struct DrmDevice<A: AsRawFd + 'static> {
|
pub struct DrmDevice<A: AsRawFd + 'static> {
|
||||||
pub(super) dev_id: dev_t,
|
pub(super) dev_id: dev_t,
|
||||||
|
@ -91,10 +94,8 @@ impl<A: AsRawFd + 'static> DrmDevice<A> {
|
||||||
{
|
{
|
||||||
let log = crate::slog_or_fallback(logger).new(o!("smithay_module" => "backend_drm"));
|
let log = crate::slog_or_fallback(logger).new(o!("smithay_module" => "backend_drm"));
|
||||||
info!(log, "DrmDevice initializing");
|
info!(log, "DrmDevice initializing");
|
||||||
|
|
||||||
let dev_id = fstat(fd.as_raw_fd())
|
let dev_id = fstat(fd.as_raw_fd()).map_err(Error::UnableToGetDeviceId)?.st_rdev;
|
||||||
.map_err(Error::UnableToGetDeviceId)?
|
|
||||||
.st_rdev;
|
|
||||||
let active = Arc::new(AtomicBool::new(true));
|
let active = Arc::new(AtomicBool::new(true));
|
||||||
let dev = Arc::new({
|
let dev = Arc::new({
|
||||||
let mut dev = FdWrapper {
|
let mut dev = FdWrapper {
|
||||||
|
@ -115,7 +116,9 @@ impl<A: AsRawFd + 'static> DrmDevice<A> {
|
||||||
dev
|
dev
|
||||||
});
|
});
|
||||||
|
|
||||||
let has_universal_planes = dev.set_client_capability(ClientCapability::UniversalPlanes, true).is_ok();
|
let has_universal_planes = dev
|
||||||
|
.set_client_capability(ClientCapability::UniversalPlanes, true)
|
||||||
|
.is_ok();
|
||||||
let resources = dev.resource_handles().map_err(|source| Error::Access {
|
let resources = dev.resource_handles().map_err(|source| Error::Access {
|
||||||
errmsg: "Error loading resource handles",
|
errmsg: "Error loading resource handles",
|
||||||
dev: dev.dev_path(),
|
dev: dev.dev_path(),
|
||||||
|
@ -126,7 +129,12 @@ impl<A: AsRawFd + 'static> DrmDevice<A> {
|
||||||
dev: dev.dev_path(),
|
dev: dev.dev_path(),
|
||||||
source,
|
source,
|
||||||
})?;
|
})?;
|
||||||
let internal = Arc::new(DrmDevice::create_internal(dev, active, disable_connectors, log.clone())?);
|
let internal = Arc::new(DrmDevice::create_internal(
|
||||||
|
dev,
|
||||||
|
active,
|
||||||
|
disable_connectors,
|
||||||
|
log.clone(),
|
||||||
|
)?);
|
||||||
|
|
||||||
Ok(DrmDevice {
|
Ok(DrmDevice {
|
||||||
dev_id,
|
dev_id,
|
||||||
|
@ -141,7 +149,12 @@ impl<A: AsRawFd + 'static> DrmDevice<A> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_internal(dev: Arc<FdWrapper<A>>, active: Arc<AtomicBool>, disable_connectors: bool, log: ::slog::Logger) -> Result<DrmDeviceInternal<A>, Error> {
|
fn create_internal(
|
||||||
|
dev: Arc<FdWrapper<A>>,
|
||||||
|
active: Arc<AtomicBool>,
|
||||||
|
disable_connectors: bool,
|
||||||
|
log: ::slog::Logger,
|
||||||
|
) -> Result<DrmDeviceInternal<A>, Error> {
|
||||||
let force_legacy = std::env::var("SMITHAY_USE_LEGACY")
|
let force_legacy = std::env::var("SMITHAY_USE_LEGACY")
|
||||||
.map(|x| {
|
.map(|x| {
|
||||||
x == "1" || x.to_lowercase() == "true" || x.to_lowercase() == "yes" || x.to_lowercase() == "y"
|
x == "1" || x.to_lowercase() == "true" || x.to_lowercase() == "yes" || x.to_lowercase() == "y"
|
||||||
|
@ -151,13 +164,15 @@ impl<A: AsRawFd + 'static> DrmDevice<A> {
|
||||||
if force_legacy {
|
if force_legacy {
|
||||||
info!(log, "SMITHAY_USE_LEGACY is set. Forcing LegacyDrmDevice.");
|
info!(log, "SMITHAY_USE_LEGACY is set. Forcing LegacyDrmDevice.");
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(if dev.set_client_capability(ClientCapability::Atomic, true).is_ok() && !force_legacy {
|
Ok(
|
||||||
DrmDeviceInternal::Atomic(AtomicDrmDevice::new(dev, active, disable_connectors, log)?)
|
if dev.set_client_capability(ClientCapability::Atomic, true).is_ok() && !force_legacy {
|
||||||
} else {
|
DrmDeviceInternal::Atomic(AtomicDrmDevice::new(dev, active, disable_connectors, log)?)
|
||||||
info!(log, "Falling back to LegacyDrmDevice");
|
} else {
|
||||||
DrmDeviceInternal::Legacy(LegacyDrmDevice::new(dev, active, disable_connectors, log)?)
|
info!(log, "Falling back to LegacyDrmDevice");
|
||||||
})
|
DrmDeviceInternal::Legacy(LegacyDrmDevice::new(dev, active, disable_connectors, log)?)
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn process_events(&mut self) {
|
pub fn process_events(&mut self) {
|
||||||
|
@ -196,7 +211,7 @@ impl<A: AsRawFd + 'static> DrmDevice<A> {
|
||||||
DrmDeviceInternal::Legacy(_) => false,
|
DrmDeviceInternal::Legacy(_) => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_handler(&mut self, handler: impl DeviceHandler + 'static) {
|
pub fn set_handler(&mut self, handler: impl DeviceHandler + 'static) {
|
||||||
let handler = Some(Box::new(handler) as Box<dyn DeviceHandler + 'static>);
|
let handler = Some(Box::new(handler) as Box<dyn DeviceHandler + 'static>);
|
||||||
*self.handler.borrow_mut() = handler;
|
*self.handler.borrow_mut() = handler;
|
||||||
|
@ -219,14 +234,20 @@ impl<A: AsRawFd + 'static> DrmDevice<A> {
|
||||||
let info = self.get_plane(*plane).map_err(|source| Error::Access {
|
let info = self.get_plane(*plane).map_err(|source| Error::Access {
|
||||||
errmsg: "Failed to get plane information",
|
errmsg: "Failed to get plane information",
|
||||||
dev: self.dev_path(),
|
dev: self.dev_path(),
|
||||||
source,
|
source,
|
||||||
})?;
|
})?;
|
||||||
let filter = info.possible_crtcs();
|
let filter = info.possible_crtcs();
|
||||||
if self.resources.filter_crtcs(filter).contains(crtc) {
|
if self.resources.filter_crtcs(filter).contains(crtc) {
|
||||||
match self.plane_type(*plane)? {
|
match self.plane_type(*plane)? {
|
||||||
PlaneType::Primary => { primary = Some(*plane); },
|
PlaneType::Primary => {
|
||||||
PlaneType::Cursor => { cursor = Some(*plane); },
|
primary = Some(*plane);
|
||||||
PlaneType::Overlay => { overlay.push(*plane); },
|
}
|
||||||
|
PlaneType::Cursor => {
|
||||||
|
cursor = Some(*plane);
|
||||||
|
}
|
||||||
|
PlaneType::Overlay => {
|
||||||
|
overlay.push(*plane);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -234,7 +255,11 @@ impl<A: AsRawFd + 'static> DrmDevice<A> {
|
||||||
Ok(Planes {
|
Ok(Planes {
|
||||||
primary: primary.expect("Crtc has no primary plane"),
|
primary: primary.expect("Crtc has no primary plane"),
|
||||||
cursor,
|
cursor,
|
||||||
overlay: if self.has_universal_planes { Some(overlay) } else { None },
|
overlay: if self.has_universal_planes {
|
||||||
|
Some(overlay)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -242,14 +267,14 @@ impl<A: AsRawFd + 'static> DrmDevice<A> {
|
||||||
let props = self.get_properties(plane).map_err(|source| Error::Access {
|
let props = self.get_properties(plane).map_err(|source| Error::Access {
|
||||||
errmsg: "Failed to get properties of plane",
|
errmsg: "Failed to get properties of plane",
|
||||||
dev: self.dev_path(),
|
dev: self.dev_path(),
|
||||||
source,
|
source,
|
||||||
})?;
|
})?;
|
||||||
let (ids, vals) = props.as_props_and_values();
|
let (ids, vals) = props.as_props_and_values();
|
||||||
for (&id, &val) in ids.iter().zip(vals.iter()) {
|
for (&id, &val) in ids.iter().zip(vals.iter()) {
|
||||||
let info = self.get_property(id).map_err(|source| Error::Access {
|
let info = self.get_property(id).map_err(|source| Error::Access {
|
||||||
errmsg: "Failed to get property info",
|
errmsg: "Failed to get property info",
|
||||||
dev: self.dev_path(),
|
dev: self.dev_path(),
|
||||||
source,
|
source,
|
||||||
})?;
|
})?;
|
||||||
if info.name().to_str().map(|x| x == "type").unwrap_or(false) {
|
if info.name().to_str().map(|x| x == "type").unwrap_or(false) {
|
||||||
return Ok(match val {
|
return Ok(match val {
|
||||||
|
@ -262,21 +287,27 @@ impl<A: AsRawFd + 'static> DrmDevice<A> {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_surface(&self, crtc: crtc::Handle, plane: plane::Handle, mode: Mode, connectors: &[connector::Handle]) -> Result<DrmSurface<A>, Error> {
|
pub fn create_surface(
|
||||||
|
&self,
|
||||||
|
crtc: crtc::Handle,
|
||||||
|
plane: plane::Handle,
|
||||||
|
mode: Mode,
|
||||||
|
connectors: &[connector::Handle],
|
||||||
|
) -> Result<DrmSurface<A>, Error> {
|
||||||
if connectors.is_empty() {
|
if connectors.is_empty() {
|
||||||
return Err(Error::SurfaceWithoutConnectors(crtc));
|
return Err(Error::SurfaceWithoutConnectors(crtc));
|
||||||
}
|
}
|
||||||
|
|
||||||
let info = self.get_plane(plane).map_err(|source| Error::Access {
|
let info = self.get_plane(plane).map_err(|source| Error::Access {
|
||||||
errmsg: "Failed to get plane info",
|
errmsg: "Failed to get plane info",
|
||||||
dev: self.dev_path(),
|
dev: self.dev_path(),
|
||||||
source
|
source,
|
||||||
})?;
|
})?;
|
||||||
let filter = info.possible_crtcs();
|
let filter = info.possible_crtcs();
|
||||||
if !self.resources.filter_crtcs(filter).contains(&crtc) {
|
if !self.resources.filter_crtcs(filter).contains(&crtc) {
|
||||||
return Err(Error::PlaneNotCompatible(crtc, plane));
|
return Err(Error::PlaneNotCompatible(crtc, plane));
|
||||||
}
|
}
|
||||||
|
|
||||||
let active = match &*self.internal {
|
let active = match &*self.internal {
|
||||||
DrmDeviceInternal::Atomic(dev) => dev.active.clone(),
|
DrmDeviceInternal::Atomic(dev) => dev.active.clone(),
|
||||||
DrmDeviceInternal::Legacy(dev) => dev.active.clone(),
|
DrmDeviceInternal::Legacy(dev) => dev.active.clone(),
|
||||||
|
@ -288,13 +319,29 @@ impl<A: AsRawFd + 'static> DrmDevice<A> {
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
DrmSurfaceInternal::Atomic(AtomicDrmSurface::new(self.internal.clone(), active, crtc, plane, mapping, mode, connectors, self.logger.clone())?)
|
DrmSurfaceInternal::Atomic(AtomicDrmSurface::new(
|
||||||
|
self.internal.clone(),
|
||||||
|
active,
|
||||||
|
crtc,
|
||||||
|
plane,
|
||||||
|
mapping,
|
||||||
|
mode,
|
||||||
|
connectors,
|
||||||
|
self.logger.clone(),
|
||||||
|
)?)
|
||||||
} else {
|
} else {
|
||||||
if self.plane_type(plane)? != PlaneType::Primary {
|
if self.plane_type(plane)? != PlaneType::Primary {
|
||||||
return Err(Error::NonPrimaryPlane(plane));
|
return Err(Error::NonPrimaryPlane(plane));
|
||||||
}
|
}
|
||||||
|
|
||||||
DrmSurfaceInternal::Legacy(LegacyDrmSurface::new(self.internal.clone(), active, crtc, mode, connectors, self.logger.clone())?)
|
DrmSurfaceInternal::Legacy(LegacyDrmSurface::new(
|
||||||
|
self.internal.clone(),
|
||||||
|
active,
|
||||||
|
crtc,
|
||||||
|
mode,
|
||||||
|
connectors,
|
||||||
|
self.logger.clone(),
|
||||||
|
)?)
|
||||||
};
|
};
|
||||||
|
|
||||||
// get plane formats
|
// get plane formats
|
||||||
|
@ -304,18 +351,25 @@ impl<A: AsRawFd + 'static> DrmDevice<A> {
|
||||||
source,
|
source,
|
||||||
})?;
|
})?;
|
||||||
let mut formats = HashSet::new();
|
let mut formats = HashSet::new();
|
||||||
for code in plane_info.formats().iter().flat_map(|x| Fourcc::try_from(*x).ok()) {
|
for code in plane_info
|
||||||
|
.formats()
|
||||||
|
.iter()
|
||||||
|
.flat_map(|x| Fourcc::try_from(*x).ok())
|
||||||
|
{
|
||||||
formats.insert(Format {
|
formats.insert(Format {
|
||||||
code,
|
code,
|
||||||
modifier: Modifier::Invalid,
|
modifier: Modifier::Invalid,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if let (Ok(1), &DrmSurfaceInternal::Atomic(ref surf)) = (self.get_driver_capability(DriverCapability::AddFB2Modifiers), &internal) {
|
if let (Ok(1), &DrmSurfaceInternal::Atomic(ref surf)) = (
|
||||||
|
self.get_driver_capability(DriverCapability::AddFB2Modifiers),
|
||||||
|
&internal,
|
||||||
|
) {
|
||||||
let set = self.get_properties(plane).map_err(|source| Error::Access {
|
let set = self.get_properties(plane).map_err(|source| Error::Access {
|
||||||
errmsg: "Failed to query properties",
|
errmsg: "Failed to query properties",
|
||||||
dev: self.dev_path(),
|
dev: self.dev_path(),
|
||||||
source
|
source,
|
||||||
})?;
|
})?;
|
||||||
if let Ok(prop) = surf.plane_prop_handle(plane, "IN_FORMATS") {
|
if let Ok(prop) = surf.plane_prop_handle(plane, "IN_FORMATS") {
|
||||||
let prop_info = self.get_property(prop).map_err(|source| Error::Access {
|
let prop_info = self.get_property(prop).map_err(|source| Error::Access {
|
||||||
|
@ -324,7 +378,11 @@ impl<A: AsRawFd + 'static> DrmDevice<A> {
|
||||||
source,
|
source,
|
||||||
})?;
|
})?;
|
||||||
let (handles, raw_values) = set.as_props_and_values();
|
let (handles, raw_values) = set.as_props_and_values();
|
||||||
let raw_value = raw_values[handles.iter().enumerate().find_map(|(i, handle)| if *handle == prop { Some(i) } else { None }).unwrap()];
|
let raw_value = raw_values[handles
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.find_map(|(i, handle)| if *handle == prop { Some(i) } else { None })
|
||||||
|
.unwrap()];
|
||||||
if let property::Value::Blob(blob) = prop_info.value_type().convert_value(raw_value) {
|
if let property::Value::Blob(blob) = prop_info.value_type().convert_value(raw_value) {
|
||||||
let data = self.get_property_blob(blob).map_err(|source| Error::Access {
|
let data = self.get_property_blob(blob).map_err(|source| Error::Access {
|
||||||
errmsg: "Failed to query property blob data",
|
errmsg: "Failed to query property blob data",
|
||||||
|
@ -337,8 +395,14 @@ impl<A: AsRawFd + 'static> DrmDevice<A> {
|
||||||
let fmt_mod_blob_ptr = data.as_ptr() as *const drm_ffi::drm_format_modifier_blob;
|
let fmt_mod_blob_ptr = data.as_ptr() as *const drm_ffi::drm_format_modifier_blob;
|
||||||
let fmt_mod_blob = &*fmt_mod_blob_ptr;
|
let fmt_mod_blob = &*fmt_mod_blob_ptr;
|
||||||
|
|
||||||
let formats_ptr: *const u32 = fmt_mod_blob_ptr.cast::<u8>().offset(fmt_mod_blob.formats_offset as isize) as *const _;
|
let formats_ptr: *const u32 = fmt_mod_blob_ptr
|
||||||
let modifiers_ptr: *const drm_ffi::drm_format_modifier = fmt_mod_blob_ptr.cast::<u8>().offset(fmt_mod_blob.modifiers_offset as isize) as *const _;
|
.cast::<u8>()
|
||||||
|
.offset(fmt_mod_blob.formats_offset as isize)
|
||||||
|
as *const _;
|
||||||
|
let modifiers_ptr: *const drm_ffi::drm_format_modifier = fmt_mod_blob_ptr
|
||||||
|
.cast::<u8>()
|
||||||
|
.offset(fmt_mod_blob.modifiers_offset as isize)
|
||||||
|
as *const _;
|
||||||
let formats_ptr = formats_ptr as *const u32;
|
let formats_ptr = formats_ptr as *const u32;
|
||||||
let modifiers_ptr = modifiers_ptr as *const drm_ffi::drm_format_modifier;
|
let modifiers_ptr = modifiers_ptr as *const drm_ffi::drm_format_modifier;
|
||||||
|
|
||||||
|
@ -346,13 +410,15 @@ impl<A: AsRawFd + 'static> DrmDevice<A> {
|
||||||
let mod_info = modifiers_ptr.offset(i as isize).read_unaligned();
|
let mod_info = modifiers_ptr.offset(i as isize).read_unaligned();
|
||||||
for j in 0..64 {
|
for j in 0..64 {
|
||||||
if mod_info.formats & (1u64 << j) != 0 {
|
if mod_info.formats & (1u64 << j) != 0 {
|
||||||
let code = Fourcc::try_from(formats_ptr.offset((j + mod_info.offset) as isize).read_unaligned()).ok();
|
let code = Fourcc::try_from(
|
||||||
|
formats_ptr
|
||||||
|
.offset((j + mod_info.offset) as isize)
|
||||||
|
.read_unaligned(),
|
||||||
|
)
|
||||||
|
.ok();
|
||||||
let modifier = Modifier::from(mod_info.modifier);
|
let modifier = Modifier::from(mod_info.modifier);
|
||||||
if let Some(code) = code {
|
if let Some(code) = code {
|
||||||
formats.insert(Format {
|
formats.insert(Format { code, modifier });
|
||||||
code,
|
|
||||||
modifier,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -377,7 +443,10 @@ impl<A: AsRawFd + 'static> DrmDevice<A> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
info!(self.logger, "Supported scan-out formats for plane ({:?}): {:?}", plane, formats);
|
info!(
|
||||||
|
self.logger,
|
||||||
|
"Supported scan-out formats for plane ({:?}): {:?}", plane, formats
|
||||||
|
);
|
||||||
|
|
||||||
Ok(DrmSurface {
|
Ok(DrmSurface {
|
||||||
crtc,
|
crtc,
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
//use crate::backend::graphics::SwapBuffersError;
|
//use crate::backend::graphics::SwapBuffersError;
|
||||||
|
use crate::backend::SwapBuffersError;
|
||||||
use drm::control::{connector, crtc, plane, Mode, RawResourceHandle};
|
use drm::control::{connector, crtc, plane, Mode, RawResourceHandle};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use crate::backend::SwapBuffersError;
|
|
||||||
|
|
||||||
/// Errors thrown by the [`DrmDevice`](::backend::drm::DrmDevice)
|
/// Errors thrown by the [`DrmDevice`](::backend::drm::DrmDevice)
|
||||||
/// and the [`DrmSurface`](::backend::drm::DrmSurface).
|
/// and the [`DrmSurface`](::backend::drm::DrmSurface).
|
||||||
|
@ -66,14 +66,15 @@ impl From<Error> for SwapBuffersError {
|
||||||
x @ Error::DeviceInactive => SwapBuffersError::TemporaryFailure(Box::new(x)),
|
x @ Error::DeviceInactive => SwapBuffersError::TemporaryFailure(Box::new(x)),
|
||||||
Error::Access {
|
Error::Access {
|
||||||
errmsg, dev, source, ..
|
errmsg, dev, source, ..
|
||||||
} if matches!(source,
|
} if matches!(
|
||||||
drm::SystemError::PermissionDenied |
|
source,
|
||||||
drm::SystemError::Unknown {
|
drm::SystemError::PermissionDenied
|
||||||
errno: nix::errno::Errno::EBUSY,
|
| drm::SystemError::Unknown {
|
||||||
} |
|
errno: nix::errno::Errno::EBUSY,
|
||||||
drm::SystemError::Unknown {
|
}
|
||||||
errno: nix::errno::Errno::EINTR,
|
| drm::SystemError::Unknown {
|
||||||
}
|
errno: nix::errno::Errno::EINTR,
|
||||||
|
}
|
||||||
) =>
|
) =>
|
||||||
{
|
{
|
||||||
SwapBuffersError::TemporaryFailure(Box::new(Error::Access { errmsg, dev, source }))
|
SwapBuffersError::TemporaryFailure(Box::new(Error::Access { errmsg, dev, source }))
|
||||||
|
@ -81,4 +82,4 @@ impl From<Error> for SwapBuffersError {
|
||||||
x => SwapBuffersError::ContextLost(Box::new(x)),
|
x => SwapBuffersError::ContextLost(Box::new(x)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
pub(crate) mod device;
|
pub(crate) mod device;
|
||||||
pub(self) mod surface;
|
|
||||||
pub(self) mod error;
|
pub(self) mod error;
|
||||||
pub(self) mod session;
|
|
||||||
mod render;
|
mod render;
|
||||||
|
pub(self) mod session;
|
||||||
|
pub(self) mod surface;
|
||||||
|
|
||||||
pub use device::{DrmDevice, DrmSource, DeviceHandler, device_bind, Planes, DevPath};
|
pub use device::{device_bind, DevPath, DeviceHandler, DrmDevice, DrmSource, Planes};
|
||||||
pub use surface::DrmSurface;
|
|
||||||
pub use error::Error as DrmError;
|
pub use error::Error as DrmError;
|
||||||
|
pub use render::{DrmRenderSurface, Error as DrmRenderError};
|
||||||
pub use session::DrmDeviceObserver;
|
pub use session::DrmDeviceObserver;
|
||||||
pub use render::{DrmRenderSurface, Error as DrmRenderError};
|
pub use surface::DrmSurface;
|
||||||
|
|
|
@ -1,20 +1,22 @@
|
||||||
use std::os::unix::io::AsRawFd;
|
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
|
use std::os::unix::io::AsRawFd;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use cgmath::Matrix3;
|
use cgmath::Matrix3;
|
||||||
use drm::buffer::PlanarBuffer;
|
use drm::buffer::PlanarBuffer;
|
||||||
use drm::control::{Device, Mode, crtc, connector, framebuffer, plane};
|
use drm::control::{connector, crtc, framebuffer, plane, Device, Mode};
|
||||||
use gbm::{Device as GbmDevice, BufferObject, BufferObjectFlags};
|
use gbm::{BufferObject, BufferObjectFlags, Device as GbmDevice};
|
||||||
#[cfg(feature = "wayland_frontend")]
|
#[cfg(feature = "wayland_frontend")]
|
||||||
use wayland_server::protocol::{wl_shm, wl_buffer};
|
use wayland_server::protocol::{wl_buffer, wl_shm};
|
||||||
|
|
||||||
use crate::backend::SwapBuffersError;
|
use super::{device::DevPath, surface::DrmSurfaceInternal, DrmError, DrmSurface};
|
||||||
use crate::backend::allocator::{Allocator, Format, Fourcc, Modifier, Swapchain, SwapchainError, Slot, Buffer, dmabuf::Dmabuf};
|
use crate::backend::allocator::{
|
||||||
use crate::backend::renderer::{Renderer, Bind, Transform, Texture};
|
dmabuf::Dmabuf, Allocator, Buffer, Format, Fourcc, Modifier, Slot, Swapchain, SwapchainError,
|
||||||
|
};
|
||||||
use crate::backend::egl::EGLBuffer;
|
use crate::backend::egl::EGLBuffer;
|
||||||
use super::{DrmSurface, DrmError, device::DevPath, surface::DrmSurfaceInternal};
|
use crate::backend::renderer::{Bind, Renderer, Texture, Transform};
|
||||||
|
use crate::backend::SwapBuffersError;
|
||||||
|
|
||||||
pub struct DrmRenderSurface<
|
pub struct DrmRenderSurface<
|
||||||
D: AsRawFd + 'static,
|
D: AsRawFd + 'static,
|
||||||
|
@ -33,16 +35,20 @@ pub struct DrmRenderSurface<
|
||||||
impl<D, A, B, R, E1, E2, E3> DrmRenderSurface<D, A, R, B>
|
impl<D, A, B, R, E1, E2, E3> DrmRenderSurface<D, A, R, B>
|
||||||
where
|
where
|
||||||
D: AsRawFd + 'static,
|
D: AsRawFd + 'static,
|
||||||
A: Allocator<B, Error=E1>,
|
A: Allocator<B, Error = E1>,
|
||||||
B: Buffer + TryInto<Dmabuf, Error=E2>,
|
B: Buffer + TryInto<Dmabuf, Error = E2>,
|
||||||
R: Bind<Dmabuf> + Renderer<Error=E3>,
|
R: Bind<Dmabuf> + Renderer<Error = E3>,
|
||||||
E1: std::error::Error + 'static,
|
E1: std::error::Error + 'static,
|
||||||
E2: std::error::Error + 'static,
|
E2: std::error::Error + 'static,
|
||||||
E3: std::error::Error + 'static,
|
E3: std::error::Error + 'static,
|
||||||
{
|
{
|
||||||
#[allow(clippy::type_complexity)]
|
#[allow(clippy::type_complexity)]
|
||||||
pub fn new<L: Into<Option<::slog::Logger>>>(drm: DrmSurface<D>, allocator: A, renderer: R, log: L) -> Result<DrmRenderSurface<D, A, R, B>, Error<E1, E2, E3>>
|
pub fn new<L: Into<Option<::slog::Logger>>>(
|
||||||
{
|
drm: DrmSurface<D>,
|
||||||
|
allocator: A,
|
||||||
|
renderer: R,
|
||||||
|
log: L,
|
||||||
|
) -> Result<DrmRenderSurface<D, A, R, B>, Error<E1, E2, E3>> {
|
||||||
// we cannot simply pick the first supported format of the intersection of *all* formats, because:
|
// we cannot simply pick the first supported format of the intersection of *all* formats, because:
|
||||||
// - we do not want something like Abgr4444, which looses color information
|
// - we do not want something like Abgr4444, which looses color information
|
||||||
// - some formats might perform terribly
|
// - some formats might perform terribly
|
||||||
|
@ -56,14 +62,29 @@ where
|
||||||
let logger = crate::slog_or_fallback(log).new(o!("backend" => "drm_render"));
|
let logger = crate::slog_or_fallback(log).new(o!("backend" => "drm_render"));
|
||||||
|
|
||||||
// select a format
|
// select a format
|
||||||
let plane_formats = drm.supported_formats().iter().filter(|fmt| fmt.code == code).cloned().collect::<HashSet<_>>();
|
let plane_formats = drm
|
||||||
let renderer_formats = Bind::<Dmabuf>::supported_formats(&renderer).expect("Dmabuf renderer without formats")
|
.supported_formats()
|
||||||
.iter().filter(|fmt| fmt.code == code).cloned().collect::<HashSet<_>>();
|
.iter()
|
||||||
|
.filter(|fmt| fmt.code == code)
|
||||||
|
.cloned()
|
||||||
|
.collect::<HashSet<_>>();
|
||||||
|
let renderer_formats = Bind::<Dmabuf>::supported_formats(&renderer)
|
||||||
|
.expect("Dmabuf renderer without formats")
|
||||||
|
.iter()
|
||||||
|
.filter(|fmt| fmt.code == code)
|
||||||
|
.cloned()
|
||||||
|
.collect::<HashSet<_>>();
|
||||||
|
|
||||||
trace!(logger, "Remaining plane formats: {:?}", plane_formats);
|
trace!(logger, "Remaining plane formats: {:?}", plane_formats);
|
||||||
trace!(logger, "Remaining renderer formats: {:?}", renderer_formats);
|
trace!(logger, "Remaining renderer formats: {:?}", renderer_formats);
|
||||||
debug!(logger, "Remaining intersected formats: {:?}", plane_formats.intersection(&renderer_formats).collect::<HashSet<_>>());
|
debug!(
|
||||||
|
logger,
|
||||||
|
"Remaining intersected formats: {:?}",
|
||||||
|
plane_formats
|
||||||
|
.intersection(&renderer_formats)
|
||||||
|
.collect::<HashSet<_>>()
|
||||||
|
);
|
||||||
|
|
||||||
if plane_formats.is_empty() {
|
if plane_formats.is_empty() {
|
||||||
return Err(Error::NoSupportedPlaneFormat);
|
return Err(Error::NoSupportedPlaneFormat);
|
||||||
} else if renderer_formats.is_empty() {
|
} else if renderer_formats.is_empty() {
|
||||||
|
@ -74,38 +95,48 @@ where
|
||||||
// Special case: if a format supports explicit LINEAR (but no implicit Modifiers)
|
// Special case: if a format supports explicit LINEAR (but no implicit Modifiers)
|
||||||
// and the other doesn't support any modifier, force LINEAR. This will force the allocator to
|
// and the other doesn't support any modifier, force LINEAR. This will force the allocator to
|
||||||
// create a buffer with a LINEAR layout instead of an implicit modifier.
|
// create a buffer with a LINEAR layout instead of an implicit modifier.
|
||||||
if
|
if (plane_formats.len() == 1
|
||||||
(plane_formats.len() == 1 &&
|
&& plane_formats.iter().next().unwrap().modifier == Modifier::Invalid
|
||||||
plane_formats.iter().next().unwrap().modifier == Modifier::Invalid
|
&& renderer_formats.iter().all(|x| x.modifier != Modifier::Invalid)
|
||||||
&& renderer_formats.iter().all(|x| x.modifier != Modifier::Invalid)
|
&& renderer_formats.iter().any(|x| x.modifier == Modifier::Linear))
|
||||||
&& renderer_formats.iter().any(|x| x.modifier == Modifier::Linear)
|
|| (renderer_formats.len() == 1
|
||||||
) || (renderer_formats.len() == 1 &&
|
&& renderer_formats.iter().next().unwrap().modifier == Modifier::Invalid
|
||||||
renderer_formats.iter().next().unwrap().modifier == Modifier::Invalid
|
|
||||||
&& plane_formats.iter().all(|x| x.modifier != Modifier::Invalid)
|
&& plane_formats.iter().all(|x| x.modifier != Modifier::Invalid)
|
||||||
&& plane_formats.iter().any(|x| x.modifier == Modifier::Linear)
|
&& plane_formats.iter().any(|x| x.modifier == Modifier::Linear))
|
||||||
) {
|
{
|
||||||
vec![Format {
|
vec![Format {
|
||||||
code,
|
code,
|
||||||
modifier: Modifier::Linear,
|
modifier: Modifier::Linear,
|
||||||
}]
|
}]
|
||||||
} else {
|
} else {
|
||||||
plane_formats.intersection(&renderer_formats).cloned().collect::<Vec<_>>()
|
plane_formats
|
||||||
|
.intersection(&renderer_formats)
|
||||||
|
.cloned()
|
||||||
|
.collect::<Vec<_>>()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
debug!(logger, "Testing Formats: {:?}", formats);
|
debug!(logger, "Testing Formats: {:?}", formats);
|
||||||
|
|
||||||
// Test explicit formats first
|
// Test explicit formats first
|
||||||
let drm = Arc::new(drm);
|
let drm = Arc::new(drm);
|
||||||
let iter = formats.iter().filter(|x| x.modifier != Modifier::Invalid && x.modifier != Modifier::Linear)
|
let iter = formats
|
||||||
|
.iter()
|
||||||
|
.filter(|x| x.modifier != Modifier::Invalid && x.modifier != Modifier::Linear)
|
||||||
.chain(formats.iter().find(|x| x.modifier == Modifier::Linear))
|
.chain(formats.iter().find(|x| x.modifier == Modifier::Linear))
|
||||||
.chain(formats.iter().find(|x| x.modifier == Modifier::Invalid)).cloned();
|
.chain(formats.iter().find(|x| x.modifier == Modifier::Invalid))
|
||||||
|
.cloned();
|
||||||
|
|
||||||
DrmRenderSurface::new_internal(drm, allocator, renderer, iter, logger)
|
DrmRenderSurface::new_internal(drm, allocator, renderer, iter, logger)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::type_complexity)]
|
#[allow(clippy::type_complexity)]
|
||||||
fn new_internal(drm: Arc<DrmSurface<D>>, allocator: A, mut renderer: R, mut formats: impl Iterator<Item=Format>, logger: ::slog::Logger) -> Result<DrmRenderSurface<D, A, R, B>, Error<E1, E2, E3>>
|
fn new_internal(
|
||||||
{
|
drm: Arc<DrmSurface<D>>,
|
||||||
|
allocator: A,
|
||||||
|
mut renderer: R,
|
||||||
|
mut formats: impl Iterator<Item = Format>,
|
||||||
|
logger: ::slog::Logger,
|
||||||
|
) -> Result<DrmRenderSurface<D, A, R, B>, Error<E1, E2, E3>> {
|
||||||
let format = formats.next().ok_or(Error::NoSupportedPlaneFormat)?;
|
let format = formats.next().ok_or(Error::NoSupportedPlaneFormat)?;
|
||||||
let mode = drm.pending_mode();
|
let mode = drm.pending_mode();
|
||||||
|
|
||||||
|
@ -117,16 +148,28 @@ where
|
||||||
|
|
||||||
{
|
{
|
||||||
let dmabuf: Dmabuf = (*buffer).clone();
|
let dmabuf: Dmabuf = (*buffer).clone();
|
||||||
match renderer.bind(dmabuf).map_err(Error::<E1, E2, E3>::RenderError)
|
match renderer
|
||||||
.and_then(|_| renderer.begin(mode.size().0 as u32, mode.size().1 as u32, Transform::Normal).map_err(Error::RenderError))
|
.bind(dmabuf)
|
||||||
.and_then(|_| renderer.clear([0.0, 0.0, 0.0, 1.0]).map_err(Error::RenderError))
|
.map_err(Error::<E1, E2, E3>::RenderError)
|
||||||
.and_then(|_| renderer.finish().map_err(|_| Error::InitialRenderingError))
|
.and_then(|_| {
|
||||||
.and_then(|_| renderer.unbind().map_err(Error::RenderError))
|
renderer
|
||||||
|
.begin(mode.size().0 as u32, mode.size().1 as u32, Transform::Normal)
|
||||||
|
.map_err(Error::RenderError)
|
||||||
|
})
|
||||||
|
.and_then(|_| renderer.clear([0.0, 0.0, 0.0, 1.0]).map_err(Error::RenderError))
|
||||||
|
.and_then(|_| renderer.finish().map_err(|_| Error::InitialRenderingError))
|
||||||
|
.and_then(|_| renderer.unbind().map_err(Error::RenderError))
|
||||||
{
|
{
|
||||||
Ok(_) => {},
|
Ok(_) => {}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
warn!(logger, "Rendering failed with format {:?}: {}", format, err);
|
warn!(logger, "Rendering failed with format {:?}: {}", format, err);
|
||||||
return DrmRenderSurface::new_internal(drm, swapchain.allocator, renderer, formats, logger);
|
return DrmRenderSurface::new_internal(
|
||||||
|
drm,
|
||||||
|
swapchain.allocator,
|
||||||
|
renderer,
|
||||||
|
formats,
|
||||||
|
logger,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -135,8 +178,7 @@ where
|
||||||
let fb = bo.userdata().unwrap().unwrap().fb;
|
let fb = bo.userdata().unwrap().unwrap().fb;
|
||||||
buffer.set_userdata(bo);
|
buffer.set_userdata(bo);
|
||||||
|
|
||||||
match drm.test_buffer(fb, &mode, true)
|
match drm.test_buffer(fb, &mode, true) {
|
||||||
{
|
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
debug!(logger, "Success, choosen format: {:?}", format);
|
debug!(logger, "Success, choosen format: {:?}", format);
|
||||||
let buffers = Buffers::new(drm.clone(), gbm, buffer);
|
let buffers = Buffers::new(drm.clone(), gbm, buffer);
|
||||||
|
@ -148,18 +190,21 @@ where
|
||||||
buffers,
|
buffers,
|
||||||
current_buffer: None,
|
current_buffer: None,
|
||||||
})
|
})
|
||||||
},
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
warn!(logger, "Mode-setting failed with buffer format {:?}: {}", format, err);
|
warn!(
|
||||||
|
logger,
|
||||||
|
"Mode-setting failed with buffer format {:?}: {}", format, err
|
||||||
|
);
|
||||||
DrmRenderSurface::new_internal(drm, swapchain.allocator, renderer, formats, logger)
|
DrmRenderSurface::new_internal(drm, swapchain.allocator, renderer, formats, logger)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn queue_frame(&mut self) -> Result<(), Error<E1, E2, E3>> {
|
pub fn queue_frame(&mut self) -> Result<(), Error<E1, E2, E3>> {
|
||||||
let mode = self.drm.pending_mode();
|
let mode = self.drm.pending_mode();
|
||||||
let (width, height) = (mode.size().0 as u32, mode.size().1 as u32);
|
let (width, height) = (mode.size().0 as u32, mode.size().1 as u32);
|
||||||
self.begin(width, height, Transform::Flipped180/* TODO */)
|
self.begin(width, height, Transform::Flipped180 /* TODO */)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn drop_frame(&mut self) -> Result<(), SwapBuffersError> {
|
pub fn drop_frame(&mut self) -> Result<(), SwapBuffersError> {
|
||||||
|
@ -177,11 +222,11 @@ where
|
||||||
pub fn frame_submitted(&mut self) -> Result<(), Error<E1, E2, E3>> {
|
pub fn frame_submitted(&mut self) -> Result<(), Error<E1, E2, E3>> {
|
||||||
self.buffers.submitted()
|
self.buffers.submitted()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn crtc(&self) -> crtc::Handle {
|
pub fn crtc(&self) -> crtc::Handle {
|
||||||
self.drm.crtc()
|
self.drm.crtc()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn plane(&self) -> plane::Handle {
|
pub fn plane(&self) -> plane::Handle {
|
||||||
self.drm.plane()
|
self.drm.plane()
|
||||||
}
|
}
|
||||||
|
@ -219,13 +264,12 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl<D, A, B, T, R, E1, E2, E3> Renderer for DrmRenderSurface<D, A, R, B>
|
impl<D, A, B, T, R, E1, E2, E3> Renderer for DrmRenderSurface<D, A, R, B>
|
||||||
where
|
where
|
||||||
D: AsRawFd + 'static,
|
D: AsRawFd + 'static,
|
||||||
A: Allocator<B, Error=E1>,
|
A: Allocator<B, Error = E1>,
|
||||||
B: Buffer + TryInto<Dmabuf, Error=E2>,
|
B: Buffer + TryInto<Dmabuf, Error = E2>,
|
||||||
R: Bind<Dmabuf> + Renderer<Error=E3, TextureId=T>,
|
R: Bind<Dmabuf> + Renderer<Error = E3, TextureId = T>,
|
||||||
T: Texture,
|
T: Texture,
|
||||||
E1: std::error::Error + 'static,
|
E1: std::error::Error + 'static,
|
||||||
E2: std::error::Error + 'static,
|
E2: std::error::Error + 'static,
|
||||||
|
@ -235,7 +279,10 @@ where
|
||||||
type TextureId = T;
|
type TextureId = T;
|
||||||
|
|
||||||
#[cfg(feature = "image")]
|
#[cfg(feature = "image")]
|
||||||
fn import_bitmap<C: std::ops::Deref<Target=[u8]>>(&mut self, image: &image::ImageBuffer<image::Rgba<u8>, C>) -> Result<Self::TextureId, Self::Error> {
|
fn import_bitmap<C: std::ops::Deref<Target = [u8]>>(
|
||||||
|
&mut self,
|
||||||
|
image: &image::ImageBuffer<image::Rgba<u8>, C>,
|
||||||
|
) -> Result<Self::TextureId, Self::Error> {
|
||||||
self.renderer.import_bitmap(image).map_err(Error::RenderError)
|
self.renderer.import_bitmap(image).map_err(Error::RenderError)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -248,16 +295,16 @@ where
|
||||||
fn import_shm(&mut self, buffer: &wl_buffer::WlBuffer) -> Result<Self::TextureId, Self::Error> {
|
fn import_shm(&mut self, buffer: &wl_buffer::WlBuffer) -> Result<Self::TextureId, Self::Error> {
|
||||||
self.renderer.import_shm(buffer).map_err(Error::RenderError)
|
self.renderer.import_shm(buffer).map_err(Error::RenderError)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "wayland_frontend")]
|
#[cfg(feature = "wayland_frontend")]
|
||||||
fn import_egl(&mut self, buffer: &EGLBuffer) -> Result<Self::TextureId, Self::Error> {
|
fn import_egl(&mut self, buffer: &EGLBuffer) -> Result<Self::TextureId, Self::Error> {
|
||||||
self.renderer.import_egl(buffer).map_err(Error::RenderError)
|
self.renderer.import_egl(buffer).map_err(Error::RenderError)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn destroy_texture(&mut self, texture: Self::TextureId) -> Result<(), Self::Error> {
|
fn destroy_texture(&mut self, texture: Self::TextureId) -> Result<(), Self::Error> {
|
||||||
self.renderer.destroy_texture(texture).map_err(Error::RenderError)
|
self.renderer.destroy_texture(texture).map_err(Error::RenderError)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn begin(&mut self, width: u32, height: u32, transform: Transform) -> Result<(), Error<E1, E2, E3>> {
|
fn begin(&mut self, width: u32, height: u32, transform: Transform) -> Result<(), Error<E1, E2, E3>> {
|
||||||
if self.current_buffer.is_some() {
|
if self.current_buffer.is_some() {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
@ -266,15 +313,24 @@ where
|
||||||
let slot = self.swapchain.acquire()?.ok_or(Error::NoFreeSlotsError)?;
|
let slot = self.swapchain.acquire()?.ok_or(Error::NoFreeSlotsError)?;
|
||||||
self.renderer.bind((*slot).clone()).map_err(Error::RenderError)?;
|
self.renderer.bind((*slot).clone()).map_err(Error::RenderError)?;
|
||||||
self.current_buffer = Some(slot);
|
self.current_buffer = Some(slot);
|
||||||
self.renderer.begin(width, height, transform).map_err(Error::RenderError)
|
self.renderer
|
||||||
|
.begin(width, height, transform)
|
||||||
|
.map_err(Error::RenderError)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clear(&mut self, color: [f32; 4]) -> Result<(), Self::Error> {
|
fn clear(&mut self, color: [f32; 4]) -> Result<(), Self::Error> {
|
||||||
self.renderer.clear(color).map_err(Error::RenderError)
|
self.renderer.clear(color).map_err(Error::RenderError)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_texture(&mut self, texture: &Self::TextureId, matrix: Matrix3<f32>, alpha: f32) -> Result<(), Self::Error> {
|
fn render_texture(
|
||||||
self.renderer.render_texture(texture, matrix, alpha).map_err(Error::RenderError)
|
&mut self,
|
||||||
|
texture: &Self::TextureId,
|
||||||
|
matrix: Matrix3<f32>,
|
||||||
|
alpha: f32,
|
||||||
|
) -> Result<(), Self::Error> {
|
||||||
|
self.renderer
|
||||||
|
.render_texture(texture, matrix, alpha)
|
||||||
|
.map_err(Error::RenderError)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn finish(&mut self) -> Result<(), SwapBuffersError> {
|
fn finish(&mut self) -> Result<(), SwapBuffersError> {
|
||||||
|
@ -284,7 +340,10 @@ where
|
||||||
|
|
||||||
let result = self.renderer.finish();
|
let result = self.renderer.finish();
|
||||||
if result.is_ok() {
|
if result.is_ok() {
|
||||||
match self.buffers.queue::<E1, E2, E3>(self.current_buffer.take().unwrap()) {
|
match self
|
||||||
|
.buffers
|
||||||
|
.queue::<E1, E2, E3>(self.current_buffer.take().unwrap())
|
||||||
|
{
|
||||||
Ok(()) => {}
|
Ok(()) => {}
|
||||||
Err(Error::DrmError(drm)) => return Err(drm.into()),
|
Err(Error::DrmError(drm)) => return Err(drm.into()),
|
||||||
Err(Error::GbmError(err)) => return Err(SwapBuffersError::ContextLost(Box::new(err))),
|
Err(Error::GbmError(err)) => return Err(SwapBuffersError::ContextLost(Box::new(err))),
|
||||||
|
@ -318,7 +377,11 @@ impl<D> Buffers<D>
|
||||||
where
|
where
|
||||||
D: AsRawFd + 'static,
|
D: AsRawFd + 'static,
|
||||||
{
|
{
|
||||||
pub fn new(drm: Arc<DrmSurface<D>>, gbm: GbmDevice<gbm::FdWrapper>, slot: Slot<Dmabuf, BufferObject<FbHandle<D>>>) -> Buffers<D> {
|
pub fn new(
|
||||||
|
drm: Arc<DrmSurface<D>>,
|
||||||
|
gbm: GbmDevice<gbm::FdWrapper>,
|
||||||
|
slot: Slot<Dmabuf, BufferObject<FbHandle<D>>>,
|
||||||
|
) -> Buffers<D> {
|
||||||
Buffers {
|
Buffers {
|
||||||
drm,
|
drm,
|
||||||
gbm,
|
gbm,
|
||||||
|
@ -328,7 +391,10 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn queue<E1, E2, E3>(&mut self, slot: Slot<Dmabuf, BufferObject<FbHandle<D>>>) -> Result<(), Error<E1, E2, E3>>
|
pub fn queue<E1, E2, E3>(
|
||||||
|
&mut self,
|
||||||
|
slot: Slot<Dmabuf, BufferObject<FbHandle<D>>>,
|
||||||
|
) -> Result<(), Error<E1, E2, E3>>
|
||||||
where
|
where
|
||||||
E1: std::error::Error + 'static,
|
E1: std::error::Error + 'static,
|
||||||
E2: std::error::Error + 'static,
|
E2: std::error::Error + 'static,
|
||||||
|
@ -347,7 +413,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn submitted<E1, E2, E3>(&mut self) -> Result<(), Error<E1, E2, E3>>
|
pub fn submitted<E1, E2, E3>(&mut self) -> Result<(), Error<E1, E2, E3>>
|
||||||
where
|
where
|
||||||
E1: std::error::Error + 'static,
|
E1: std::error::Error + 'static,
|
||||||
E2: std::error::Error + 'static,
|
E2: std::error::Error + 'static,
|
||||||
|
@ -364,7 +430,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn submit<E1, E2, E3>(&mut self) -> Result<(), Error<E1, E2, E3>>
|
fn submit<E1, E2, E3>(&mut self) -> Result<(), Error<E1, E2, E3>>
|
||||||
where
|
where
|
||||||
E1: std::error::Error + 'static,
|
E1: std::error::Error + 'static,
|
||||||
E2: std::error::Error + 'static,
|
E2: std::error::Error + 'static,
|
||||||
|
@ -386,7 +452,11 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn import_dmabuf<A, E1, E2, E3>(drm: &Arc<DrmSurface<A>>, gbm: &GbmDevice<gbm::FdWrapper>, buffer: &Dmabuf) -> Result<BufferObject<FbHandle<A>>, Error<E1, E2, E3>>
|
fn import_dmabuf<A, E1, E2, E3>(
|
||||||
|
drm: &Arc<DrmSurface<A>>,
|
||||||
|
gbm: &GbmDevice<gbm::FdWrapper>,
|
||||||
|
buffer: &Dmabuf,
|
||||||
|
) -> Result<BufferObject<FbHandle<A>>, Error<E1, E2, E3>>
|
||||||
where
|
where
|
||||||
A: AsRawFd + 'static,
|
A: AsRawFd + 'static,
|
||||||
E1: std::error::Error + 'static,
|
E1: std::error::Error + 'static,
|
||||||
|
@ -399,32 +469,29 @@ where
|
||||||
Modifier::Invalid => None,
|
Modifier::Invalid => None,
|
||||||
x => Some(x),
|
x => Some(x),
|
||||||
};
|
};
|
||||||
|
|
||||||
let logger = match &*(*drm).internal {
|
let logger = match &*(*drm).internal {
|
||||||
DrmSurfaceInternal::Atomic(surf) => surf.logger.clone(),
|
DrmSurfaceInternal::Atomic(surf) => surf.logger.clone(),
|
||||||
DrmSurfaceInternal::Legacy(surf) => surf.logger.clone(),
|
DrmSurfaceInternal::Legacy(surf) => surf.logger.clone(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let fb = match
|
let fb = match if modifier.is_some() {
|
||||||
if modifier.is_some() {
|
let num = bo.plane_count().unwrap();
|
||||||
let num = bo.plane_count().unwrap();
|
let modifiers = [
|
||||||
let modifiers = [
|
modifier,
|
||||||
modifier,
|
if num > 1 { modifier } else { None },
|
||||||
if num > 1 { modifier } else { None },
|
if num > 2 { modifier } else { None },
|
||||||
if num > 2 { modifier } else { None },
|
if num > 3 { modifier } else { None },
|
||||||
if num > 3 { modifier } else { None },
|
];
|
||||||
];
|
drm.add_planar_framebuffer(&bo, &modifiers, drm_ffi::DRM_MODE_FB_MODIFIERS)
|
||||||
drm.add_planar_framebuffer(&bo, &modifiers, drm_ffi::DRM_MODE_FB_MODIFIERS)
|
} else {
|
||||||
} else {
|
drm.add_planar_framebuffer(&bo, &[None, None, None, None], 0)
|
||||||
drm.add_planar_framebuffer(&bo, &[None, None, None, None], 0)
|
} {
|
||||||
}
|
|
||||||
{
|
|
||||||
Ok(fb) => fb,
|
Ok(fb) => fb,
|
||||||
Err(source) => {
|
Err(source) => {
|
||||||
// We only support this as a fallback of last resort for ARGB8888 visuals,
|
// We only support this as a fallback of last resort for ARGB8888 visuals,
|
||||||
// like xf86-video-modesetting does.
|
// like xf86-video-modesetting does.
|
||||||
if drm::buffer::Buffer::format(&bo) != Fourcc::Argb8888
|
if drm::buffer::Buffer::format(&bo) != Fourcc::Argb8888 || bo.handles()[1].is_some() {
|
||||||
|| bo.handles()[1].is_some() {
|
|
||||||
return Err(Error::DrmError(DrmError::Access {
|
return Err(Error::DrmError(DrmError::Access {
|
||||||
errmsg: "Failed to add framebuffer",
|
errmsg: "Failed to add framebuffer",
|
||||||
dev: drm.dev_path(),
|
dev: drm.dev_path(),
|
||||||
|
@ -432,17 +499,15 @@ where
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
debug!(logger, "Failed to add framebuffer, trying legacy method");
|
debug!(logger, "Failed to add framebuffer, trying legacy method");
|
||||||
drm.add_framebuffer(&bo, 32, 32).map_err(|source| DrmError::Access {
|
drm.add_framebuffer(&bo, 32, 32)
|
||||||
errmsg: "Failed to add framebuffer",
|
.map_err(|source| DrmError::Access {
|
||||||
dev: drm.dev_path(),
|
errmsg: "Failed to add framebuffer",
|
||||||
source,
|
dev: drm.dev_path(),
|
||||||
})?
|
source,
|
||||||
|
})?
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
bo.set_userdata(FbHandle {
|
bo.set_userdata(FbHandle { drm: drm.clone(), fb }).unwrap();
|
||||||
drm: drm.clone(),
|
|
||||||
fb,
|
|
||||||
}).unwrap();
|
|
||||||
|
|
||||||
Ok(bo)
|
Ok(bo)
|
||||||
}
|
}
|
||||||
|
@ -471,21 +536,21 @@ where
|
||||||
#[error("The swapchain encounted an error: {0}")]
|
#[error("The swapchain encounted an error: {0}")]
|
||||||
SwapchainError(#[from] SwapchainError<E1, E2>),
|
SwapchainError(#[from] SwapchainError<E1, E2>),
|
||||||
#[error("The renderer encounted an error: {0}")]
|
#[error("The renderer encounted an error: {0}")]
|
||||||
RenderError(#[source] E3)
|
RenderError(#[source] E3),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<
|
impl<
|
||||||
E1: std::error::Error + 'static,
|
E1: std::error::Error + 'static,
|
||||||
E2: std::error::Error + 'static,
|
E2: std::error::Error + 'static,
|
||||||
E3: std::error::Error + Into<SwapBuffersError> + 'static,
|
E3: std::error::Error + Into<SwapBuffersError> + 'static,
|
||||||
> From<Error<E1, E2, E3>> for SwapBuffersError {
|
> From<Error<E1, E2, E3>> for SwapBuffersError
|
||||||
|
{
|
||||||
fn from(err: Error<E1, E2, E3>) -> SwapBuffersError {
|
fn from(err: Error<E1, E2, E3>) -> SwapBuffersError {
|
||||||
match err {
|
match err {
|
||||||
x @ Error::NoSupportedPlaneFormat
|
x @ Error::NoSupportedPlaneFormat
|
||||||
| x @ Error::NoSupportedRendererFormat
|
| x @ Error::NoSupportedRendererFormat
|
||||||
| x @ Error::FormatsNotCompatible
|
| x @ Error::FormatsNotCompatible
|
||||||
| x @ Error::InitialRenderingError
|
| x @ Error::InitialRenderingError => SwapBuffersError::ContextLost(Box::new(x)),
|
||||||
=> SwapBuffersError::ContextLost(Box::new(x)),
|
|
||||||
x @ Error::NoFreeSlotsError => SwapBuffersError::TemporaryFailure(Box::new(x)),
|
x @ Error::NoFreeSlotsError => SwapBuffersError::TemporaryFailure(Box::new(x)),
|
||||||
Error::DrmError(err) => err.into(),
|
Error::DrmError(err) => err.into(),
|
||||||
Error::GbmError(err) => SwapBuffersError::ContextLost(Box::new(err)),
|
Error::GbmError(err) => SwapBuffersError::ContextLost(Box::new(err)),
|
||||||
|
@ -493,4 +558,4 @@ impl<
|
||||||
Error::RenderError(err) => err.into(),
|
Error::RenderError(err) => err.into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
use std::sync::{Arc, Weak, atomic::{AtomicBool, Ordering}};
|
|
||||||
use std::os::unix::io::{AsRawFd, RawFd};
|
use std::os::unix::io::{AsRawFd, RawFd};
|
||||||
|
use std::sync::{
|
||||||
|
atomic::{AtomicBool, Ordering},
|
||||||
|
Arc, Weak,
|
||||||
|
};
|
||||||
|
|
||||||
use drm::Device as BasicDevice;
|
use drm::Device as BasicDevice;
|
||||||
use nix::libc::dev_t;
|
use nix::libc::dev_t;
|
||||||
|
@ -92,17 +95,17 @@ impl<A: AsRawFd + 'static> DrmDeviceObserver<A> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// okay, the previous session/whatever might left the drm devices in any state...
|
// okay, the previous session/whatever might left the drm devices in any state...
|
||||||
// lets fix that
|
// lets fix that
|
||||||
if let Err(err) = self.reset_state() {
|
if let Err(err) = self.reset_state() {
|
||||||
warn!(self.logger, "Unable to reset state after tty switch: {}", err);
|
warn!(self.logger, "Unable to reset state after tty switch: {}", err);
|
||||||
// TODO call drm-handler::error
|
// TODO call drm-handler::error
|
||||||
}
|
}
|
||||||
|
|
||||||
self.active.store(true, Ordering::SeqCst);
|
self.active.store(true, Ordering::SeqCst);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reset_state(&mut self) -> Result<(), Error> {
|
fn reset_state(&mut self) -> Result<(), Error> {
|
||||||
if let Some(dev) = self.dev.upgrade() {
|
if let Some(dev) = self.dev.upgrade() {
|
||||||
dev.reset_state()
|
dev.reset_state()
|
||||||
|
@ -110,4 +113,4 @@ impl<A: AsRawFd + 'static> DrmDeviceObserver<A> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,11 +6,14 @@ use drm::control::{
|
||||||
|
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::os::unix::io::AsRawFd;
|
use std::os::unix::io::AsRawFd;
|
||||||
use std::sync::{atomic::{AtomicBool, Ordering}, Arc, Mutex, RwLock};
|
use std::sync::{
|
||||||
|
atomic::{AtomicBool, Ordering},
|
||||||
|
Arc, Mutex, RwLock,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::backend::drm::{
|
use crate::backend::drm::{
|
||||||
device::{DevPath, DrmDeviceInternal},
|
|
||||||
device::atomic::Mapping,
|
device::atomic::Mapping,
|
||||||
|
device::{DevPath, DrmDeviceInternal},
|
||||||
error::Error,
|
error::Error,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -48,7 +51,11 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
|
||||||
let logger = logger.new(o!("smithay_module" => "backend_drm_atomic", "drm_module" => "surface"));
|
let logger = logger.new(o!("smithay_module" => "backend_drm_atomic", "drm_module" => "surface"));
|
||||||
info!(
|
info!(
|
||||||
logger,
|
logger,
|
||||||
"Initializing drm surface ({:?}:{:?}) with mode {:?} and connectors {:?}", crtc, plane, mode, connectors
|
"Initializing drm surface ({:?}:{:?}) with mode {:?} and connectors {:?}",
|
||||||
|
crtc,
|
||||||
|
plane,
|
||||||
|
mode,
|
||||||
|
connectors
|
||||||
);
|
);
|
||||||
|
|
||||||
let crtc_info = fd.get_crtc(crtc).map_err(|source| Error::Access {
|
let crtc_info = fd.get_crtc(crtc).map_err(|source| Error::Access {
|
||||||
|
@ -63,30 +70,25 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
|
||||||
// So we cheat, because it works and is easier to handle later.
|
// So we cheat, because it works and is easier to handle later.
|
||||||
let current_mode = crtc_info.mode().unwrap_or_else(|| unsafe { std::mem::zeroed() });
|
let current_mode = crtc_info.mode().unwrap_or_else(|| unsafe { std::mem::zeroed() });
|
||||||
let current_blob = match crtc_info.mode() {
|
let current_blob = match crtc_info.mode() {
|
||||||
Some(mode) => fd
|
Some(mode) => fd.create_property_blob(&mode).map_err(|source| Error::Access {
|
||||||
.create_property_blob(&mode)
|
|
||||||
.map_err(|source| Error::Access {
|
|
||||||
errmsg: "Failed to create Property Blob for mode",
|
|
||||||
dev: fd.dev_path(),
|
|
||||||
source,
|
|
||||||
})?,
|
|
||||||
None => property::Value::Unknown(0),
|
|
||||||
};
|
|
||||||
|
|
||||||
let blob = fd
|
|
||||||
.create_property_blob(&mode)
|
|
||||||
.map_err(|source| Error::Access {
|
|
||||||
errmsg: "Failed to create Property Blob for mode",
|
errmsg: "Failed to create Property Blob for mode",
|
||||||
dev: fd.dev_path(),
|
dev: fd.dev_path(),
|
||||||
source,
|
source,
|
||||||
})?;
|
})?,
|
||||||
|
None => property::Value::Unknown(0),
|
||||||
|
};
|
||||||
|
|
||||||
let res_handles = fd.resource_handles()
|
let blob = fd.create_property_blob(&mode).map_err(|source| Error::Access {
|
||||||
.map_err(|source| Error::Access {
|
errmsg: "Failed to create Property Blob for mode",
|
||||||
errmsg: "Error loading drm resources",
|
dev: fd.dev_path(),
|
||||||
dev: fd.dev_path(),
|
source,
|
||||||
source,
|
})?;
|
||||||
})?;
|
|
||||||
|
let res_handles = fd.resource_handles().map_err(|source| Error::Access {
|
||||||
|
errmsg: "Error loading drm resources",
|
||||||
|
dev: fd.dev_path(),
|
||||||
|
source,
|
||||||
|
})?;
|
||||||
|
|
||||||
// the current set of connectors are those, that already have the correct `CRTC_ID` set.
|
// the current set of connectors are those, that already have the correct `CRTC_ID` set.
|
||||||
// so we collect them for `current_state` and set the user-given once in `pending_state`.
|
// so we collect them for `current_state` and set the user-given once in `pending_state`.
|
||||||
|
@ -94,8 +96,7 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
|
||||||
// If they don't match, `commit_pending` will return true and they will be changed on the next `commit`.
|
// If they don't match, `commit_pending` will return true and they will be changed on the next `commit`.
|
||||||
let mut current_connectors = HashSet::new();
|
let mut current_connectors = HashSet::new();
|
||||||
for conn in res_handles.connectors() {
|
for conn in res_handles.connectors() {
|
||||||
let crtc_prop =
|
let crtc_prop = prop_mapping
|
||||||
prop_mapping
|
|
||||||
.0
|
.0
|
||||||
.get(&conn)
|
.get(&conn)
|
||||||
.expect("Unknown handle")
|
.expect("Unknown handle")
|
||||||
|
@ -105,8 +106,7 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
|
||||||
name: "CRTC_ID",
|
name: "CRTC_ID",
|
||||||
})
|
})
|
||||||
.map(|x| *x)?;
|
.map(|x| *x)?;
|
||||||
if let (Ok(crtc_prop_info), Ok(props)) = (fd.get_property(crtc_prop), fd.get_properties(*conn))
|
if let (Ok(crtc_prop_info), Ok(props)) = (fd.get_property(crtc_prop), fd.get_properties(*conn)) {
|
||||||
{
|
|
||||||
let (ids, vals) = props.as_props_and_values();
|
let (ids, vals) = props.as_props_and_values();
|
||||||
for (&id, &val) in ids.iter().zip(vals.iter()) {
|
for (&id, &val) in ids.iter().zip(vals.iter()) {
|
||||||
if id == crtc_prop {
|
if id == crtc_prop {
|
||||||
|
@ -152,14 +152,20 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
|
||||||
// here we create a dumbbuffer for that purpose.
|
// here we create a dumbbuffer for that purpose.
|
||||||
fn create_test_buffer(&self, mode: &Mode) -> Result<framebuffer::Handle, Error> {
|
fn create_test_buffer(&self, mode: &Mode) -> Result<framebuffer::Handle, Error> {
|
||||||
let (w, h) = mode.size();
|
let (w, h) = mode.size();
|
||||||
let db = self.fd
|
let db = self
|
||||||
.create_dumb_buffer((w as u32, h as u32), crate::backend::allocator::Fourcc::Argb8888, 32)
|
.fd
|
||||||
|
.create_dumb_buffer(
|
||||||
|
(w as u32, h as u32),
|
||||||
|
crate::backend::allocator::Fourcc::Argb8888,
|
||||||
|
32,
|
||||||
|
)
|
||||||
.map_err(|source| Error::Access {
|
.map_err(|source| Error::Access {
|
||||||
errmsg: "Failed to create dumb buffer",
|
errmsg: "Failed to create dumb buffer",
|
||||||
dev: self.fd.dev_path(),
|
dev: self.fd.dev_path(),
|
||||||
source,
|
source,
|
||||||
})?;
|
})?;
|
||||||
let fb = self.fd
|
let fb = self
|
||||||
|
.fd
|
||||||
.add_framebuffer(&db, 32, 32)
|
.add_framebuffer(&db, 32, 32)
|
||||||
.map_err(|source| Error::Access {
|
.map_err(|source| Error::Access {
|
||||||
errmsg: "Failed to create framebuffer",
|
errmsg: "Failed to create framebuffer",
|
||||||
|
@ -198,13 +204,11 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
|
||||||
return Err(Error::DeviceInactive);
|
return Err(Error::DeviceInactive);
|
||||||
}
|
}
|
||||||
|
|
||||||
let info = self.fd
|
let info = self.fd.get_connector(conn).map_err(|source| Error::Access {
|
||||||
.get_connector(conn)
|
errmsg: "Error loading connector info",
|
||||||
.map_err(|source| Error::Access {
|
dev: self.fd.dev_path(),
|
||||||
errmsg: "Error loading connector info",
|
source,
|
||||||
dev: self.fd.dev_path(),
|
})?;
|
||||||
source,
|
|
||||||
})?;
|
|
||||||
|
|
||||||
let mut pending = self.pending.write().unwrap();
|
let mut pending = self.pending.write().unwrap();
|
||||||
|
|
||||||
|
@ -219,11 +223,12 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
|
||||||
Some(pending.mode),
|
Some(pending.mode),
|
||||||
Some(pending.blob),
|
Some(pending.blob),
|
||||||
)?;
|
)?;
|
||||||
self.fd.atomic_commit(
|
self.fd
|
||||||
&[AtomicCommitFlags::AllowModeset, AtomicCommitFlags::TestOnly],
|
.atomic_commit(
|
||||||
req,
|
&[AtomicCommitFlags::AllowModeset, AtomicCommitFlags::TestOnly],
|
||||||
)
|
req,
|
||||||
.map_err(|_| Error::TestFailed(self.crtc))?;
|
)
|
||||||
|
.map_err(|_| Error::TestFailed(self.crtc))?;
|
||||||
|
|
||||||
// seems to be, lets add the connector
|
// seems to be, lets add the connector
|
||||||
pending.connectors.insert(conn);
|
pending.connectors.insert(conn);
|
||||||
|
@ -255,11 +260,12 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
|
||||||
Some(pending.mode),
|
Some(pending.mode),
|
||||||
Some(pending.blob),
|
Some(pending.blob),
|
||||||
)?;
|
)?;
|
||||||
self.fd.atomic_commit(
|
self.fd
|
||||||
&[AtomicCommitFlags::AllowModeset, AtomicCommitFlags::TestOnly],
|
.atomic_commit(
|
||||||
req,
|
&[AtomicCommitFlags::AllowModeset, AtomicCommitFlags::TestOnly],
|
||||||
)
|
req,
|
||||||
.map_err(|_| Error::TestFailed(self.crtc))?;
|
)
|
||||||
|
.map_err(|_| Error::TestFailed(self.crtc))?;
|
||||||
|
|
||||||
// seems to be, lets remove the connector
|
// seems to be, lets remove the connector
|
||||||
pending.connectors.remove(&conn);
|
pending.connectors.remove(&conn);
|
||||||
|
@ -293,11 +299,12 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
|
||||||
Some(pending.blob),
|
Some(pending.blob),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
self.fd.atomic_commit(
|
self.fd
|
||||||
&[AtomicCommitFlags::AllowModeset, AtomicCommitFlags::TestOnly],
|
.atomic_commit(
|
||||||
req,
|
&[AtomicCommitFlags::AllowModeset, AtomicCommitFlags::TestOnly],
|
||||||
)
|
req,
|
||||||
.map_err(|_| Error::TestFailed(self.crtc))?;
|
)
|
||||||
|
.map_err(|_| Error::TestFailed(self.crtc))?;
|
||||||
|
|
||||||
pending.connectors = conns;
|
pending.connectors = conns;
|
||||||
|
|
||||||
|
@ -312,7 +319,8 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
|
||||||
let mut pending = self.pending.write().unwrap();
|
let mut pending = self.pending.write().unwrap();
|
||||||
|
|
||||||
// check if new config is supported
|
// check if new config is supported
|
||||||
let new_blob = self.fd
|
let new_blob = self
|
||||||
|
.fd
|
||||||
.create_property_blob(&mode)
|
.create_property_blob(&mode)
|
||||||
.map_err(|source| Error::Access {
|
.map_err(|source| Error::Access {
|
||||||
errmsg: "Failed to create Property Blob for mode",
|
errmsg: "Failed to create Property Blob for mode",
|
||||||
|
@ -329,7 +337,8 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
|
||||||
Some(mode),
|
Some(mode),
|
||||||
Some(new_blob),
|
Some(new_blob),
|
||||||
)?;
|
)?;
|
||||||
if let Err(err) = self.fd
|
if let Err(err) = self
|
||||||
|
.fd
|
||||||
.atomic_commit(
|
.atomic_commit(
|
||||||
&[AtomicCommitFlags::AllowModeset, AtomicCommitFlags::TestOnly],
|
&[AtomicCommitFlags::AllowModeset, AtomicCommitFlags::TestOnly],
|
||||||
req,
|
req,
|
||||||
|
@ -346,7 +355,7 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn commit_pending(&self) -> bool {
|
pub fn commit_pending(&self) -> bool {
|
||||||
*self.pending.read().unwrap() != *self.state.read().unwrap()
|
*self.pending.read().unwrap() != *self.state.read().unwrap()
|
||||||
}
|
}
|
||||||
|
@ -403,7 +412,8 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
|
||||||
Some(pending.blob),
|
Some(pending.blob),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
if let Err(err) = self.fd
|
if let Err(err) = self
|
||||||
|
.fd
|
||||||
.atomic_commit(
|
.atomic_commit(
|
||||||
&[AtomicCommitFlags::AllowModeset, AtomicCommitFlags::TestOnly],
|
&[AtomicCommitFlags::AllowModeset, AtomicCommitFlags::TestOnly],
|
||||||
req.clone(),
|
req.clone(),
|
||||||
|
@ -429,7 +439,8 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
|
||||||
};
|
};
|
||||||
|
|
||||||
debug!(self.logger, "Setting screen: {:?}", req);
|
debug!(self.logger, "Setting screen: {:?}", req);
|
||||||
let result = self.fd
|
let result = self
|
||||||
|
.fd
|
||||||
.atomic_commit(
|
.atomic_commit(
|
||||||
if event {
|
if event {
|
||||||
&[
|
&[
|
||||||
|
@ -441,10 +452,7 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
|
||||||
AtomicCommitFlags::Nonblock,
|
AtomicCommitFlags::Nonblock,
|
||||||
]
|
]
|
||||||
} else {
|
} else {
|
||||||
&[
|
&[AtomicCommitFlags::AllowModeset, AtomicCommitFlags::Nonblock]
|
||||||
AtomicCommitFlags::AllowModeset,
|
|
||||||
AtomicCommitFlags::Nonblock,
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
req,
|
req,
|
||||||
)
|
)
|
||||||
|
@ -480,36 +488,38 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
|
||||||
// If we would set anything here, that would require a modeset, this would fail,
|
// If we would set anything here, that would require a modeset, this would fail,
|
||||||
// indicating a problem in our assumptions.
|
// indicating a problem in our assumptions.
|
||||||
trace!(self.logger, "Queueing page flip: {:?}", req);
|
trace!(self.logger, "Queueing page flip: {:?}", req);
|
||||||
self.fd.atomic_commit(
|
self.fd
|
||||||
if event {
|
.atomic_commit(
|
||||||
&[AtomicCommitFlags::PageFlipEvent, AtomicCommitFlags::Nonblock]
|
if event {
|
||||||
} else {
|
&[AtomicCommitFlags::PageFlipEvent, AtomicCommitFlags::Nonblock]
|
||||||
&[AtomicCommitFlags::Nonblock]
|
} else {
|
||||||
},
|
&[AtomicCommitFlags::Nonblock]
|
||||||
req,
|
},
|
||||||
)
|
req,
|
||||||
.map_err(|source| Error::Access {
|
)
|
||||||
errmsg: "Page flip commit failed",
|
.map_err(|source| Error::Access {
|
||||||
dev: self.fd.dev_path(),
|
errmsg: "Page flip commit failed",
|
||||||
source,
|
dev: self.fd.dev_path(),
|
||||||
})?;
|
source,
|
||||||
|
})?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn test_buffer(&self, fb: framebuffer::Handle, mode: &Mode) -> Result<bool, Error> {
|
pub fn test_buffer(&self, fb: framebuffer::Handle, mode: &Mode) -> Result<bool, Error> {
|
||||||
if !self.active.load(Ordering::SeqCst) {
|
if !self.active.load(Ordering::SeqCst) {
|
||||||
return Err(Error::DeviceInactive);
|
return Err(Error::DeviceInactive);
|
||||||
}
|
}
|
||||||
|
|
||||||
let blob = self.fd
|
let blob = self
|
||||||
|
.fd
|
||||||
.create_property_blob(&mode)
|
.create_property_blob(&mode)
|
||||||
.map_err(|source| Error::Access {
|
.map_err(|source| Error::Access {
|
||||||
errmsg: "Failed to create Property Blob for mode",
|
errmsg: "Failed to create Property Blob for mode",
|
||||||
dev: self.fd.dev_path(),
|
dev: self.fd.dev_path(),
|
||||||
source,
|
source,
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let current = self.state.read().unwrap();
|
let current = self.state.read().unwrap();
|
||||||
let pending = self.pending.read().unwrap();
|
let pending = self.pending.read().unwrap();
|
||||||
|
|
||||||
|
@ -524,10 +534,16 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
|
||||||
self.plane,
|
self.plane,
|
||||||
Some(fb),
|
Some(fb),
|
||||||
Some(*mode),
|
Some(*mode),
|
||||||
Some(blob)
|
Some(blob),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let result = self.fd.atomic_commit(&[AtomicCommitFlags::AllowModeset, AtomicCommitFlags::TestOnly], req).is_ok();
|
let result = self
|
||||||
|
.fd
|
||||||
|
.atomic_commit(
|
||||||
|
&[AtomicCommitFlags::AllowModeset, AtomicCommitFlags::TestOnly],
|
||||||
|
req,
|
||||||
|
)
|
||||||
|
.is_ok();
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -536,8 +552,7 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
|
||||||
handle: connector::Handle,
|
handle: connector::Handle,
|
||||||
name: &'static str,
|
name: &'static str,
|
||||||
) -> Result<property::Handle, Error> {
|
) -> Result<property::Handle, Error> {
|
||||||
self
|
self.prop_mapping
|
||||||
.prop_mapping
|
|
||||||
.0
|
.0
|
||||||
.get(&handle)
|
.get(&handle)
|
||||||
.expect("Unknown handle")
|
.expect("Unknown handle")
|
||||||
|
@ -549,9 +564,12 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
|
||||||
.map(|x| *x)
|
.map(|x| *x)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn crtc_prop_handle(&self, handle: crtc::Handle, name: &'static str) -> Result<property::Handle, Error> {
|
pub(crate) fn crtc_prop_handle(
|
||||||
self
|
&self,
|
||||||
.prop_mapping
|
handle: crtc::Handle,
|
||||||
|
name: &'static str,
|
||||||
|
) -> Result<property::Handle, Error> {
|
||||||
|
self.prop_mapping
|
||||||
.1
|
.1
|
||||||
.get(&handle)
|
.get(&handle)
|
||||||
.expect("Unknown handle")
|
.expect("Unknown handle")
|
||||||
|
@ -569,8 +587,7 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
|
||||||
handle: framebuffer::Handle,
|
handle: framebuffer::Handle,
|
||||||
name: &'static str,
|
name: &'static str,
|
||||||
) -> Result<property::Handle, Error> {
|
) -> Result<property::Handle, Error> {
|
||||||
self
|
self.prop_mapping
|
||||||
.prop_mapping
|
|
||||||
.2
|
.2
|
||||||
.get(&handle)
|
.get(&handle)
|
||||||
.expect("Unknown handle")
|
.expect("Unknown handle")
|
||||||
|
@ -587,8 +604,7 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
|
||||||
handle: plane::Handle,
|
handle: plane::Handle,
|
||||||
name: &'static str,
|
name: &'static str,
|
||||||
) -> Result<property::Handle, Error> {
|
) -> Result<property::Handle, Error> {
|
||||||
self
|
self.prop_mapping
|
||||||
.prop_mapping
|
|
||||||
.3
|
.3
|
||||||
.get(&handle)
|
.get(&handle)
|
||||||
.expect("Unknown handle")
|
.expect("Unknown handle")
|
||||||
|
@ -657,7 +673,7 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
|
||||||
property::Value::Framebuffer(Some(fb)),
|
property::Value::Framebuffer(Some(fb)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// we also need to connect the plane
|
// we also need to connect the plane
|
||||||
req.add_property(
|
req.add_property(
|
||||||
plane,
|
plane,
|
||||||
|
@ -733,10 +749,12 @@ impl<A: AsRawFd + 'static> AtomicDrmSurface<A> {
|
||||||
property::Value::Framebuffer(None),
|
property::Value::Framebuffer(None),
|
||||||
);
|
);
|
||||||
|
|
||||||
self.fd.atomic_commit(&[AtomicCommitFlags::TestOnly], req.clone())
|
self.fd
|
||||||
|
.atomic_commit(&[AtomicCommitFlags::TestOnly], req.clone())
|
||||||
.map_err(|_| Error::TestFailed(self.crtc))?;
|
.map_err(|_| Error::TestFailed(self.crtc))?;
|
||||||
|
|
||||||
self.fd.atomic_commit(&[AtomicCommitFlags::Nonblock], req)
|
self.fd
|
||||||
|
.atomic_commit(&[AtomicCommitFlags::Nonblock], req)
|
||||||
.map_err(|source| Error::Access {
|
.map_err(|source| Error::Access {
|
||||||
errmsg: "Failed to commit on clear_plane",
|
errmsg: "Failed to commit on clear_plane",
|
||||||
dev: self.fd.dev_path(),
|
dev: self.fd.dev_path(),
|
||||||
|
@ -763,10 +781,7 @@ impl<A: AsRawFd + 'static> Drop for AtomicDrmSurface<A> {
|
||||||
// other ttys that use no cursor, might not clear it themselves.
|
// other ttys that use no cursor, might not clear it themselves.
|
||||||
// This makes sure our cursor won't stay visible.
|
// This makes sure our cursor won't stay visible.
|
||||||
if let Err(err) = self.clear_plane() {
|
if let Err(err) = self.clear_plane() {
|
||||||
warn!(
|
warn!(self.logger, "Failed to clear plane on {:?}: {}", self.crtc, err);
|
||||||
self.logger,
|
|
||||||
"Failed to clear plane on {:?}: {}", self.crtc, err
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// disable connectors again
|
// disable connectors again
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
use drm::control::{
|
use drm::control::{connector, crtc, encoder, framebuffer, Device as ControlDevice, Mode, PageFlipFlags};
|
||||||
connector, crtc, encoder, framebuffer, Device as ControlDevice, Mode,
|
|
||||||
PageFlipFlags,
|
|
||||||
};
|
|
||||||
|
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::os::unix::io::AsRawFd;
|
use std::os::unix::io::AsRawFd;
|
||||||
use std::sync::{atomic::{AtomicBool, Ordering}, Arc, RwLock};
|
use std::sync::{
|
||||||
|
atomic::{AtomicBool, Ordering},
|
||||||
|
Arc, RwLock,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::backend::drm::{
|
use crate::backend::drm::{
|
||||||
device::{DevPath, DrmDeviceInternal},
|
|
||||||
device::legacy::set_connector_state,
|
device::legacy::set_connector_state,
|
||||||
|
device::{DevPath, DrmDeviceInternal},
|
||||||
error::Error,
|
error::Error,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -54,12 +54,11 @@ impl<A: AsRawFd + 'static> LegacyDrmSurface<A> {
|
||||||
let current_mode = crtc_info.mode();
|
let current_mode = crtc_info.mode();
|
||||||
|
|
||||||
let mut current_connectors = HashSet::new();
|
let mut current_connectors = HashSet::new();
|
||||||
let res_handles = fd.resource_handles()
|
let res_handles = fd.resource_handles().map_err(|source| Error::Access {
|
||||||
.map_err(|source| Error::Access {
|
errmsg: "Error loading drm resources",
|
||||||
errmsg: "Error loading drm resources",
|
dev: fd.dev_path(),
|
||||||
dev: fd.dev_path(),
|
source,
|
||||||
source,
|
})?;
|
||||||
})?;
|
|
||||||
for &con in res_handles.connectors() {
|
for &con in res_handles.connectors() {
|
||||||
let con_info = fd.get_connector(con).map_err(|source| Error::Access {
|
let con_info = fd.get_connector(con).map_err(|source| Error::Access {
|
||||||
errmsg: "Error loading connector info",
|
errmsg: "Error loading connector info",
|
||||||
|
@ -179,7 +178,8 @@ impl<A: AsRawFd + 'static> LegacyDrmSurface<A> {
|
||||||
|
|
||||||
// check the connectors to see if this mode is supported
|
// check the connectors to see if this mode is supported
|
||||||
for connector in &pending.connectors {
|
for connector in &pending.connectors {
|
||||||
if !self.fd
|
if !self
|
||||||
|
.fd
|
||||||
.get_connector(*connector)
|
.get_connector(*connector)
|
||||||
.map_err(|source| Error::Access {
|
.map_err(|source| Error::Access {
|
||||||
errmsg: "Error loading connector info",
|
errmsg: "Error loading connector info",
|
||||||
|
@ -229,7 +229,8 @@ impl<A: AsRawFd + 'static> LegacyDrmSurface<A> {
|
||||||
|
|
||||||
if conn_removed {
|
if conn_removed {
|
||||||
// null commit (necessary to trigger removal on the kernel side with the legacy api.)
|
// null commit (necessary to trigger removal on the kernel side with the legacy api.)
|
||||||
self.fd.set_crtc(self.crtc, None, (0, 0), &[], None)
|
self.fd
|
||||||
|
.set_crtc(self.crtc, None, (0, 0), &[], None)
|
||||||
.map_err(|source| Error::Access {
|
.map_err(|source| Error::Access {
|
||||||
errmsg: "Error setting crtc",
|
errmsg: "Error setting crtc",
|
||||||
dev: self.fd.dev_path(),
|
dev: self.fd.dev_path(),
|
||||||
|
@ -253,22 +254,23 @@ impl<A: AsRawFd + 'static> LegacyDrmSurface<A> {
|
||||||
|
|
||||||
debug!(self.logger, "Setting screen");
|
debug!(self.logger, "Setting screen");
|
||||||
// do a modeset and attach the given framebuffer
|
// do a modeset and attach the given framebuffer
|
||||||
self.fd.set_crtc(
|
self.fd
|
||||||
self.crtc,
|
.set_crtc(
|
||||||
Some(framebuffer),
|
self.crtc,
|
||||||
(0, 0),
|
Some(framebuffer),
|
||||||
&pending
|
(0, 0),
|
||||||
.connectors
|
&pending
|
||||||
.iter()
|
.connectors
|
||||||
.copied()
|
.iter()
|
||||||
.collect::<Vec<connector::Handle>>(),
|
.copied()
|
||||||
Some(pending.mode),
|
.collect::<Vec<connector::Handle>>(),
|
||||||
)
|
Some(pending.mode),
|
||||||
.map_err(|source| Error::Access {
|
)
|
||||||
errmsg: "Error setting crtc",
|
.map_err(|source| Error::Access {
|
||||||
dev: self.fd.dev_path(),
|
errmsg: "Error setting crtc",
|
||||||
source,
|
dev: self.fd.dev_path(),
|
||||||
})?;
|
source,
|
||||||
|
})?;
|
||||||
|
|
||||||
*current = pending.clone();
|
*current = pending.clone();
|
||||||
|
|
||||||
|
@ -306,7 +308,11 @@ impl<A: AsRawFd + 'static> LegacyDrmSurface<A> {
|
||||||
&*self.fd,
|
&*self.fd,
|
||||||
self.crtc,
|
self.crtc,
|
||||||
framebuffer,
|
framebuffer,
|
||||||
if event { &[PageFlipFlags::PageFlipEvent] } else { &[] },
|
if event {
|
||||||
|
&[PageFlipFlags::PageFlipEvent]
|
||||||
|
} else {
|
||||||
|
&[]
|
||||||
|
},
|
||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
.map_err(|source| Error::Access {
|
.map_err(|source| Error::Access {
|
||||||
|
@ -320,21 +326,24 @@ impl<A: AsRawFd + 'static> LegacyDrmSurface<A> {
|
||||||
if !self.active.load(Ordering::SeqCst) {
|
if !self.active.load(Ordering::SeqCst) {
|
||||||
return Err(Error::DeviceInactive);
|
return Err(Error::DeviceInactive);
|
||||||
}
|
}
|
||||||
|
|
||||||
let pending = self.pending.read().unwrap();
|
let pending = self.pending.read().unwrap();
|
||||||
|
|
||||||
debug!(self.logger, "Setting screen for buffer *testing*");
|
debug!(self.logger, "Setting screen for buffer *testing*");
|
||||||
Ok(self.fd.set_crtc(
|
Ok(self
|
||||||
self.crtc,
|
.fd
|
||||||
Some(fb),
|
.set_crtc(
|
||||||
(0, 0),
|
self.crtc,
|
||||||
&pending
|
Some(fb),
|
||||||
.connectors
|
(0, 0),
|
||||||
.iter()
|
&pending
|
||||||
.copied()
|
.connectors
|
||||||
.collect::<Vec<connector::Handle>>(),
|
.iter()
|
||||||
Some(*mode),
|
.copied()
|
||||||
).is_ok())
|
.collect::<Vec<connector::Handle>>(),
|
||||||
|
Some(*mode),
|
||||||
|
)
|
||||||
|
.is_ok())
|
||||||
}
|
}
|
||||||
|
|
||||||
// we use this function to verify, if a certain connector/mode combination
|
// we use this function to verify, if a certain connector/mode combination
|
||||||
|
@ -345,13 +354,11 @@ impl<A: AsRawFd + 'static> LegacyDrmSurface<A> {
|
||||||
// Better would be some kind of test commit to ask the driver,
|
// Better would be some kind of test commit to ask the driver,
|
||||||
// but that only exists for the atomic api.
|
// but that only exists for the atomic api.
|
||||||
fn check_connector(&self, conn: connector::Handle, mode: &Mode) -> Result<bool, Error> {
|
fn check_connector(&self, conn: connector::Handle, mode: &Mode) -> Result<bool, Error> {
|
||||||
let info = self.fd
|
let info = self.fd.get_connector(conn).map_err(|source| Error::Access {
|
||||||
.get_connector(conn)
|
errmsg: "Error loading connector info",
|
||||||
.map_err(|source| Error::Access {
|
dev: self.fd.dev_path(),
|
||||||
errmsg: "Error loading connector info",
|
source,
|
||||||
dev: self.fd.dev_path(),
|
})?;
|
||||||
source,
|
|
||||||
})?;
|
|
||||||
|
|
||||||
// check if the connector can handle the current mode
|
// check if the connector can handle the current mode
|
||||||
if info.modes().contains(mode) {
|
if info.modes().contains(mode) {
|
||||||
|
@ -362,12 +369,11 @@ impl<A: AsRawFd + 'static> LegacyDrmSurface<A> {
|
||||||
.filter(|enc| enc.is_some())
|
.filter(|enc| enc.is_some())
|
||||||
.map(|enc| enc.unwrap())
|
.map(|enc| enc.unwrap())
|
||||||
.map(|encoder| {
|
.map(|encoder| {
|
||||||
self.fd.get_encoder(encoder)
|
self.fd.get_encoder(encoder).map_err(|source| Error::Access {
|
||||||
.map_err(|source| Error::Access {
|
errmsg: "Error loading encoder info",
|
||||||
errmsg: "Error loading encoder info",
|
dev: self.fd.dev_path(),
|
||||||
dev: self.fd.dev_path(),
|
source,
|
||||||
source,
|
})
|
||||||
})
|
|
||||||
})
|
})
|
||||||
.collect::<Result<Vec<encoder::Info>, _>>()?;
|
.collect::<Result<Vec<encoder::Info>, _>>()?;
|
||||||
|
|
||||||
|
@ -406,9 +412,7 @@ impl<A: AsRawFd + 'static> Drop for LegacyDrmSurface<A> {
|
||||||
|
|
||||||
// disable connectors again
|
// disable connectors again
|
||||||
let current = self.state.read().unwrap();
|
let current = self.state.read().unwrap();
|
||||||
if set_connector_state(&*self.fd, current.connectors.iter().copied(), false)
|
if set_connector_state(&*self.fd, current.connectors.iter().copied(), false).is_ok() {
|
||||||
.is_ok()
|
|
||||||
{
|
|
||||||
// null commit
|
// null commit
|
||||||
let _ = self.fd.set_crtc(self.crtc, None, (0, 0), &[], None);
|
let _ = self.fd.set_crtc(self.crtc, None, (0, 0), &[], None);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,18 +2,17 @@ use std::collections::HashSet;
|
||||||
use std::os::unix::io::{AsRawFd, RawFd};
|
use std::os::unix::io::{AsRawFd, RawFd};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use drm::control::{connector, crtc, framebuffer, plane, Device as ControlDevice, Mode};
|
||||||
use drm::Device as BasicDevice;
|
use drm::Device as BasicDevice;
|
||||||
use drm::control::{Device as ControlDevice, Mode, crtc, connector, framebuffer, plane};
|
|
||||||
|
|
||||||
pub(super) mod atomic;
|
pub(super) mod atomic;
|
||||||
pub(super) mod legacy;
|
pub(super) mod legacy;
|
||||||
use super::error::Error;
|
use super::error::Error;
|
||||||
|
use crate::backend::allocator::Format;
|
||||||
use atomic::AtomicDrmSurface;
|
use atomic::AtomicDrmSurface;
|
||||||
use legacy::LegacyDrmSurface;
|
use legacy::LegacyDrmSurface;
|
||||||
use crate::backend::allocator::Format;
|
|
||||||
|
|
||||||
pub struct DrmSurface<A: AsRawFd + 'static>
|
pub struct DrmSurface<A: AsRawFd + 'static> {
|
||||||
{
|
|
||||||
pub(super) crtc: crtc::Handle,
|
pub(super) crtc: crtc::Handle,
|
||||||
pub(super) plane: plane::Handle,
|
pub(super) plane: plane::Handle,
|
||||||
pub(super) internal: Arc<DrmSurfaceInternal<A>>,
|
pub(super) internal: Arc<DrmSurfaceInternal<A>>,
|
||||||
|
@ -46,7 +45,7 @@ impl<A: AsRawFd + 'static> DrmSurface<A> {
|
||||||
pub fn plane(&self) -> plane::Handle {
|
pub fn plane(&self) -> plane::Handle {
|
||||||
self.plane
|
self.plane
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Currently used [`connector`](drm::control::connector)s of this `Surface`
|
/// Currently used [`connector`](drm::control::connector)s of this `Surface`
|
||||||
pub fn current_connectors(&self) -> impl IntoIterator<Item = connector::Handle> {
|
pub fn current_connectors(&self) -> impl IntoIterator<Item = connector::Handle> {
|
||||||
match &*self.internal {
|
match &*self.internal {
|
||||||
|
@ -185,12 +184,21 @@ impl<A: AsRawFd + 'static> DrmSurface<A> {
|
||||||
&self.formats
|
&self.formats
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn test_buffer(&self, fb: framebuffer::Handle, mode: &Mode, allow_screen_change: bool) -> Result<bool, Error> {
|
pub fn test_buffer(
|
||||||
|
&self,
|
||||||
|
fb: framebuffer::Handle,
|
||||||
|
mode: &Mode,
|
||||||
|
allow_screen_change: bool,
|
||||||
|
) -> Result<bool, Error> {
|
||||||
match &*self.internal {
|
match &*self.internal {
|
||||||
DrmSurfaceInternal::Atomic(surf) => surf.test_buffer(fb, mode),
|
DrmSurfaceInternal::Atomic(surf) => surf.test_buffer(fb, mode),
|
||||||
DrmSurfaceInternal::Legacy(surf) => if allow_screen_change {
|
DrmSurfaceInternal::Legacy(surf) => {
|
||||||
surf.test_buffer(fb, mode)
|
if allow_screen_change {
|
||||||
} else { Ok(false) } // There is no test-commiting with the legacy interface
|
surf.test_buffer(fb, mode)
|
||||||
|
} else {
|
||||||
|
Ok(false)
|
||||||
|
}
|
||||||
|
} // There is no test-commiting with the legacy interface
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,6 @@ use super::{ffi, wrap_egl_call, Error, MakeCurrentError};
|
||||||
use crate::backend::egl::display::{EGLDisplay, PixelFormat};
|
use crate::backend::egl::display::{EGLDisplay, PixelFormat};
|
||||||
use crate::backend::egl::EGLSurface;
|
use crate::backend::egl::EGLSurface;
|
||||||
|
|
||||||
|
|
||||||
/// EGL context for rendering
|
/// EGL context for rendering
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct EGLContext {
|
pub struct EGLContext {
|
||||||
|
@ -20,10 +19,7 @@ unsafe impl Send for EGLContext {}
|
||||||
unsafe impl Sync for EGLContext {}
|
unsafe impl Sync for EGLContext {}
|
||||||
|
|
||||||
impl EGLContext {
|
impl EGLContext {
|
||||||
pub fn new<L>(
|
pub fn new<L>(display: &EGLDisplay, log: L) -> Result<EGLContext, Error>
|
||||||
display: &EGLDisplay,
|
|
||||||
log: L,
|
|
||||||
) -> Result<EGLContext, Error>
|
|
||||||
where
|
where
|
||||||
L: Into<Option<::slog::Logger>>,
|
L: Into<Option<::slog::Logger>>,
|
||||||
{
|
{
|
||||||
|
@ -43,17 +39,13 @@ impl EGLContext {
|
||||||
Self::new_internal(display, None, Some((attributes, reqs)), log)
|
Self::new_internal(display, None, Some((attributes, reqs)), log)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_shared<L>(
|
pub fn new_shared<L>(display: &EGLDisplay, share: &EGLContext, log: L) -> Result<EGLContext, Error>
|
||||||
display: &EGLDisplay,
|
|
||||||
share: &EGLContext,
|
|
||||||
log: L,
|
|
||||||
) -> Result<EGLContext, Error>
|
|
||||||
where
|
where
|
||||||
L: Into<Option<::slog::Logger>>,
|
L: Into<Option<::slog::Logger>>,
|
||||||
{
|
{
|
||||||
Self::new_internal(display, Some(share), None, log)
|
Self::new_internal(display, Some(share), None, log)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_shared_with_config<L>(
|
pub fn new_shared_with_config<L>(
|
||||||
display: &EGLDisplay,
|
display: &EGLDisplay,
|
||||||
share: &EGLContext,
|
share: &EGLContext,
|
||||||
|
@ -82,13 +74,26 @@ impl EGLContext {
|
||||||
Some((attributes, reqs)) => {
|
Some((attributes, reqs)) => {
|
||||||
let (format, config_id) = display.choose_config(attributes, reqs)?;
|
let (format, config_id) = display.choose_config(attributes, reqs)?;
|
||||||
(Some(format), config_id)
|
(Some(format), config_id)
|
||||||
},
|
}
|
||||||
None => {
|
None => {
|
||||||
if !display.extensions.iter().any(|x| x == "EGL_KHR_no_config_context") &&
|
if !display
|
||||||
!display.extensions.iter().any(|x| x == "EGL_MESA_configless_context") &&
|
.extensions
|
||||||
!display.extensions.iter().any(|x| x == "EGL_KHR_surfaceless_context")
|
.iter()
|
||||||
|
.any(|x| x == "EGL_KHR_no_config_context")
|
||||||
|
&& !display
|
||||||
|
.extensions
|
||||||
|
.iter()
|
||||||
|
.any(|x| x == "EGL_MESA_configless_context")
|
||||||
|
&& !display
|
||||||
|
.extensions
|
||||||
|
.iter()
|
||||||
|
.any(|x| x == "EGL_KHR_surfaceless_context")
|
||||||
{
|
{
|
||||||
return Err(Error::EglExtensionNotSupported(&["EGL_KHR_no_config_context", "EGL_MESA_configless_context", "EGL_KHR_surfaceless_context"]));
|
return Err(Error::EglExtensionNotSupported(&[
|
||||||
|
"EGL_KHR_no_config_context",
|
||||||
|
"EGL_MESA_configless_context",
|
||||||
|
"EGL_KHR_surfaceless_context",
|
||||||
|
]));
|
||||||
}
|
}
|
||||||
(None, ffi::egl::NO_CONFIG_KHR)
|
(None, ffi::egl::NO_CONFIG_KHR)
|
||||||
}
|
}
|
||||||
|
@ -99,7 +104,9 @@ impl EGLContext {
|
||||||
if let Some((attributes, _)) = config {
|
if let Some((attributes, _)) = config {
|
||||||
let version = attributes.version;
|
let version = attributes.version;
|
||||||
|
|
||||||
if display.egl_version >= (1, 5) || display.extensions.iter().any(|s| s == "EGL_KHR_create_context") {
|
if display.egl_version >= (1, 5)
|
||||||
|
|| display.extensions.iter().any(|s| s == "EGL_KHR_create_context")
|
||||||
|
{
|
||||||
trace!(log, "Setting CONTEXT_MAJOR_VERSION to {}", version.0);
|
trace!(log, "Setting CONTEXT_MAJOR_VERSION to {}", version.0);
|
||||||
context_attributes.push(ffi::egl::CONTEXT_MAJOR_VERSION as i32);
|
context_attributes.push(ffi::egl::CONTEXT_MAJOR_VERSION as i32);
|
||||||
context_attributes.push(version.0 as i32);
|
context_attributes.push(version.0 as i32);
|
||||||
|
@ -134,7 +141,9 @@ impl EGLContext {
|
||||||
ffi::egl::CreateContext(
|
ffi::egl::CreateContext(
|
||||||
**display.display,
|
**display.display,
|
||||||
config_id,
|
config_id,
|
||||||
shared.map(|context| context.context).unwrap_or(ffi::egl::NO_CONTEXT),
|
shared
|
||||||
|
.map(|context| context.context)
|
||||||
|
.unwrap_or(ffi::egl::NO_CONTEXT),
|
||||||
context_attributes.as_ptr(),
|
context_attributes.as_ptr(),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
@ -157,12 +166,13 @@ impl EGLContext {
|
||||||
///
|
///
|
||||||
/// This function is marked unsafe, because the context cannot be made current
|
/// This function is marked unsafe, because the context cannot be made current
|
||||||
/// on multiple threads.
|
/// on multiple threads.
|
||||||
pub unsafe fn make_current_with_surface(&self, surface: &EGLSurface) -> Result<(), MakeCurrentError>
|
pub unsafe fn make_current_with_surface(&self, surface: &EGLSurface) -> Result<(), MakeCurrentError> {
|
||||||
{
|
|
||||||
let surface_ptr = surface.surface.load(Ordering::SeqCst);
|
let surface_ptr = surface.surface.load(Ordering::SeqCst);
|
||||||
wrap_egl_call(|| ffi::egl::MakeCurrent(**self.display.display, surface_ptr, surface_ptr, self.context))
|
wrap_egl_call(|| {
|
||||||
.map(|_| ())
|
ffi::egl::MakeCurrent(**self.display.display, surface_ptr, surface_ptr, self.context)
|
||||||
.map_err(Into::into)
|
})
|
||||||
|
.map(|_| ())
|
||||||
|
.map_err(Into::into)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Makes the OpenGL context the current context in the current thread with no surface bound.
|
/// Makes the OpenGL context the current context in the current thread with no surface bound.
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
//! Type safe native types for safe egl initialisation
|
//! Type safe native types for safe egl initialisation
|
||||||
|
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::sync::Arc;
|
|
||||||
use std::ffi::CStr;
|
use std::ffi::CStr;
|
||||||
use std::mem::MaybeUninit;
|
use std::mem::MaybeUninit;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
use nix::libc::c_int;
|
use nix::libc::c_int;
|
||||||
#[cfg(all(feature = "use_system_lib", feature = "wayland_frontend"))]
|
#[cfg(all(feature = "use_system_lib", feature = "wayland_frontend"))]
|
||||||
|
@ -12,13 +12,13 @@ use wayland_server::{protocol::wl_buffer::WlBuffer, Display};
|
||||||
#[cfg(feature = "use_system_lib")]
|
#[cfg(feature = "use_system_lib")]
|
||||||
use wayland_sys::server::wl_display;
|
use wayland_sys::server::wl_display;
|
||||||
|
|
||||||
use crate::backend::allocator::{Buffer, dmabuf::Dmabuf, Fourcc, Modifier, Format as DrmFormat};
|
use crate::backend::allocator::{dmabuf::Dmabuf, Buffer, Format as DrmFormat, Fourcc, Modifier};
|
||||||
use crate::backend::egl::{
|
use crate::backend::egl::{
|
||||||
ffi::egl::types::EGLImage,
|
|
||||||
ffi, wrap_egl_call, EGLError, Error,
|
|
||||||
context::{GlAttributes, PixelFormatRequirements},
|
context::{GlAttributes, PixelFormatRequirements},
|
||||||
native::{EGLNativeDisplay},
|
ffi,
|
||||||
BufferAccessError, EGLBuffer, Format,
|
ffi::egl::types::EGLImage,
|
||||||
|
native::EGLNativeDisplay,
|
||||||
|
wrap_egl_call, BufferAccessError, EGLBuffer, EGLError, Error, Format,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Wrapper around [`ffi::EGLDisplay`](ffi::egl::types::EGLDisplay) to ensure display is only destroyed
|
/// Wrapper around [`ffi::EGLDisplay`](ffi::egl::types::EGLDisplay) to ensure display is only destroyed
|
||||||
|
@ -94,7 +94,7 @@ impl EGLDisplay {
|
||||||
return Err(Error::EglExtensionNotSupported(native.required_extensions()));
|
return Err(Error::EglExtensionNotSupported(native.required_extensions()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let (platform, native_ptr, attributes) = native.platform_display();
|
let (platform, native_ptr, attributes) = native.platform_display();
|
||||||
// we create an EGLDisplay
|
// we create an EGLDisplay
|
||||||
let display = unsafe {
|
let display = unsafe {
|
||||||
|
@ -355,62 +355,92 @@ impl EGLDisplay {
|
||||||
|
|
||||||
/// Imports a dmabuf as an eglimage
|
/// Imports a dmabuf as an eglimage
|
||||||
pub fn create_image_from_dmabuf(&self, dmabuf: &Dmabuf) -> Result<EGLImage, Error> {
|
pub fn create_image_from_dmabuf(&self, dmabuf: &Dmabuf) -> Result<EGLImage, Error> {
|
||||||
if !self.extensions.iter().any(|s| s == "EGL_KHR_image_base") &&
|
if !self.extensions.iter().any(|s| s == "EGL_KHR_image_base")
|
||||||
!self.extensions.iter().any(|s| s == "EGL_EXT_image_dma_buf_import")
|
&& !self
|
||||||
|
.extensions
|
||||||
|
.iter()
|
||||||
|
.any(|s| s == "EGL_EXT_image_dma_buf_import")
|
||||||
{
|
{
|
||||||
return Err(Error::EglExtensionNotSupported(&["EGL_KHR_image_base", "EGL_EXT_image_dma_buf_import"]));
|
return Err(Error::EglExtensionNotSupported(&[
|
||||||
|
"EGL_KHR_image_base",
|
||||||
|
"EGL_EXT_image_dma_buf_import",
|
||||||
|
]));
|
||||||
}
|
}
|
||||||
|
|
||||||
if dmabuf.has_modifier() && !self.extensions.iter().any(|s| s == "EGL_EXT_image_dma_buf_import_modifiers") {
|
if dmabuf.has_modifier()
|
||||||
return Err(Error::EglExtensionNotSupported(&["EGL_EXT_image_dma_buf_import_modifiers"]));
|
&& !self
|
||||||
|
.extensions
|
||||||
|
.iter()
|
||||||
|
.any(|s| s == "EGL_EXT_image_dma_buf_import_modifiers")
|
||||||
|
{
|
||||||
|
return Err(Error::EglExtensionNotSupported(&[
|
||||||
|
"EGL_EXT_image_dma_buf_import_modifiers",
|
||||||
|
]));
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut out: Vec<c_int> = Vec::with_capacity(50);
|
let mut out: Vec<c_int> = Vec::with_capacity(50);
|
||||||
|
|
||||||
out.extend(&[
|
out.extend(&[
|
||||||
ffi::egl::WIDTH as i32, dmabuf.width() as i32,
|
ffi::egl::WIDTH as i32,
|
||||||
ffi::egl::HEIGHT as i32, dmabuf.height() as i32,
|
dmabuf.width() as i32,
|
||||||
ffi::egl::LINUX_DRM_FOURCC_EXT as i32, dmabuf.format().code as u32 as i32,
|
ffi::egl::HEIGHT as i32,
|
||||||
|
dmabuf.height() as i32,
|
||||||
|
ffi::egl::LINUX_DRM_FOURCC_EXT as i32,
|
||||||
|
dmabuf.format().code as u32 as i32,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
let names = [
|
let names = [
|
||||||
[
|
[
|
||||||
ffi::egl::DMA_BUF_PLANE0_FD_EXT,
|
ffi::egl::DMA_BUF_PLANE0_FD_EXT,
|
||||||
ffi::egl::DMA_BUF_PLANE0_OFFSET_EXT,
|
ffi::egl::DMA_BUF_PLANE0_OFFSET_EXT,
|
||||||
ffi::egl::DMA_BUF_PLANE0_PITCH_EXT,
|
ffi::egl::DMA_BUF_PLANE0_PITCH_EXT,
|
||||||
ffi::egl::DMA_BUF_PLANE0_MODIFIER_LO_EXT,
|
ffi::egl::DMA_BUF_PLANE0_MODIFIER_LO_EXT,
|
||||||
ffi::egl::DMA_BUF_PLANE0_MODIFIER_HI_EXT
|
ffi::egl::DMA_BUF_PLANE0_MODIFIER_HI_EXT,
|
||||||
], [
|
],
|
||||||
|
[
|
||||||
ffi::egl::DMA_BUF_PLANE1_FD_EXT,
|
ffi::egl::DMA_BUF_PLANE1_FD_EXT,
|
||||||
ffi::egl::DMA_BUF_PLANE1_OFFSET_EXT,
|
ffi::egl::DMA_BUF_PLANE1_OFFSET_EXT,
|
||||||
ffi::egl::DMA_BUF_PLANE1_PITCH_EXT,
|
ffi::egl::DMA_BUF_PLANE1_PITCH_EXT,
|
||||||
ffi::egl::DMA_BUF_PLANE1_MODIFIER_LO_EXT,
|
ffi::egl::DMA_BUF_PLANE1_MODIFIER_LO_EXT,
|
||||||
ffi::egl::DMA_BUF_PLANE1_MODIFIER_HI_EXT
|
ffi::egl::DMA_BUF_PLANE1_MODIFIER_HI_EXT,
|
||||||
], [
|
],
|
||||||
|
[
|
||||||
ffi::egl::DMA_BUF_PLANE2_FD_EXT,
|
ffi::egl::DMA_BUF_PLANE2_FD_EXT,
|
||||||
ffi::egl::DMA_BUF_PLANE2_OFFSET_EXT,
|
ffi::egl::DMA_BUF_PLANE2_OFFSET_EXT,
|
||||||
ffi::egl::DMA_BUF_PLANE2_PITCH_EXT,
|
ffi::egl::DMA_BUF_PLANE2_PITCH_EXT,
|
||||||
ffi::egl::DMA_BUF_PLANE2_MODIFIER_LO_EXT,
|
ffi::egl::DMA_BUF_PLANE2_MODIFIER_LO_EXT,
|
||||||
ffi::egl::DMA_BUF_PLANE2_MODIFIER_HI_EXT
|
ffi::egl::DMA_BUF_PLANE2_MODIFIER_HI_EXT,
|
||||||
], [
|
],
|
||||||
|
[
|
||||||
ffi::egl::DMA_BUF_PLANE3_FD_EXT,
|
ffi::egl::DMA_BUF_PLANE3_FD_EXT,
|
||||||
ffi::egl::DMA_BUF_PLANE3_OFFSET_EXT,
|
ffi::egl::DMA_BUF_PLANE3_OFFSET_EXT,
|
||||||
ffi::egl::DMA_BUF_PLANE3_PITCH_EXT,
|
ffi::egl::DMA_BUF_PLANE3_PITCH_EXT,
|
||||||
ffi::egl::DMA_BUF_PLANE3_MODIFIER_LO_EXT,
|
ffi::egl::DMA_BUF_PLANE3_MODIFIER_LO_EXT,
|
||||||
ffi::egl::DMA_BUF_PLANE3_MODIFIER_HI_EXT
|
ffi::egl::DMA_BUF_PLANE3_MODIFIER_HI_EXT,
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
for (i, ((fd, offset), stride)) in dmabuf.handles().iter().zip(dmabuf.offsets()).zip(dmabuf.strides()).enumerate() {
|
for (i, ((fd, offset), stride)) in dmabuf
|
||||||
|
.handles()
|
||||||
|
.iter()
|
||||||
|
.zip(dmabuf.offsets())
|
||||||
|
.zip(dmabuf.strides())
|
||||||
|
.enumerate()
|
||||||
|
{
|
||||||
out.extend(&[
|
out.extend(&[
|
||||||
names[i][0] as i32, *fd,
|
names[i][0] as i32,
|
||||||
names[i][1] as i32, *offset as i32,
|
*fd,
|
||||||
names[i][2] as i32, *stride as i32,
|
names[i][1] as i32,
|
||||||
|
*offset as i32,
|
||||||
|
names[i][2] as i32,
|
||||||
|
*stride as i32,
|
||||||
]);
|
]);
|
||||||
if dmabuf.has_modifier() {
|
if dmabuf.has_modifier() {
|
||||||
out.extend(&[
|
out.extend(&[
|
||||||
names[i][3] as i32, (Into::<u64>::into(dmabuf.format().modifier) & 0xFFFFFFFF) as i32,
|
names[i][3] as i32,
|
||||||
names[i][4] as i32, (Into::<u64>::into(dmabuf.format().modifier) >> 32) as i32,
|
(Into::<u64>::into(dmabuf.format().modifier) & 0xFFFFFFFF) as i32,
|
||||||
|
names[i][4] as i32,
|
||||||
|
(Into::<u64>::into(dmabuf.format().modifier) >> 32) as i32,
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -460,8 +490,11 @@ impl EGLDisplay {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_dmabuf_formats(display: &ffi::egl::types::EGLDisplay, extensions: &[String], log: &::slog::Logger) -> Result<(HashSet<DrmFormat>, HashSet<DrmFormat>), EGLError>
|
fn get_dmabuf_formats(
|
||||||
{
|
display: &ffi::egl::types::EGLDisplay,
|
||||||
|
extensions: &[String],
|
||||||
|
log: &::slog::Logger,
|
||||||
|
) -> Result<(HashSet<DrmFormat>, HashSet<DrmFormat>), EGLError> {
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
|
|
||||||
if !extensions.iter().any(|s| s == "EGL_EXT_image_dma_buf_import") {
|
if !extensions.iter().any(|s| s == "EGL_EXT_image_dma_buf_import") {
|
||||||
|
@ -475,11 +508,11 @@ fn get_dmabuf_formats(display: &ffi::egl::types::EGLDisplay, extensions: &[Strin
|
||||||
// supported; it's the intended way to just try to create buffers.
|
// supported; it's the intended way to just try to create buffers.
|
||||||
// Just a guess but better than not supporting dmabufs at all,
|
// Just a guess but better than not supporting dmabufs at all,
|
||||||
// given that the modifiers extension isn't supported everywhere.
|
// given that the modifiers extension isn't supported everywhere.
|
||||||
if !extensions.iter().any(|s| s == "EGL_EXT_image_dma_buf_import_modifiers") {
|
if !extensions
|
||||||
vec![
|
.iter()
|
||||||
Fourcc::Argb8888,
|
.any(|s| s == "EGL_EXT_image_dma_buf_import_modifiers")
|
||||||
Fourcc::Xrgb8888,
|
{
|
||||||
]
|
vec![Fourcc::Argb8888, Fourcc::Xrgb8888]
|
||||||
} else {
|
} else {
|
||||||
let mut num = 0i32;
|
let mut num = 0i32;
|
||||||
wrap_egl_call(|| unsafe {
|
wrap_egl_call(|| unsafe {
|
||||||
|
@ -490,12 +523,20 @@ fn get_dmabuf_formats(display: &ffi::egl::types::EGLDisplay, extensions: &[Strin
|
||||||
}
|
}
|
||||||
let mut formats: Vec<u32> = Vec::with_capacity(num as usize);
|
let mut formats: Vec<u32> = Vec::with_capacity(num as usize);
|
||||||
wrap_egl_call(|| unsafe {
|
wrap_egl_call(|| unsafe {
|
||||||
ffi::egl::QueryDmaBufFormatsEXT(*display, num, formats.as_mut_ptr() as *mut _, &mut num as *mut _)
|
ffi::egl::QueryDmaBufFormatsEXT(
|
||||||
|
*display,
|
||||||
|
num,
|
||||||
|
formats.as_mut_ptr() as *mut _,
|
||||||
|
&mut num as *mut _,
|
||||||
|
)
|
||||||
})?;
|
})?;
|
||||||
unsafe {
|
unsafe {
|
||||||
formats.set_len(num as usize);
|
formats.set_len(num as usize);
|
||||||
}
|
}
|
||||||
formats.into_iter().flat_map(|x| Fourcc::try_from(x).ok()).collect::<Vec<_>>()
|
formats
|
||||||
|
.into_iter()
|
||||||
|
.flat_map(|x| Fourcc::try_from(x).ok())
|
||||||
|
.collect::<Vec<_>>()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -505,24 +546,38 @@ fn get_dmabuf_formats(display: &ffi::egl::types::EGLDisplay, extensions: &[Strin
|
||||||
for fourcc in formats {
|
for fourcc in formats {
|
||||||
let mut num = 0i32;
|
let mut num = 0i32;
|
||||||
wrap_egl_call(|| unsafe {
|
wrap_egl_call(|| unsafe {
|
||||||
ffi::egl::QueryDmaBufModifiersEXT(*display, fourcc as i32, 0, std::ptr::null_mut(), std::ptr::null_mut(), &mut num as *mut _)
|
ffi::egl::QueryDmaBufModifiersEXT(
|
||||||
|
*display,
|
||||||
|
fourcc as i32,
|
||||||
|
0,
|
||||||
|
std::ptr::null_mut(),
|
||||||
|
std::ptr::null_mut(),
|
||||||
|
&mut num as *mut _,
|
||||||
|
)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
if num == 0 {
|
if num == 0 {
|
||||||
texture_formats.insert(DrmFormat {
|
texture_formats.insert(DrmFormat {
|
||||||
code: fourcc,
|
code: fourcc,
|
||||||
modifier: Modifier::Invalid
|
modifier: Modifier::Invalid,
|
||||||
});
|
});
|
||||||
render_formats.insert(DrmFormat {
|
render_formats.insert(DrmFormat {
|
||||||
code: fourcc,
|
code: fourcc,
|
||||||
modifier: Modifier::Invalid
|
modifier: Modifier::Invalid,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
let mut mods: Vec<u64> = Vec::with_capacity(num as usize);
|
let mut mods: Vec<u64> = Vec::with_capacity(num as usize);
|
||||||
let mut external: Vec<ffi::egl::types::EGLBoolean> = Vec::with_capacity(num as usize);
|
let mut external: Vec<ffi::egl::types::EGLBoolean> = Vec::with_capacity(num as usize);
|
||||||
|
|
||||||
wrap_egl_call(|| unsafe {
|
wrap_egl_call(|| unsafe {
|
||||||
ffi::egl::QueryDmaBufModifiersEXT(*display, fourcc as i32, num, mods.as_mut_ptr(), external.as_mut_ptr(), &mut num as *mut _)
|
ffi::egl::QueryDmaBufModifiersEXT(
|
||||||
|
*display,
|
||||||
|
fourcc as i32,
|
||||||
|
num,
|
||||||
|
mods.as_mut_ptr(),
|
||||||
|
external.as_mut_ptr(),
|
||||||
|
&mut num as *mut _,
|
||||||
|
)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -572,10 +627,7 @@ impl fmt::Debug for EGLBufferReader {
|
||||||
#[cfg(feature = "use_system_lib")]
|
#[cfg(feature = "use_system_lib")]
|
||||||
impl EGLBufferReader {
|
impl EGLBufferReader {
|
||||||
fn new(display: Arc<EGLDisplayHandle>, wayland: *mut wl_display) -> Self {
|
fn new(display: Arc<EGLDisplayHandle>, wayland: *mut wl_display) -> Self {
|
||||||
Self {
|
Self { display, wayland }
|
||||||
display,
|
|
||||||
wayland,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Try to receive [`EGLImages`] from a given [`WlBuffer`].
|
/// Try to receive [`EGLImages`] from a given [`WlBuffer`].
|
||||||
|
@ -605,9 +657,15 @@ impl EGLBufferReader {
|
||||||
x if x == ffi::egl::TEXTURE_RGB as i32 => Format::RGB,
|
x if x == ffi::egl::TEXTURE_RGB as i32 => Format::RGB,
|
||||||
x if x == ffi::egl::TEXTURE_RGBA as i32 => Format::RGBA,
|
x if x == ffi::egl::TEXTURE_RGBA as i32 => Format::RGBA,
|
||||||
ffi::egl::TEXTURE_EXTERNAL_WL => Format::External,
|
ffi::egl::TEXTURE_EXTERNAL_WL => Format::External,
|
||||||
ffi::egl::TEXTURE_Y_UV_WL => return Err(BufferAccessError::UnsupportedMultiPlanarFormat(Format::Y_UV)),
|
ffi::egl::TEXTURE_Y_UV_WL => {
|
||||||
ffi::egl::TEXTURE_Y_U_V_WL => return Err(BufferAccessError::UnsupportedMultiPlanarFormat(Format::Y_U_V)),
|
return Err(BufferAccessError::UnsupportedMultiPlanarFormat(Format::Y_UV))
|
||||||
ffi::egl::TEXTURE_Y_XUXV_WL => return Err(BufferAccessError::UnsupportedMultiPlanarFormat(Format::Y_XUXV)),
|
}
|
||||||
|
ffi::egl::TEXTURE_Y_U_V_WL => {
|
||||||
|
return Err(BufferAccessError::UnsupportedMultiPlanarFormat(Format::Y_U_V))
|
||||||
|
}
|
||||||
|
ffi::egl::TEXTURE_Y_XUXV_WL => {
|
||||||
|
return Err(BufferAccessError::UnsupportedMultiPlanarFormat(Format::Y_XUXV))
|
||||||
|
}
|
||||||
x => panic!("EGL returned invalid texture type: {}", x),
|
x => panic!("EGL returned invalid texture type: {}", x),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -646,11 +704,7 @@ impl EGLBufferReader {
|
||||||
|
|
||||||
let mut images = Vec::with_capacity(format.num_planes());
|
let mut images = Vec::with_capacity(format.num_planes());
|
||||||
for i in 0..format.num_planes() {
|
for i in 0..format.num_planes() {
|
||||||
let out = [
|
let out = [ffi::egl::WAYLAND_PLANE_WL as i32, i as i32, ffi::egl::NONE as i32];
|
||||||
ffi::egl::WAYLAND_PLANE_WL as i32,
|
|
||||||
i as i32,
|
|
||||||
ffi::egl::NONE as i32,
|
|
||||||
];
|
|
||||||
|
|
||||||
images.push({
|
images.push({
|
||||||
wrap_egl_call(|| unsafe {
|
wrap_egl_call(|| unsafe {
|
||||||
|
@ -740,4 +794,4 @@ pub struct PixelFormat {
|
||||||
pub multisampling: Option<u16>,
|
pub multisampling: Option<u16>,
|
||||||
/// is srgb enabled
|
/// is srgb enabled
|
||||||
pub srgb: bool,
|
pub srgb: bool,
|
||||||
}
|
}
|
||||||
|
|
|
@ -106,8 +106,11 @@ impl fmt::Debug for BufferAccessError {
|
||||||
write!(formatter, "BufferAccessError::EGLImageCreationFailed")
|
write!(formatter, "BufferAccessError::EGLImageCreationFailed")
|
||||||
}
|
}
|
||||||
BufferAccessError::EglExtensionNotSupported(ref err) => write!(formatter, "{:?}", err),
|
BufferAccessError::EglExtensionNotSupported(ref err) => write!(formatter, "{:?}", err),
|
||||||
BufferAccessError::UnsupportedMultiPlanarFormat(ref fmt) =>
|
BufferAccessError::UnsupportedMultiPlanarFormat(ref fmt) => write!(
|
||||||
write!(formatter, "BufferAccessError::UnsupportedMultiPlanerFormat({:?})", fmt),
|
formatter,
|
||||||
|
"BufferAccessError::UnsupportedMultiPlanerFormat({:?})",
|
||||||
|
fmt
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -132,9 +135,7 @@ impl std::convert::From<SwapBuffersError> for GraphicsSwapBuffersError {
|
||||||
}
|
}
|
||||||
// the rest is either never happening or are unrecoverable
|
// the rest is either never happening or are unrecoverable
|
||||||
x @ SwapBuffersError::EGLSwapBuffers(_) => GraphicsSwapBuffersError::ContextLost(Box::new(x)),
|
x @ SwapBuffersError::EGLSwapBuffers(_) => GraphicsSwapBuffersError::ContextLost(Box::new(x)),
|
||||||
x @ SwapBuffersError::EGLCreateSurface(_) => {
|
x @ SwapBuffersError::EGLCreateSurface(_) => GraphicsSwapBuffersError::ContextLost(Box::new(x)),
|
||||||
GraphicsSwapBuffersError::ContextLost(Box::new(x))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,10 @@
|
||||||
//! Type safe native types for safe context/surface creation
|
//! Type safe native types for safe context/surface creation
|
||||||
|
|
||||||
use super::{
|
use super::{display::EGLDisplayHandle, ffi, wrap_egl_call, SwapBuffersError};
|
||||||
display::EGLDisplayHandle, ffi, wrap_egl_call, SwapBuffersError,
|
|
||||||
};
|
|
||||||
use nix::libc::{c_int, c_void};
|
use nix::libc::{c_int, c_void};
|
||||||
use std::sync::Arc;
|
|
||||||
#[cfg(feature = "backend_gbm")]
|
#[cfg(feature = "backend_gbm")]
|
||||||
use std::os::unix::io::AsRawFd;
|
use std::os::unix::io::AsRawFd;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
#[cfg(feature = "backend_winit")]
|
#[cfg(feature = "backend_winit")]
|
||||||
use wayland_egl as wegl;
|
use wayland_egl as wegl;
|
||||||
|
@ -33,7 +31,11 @@ impl<A: AsRawFd + Send + 'static> EGLNativeDisplay for GbmDevice<A> {
|
||||||
&["EGL_MESA_platform_gbm"]
|
&["EGL_MESA_platform_gbm"]
|
||||||
}
|
}
|
||||||
fn platform_display(&self) -> (ffi::egl::types::EGLenum, *mut c_void, Vec<ffi::EGLint>) {
|
fn platform_display(&self) -> (ffi::egl::types::EGLenum, *mut c_void, Vec<ffi::EGLint>) {
|
||||||
(ffi::egl::PLATFORM_GBM_MESA, self.as_raw() as *mut _, vec![ffi::egl::NONE as ffi::EGLint])
|
(
|
||||||
|
ffi::egl::PLATFORM_GBM_MESA,
|
||||||
|
self.as_raw() as *mut _,
|
||||||
|
vec![ffi::egl::NONE as ffi::EGLint],
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,9 +53,17 @@ impl EGLNativeDisplay for WinitWindow {
|
||||||
|
|
||||||
fn platform_display(&self) -> (ffi::egl::types::EGLenum, *mut c_void, Vec<ffi::EGLint>) {
|
fn platform_display(&self) -> (ffi::egl::types::EGLenum, *mut c_void, Vec<ffi::EGLint>) {
|
||||||
if let Some(display) = self.wayland_display() {
|
if let Some(display) = self.wayland_display() {
|
||||||
(ffi::egl::PLATFORM_WAYLAND_EXT, display as *mut _, vec![ffi::egl::NONE as ffi::EGLint])
|
(
|
||||||
|
ffi::egl::PLATFORM_WAYLAND_EXT,
|
||||||
|
display as *mut _,
|
||||||
|
vec![ffi::egl::NONE as ffi::EGLint],
|
||||||
|
)
|
||||||
} else if let Some(display) = self.xlib_display() {
|
} else if let Some(display) = self.xlib_display() {
|
||||||
(ffi::egl::PLATFORM_X11_EXT, display as *mut _, vec![ffi::egl::NONE as ffi::EGLint])
|
(
|
||||||
|
ffi::egl::PLATFORM_X11_EXT,
|
||||||
|
display as *mut _,
|
||||||
|
vec![ffi::egl::NONE as ffi::EGLint],
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
unreachable!("No backends for winit other then Wayland and X11 are supported")
|
unreachable!("No backends for winit other then Wayland and X11 are supported")
|
||||||
}
|
}
|
||||||
|
@ -91,13 +101,13 @@ pub unsafe trait EGLNativeSurface: Send + Sync {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If the surface supports resizing you may implement and use this function.
|
/// If the surface supports resizing you may implement and use this function.
|
||||||
///
|
///
|
||||||
/// The two first arguments (width, height) are the new size of the surface,
|
/// The two first arguments (width, height) are the new size of the surface,
|
||||||
/// the two others (dx, dy) represent the displacement of the top-left corner of the surface.
|
/// the two others (dx, dy) represent the displacement of the top-left corner of the surface.
|
||||||
/// It allows you to control the direction of the resizing if necessary.
|
/// It allows you to control the direction of the resizing if necessary.
|
||||||
///
|
///
|
||||||
/// Implementations may ignore the dx and dy arguments.
|
/// Implementations may ignore the dx and dy arguments.
|
||||||
///
|
///
|
||||||
/// Returns true if the resize was successful.
|
/// Returns true if the resize was successful.
|
||||||
fn resize(&self, _width: i32, _height: i32, _dx: i32, _dy: i32) -> bool {
|
fn resize(&self, _width: i32, _height: i32, _dx: i32, _dy: i32) -> bool {
|
||||||
false
|
false
|
||||||
|
@ -160,7 +170,7 @@ unsafe impl EGLNativeSurface for wegl::WlEglSurface {
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resize(&self, width: i32, height: i32, dx: i32, dy: i32) -> bool {
|
fn resize(&self, width: i32, height: i32, dx: i32, dy: i32) -> bool {
|
||||||
wegl::WlEglSurface::resize(self, width, height, dx, dy);
|
wegl::WlEglSurface::resize(self, width, height, dx, dy);
|
||||||
true
|
true
|
||||||
|
|
|
@ -9,11 +9,11 @@ use nix::libc::c_int;
|
||||||
|
|
||||||
use crate::backend::egl::{
|
use crate::backend::egl::{
|
||||||
display::{EGLDisplay, EGLDisplayHandle, PixelFormat},
|
display::{EGLDisplay, EGLDisplayHandle, PixelFormat},
|
||||||
|
ffi,
|
||||||
native::EGLNativeSurface,
|
native::EGLNativeSurface,
|
||||||
ffi, EGLError, SwapBuffersError
|
EGLError, SwapBuffersError,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/// EGL surface of a given EGL context for rendering
|
/// EGL surface of a given EGL context for rendering
|
||||||
pub struct EGLSurface {
|
pub struct EGLSurface {
|
||||||
pub(crate) display: Arc<EGLDisplayHandle>,
|
pub(crate) display: Arc<EGLDisplayHandle>,
|
||||||
|
@ -98,14 +98,17 @@ impl EGLSurface {
|
||||||
);
|
);
|
||||||
|
|
||||||
if self.native.needs_recreation() || surface.is_null() || is_bad_surface {
|
if self.native.needs_recreation() || surface.is_null() || is_bad_surface {
|
||||||
let previous = self.surface.compare_exchange(
|
let previous = self
|
||||||
surface,
|
.surface
|
||||||
self.native
|
.compare_exchange(
|
||||||
.create(&self.display, self.config_id, &self.surface_attributes)
|
surface,
|
||||||
.map_err(SwapBuffersError::EGLCreateSurface)? as *mut _,
|
self.native
|
||||||
Ordering::SeqCst,
|
.create(&self.display, self.config_id, &self.surface_attributes)
|
||||||
Ordering::SeqCst,
|
.map_err(SwapBuffersError::EGLCreateSurface)? as *mut _,
|
||||||
).expect("The surface pointer changed in between?");
|
Ordering::SeqCst,
|
||||||
|
Ordering::SeqCst,
|
||||||
|
)
|
||||||
|
.expect("The surface pointer changed in between?");
|
||||||
if previous == surface && !surface.is_null() {
|
if previous == surface && !surface.is_null() {
|
||||||
let _ = unsafe { ffi::egl::DestroySurface(**self.display, surface as *const _) };
|
let _ = unsafe { ffi::egl::DestroySurface(**self.display, surface as *const _) };
|
||||||
}
|
}
|
||||||
|
@ -139,15 +142,15 @@ impl EGLSurface {
|
||||||
pub fn pixel_format(&self) -> PixelFormat {
|
pub fn pixel_format(&self) -> PixelFormat {
|
||||||
self.pixel_format
|
self.pixel_format
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tries to resize the underlying native surface.
|
/// Tries to resize the underlying native surface.
|
||||||
///
|
///
|
||||||
/// The two first arguments (width, height) are the new size of the surface,
|
/// The two first arguments (width, height) are the new size of the surface,
|
||||||
/// the two others (dx, dy) represent the displacement of the top-left corner of the surface.
|
/// the two others (dx, dy) represent the displacement of the top-left corner of the surface.
|
||||||
/// It allows you to control the direction of the resizing if necessary.
|
/// It allows you to control the direction of the resizing if necessary.
|
||||||
///
|
///
|
||||||
/// Implementations may ignore the dx and dy arguments.
|
/// Implementations may ignore the dx and dy arguments.
|
||||||
///
|
///
|
||||||
/// Returns true if the resize was successful.
|
/// Returns true if the resize was successful.
|
||||||
pub fn resize(&self, width: i32, height: i32, dx: i32, dy: i32) -> bool {
|
pub fn resize(&self, width: i32, height: i32, dx: i32, dy: i32) -> bool {
|
||||||
self.native.resize(width, height, dx, dy)
|
self.native.resize(width, height, dx, dy)
|
||||||
|
|
|
@ -18,8 +18,8 @@
|
||||||
#![allow(missing_docs)]
|
#![allow(missing_docs)]
|
||||||
|
|
||||||
//pub mod graphics;
|
//pub mod graphics;
|
||||||
pub mod input;
|
|
||||||
pub mod allocator;
|
pub mod allocator;
|
||||||
|
pub mod input;
|
||||||
pub mod renderer;
|
pub mod renderer;
|
||||||
|
|
||||||
#[cfg(feature = "backend_drm")]
|
#[cfg(feature = "backend_drm")]
|
||||||
|
@ -66,4 +66,4 @@ pub enum SwapBuffersError {
|
||||||
/// recreation.
|
/// recreation.
|
||||||
#[error("A temporary condition caused the page flip to fail: {0}")]
|
#[error("A temporary condition caused the page flip to fail: {0}")]
|
||||||
TemporaryFailure(Box<dyn std::error::Error>),
|
TemporaryFailure(Box<dyn std::error::Error>),
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,13 +6,18 @@ use std::rc::Rc;
|
||||||
use cgmath::{prelude::*, Matrix3};
|
use cgmath::{prelude::*, Matrix3};
|
||||||
|
|
||||||
mod shaders;
|
mod shaders;
|
||||||
|
use super::{Bind, Renderer, Texture, Transform, Unbind};
|
||||||
|
use crate::backend::allocator::{
|
||||||
|
dmabuf::{Dmabuf, WeakDmabuf},
|
||||||
|
Format,
|
||||||
|
};
|
||||||
|
use crate::backend::egl::{
|
||||||
|
ffi::egl::types::EGLImage, EGLBuffer, EGLContext, EGLSurface, Format as EGLFormat, MakeCurrentError,
|
||||||
|
};
|
||||||
use crate::backend::SwapBuffersError;
|
use crate::backend::SwapBuffersError;
|
||||||
use crate::backend::allocator::{dmabuf::{Dmabuf, WeakDmabuf}, Format};
|
|
||||||
use crate::backend::egl::{EGLContext, EGLSurface, EGLBuffer, Format as EGLFormat, ffi::egl::types::EGLImage, MakeCurrentError};
|
|
||||||
use super::{Renderer, Bind, Unbind, Transform, Texture};
|
|
||||||
|
|
||||||
#[cfg(feature = "wayland_frontend")]
|
#[cfg(feature = "wayland_frontend")]
|
||||||
use wayland_server::protocol::{wl_shm, wl_buffer};
|
use wayland_server::protocol::{wl_buffer, wl_shm};
|
||||||
|
|
||||||
#[allow(clippy::all, missing_docs)]
|
#[allow(clippy::all, missing_docs)]
|
||||||
pub mod ffi {
|
pub mod ffi {
|
||||||
|
@ -109,44 +114,52 @@ impl From<Gles2Error> for SwapBuffersError {
|
||||||
| x @ Gles2Error::ProgramLinkError
|
| x @ Gles2Error::ProgramLinkError
|
||||||
| x @ Gles2Error::GLFunctionLoaderError
|
| x @ Gles2Error::GLFunctionLoaderError
|
||||||
| x @ Gles2Error::GLExtensionNotSupported(_)
|
| x @ Gles2Error::GLExtensionNotSupported(_)
|
||||||
| x @ Gles2Error::UnconstraintRenderingOperation
|
| x @ Gles2Error::UnconstraintRenderingOperation => SwapBuffersError::ContextLost(Box::new(x)),
|
||||||
=> SwapBuffersError::ContextLost(Box::new(x)),
|
|
||||||
Gles2Error::ContextActivationError(err) => err.into(),
|
Gles2Error::ContextActivationError(err) => err.into(),
|
||||||
x @ Gles2Error::FramebufferBindingError
|
x @ Gles2Error::FramebufferBindingError
|
||||||
| x @ Gles2Error::BindBufferEGLError(_)
|
| x @ Gles2Error::BindBufferEGLError(_)
|
||||||
| x @ Gles2Error::UnsupportedPixelFormat(_)
|
| x @ Gles2Error::UnsupportedPixelFormat(_)
|
||||||
| x @ Gles2Error::BufferAccessError(_)
|
| x @ Gles2Error::BufferAccessError(_) => SwapBuffersError::TemporaryFailure(Box::new(x)),
|
||||||
=> SwapBuffersError::TemporaryFailure(Box::new(x)),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "system" fn gl_debug_log(_source: ffi::types::GLenum,
|
extern "system" fn gl_debug_log(
|
||||||
gltype: ffi::types::GLenum,
|
_source: ffi::types::GLenum,
|
||||||
_id: ffi::types::GLuint,
|
gltype: ffi::types::GLenum,
|
||||||
_severity: ffi::types::GLenum,
|
_id: ffi::types::GLuint,
|
||||||
_length: ffi::types::GLsizei,
|
_severity: ffi::types::GLenum,
|
||||||
message: *const ffi::types::GLchar,
|
_length: ffi::types::GLsizei,
|
||||||
user_param: *mut nix::libc::c_void)
|
message: *const ffi::types::GLchar,
|
||||||
{
|
user_param: *mut nix::libc::c_void,
|
||||||
let _ = std::panic::catch_unwind(move || {
|
) {
|
||||||
unsafe {
|
let _ = std::panic::catch_unwind(move || unsafe {
|
||||||
let msg = CStr::from_ptr(message);
|
let msg = CStr::from_ptr(message);
|
||||||
let log = Box::from_raw(user_param as *mut ::slog::Logger);
|
let log = Box::from_raw(user_param as *mut ::slog::Logger);
|
||||||
let message_utf8 = msg.to_string_lossy();
|
let message_utf8 = msg.to_string_lossy();
|
||||||
match gltype {
|
match gltype {
|
||||||
ffi::DEBUG_TYPE_ERROR | ffi::DEBUG_TYPE_UNDEFINED_BEHAVIOR => error!(log, "[GL] {}", message_utf8),
|
ffi::DEBUG_TYPE_ERROR | ffi::DEBUG_TYPE_UNDEFINED_BEHAVIOR => {
|
||||||
ffi::DEBUG_TYPE_DEPRECATED_BEHAVIOR => warn!(log, "[GL] {}", message_utf8),
|
error!(log, "[GL] {}", message_utf8)
|
||||||
_ => debug!(log, "[GL] {}", message_utf8),
|
}
|
||||||
};
|
ffi::DEBUG_TYPE_DEPRECATED_BEHAVIOR => warn!(log, "[GL] {}", message_utf8),
|
||||||
std::mem::forget(log);
|
_ => debug!(log, "[GL] {}", message_utf8),
|
||||||
}
|
};
|
||||||
|
std::mem::forget(log);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn compile_shader(gl: &ffi::Gles2, variant: ffi::types::GLuint, src: &'static str) -> Result<ffi::types::GLuint, Gles2Error> {
|
unsafe fn compile_shader(
|
||||||
|
gl: &ffi::Gles2,
|
||||||
|
variant: ffi::types::GLuint,
|
||||||
|
src: &'static str,
|
||||||
|
) -> Result<ffi::types::GLuint, Gles2Error> {
|
||||||
let shader = gl.CreateShader(variant);
|
let shader = gl.CreateShader(variant);
|
||||||
gl.ShaderSource(shader, 1, &src.as_ptr() as *const *const u8 as *const *const i8, &(src.len() as i32) as *const _);
|
gl.ShaderSource(
|
||||||
|
shader,
|
||||||
|
1,
|
||||||
|
&src.as_ptr() as *const *const u8 as *const *const i8,
|
||||||
|
&(src.len() as i32) as *const _,
|
||||||
|
);
|
||||||
gl.CompileShader(shader);
|
gl.CompileShader(shader);
|
||||||
|
|
||||||
let mut status = ffi::FALSE as i32;
|
let mut status = ffi::FALSE as i32;
|
||||||
|
@ -159,7 +172,11 @@ unsafe fn compile_shader(gl: &ffi::Gles2, variant: ffi::types::GLuint, src: &'st
|
||||||
Ok(shader)
|
Ok(shader)
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn link_program(gl: &ffi::Gles2, vert_src: &'static str, frag_src: &'static str) -> Result<ffi::types::GLuint, Gles2Error> {
|
unsafe fn link_program(
|
||||||
|
gl: &ffi::Gles2,
|
||||||
|
vert_src: &'static str,
|
||||||
|
frag_src: &'static str,
|
||||||
|
) -> Result<ffi::types::GLuint, Gles2Error> {
|
||||||
let vert = compile_shader(gl, ffi::VERTEX_SHADER, vert_src)?;
|
let vert = compile_shader(gl, ffi::VERTEX_SHADER, vert_src)?;
|
||||||
let frag = compile_shader(gl, ffi::FRAGMENT_SHADER, frag_src)?;
|
let frag = compile_shader(gl, ffi::FRAGMENT_SHADER, frag_src)?;
|
||||||
let program = gl.CreateProgram();
|
let program = gl.CreateProgram();
|
||||||
|
@ -183,7 +200,7 @@ unsafe fn link_program(gl: &ffi::Gles2, vert_src: &'static str, frag_src: &'stat
|
||||||
|
|
||||||
unsafe fn texture_program(gl: &ffi::Gles2, frag: &'static str) -> Result<Gles2Program, Gles2Error> {
|
unsafe fn texture_program(gl: &ffi::Gles2, frag: &'static str) -> Result<Gles2Program, Gles2Error> {
|
||||||
let program = link_program(&gl, shaders::VERTEX_SHADER, frag)?;
|
let program = link_program(&gl, shaders::VERTEX_SHADER, frag)?;
|
||||||
|
|
||||||
let position = CStr::from_bytes_with_nul(b"position\0").expect("NULL terminated");
|
let position = CStr::from_bytes_with_nul(b"position\0").expect("NULL terminated");
|
||||||
let tex_coords = CStr::from_bytes_with_nul(b"tex_coords\0").expect("NULL terminated");
|
let tex_coords = CStr::from_bytes_with_nul(b"tex_coords\0").expect("NULL terminated");
|
||||||
let tex = CStr::from_bytes_with_nul(b"tex\0").expect("NULL terminated");
|
let tex = CStr::from_bytes_with_nul(b"tex\0").expect("NULL terminated");
|
||||||
|
@ -205,7 +222,7 @@ unsafe fn texture_program(gl: &ffi::Gles2, frag: &'static str) -> Result<Gles2Pr
|
||||||
impl Gles2Renderer {
|
impl Gles2Renderer {
|
||||||
pub unsafe fn new<L>(context: EGLContext, logger: L) -> Result<Gles2Renderer, Gles2Error>
|
pub unsafe fn new<L>(context: EGLContext, logger: L) -> Result<Gles2Renderer, Gles2Error>
|
||||||
where
|
where
|
||||||
L: Into<Option<::slog::Logger>>
|
L: Into<Option<::slog::Logger>>,
|
||||||
{
|
{
|
||||||
let log = crate::slog_or_fallback(logger).new(o!("smithay_module" => "renderer_gles2"));
|
let log = crate::slog_or_fallback(logger).new(o!("smithay_module" => "renderer_gles2"));
|
||||||
|
|
||||||
|
@ -225,14 +242,28 @@ impl Gles2Renderer {
|
||||||
};
|
};
|
||||||
|
|
||||||
info!(log, "Initializing OpenGL ES Renderer");
|
info!(log, "Initializing OpenGL ES Renderer");
|
||||||
info!(log, "GL Version: {:?}", CStr::from_ptr(gl.GetString(ffi::VERSION) as *const i8));
|
info!(
|
||||||
info!(log, "GL Vendor: {:?}", CStr::from_ptr(gl.GetString(ffi::VENDOR) as *const i8));
|
log,
|
||||||
info!(log, "GL Renderer: {:?}", CStr::from_ptr(gl.GetString(ffi::RENDERER) as *const i8));
|
"GL Version: {:?}",
|
||||||
|
CStr::from_ptr(gl.GetString(ffi::VERSION) as *const i8)
|
||||||
|
);
|
||||||
|
info!(
|
||||||
|
log,
|
||||||
|
"GL Vendor: {:?}",
|
||||||
|
CStr::from_ptr(gl.GetString(ffi::VENDOR) as *const i8)
|
||||||
|
);
|
||||||
|
info!(
|
||||||
|
log,
|
||||||
|
"GL Renderer: {:?}",
|
||||||
|
CStr::from_ptr(gl.GetString(ffi::RENDERER) as *const i8)
|
||||||
|
);
|
||||||
info!(log, "Supported GL Extensions: {:?}", exts);
|
info!(log, "Supported GL Extensions: {:?}", exts);
|
||||||
|
|
||||||
// required for the manditory wl_shm formats
|
// required for the manditory wl_shm formats
|
||||||
if !exts.iter().any(|ext| ext == "GL_EXT_texture_format_BGRA8888") {
|
if !exts.iter().any(|ext| ext == "GL_EXT_texture_format_BGRA8888") {
|
||||||
return Err(Gles2Error::GLExtensionNotSupported(&["GL_EXT_texture_format_BGRA8888"]));
|
return Err(Gles2Error::GLExtensionNotSupported(&[
|
||||||
|
"GL_EXT_texture_format_BGRA8888",
|
||||||
|
]));
|
||||||
}
|
}
|
||||||
// required for buffers without linear memory layout
|
// required for buffers without linear memory layout
|
||||||
if !exts.iter().any(|ext| ext == "GL_EXT_unpack_subimage") {
|
if !exts.iter().any(|ext| ext == "GL_EXT_unpack_subimage") {
|
||||||
|
@ -245,17 +276,19 @@ impl Gles2Renderer {
|
||||||
gl.Enable(ffi::DEBUG_OUTPUT_SYNCHRONOUS);
|
gl.Enable(ffi::DEBUG_OUTPUT_SYNCHRONOUS);
|
||||||
gl.DebugMessageCallback(Some(gl_debug_log), logger as *mut nix::libc::c_void);
|
gl.DebugMessageCallback(Some(gl_debug_log), logger as *mut nix::libc::c_void);
|
||||||
Some(logger)
|
Some(logger)
|
||||||
} else { None };
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
(gl, exts, logger)
|
(gl, exts, logger)
|
||||||
};
|
};
|
||||||
|
|
||||||
let programs = [
|
let programs = [
|
||||||
texture_program(&gl, shaders::FRAGMENT_SHADER_ABGR)?,
|
texture_program(&gl, shaders::FRAGMENT_SHADER_ABGR)?,
|
||||||
texture_program(&gl, shaders::FRAGMENT_SHADER_XBGR)?,
|
texture_program(&gl, shaders::FRAGMENT_SHADER_XBGR)?,
|
||||||
texture_program(&gl, shaders::FRAGMENT_SHADER_BGRA)?,
|
texture_program(&gl, shaders::FRAGMENT_SHADER_BGRA)?,
|
||||||
texture_program(&gl, shaders::FRAGMENT_SHADER_BGRX)?,
|
texture_program(&gl, shaders::FRAGMENT_SHADER_BGRX)?,
|
||||||
texture_program(&gl, shaders::FRAGMENT_SHADER_EXTERNAL)?,
|
texture_program(&gl, shaders::FRAGMENT_SHADER_EXTERNAL)?,
|
||||||
];
|
];
|
||||||
|
|
||||||
let renderer = Gles2Renderer {
|
let renderer = Gles2Renderer {
|
||||||
|
@ -312,31 +345,45 @@ impl Bind<Dmabuf> for Gles2Renderer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let buffer = self.buffers
|
let buffer = self
|
||||||
|
.buffers
|
||||||
.iter()
|
.iter()
|
||||||
.find(|buffer| dmabuf == buffer.dmabuf)
|
.find(|buffer| dmabuf == buffer.dmabuf)
|
||||||
.map(|buf| {
|
.map(|buf| {
|
||||||
let dmabuf = buf.dmabuf.upgrade().expect("Dmabuf equal check succeeded for freed buffer");
|
let dmabuf = buf
|
||||||
|
.dmabuf
|
||||||
|
.upgrade()
|
||||||
|
.expect("Dmabuf equal check succeeded for freed buffer");
|
||||||
Ok(Gles2Buffer {
|
Ok(Gles2Buffer {
|
||||||
internal: buf.clone(),
|
internal: buf.clone(),
|
||||||
// we keep the dmabuf alive as long as we are bound
|
// we keep the dmabuf alive as long as we are bound
|
||||||
_dmabuf: dmabuf
|
_dmabuf: dmabuf,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.unwrap_or_else(|| {
|
.unwrap_or_else(|| {
|
||||||
let image = self.egl.display.create_image_from_dmabuf(&dmabuf).map_err(Gles2Error::BindBufferEGLError)?;
|
let image = self
|
||||||
|
.egl
|
||||||
|
.display
|
||||||
|
.create_image_from_dmabuf(&dmabuf)
|
||||||
|
.map_err(Gles2Error::BindBufferEGLError)?;
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut rbo = 0;
|
let mut rbo = 0;
|
||||||
self.gl.GenRenderbuffers(1, &mut rbo as *mut _);
|
self.gl.GenRenderbuffers(1, &mut rbo as *mut _);
|
||||||
self.gl.BindRenderbuffer(ffi::RENDERBUFFER, rbo);
|
self.gl.BindRenderbuffer(ffi::RENDERBUFFER, rbo);
|
||||||
self.gl.EGLImageTargetRenderbufferStorageOES(ffi::RENDERBUFFER, image);
|
self.gl
|
||||||
|
.EGLImageTargetRenderbufferStorageOES(ffi::RENDERBUFFER, image);
|
||||||
self.gl.BindRenderbuffer(ffi::RENDERBUFFER, 0);
|
self.gl.BindRenderbuffer(ffi::RENDERBUFFER, 0);
|
||||||
|
|
||||||
let mut fbo = 0;
|
let mut fbo = 0;
|
||||||
self.gl.GenFramebuffers(1, &mut fbo as *mut _);
|
self.gl.GenFramebuffers(1, &mut fbo as *mut _);
|
||||||
self.gl.BindFramebuffer(ffi::FRAMEBUFFER, fbo);
|
self.gl.BindFramebuffer(ffi::FRAMEBUFFER, fbo);
|
||||||
self.gl.FramebufferRenderbuffer(ffi::FRAMEBUFFER, ffi::COLOR_ATTACHMENT0, ffi::RENDERBUFFER, rbo);
|
self.gl.FramebufferRenderbuffer(
|
||||||
|
ffi::FRAMEBUFFER,
|
||||||
|
ffi::COLOR_ATTACHMENT0,
|
||||||
|
ffi::RENDERBUFFER,
|
||||||
|
rbo,
|
||||||
|
);
|
||||||
let status = self.gl.CheckFramebufferStatus(ffi::FRAMEBUFFER);
|
let status = self.gl.CheckFramebufferStatus(ffi::FRAMEBUFFER);
|
||||||
self.gl.BindFramebuffer(ffi::FRAMEBUFFER, 0);
|
self.gl.BindFramebuffer(ffi::FRAMEBUFFER, 0);
|
||||||
|
|
||||||
|
@ -356,7 +403,7 @@ impl Bind<Dmabuf> for Gles2Renderer {
|
||||||
|
|
||||||
Ok(Gles2Buffer {
|
Ok(Gles2Buffer {
|
||||||
internal: weak,
|
internal: weak,
|
||||||
_dmabuf: dmabuf
|
_dmabuf: dmabuf,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})?;
|
})?;
|
||||||
|
@ -364,7 +411,7 @@ impl Bind<Dmabuf> for Gles2Renderer {
|
||||||
unsafe {
|
unsafe {
|
||||||
self.gl.BindFramebuffer(ffi::FRAMEBUFFER, buffer.internal.fbo);
|
self.gl.BindFramebuffer(ffi::FRAMEBUFFER, buffer.internal.fbo);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.target_buffer = Some(buffer);
|
self.target_buffer = Some(buffer);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -437,21 +484,36 @@ impl Renderer for Gles2Renderer {
|
||||||
wl_shm::Format::Xrgb8888,
|
wl_shm::Format::Xrgb8888,
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "image")]
|
#[cfg(feature = "image")]
|
||||||
fn import_bitmap<C: std::ops::Deref<Target=[u8]>>(&mut self, image: &image::ImageBuffer<image::Rgba<u8>, C>) -> Result<Self::TextureId, Self::Error> {
|
fn import_bitmap<C: std::ops::Deref<Target = [u8]>>(
|
||||||
|
&mut self,
|
||||||
|
image: &image::ImageBuffer<image::Rgba<u8>, C>,
|
||||||
|
) -> Result<Self::TextureId, Self::Error> {
|
||||||
self.make_current()?;
|
self.make_current()?;
|
||||||
|
|
||||||
let mut tex = 0;
|
let mut tex = 0;
|
||||||
unsafe {
|
unsafe {
|
||||||
self.gl.GenTextures(1, &mut tex);
|
self.gl.GenTextures(1, &mut tex);
|
||||||
self.gl.BindTexture(ffi::TEXTURE_2D, tex);
|
self.gl.BindTexture(ffi::TEXTURE_2D, tex);
|
||||||
self.gl.TexParameteri(ffi::TEXTURE_2D, ffi::TEXTURE_WRAP_S, ffi::CLAMP_TO_EDGE as i32);
|
self.gl
|
||||||
self.gl.TexParameteri(ffi::TEXTURE_2D, ffi::TEXTURE_WRAP_T, ffi::CLAMP_TO_EDGE as i32);
|
.TexParameteri(ffi::TEXTURE_2D, ffi::TEXTURE_WRAP_S, ffi::CLAMP_TO_EDGE as i32);
|
||||||
self.gl.TexImage2D(ffi::TEXTURE_2D, 0, ffi::RGBA as i32, image.width() as i32, image.height() as i32, 0, ffi::RGBA, ffi::UNSIGNED_BYTE as u32, image.as_ptr() as *const _);
|
self.gl
|
||||||
|
.TexParameteri(ffi::TEXTURE_2D, ffi::TEXTURE_WRAP_T, ffi::CLAMP_TO_EDGE as i32);
|
||||||
|
self.gl.TexImage2D(
|
||||||
|
ffi::TEXTURE_2D,
|
||||||
|
0,
|
||||||
|
ffi::RGBA as i32,
|
||||||
|
image.width() as i32,
|
||||||
|
image.height() as i32,
|
||||||
|
0,
|
||||||
|
ffi::RGBA,
|
||||||
|
ffi::UNSIGNED_BYTE as u32,
|
||||||
|
image.as_ptr() as *const _,
|
||||||
|
);
|
||||||
self.gl.BindTexture(ffi::TEXTURE_2D, 0);
|
self.gl.BindTexture(ffi::TEXTURE_2D, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
let texture = Gles2Texture {
|
let texture = Gles2Texture {
|
||||||
texture: tex,
|
texture: tex,
|
||||||
texture_kind: 2,
|
texture_kind: 2,
|
||||||
|
@ -461,10 +523,9 @@ impl Renderer for Gles2Renderer {
|
||||||
height: image.height(),
|
height: image.height(),
|
||||||
};
|
};
|
||||||
self.egl.unbind()?;
|
self.egl.unbind()?;
|
||||||
|
|
||||||
Ok(texture)
|
Ok(texture)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[cfg(feature = "wayland_frontend")]
|
#[cfg(feature = "wayland_frontend")]
|
||||||
fn import_shm(&mut self, buffer: &wl_buffer::WlBuffer) -> Result<Self::TextureId, Self::Error> {
|
fn import_shm(&mut self, buffer: &wl_buffer::WlBuffer) -> Result<Self::TextureId, Self::Error> {
|
||||||
|
@ -472,7 +533,7 @@ impl Renderer for Gles2Renderer {
|
||||||
|
|
||||||
with_buffer_contents(&buffer, |slice, data| {
|
with_buffer_contents(&buffer, |slice, data| {
|
||||||
self.make_current()?;
|
self.make_current()?;
|
||||||
|
|
||||||
let offset = data.offset as i32;
|
let offset = data.offset as i32;
|
||||||
let width = data.width as i32;
|
let width = data.width as i32;
|
||||||
let height = data.height as i32;
|
let height = data.height as i32;
|
||||||
|
@ -492,16 +553,28 @@ impl Renderer for Gles2Renderer {
|
||||||
wl_shm::Format::Xrgb8888 => (ffi::BGRA_EXT, 3),
|
wl_shm::Format::Xrgb8888 => (ffi::BGRA_EXT, 3),
|
||||||
format => return Err(Gles2Error::UnsupportedPixelFormat(format)),
|
format => return Err(Gles2Error::UnsupportedPixelFormat(format)),
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut tex = 0;
|
let mut tex = 0;
|
||||||
unsafe {
|
unsafe {
|
||||||
self.gl.GenTextures(1, &mut tex);
|
self.gl.GenTextures(1, &mut tex);
|
||||||
self.gl.BindTexture(ffi::TEXTURE_2D, tex);
|
self.gl.BindTexture(ffi::TEXTURE_2D, tex);
|
||||||
|
|
||||||
self.gl.TexParameteri(ffi::TEXTURE_2D, ffi::TEXTURE_WRAP_S, ffi::CLAMP_TO_EDGE as i32);
|
self.gl
|
||||||
self.gl.TexParameteri(ffi::TEXTURE_2D, ffi::TEXTURE_WRAP_T, ffi::CLAMP_TO_EDGE as i32);
|
.TexParameteri(ffi::TEXTURE_2D, ffi::TEXTURE_WRAP_S, ffi::CLAMP_TO_EDGE as i32);
|
||||||
|
self.gl
|
||||||
|
.TexParameteri(ffi::TEXTURE_2D, ffi::TEXTURE_WRAP_T, ffi::CLAMP_TO_EDGE as i32);
|
||||||
self.gl.PixelStorei(ffi::UNPACK_ROW_LENGTH, stride / pixelsize);
|
self.gl.PixelStorei(ffi::UNPACK_ROW_LENGTH, stride / pixelsize);
|
||||||
self.gl.TexImage2D(ffi::TEXTURE_2D, 0, gl_format as i32, width, height, 0, gl_format, ffi::UNSIGNED_BYTE as u32, slice.as_ptr() as *const _);
|
self.gl.TexImage2D(
|
||||||
|
ffi::TEXTURE_2D,
|
||||||
|
0,
|
||||||
|
gl_format as i32,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
0,
|
||||||
|
gl_format,
|
||||||
|
ffi::UNSIGNED_BYTE as u32,
|
||||||
|
slice.as_ptr() as *const _,
|
||||||
|
);
|
||||||
|
|
||||||
self.gl.PixelStorei(ffi::UNPACK_ROW_LENGTH, 0);
|
self.gl.PixelStorei(ffi::UNPACK_ROW_LENGTH, 0);
|
||||||
self.gl.BindTexture(ffi::TEXTURE_2D, 0);
|
self.gl.BindTexture(ffi::TEXTURE_2D, 0);
|
||||||
|
@ -516,11 +589,12 @@ impl Renderer for Gles2Renderer {
|
||||||
height: height as u32,
|
height: height as u32,
|
||||||
};
|
};
|
||||||
self.egl.unbind()?;
|
self.egl.unbind()?;
|
||||||
|
|
||||||
Ok(texture)
|
Ok(texture)
|
||||||
}).map_err(Gles2Error::BufferAccessError)?
|
})
|
||||||
|
.map_err(Gles2Error::BufferAccessError)?
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "wayland_frontend")]
|
#[cfg(feature = "wayland_frontend")]
|
||||||
fn import_egl(&mut self, buffer: &EGLBuffer) -> Result<Self::TextureId, Self::Error> {
|
fn import_egl(&mut self, buffer: &EGLBuffer) -> Result<Self::TextureId, Self::Error> {
|
||||||
if !self.extensions.iter().any(|ext| ext == "GL_OES_EGL_image") {
|
if !self.extensions.iter().any(|ext| ext == "GL_OES_EGL_image") {
|
||||||
|
@ -530,21 +604,23 @@ impl Renderer for Gles2Renderer {
|
||||||
self.make_current()?;
|
self.make_current()?;
|
||||||
|
|
||||||
let mut tex = 0;
|
let mut tex = 0;
|
||||||
let target = if buffer.format == EGLFormat::External { ffi::TEXTURE_EXTERNAL_OES } else { ffi::TEXTURE_2D };
|
let target = if buffer.format == EGLFormat::External {
|
||||||
|
ffi::TEXTURE_EXTERNAL_OES
|
||||||
|
} else {
|
||||||
|
ffi::TEXTURE_2D
|
||||||
|
};
|
||||||
unsafe {
|
unsafe {
|
||||||
self.gl.GenTextures(1, &mut tex);
|
self.gl.GenTextures(1, &mut tex);
|
||||||
self.gl.BindTexture(target, tex);
|
self.gl.BindTexture(target, tex);
|
||||||
|
|
||||||
self.gl.EGLImageTargetTexture2DOES(
|
self.gl
|
||||||
target,
|
.EGLImageTargetTexture2DOES(target, buffer.image(0).unwrap());
|
||||||
buffer.image(0).unwrap(),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let texture = Gles2Texture {
|
let texture = Gles2Texture {
|
||||||
texture: tex,
|
texture: tex,
|
||||||
texture_kind: match buffer.format {
|
texture_kind: match buffer.format {
|
||||||
EGLFormat::RGB => 3,
|
EGLFormat::RGB => 3,
|
||||||
EGLFormat::RGBA => 2,
|
EGLFormat::RGBA => 2,
|
||||||
EGLFormat::External => 4,
|
EGLFormat::External => 4,
|
||||||
_ => unreachable!("EGLBuffer currenly does not expose multi-planar buffers to us"),
|
_ => unreachable!("EGLBuffer currenly does not expose multi-planar buffers to us"),
|
||||||
|
@ -555,10 +631,10 @@ impl Renderer for Gles2Renderer {
|
||||||
height: buffer.height,
|
height: buffer.height,
|
||||||
};
|
};
|
||||||
self.egl.unbind()?;
|
self.egl.unbind()?;
|
||||||
|
|
||||||
Ok(texture)
|
Ok(texture)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn destroy_texture(&mut self, texture: Self::TextureId) -> Result<(), Self::Error> {
|
fn destroy_texture(&mut self, texture: Self::TextureId) -> Result<(), Self::Error> {
|
||||||
self.make_current()?;
|
self.make_current()?;
|
||||||
|
|
||||||
|
@ -570,12 +646,11 @@ impl Renderer for Gles2Renderer {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn begin(&mut self, width: u32, height: u32, transform: Transform) -> Result<(), Gles2Error> {
|
fn begin(&mut self, width: u32, height: u32, transform: Transform) -> Result<(), Gles2Error> {
|
||||||
self.make_current()?;
|
self.make_current()?;
|
||||||
unsafe {
|
unsafe {
|
||||||
self.gl.Viewport(0, 0, width as i32, height as i32);
|
self.gl.Viewport(0, 0, width as i32, height as i32);
|
||||||
|
|
||||||
self.gl.Enable(ffi::BLEND);
|
self.gl.Enable(ffi::BLEND);
|
||||||
self.gl.BlendFunc(ffi::ONE, ffi::ONE_MINUS_SRC_ALPHA);
|
self.gl.BlendFunc(ffi::ONE, ffi::ONE_MINUS_SRC_ALPHA);
|
||||||
}
|
}
|
||||||
|
@ -601,7 +676,7 @@ impl Renderer for Gles2Renderer {
|
||||||
self.current_projection = Some(transform.matrix() * renderer);
|
self.current_projection = Some(transform.matrix() * renderer);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clear(&mut self, color: [f32; 4]) -> Result<(), Self::Error> {
|
fn clear(&mut self, color: [f32; 4]) -> Result<(), Self::Error> {
|
||||||
self.make_current()?;
|
self.make_current()?;
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -612,7 +687,12 @@ impl Renderer for Gles2Renderer {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_texture(&mut self, tex: &Self::TextureId, mut matrix: Matrix3<f32>, alpha: f32) -> Result<(), Self::Error> {
|
fn render_texture(
|
||||||
|
&mut self,
|
||||||
|
tex: &Self::TextureId,
|
||||||
|
mut matrix: Matrix3<f32>,
|
||||||
|
alpha: f32,
|
||||||
|
) -> Result<(), Self::Error> {
|
||||||
self.make_current()?;
|
self.make_current()?;
|
||||||
if self.current_projection.is_none() {
|
if self.current_projection.is_none() {
|
||||||
return Err(Gles2Error::UnconstraintRenderingOperation);
|
return Err(Gles2Error::UnconstraintRenderingOperation);
|
||||||
|
@ -621,31 +701,63 @@ impl Renderer for Gles2Renderer {
|
||||||
//apply output transformation
|
//apply output transformation
|
||||||
matrix = self.current_projection.as_ref().unwrap() * matrix;
|
matrix = self.current_projection.as_ref().unwrap() * matrix;
|
||||||
|
|
||||||
let target = if tex.is_external { ffi::TEXTURE_EXTERNAL_OES } else { ffi::TEXTURE_2D };
|
let target = if tex.is_external {
|
||||||
|
ffi::TEXTURE_EXTERNAL_OES
|
||||||
|
} else {
|
||||||
|
ffi::TEXTURE_2D
|
||||||
|
};
|
||||||
|
|
||||||
// render
|
// render
|
||||||
unsafe {
|
unsafe {
|
||||||
self.gl.ActiveTexture(ffi::TEXTURE0);
|
self.gl.ActiveTexture(ffi::TEXTURE0);
|
||||||
self.gl.BindTexture(target, tex.texture);
|
self.gl.BindTexture(target, tex.texture);
|
||||||
self.gl.TexParameteri(target, ffi::TEXTURE_MIN_FILTER, ffi::LINEAR as i32);
|
self.gl
|
||||||
|
.TexParameteri(target, ffi::TEXTURE_MIN_FILTER, ffi::LINEAR as i32);
|
||||||
self.gl.UseProgram(self.programs[tex.texture_kind].program);
|
self.gl.UseProgram(self.programs[tex.texture_kind].program);
|
||||||
|
|
||||||
self.gl.Uniform1i(self.programs[tex.texture_kind].uniform_tex, 0);
|
self.gl.Uniform1i(self.programs[tex.texture_kind].uniform_tex, 0);
|
||||||
self.gl.UniformMatrix3fv(self.programs[tex.texture_kind].uniform_matrix, 1, ffi::FALSE, matrix.as_ptr());
|
self.gl.UniformMatrix3fv(
|
||||||
self.gl.Uniform1i(self.programs[tex.texture_kind].uniform_invert_y, if tex.y_inverted { 1 } else { 0 });
|
self.programs[tex.texture_kind].uniform_matrix,
|
||||||
self.gl.Uniform1f(self.programs[tex.texture_kind].uniform_alpha, alpha);
|
1,
|
||||||
|
ffi::FALSE,
|
||||||
self.gl.VertexAttribPointer(self.programs[tex.texture_kind].attrib_position as u32, 2, ffi::FLOAT, ffi::FALSE, 0, VERTS.as_ptr() as *const _);
|
matrix.as_ptr(),
|
||||||
self.gl.VertexAttribPointer(self.programs[tex.texture_kind].attrib_tex_coords as u32, 2, ffi::FLOAT, ffi::FALSE, 0, TEX_COORDS.as_ptr() as *const _);
|
);
|
||||||
|
self.gl.Uniform1i(
|
||||||
self.gl.EnableVertexAttribArray(self.programs[tex.texture_kind].attrib_position as u32);
|
self.programs[tex.texture_kind].uniform_invert_y,
|
||||||
self.gl.EnableVertexAttribArray(self.programs[tex.texture_kind].attrib_tex_coords as u32);
|
if tex.y_inverted { 1 } else { 0 },
|
||||||
|
);
|
||||||
|
self.gl
|
||||||
|
.Uniform1f(self.programs[tex.texture_kind].uniform_alpha, alpha);
|
||||||
|
|
||||||
|
self.gl.VertexAttribPointer(
|
||||||
|
self.programs[tex.texture_kind].attrib_position as u32,
|
||||||
|
2,
|
||||||
|
ffi::FLOAT,
|
||||||
|
ffi::FALSE,
|
||||||
|
0,
|
||||||
|
VERTS.as_ptr() as *const _,
|
||||||
|
);
|
||||||
|
self.gl.VertexAttribPointer(
|
||||||
|
self.programs[tex.texture_kind].attrib_tex_coords as u32,
|
||||||
|
2,
|
||||||
|
ffi::FLOAT,
|
||||||
|
ffi::FALSE,
|
||||||
|
0,
|
||||||
|
TEX_COORDS.as_ptr() as *const _,
|
||||||
|
);
|
||||||
|
|
||||||
|
self.gl
|
||||||
|
.EnableVertexAttribArray(self.programs[tex.texture_kind].attrib_position as u32);
|
||||||
|
self.gl
|
||||||
|
.EnableVertexAttribArray(self.programs[tex.texture_kind].attrib_tex_coords as u32);
|
||||||
|
|
||||||
self.gl.DrawArrays(ffi::TRIANGLE_STRIP, 0, 4);
|
self.gl.DrawArrays(ffi::TRIANGLE_STRIP, 0, 4);
|
||||||
|
|
||||||
self.gl.DisableVertexAttribArray(self.programs[tex.texture_kind].attrib_position as u32);
|
self.gl
|
||||||
self.gl.DisableVertexAttribArray(self.programs[tex.texture_kind].attrib_tex_coords as u32);
|
.DisableVertexAttribArray(self.programs[tex.texture_kind].attrib_position as u32);
|
||||||
|
self.gl
|
||||||
|
.DisableVertexAttribArray(self.programs[tex.texture_kind].attrib_tex_coords as u32);
|
||||||
|
|
||||||
self.gl.BindTexture(target, 0);
|
self.gl.BindTexture(target, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -89,4 +89,4 @@ varying vec2 v_tex_coords;
|
||||||
void main() {
|
void main() {
|
||||||
gl_FragColor = texture2D(tex, v_tex_coords) * alpha;
|
gl_FragColor = texture2D(tex, v_tex_coords) * alpha;
|
||||||
}
|
}
|
||||||
"#;
|
"#;
|
||||||
|
|
|
@ -3,7 +3,7 @@ use std::error::Error;
|
||||||
|
|
||||||
use cgmath::{prelude::*, Matrix3, Vector2};
|
use cgmath::{prelude::*, Matrix3, Vector2};
|
||||||
#[cfg(feature = "wayland_frontend")]
|
#[cfg(feature = "wayland_frontend")]
|
||||||
use wayland_server::protocol::{wl_shm, wl_buffer};
|
use wayland_server::protocol::{wl_buffer, wl_shm};
|
||||||
|
|
||||||
use crate::backend::SwapBuffersError;
|
use crate::backend::SwapBuffersError;
|
||||||
#[cfg(feature = "renderer_gl")]
|
#[cfg(feature = "renderer_gl")]
|
||||||
|
@ -26,46 +26,14 @@ pub enum Transform {
|
||||||
impl Transform {
|
impl Transform {
|
||||||
pub fn matrix(&self) -> Matrix3<f32> {
|
pub fn matrix(&self) -> Matrix3<f32> {
|
||||||
match self {
|
match self {
|
||||||
Transform::Normal => Matrix3::new(
|
Transform::Normal => Matrix3::new(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0),
|
||||||
1.0, 0.0, 0.0,
|
Transform::_90 => Matrix3::new(0.0, -1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0),
|
||||||
0.0, 1.0, 0.0,
|
Transform::_180 => Matrix3::new(-1.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0, 0.0, 1.0),
|
||||||
0.0, 0.0, 1.0,
|
Transform::_270 => Matrix3::new(0.0, 1.0, 0.0, -1.0, 0.0, 0.0, 0.0, 0.0, 1.0),
|
||||||
),
|
Transform::Flipped => Matrix3::new(-1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0),
|
||||||
Transform::_90 => Matrix3::new(
|
Transform::Flipped90 => Matrix3::new(0.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0),
|
||||||
0.0, -1.0, 0.0,
|
Transform::Flipped180 => Matrix3::new(1.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0, 0.0, 1.0),
|
||||||
1.0, 0.0, 0.0,
|
Transform::Flipped270 => Matrix3::new(0.0, -1.0, 0.0, -1.0, 0.0, 0.0, 0.0, 0.0, 1.0),
|
||||||
0.0, 0.0, 1.0,
|
|
||||||
),
|
|
||||||
Transform::_180 => Matrix3::new(
|
|
||||||
-1.0, 0.0, 0.0,
|
|
||||||
0.0, -1.0, 0.0,
|
|
||||||
0.0, 0.0, 1.0,
|
|
||||||
),
|
|
||||||
Transform::_270 => Matrix3::new(
|
|
||||||
0.0, 1.0, 0.0,
|
|
||||||
-1.0, 0.0, 0.0,
|
|
||||||
0.0, 0.0, 1.0,
|
|
||||||
),
|
|
||||||
Transform::Flipped => Matrix3::new(
|
|
||||||
-1.0, 0.0, 0.0,
|
|
||||||
0.0, 1.0, 0.0,
|
|
||||||
0.0, 0.0, 1.0,
|
|
||||||
),
|
|
||||||
Transform::Flipped90 => Matrix3::new(
|
|
||||||
0.0, 1.0, 0.0,
|
|
||||||
1.0, 0.0, 0.0,
|
|
||||||
0.0, 0.0, 1.0,
|
|
||||||
),
|
|
||||||
Transform::Flipped180 => Matrix3::new(
|
|
||||||
1.0, 0.0, 0.0,
|
|
||||||
0.0, -1.0, 0.0,
|
|
||||||
0.0, 0.0, 1.0,
|
|
||||||
),
|
|
||||||
Transform::Flipped270 => Matrix3::new(
|
|
||||||
0.0, -1.0, 0.0,
|
|
||||||
-1.0, 0.0, 0.0,
|
|
||||||
0.0, 0.0, 1.0,
|
|
||||||
),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,7 +105,10 @@ pub trait Renderer {
|
||||||
type TextureId: Texture;
|
type TextureId: Texture;
|
||||||
|
|
||||||
#[cfg(feature = "image")]
|
#[cfg(feature = "image")]
|
||||||
fn import_bitmap<C: std::ops::Deref<Target=[u8]>>(&mut self, image: &image::ImageBuffer<image::Rgba<u8>, C>) -> Result<Self::TextureId, Self::Error>;
|
fn import_bitmap<C: std::ops::Deref<Target = [u8]>>(
|
||||||
|
&mut self,
|
||||||
|
image: &image::ImageBuffer<image::Rgba<u8>, C>,
|
||||||
|
) -> Result<Self::TextureId, Self::Error>;
|
||||||
#[cfg(feature = "wayland_frontend")]
|
#[cfg(feature = "wayland_frontend")]
|
||||||
fn shm_formats(&self) -> &[wl_shm::Format] {
|
fn shm_formats(&self) -> &[wl_shm::Format] {
|
||||||
// Mandatory
|
// Mandatory
|
||||||
|
@ -149,14 +120,30 @@ pub trait Renderer {
|
||||||
fn import_egl(&mut self, buffer: &EGLBuffer) -> Result<Self::TextureId, Self::Error>;
|
fn import_egl(&mut self, buffer: &EGLBuffer) -> Result<Self::TextureId, Self::Error>;
|
||||||
fn destroy_texture(&mut self, texture: Self::TextureId) -> Result<(), Self::Error>;
|
fn destroy_texture(&mut self, texture: Self::TextureId) -> Result<(), Self::Error>;
|
||||||
|
|
||||||
fn begin(&mut self, width: u32, height: u32, transform: Transform) -> Result<(), <Self as Renderer>::Error>;
|
fn begin(
|
||||||
|
&mut self,
|
||||||
|
width: u32,
|
||||||
|
height: u32,
|
||||||
|
transform: Transform,
|
||||||
|
) -> Result<(), <Self as Renderer>::Error>;
|
||||||
fn finish(&mut self) -> Result<(), SwapBuffersError>;
|
fn finish(&mut self) -> Result<(), SwapBuffersError>;
|
||||||
|
|
||||||
fn clear(&mut self, color: [f32; 4]) -> Result<(), Self::Error>;
|
fn clear(&mut self, color: [f32; 4]) -> Result<(), Self::Error>;
|
||||||
fn render_texture(&mut self, texture: &Self::TextureId, matrix: Matrix3<f32>, alpha: f32) -> Result<(), Self::Error>;
|
fn render_texture(
|
||||||
fn render_texture_at(&mut self, texture: &Self::TextureId, pos: (i32, i32), transform: Transform, alpha: f32) -> Result<(), Self::Error> {
|
&mut self,
|
||||||
|
texture: &Self::TextureId,
|
||||||
|
matrix: Matrix3<f32>,
|
||||||
|
alpha: f32,
|
||||||
|
) -> Result<(), Self::Error>;
|
||||||
|
fn render_texture_at(
|
||||||
|
&mut self,
|
||||||
|
texture: &Self::TextureId,
|
||||||
|
pos: (i32, i32),
|
||||||
|
transform: Transform,
|
||||||
|
alpha: f32,
|
||||||
|
) -> Result<(), Self::Error> {
|
||||||
let mut mat = Matrix3::<f32>::identity();
|
let mut mat = Matrix3::<f32>::identity();
|
||||||
|
|
||||||
// position and scale
|
// position and scale
|
||||||
let size = texture.size();
|
let size = texture.size();
|
||||||
mat = mat * Matrix3::from_translation(Vector2::new(pos.0 as f32, pos.1 as f32));
|
mat = mat * Matrix3::from_translation(Vector2::new(pos.0 as f32, pos.1 as f32));
|
||||||
|
@ -173,5 +160,4 @@ pub trait Renderer {
|
||||||
|
|
||||||
self.render_texture(texture, mat, alpha)
|
self.render_texture(texture, mat, alpha)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -2,28 +2,24 @@
|
||||||
|
|
||||||
use crate::backend::egl::display::EGLDisplay;
|
use crate::backend::egl::display::EGLDisplay;
|
||||||
use crate::backend::{
|
use crate::backend::{
|
||||||
egl::{context::GlAttributes, native, EGLContext, EGLSurface, EGLBuffer, Error as EGLError},
|
egl::{context::GlAttributes, native, EGLBuffer, EGLContext, EGLSurface, Error as EGLError},
|
||||||
renderer::{
|
|
||||||
Renderer, Bind, Transform,
|
|
||||||
gles2::{Gles2Renderer, Gles2Error, Gles2Texture},
|
|
||||||
},
|
|
||||||
input::{
|
input::{
|
||||||
Axis, AxisSource, Event as BackendEvent, InputBackend, InputEvent, KeyState, KeyboardKeyEvent,
|
Axis, AxisSource, Event as BackendEvent, InputBackend, InputEvent, KeyState, KeyboardKeyEvent,
|
||||||
MouseButton, MouseButtonState, PointerAxisEvent, PointerButtonEvent, PointerMotionAbsoluteEvent,
|
MouseButton, MouseButtonState, PointerAxisEvent, PointerButtonEvent, PointerMotionAbsoluteEvent,
|
||||||
Seat, SeatCapabilities, TouchCancelEvent, TouchDownEvent, TouchMotionEvent, TouchSlot, TouchUpEvent,
|
Seat, SeatCapabilities, TouchCancelEvent, TouchDownEvent, TouchMotionEvent, TouchSlot, TouchUpEvent,
|
||||||
UnusedEvent,
|
UnusedEvent,
|
||||||
},
|
},
|
||||||
};
|
renderer::{
|
||||||
use std::{
|
gles2::{Gles2Error, Gles2Renderer, Gles2Texture},
|
||||||
cell::RefCell,
|
Bind, Renderer, Transform,
|
||||||
rc::Rc,
|
},
|
||||||
time::Instant,
|
|
||||||
};
|
};
|
||||||
use cgmath::Matrix3;
|
use cgmath::Matrix3;
|
||||||
|
use std::{cell::RefCell, rc::Rc, time::Instant};
|
||||||
use wayland_egl as wegl;
|
use wayland_egl as wegl;
|
||||||
use wayland_server::Display;
|
|
||||||
#[cfg(feature = "wayland_frontend")]
|
#[cfg(feature = "wayland_frontend")]
|
||||||
use wayland_server::protocol::{wl_shm, wl_buffer};
|
use wayland_server::protocol::{wl_buffer, wl_shm};
|
||||||
|
use wayland_server::Display;
|
||||||
use winit::{
|
use winit::{
|
||||||
dpi::{LogicalPosition, LogicalSize, PhysicalSize},
|
dpi::{LogicalPosition, LogicalSize, PhysicalSize},
|
||||||
event::{
|
event::{
|
||||||
|
@ -37,7 +33,7 @@ use winit::{
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(feature = "use_system_lib")]
|
#[cfg(feature = "use_system_lib")]
|
||||||
use crate::backend::egl::{display::EGLBufferReader};
|
use crate::backend::egl::display::EGLBufferReader;
|
||||||
|
|
||||||
/// Errors thrown by the `winit` backends
|
/// Errors thrown by the `winit` backends
|
||||||
#[derive(thiserror::Error, Debug)]
|
#[derive(thiserror::Error, Debug)]
|
||||||
|
@ -158,23 +154,33 @@ where
|
||||||
let surface = unsafe {
|
let surface = unsafe {
|
||||||
wegl::WlEglSurface::new_from_raw(wl_surface as *mut _, size.width as i32, size.height as i32)
|
wegl::WlEglSurface::new_from_raw(wl_surface as *mut _, size.width as i32, size.height as i32)
|
||||||
};
|
};
|
||||||
EGLSurface::new(&display, context.pixel_format().unwrap(), reqs.double_buffer, context.config_id(), surface, log.clone())
|
EGLSurface::new(
|
||||||
.map_err(EGLError::CreationFailed)?
|
&display,
|
||||||
|
context.pixel_format().unwrap(),
|
||||||
|
reqs.double_buffer,
|
||||||
|
context.config_id(),
|
||||||
|
surface,
|
||||||
|
log.clone(),
|
||||||
|
)
|
||||||
|
.map_err(EGLError::CreationFailed)?
|
||||||
} else if let Some(xlib_window) = winit_window.xlib_window().map(native::XlibWindow) {
|
} else if let Some(xlib_window) = winit_window.xlib_window().map(native::XlibWindow) {
|
||||||
debug!(log, "Winit backend: X11");
|
debug!(log, "Winit backend: X11");
|
||||||
EGLSurface::new(&display, context.pixel_format().unwrap(), reqs.double_buffer, context.config_id(), xlib_window, log.clone())
|
EGLSurface::new(
|
||||||
.map_err(EGLError::CreationFailed)?
|
&display,
|
||||||
|
context.pixel_format().unwrap(),
|
||||||
|
reqs.double_buffer,
|
||||||
|
context.config_id(),
|
||||||
|
xlib_window,
|
||||||
|
log.clone(),
|
||||||
|
)
|
||||||
|
.map_err(EGLError::CreationFailed)?
|
||||||
} else {
|
} else {
|
||||||
unreachable!("No backends for winit other then Wayland and X11 are supported")
|
unreachable!("No backends for winit other then Wayland and X11 are supported")
|
||||||
};
|
};
|
||||||
|
|
||||||
let _ = context.unbind();
|
let _ = context.unbind();
|
||||||
|
|
||||||
(
|
(display, context, surface)
|
||||||
display,
|
|
||||||
context,
|
|
||||||
surface,
|
|
||||||
)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let size = Rc::new(RefCell::new(WindowSize {
|
let size = Rc::new(RefCell::new(WindowSize {
|
||||||
|
@ -250,7 +256,7 @@ impl WinitGraphicsBackend {
|
||||||
let size = self.size.borrow();
|
let size = self.size.borrow();
|
||||||
size.physical_size.into()
|
size.physical_size.into()
|
||||||
};
|
};
|
||||||
|
|
||||||
self.renderer.bind(self.egl.clone())?;
|
self.renderer.bind(self.egl.clone())?;
|
||||||
self.renderer.begin(width, height, Transform::Normal)
|
self.renderer.begin(width, height, Transform::Normal)
|
||||||
}
|
}
|
||||||
|
@ -259,12 +265,15 @@ impl WinitGraphicsBackend {
|
||||||
impl Renderer for WinitGraphicsBackend {
|
impl Renderer for WinitGraphicsBackend {
|
||||||
type Error = Gles2Error;
|
type Error = Gles2Error;
|
||||||
type TextureId = Gles2Texture;
|
type TextureId = Gles2Texture;
|
||||||
|
|
||||||
#[cfg(feature = "image")]
|
#[cfg(feature = "image")]
|
||||||
fn import_bitmap<C: std::ops::Deref<Target=[u8]>>(&mut self, image: &image::ImageBuffer<image::Rgba<u8>, C>) -> Result<Self::TextureId, Self::Error> {
|
fn import_bitmap<C: std::ops::Deref<Target = [u8]>>(
|
||||||
|
&mut self,
|
||||||
|
image: &image::ImageBuffer<image::Rgba<u8>, C>,
|
||||||
|
) -> Result<Self::TextureId, Self::Error> {
|
||||||
self.renderer.import_bitmap(image)
|
self.renderer.import_bitmap(image)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "wayland_frontend")]
|
#[cfg(feature = "wayland_frontend")]
|
||||||
fn shm_formats(&self) -> &[wl_shm::Format] {
|
fn shm_formats(&self) -> &[wl_shm::Format] {
|
||||||
Renderer::shm_formats(&self.renderer)
|
Renderer::shm_formats(&self.renderer)
|
||||||
|
@ -274,17 +283,22 @@ impl Renderer for WinitGraphicsBackend {
|
||||||
fn import_shm(&mut self, buffer: &wl_buffer::WlBuffer) -> Result<Self::TextureId, Self::Error> {
|
fn import_shm(&mut self, buffer: &wl_buffer::WlBuffer) -> Result<Self::TextureId, Self::Error> {
|
||||||
self.renderer.import_shm(buffer)
|
self.renderer.import_shm(buffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "wayland_frontend")]
|
#[cfg(feature = "wayland_frontend")]
|
||||||
fn import_egl(&mut self, buffer: &EGLBuffer) -> Result<Self::TextureId, Self::Error> {
|
fn import_egl(&mut self, buffer: &EGLBuffer) -> Result<Self::TextureId, Self::Error> {
|
||||||
self.renderer.import_egl(buffer)
|
self.renderer.import_egl(buffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn destroy_texture(&mut self, texture: Self::TextureId) -> Result<(), Self::Error> {
|
fn destroy_texture(&mut self, texture: Self::TextureId) -> Result<(), Self::Error> {
|
||||||
self.renderer.destroy_texture(texture)
|
self.renderer.destroy_texture(texture)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn begin(&mut self, width: u32, height: u32, transform: Transform) -> Result<(), <Self as Renderer>::Error> {
|
fn begin(
|
||||||
|
&mut self,
|
||||||
|
width: u32,
|
||||||
|
height: u32,
|
||||||
|
transform: Transform,
|
||||||
|
) -> Result<(), <Self as Renderer>::Error> {
|
||||||
self.renderer.bind(self.egl.clone())?;
|
self.renderer.bind(self.egl.clone())?;
|
||||||
self.renderer.begin(width, height, transform)
|
self.renderer.begin(width, height, transform)
|
||||||
}
|
}
|
||||||
|
@ -293,7 +307,12 @@ impl Renderer for WinitGraphicsBackend {
|
||||||
self.renderer.clear(color)
|
self.renderer.clear(color)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_texture(&mut self, texture: &Self::TextureId, matrix: Matrix3<f32>, alpha: f32) -> Result<(), Self::Error> {
|
fn render_texture(
|
||||||
|
&mut self,
|
||||||
|
texture: &Self::TextureId,
|
||||||
|
matrix: Matrix3<f32>,
|
||||||
|
alpha: f32,
|
||||||
|
) -> Result<(), Self::Error> {
|
||||||
self.renderer.render_texture(texture, matrix, alpha)
|
self.renderer.render_texture(texture, matrix, alpha)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -255,7 +255,11 @@ where
|
||||||
for f in &*formats {
|
for f in &*formats {
|
||||||
dmabuf.format(f.format as u32);
|
dmabuf.format(f.format as u32);
|
||||||
if version >= 3 {
|
if version >= 3 {
|
||||||
dmabuf.modifier(f.format as u32, (Into::<u64>::into(f.modifier) >> 32) as u32, Into::<u64>::into(f.modifier) as u32);
|
dmabuf.modifier(
|
||||||
|
f.format as u32,
|
||||||
|
(Into::<u64>::into(f.modifier) >> 32) as u32,
|
||||||
|
Into::<u64>::into(f.modifier) as u32,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in New Issue