deps: Update smithay

Integrate new multigpu allocator code for gpu->gpu copies using the vulkan allocator.

Also integrates Xwayland clipboard sync.
This commit is contained in:
Victoria Brekenfeld 2023-02-13 17:44:24 +01:00
parent 32762fb983
commit 4a9dfcead0
11 changed files with 450 additions and 115 deletions

7
Cargo.lock generated
View file

@ -1753,9 +1753,9 @@ dependencies = [
[[package]] [[package]]
name = "input" name = "input"
version = "0.8.1" version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4669c07fe301ce2eb323ff23b9480e6a19d8e94520236862caca51b2b5c45e3" checksum = "eeb3afdf1f8137428002b354eaf87aa629178995683941d94b04c6d145ec8937"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"input-sys", "input-sys",
@ -3292,9 +3292,10 @@ checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
[[package]] [[package]]
name = "smithay" name = "smithay"
version = "0.3.0" version = "0.3.0"
source = "git+https://github.com/pop-os/smithay?rev=3437fe15ca#3437fe15caf1661bc3e93a9a20425be3189a4dc7" source = "git+https://github.com/smithay//smithay?rev=09e29418e5#09e29418e5d973dd21fc636433cca0b4dc3a17b3"
dependencies = [ dependencies = [
"appendlist", "appendlist",
"ash",
"bitflags", "bitflags",
"calloop", "calloop",
"cc", "cc",

View file

@ -47,7 +47,7 @@ version = "0.3"
git = "https://github.com/Smithay/smithay.git" git = "https://github.com/Smithay/smithay.git"
rev = "2de946cf9e" rev = "2de946cf9e"
default-features = false default-features = false
features = ["backend_drm", "backend_gbm", "backend_egl", "backend_libinput", "backend_session_libseat", "backend_udev", "backend_winit", "backend_x11", "desktop", "use_system_lib", "renderer_glow", "renderer_multi", "wayland_frontend", "slog-stdlog", "xwayland"] features = ["backend_drm", "backend_gbm", "backend_egl", "backend_libinput", "backend_session_libseat", "backend_udev", "backend_winit", "backend_vulkan", "backend_x11", "desktop", "use_system_lib", "renderer_glow", "renderer_multi", "wayland_frontend", "slog-stdlog", "xwayland"]
[dependencies.smithay-egui] [dependencies.smithay-egui]
git = "https://github.com/Smithay/smithay-egui.git" git = "https://github.com/Smithay/smithay-egui.git"
@ -70,4 +70,4 @@ debug = true
lto = "fat" lto = "fat"
[patch."https://github.com/Smithay/smithay.git"] [patch."https://github.com/Smithay/smithay.git"]
smithay = { git = "https://github.com/pop-os/smithay", rev = "3437fe15ca" } smithay = { git = "https://github.com/smithay//smithay", rev = "09e29418e5" }

View file

@ -15,7 +15,12 @@ use crate::{
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use smithay::{ use smithay::{
backend::{ backend::{
allocator::{dmabuf::Dmabuf, gbm::GbmDevice, Format}, allocator::{
dmabuf::{AnyError, Dmabuf, DmabufAllocator},
gbm::{GbmAllocator, GbmBufferFlags, GbmDevice},
vulkan::{ImageUsageFlags, VulkanAllocator},
Allocator, Format,
},
drm::{ drm::{
DrmDevice, DrmDeviceFd, DrmEvent, DrmEventTime, DrmNode, GbmBufferedSurface, NodeType, DrmDevice, DrmDeviceFd, DrmEvent, DrmEventTime, DrmNode, GbmBufferedSurface, NodeType,
}, },
@ -26,10 +31,11 @@ use smithay::{
damage::DamageTrackedRenderer, damage::DamageTrackedRenderer,
gles2::Gles2Renderbuffer, gles2::Gles2Renderbuffer,
glow::GlowRenderer, glow::GlowRenderer,
multigpu::{egl::EglGlesBackend, GpuManager}, multigpu::{gbm::GbmGlesBackend, GpuManager},
}, },
session::{libseat::LibSeatSession, Event as SessionEvent, Session}, session::{libseat::LibSeatSession, Event as SessionEvent, Session},
udev::{all_gpus, primary_gpu, UdevBackend, UdevEvent}, udev::{all_gpus, primary_gpu, UdevBackend, UdevEvent},
vulkan::{version::Version, Instance, PhysicalDevice},
}, },
desktop::utils::OutputPresentationFeedback, desktop::utils::OutputPresentationFeedback,
input::Seat, input::Seat,
@ -53,6 +59,7 @@ use smithay::{
use std::{ use std::{
cell::RefCell, cell::RefCell,
collections::{HashMap, HashSet}, collections::{HashMap, HashSet},
ffi::CStr,
os::unix::io::FromRawFd, os::unix::io::FromRawFd,
path::PathBuf, path::PathBuf,
time::Duration, time::Duration,
@ -68,7 +75,7 @@ const MIN_RENDER_TIME: Duration = Duration::from_millis(3);
pub struct KmsState { pub struct KmsState {
devices: HashMap<DrmNode, Device>, devices: HashMap<DrmNode, Device>,
pub api: GpuManager<EglGlesBackend<GlowRenderer>>, pub api: GpuManager<GbmGlesBackend<GlowRenderer>>,
pub primary: DrmNode, pub primary: DrmNode,
session: LibSeatSession, session: LibSeatSession,
_tokens: Vec<RegistrationToken>, _tokens: Vec<RegistrationToken>,
@ -77,8 +84,9 @@ pub struct KmsState {
pub struct Device { pub struct Device {
render_node: DrmNode, render_node: DrmNode,
surfaces: HashMap<crtc::Handle, Surface>, surfaces: HashMap<crtc::Handle, Surface>,
allocator: GbmDevice<DrmDeviceFd>,
drm: Dispatcher<'static, DrmDevice, Data>, drm: Dispatcher<'static, DrmDevice, Data>,
gbm: GbmDevice<DrmDeviceFd>,
allocator: Box<dyn Allocator<Buffer = Dmabuf, Error = AnyError>>,
formats: HashSet<Format>, formats: HashSet<Format>,
supports_atomic: bool, supports_atomic: bool,
event_token: Option<RegistrationToken>, event_token: Option<RegistrationToken>,
@ -86,7 +94,8 @@ pub struct Device {
} }
pub struct Surface { pub struct Surface {
surface: Option<GbmBufferedSurface<GbmDevice<DrmDeviceFd>, Option<OutputPresentationFeedback>>>, surface:
Option<GbmBufferedSurface<GbmAllocator<DrmDeviceFd>, Option<OutputPresentationFeedback>>>,
damage_tracker: DamageTrackedRenderer, damage_tracker: DamageTrackedRenderer,
connector: connector::Handle, connector: connector::Handle,
output: Output, output: Output,
@ -137,7 +146,7 @@ pub fn init_backend(
}) })
.map_err(|err| err.error) .map_err(|err| err.error)
.context("Failed to initialize libinput event source")?; .context("Failed to initialize libinput event source")?;
let api = GpuManager::new(EglGlesBackend::<GlowRenderer>::default(), None) let api = GpuManager::new(GbmGlesBackend::<GlowRenderer>::default(), None)
.context("Failed to initialize renderers")?; .context("Failed to initialize renderers")?;
// TODO get this info from system76-power, if available and setup a watcher // TODO get this info from system76-power, if available and setup a watcher
@ -359,12 +368,7 @@ impl State {
.try_get_render_node() .try_get_render_node()
.ok() .ok()
.and_then(std::convert::identity) .and_then(std::convert::identity)
.with_context(|| { .unwrap_or(drm_node);
format!(
"Failed to determine path of egl device for {}",
path.display()
)
})?;
let egl_context = EGLContext::new(&egl_display, None).with_context(|| { let egl_context = EGLContext::new(&egl_display, None).with_context(|| {
format!( format!(
"Failed to create EGLContext for device {:?}:{}", "Failed to create EGLContext for device {:?}:{}",
@ -483,10 +487,15 @@ impl State {
} }
}; };
let allocator = Box::new(DmabufAllocator(GbmAllocator::new(
gbm.clone(),
GbmBufferFlags::RENDERING,
)));
let mut device = Device { let mut device = Device {
render_node, render_node,
surfaces: HashMap::new(), surfaces: HashMap::new(),
allocator: gbm, gbm,
allocator,
drm: dispatcher, drm: dispatcher,
formats, formats,
supports_atomic, supports_atomic,
@ -500,7 +509,7 @@ impl State {
{ {
let backend = self.backend.kms(); let backend = self.backend.kms();
for (crtc, conn) in outputs { for (crtc, conn) in outputs {
let mut renderer = match backend.api.renderer(&render_node, &render_node) { let mut renderer = match backend.api.single_renderer(&render_node) {
Ok(renderer) => renderer, Ok(renderer) => renderer,
Err(err) => { Err(err) => {
slog_scope::warn!("Failed to initialize output: {}", err); slog_scope::warn!("Failed to initialize output: {}", err);
@ -536,6 +545,44 @@ impl State {
&self.common.event_loop_handle, &self.common.event_loop_handle,
); );
if let Ok(instance) = Instance::new(Version::VERSION_1_2, None, None) {
if let Some(physical_device) =
PhysicalDevice::enumerate(&instance)
.ok()
.and_then(|devices| {
devices
.filter(|phd| {
phd.has_device_extension(unsafe {
CStr::from_bytes_with_nul_unchecked(
b"VK_EXT_physical_device_drm\0",
)
})
})
.find(|phd| {
phd.primary_node().unwrap() == Some(render_node)
|| phd.render_node().unwrap() == Some(render_node)
})
})
{
match VulkanAllocator::new(
&physical_device,
ImageUsageFlags::COLOR_ATTACHMENT | ImageUsageFlags::SAMPLED,
) {
Ok(allocator) => {
self.backend
.kms()
.devices
.get_mut(&drm_node)
.unwrap()
.allocator = Box::new(DmabufAllocator(allocator));
}
Err(err) => {
slog_scope::warn!("Failed to create vulkan allocator: {}", err);
}
}
}
}
Ok(()) Ok(())
} }
@ -562,10 +609,7 @@ impl State {
} }
} }
for (crtc, conn) in changes.added { for (crtc, conn) in changes.added {
let mut renderer = match backend let mut renderer = match backend.api.single_renderer(&device.render_node) {
.api
.renderer(&device.render_node, &device.render_node)
{
Ok(renderer) => renderer, Ok(renderer) => renderer,
Err(err) => { Err(err) => {
slog_scope::warn!("Failed to initialize output: {}", err); slog_scope::warn!("Failed to initialize output: {}", err);
@ -701,7 +745,7 @@ impl Device {
crtc: crtc::Handle, crtc: crtc::Handle,
conn: connector::Handle, conn: connector::Handle,
position: (i32, i32), position: (i32, i32),
renderer: &mut GlMultiRenderer<'_>, renderer: &mut GlMultiRenderer<'_, '_>,
) -> Result<Output> { ) -> Result<Output> {
let drm = &mut *self.drm.as_source_mut(); let drm = &mut *self.drm.as_source_mut();
let crtc_info = drm.get_crtc(crtc)?; let crtc_info = drm.get_crtc(crtc)?;
@ -828,8 +872,11 @@ fn render_node_for_output(
impl Surface { impl Surface {
pub fn render_output( pub fn render_output(
&mut self, &mut self,
dh: &DisplayHandle, api: &mut GpuManager<GbmGlesBackend<GlowRenderer>>,
api: &mut GpuManager<EglGlesBackend<GlowRenderer>>, render_node: Option<(
&DrmNode,
&mut dyn Allocator<Buffer = Dmabuf, Error = AnyError>,
)>,
target_node: &DrmNode, target_node: &DrmNode,
state: &mut Common, state: &mut Common,
screencopy: Option<&[(ScreencopySession, BufferParams)]>, screencopy: Option<&[(ScreencopySession, BufferParams)]>,
@ -838,10 +885,16 @@ impl Surface {
return Ok(()); return Ok(());
} }
let render_node = render_node_for_output(dh, &self.output, *target_node, &state.shell);
let mut renderer: GlMultiRenderer = api.renderer(&render_node, &target_node).unwrap();
let surface = self.surface.as_mut().unwrap(); let surface = self.surface.as_mut().unwrap();
let (render_node, mut renderer) = match render_node {
Some((render_node, allocator)) => (
render_node,
api.renderer(&render_node, &target_node, allocator, surface.format())
.unwrap(),
),
None => (target_node, api.single_renderer(&target_node).unwrap()),
};
let (buffer, age) = surface let (buffer, age) = surface
.next_buffer() .next_buffer()
.with_context(|| "Failed to allocate buffer")?; .with_context(|| "Failed to allocate buffer")?;
@ -957,7 +1010,10 @@ impl KmsState {
let drm_surface = drm.create_surface(*crtc, *mode, &[conn])?; let drm_surface = drm.create_surface(*crtc, *mode, &[conn])?;
let target = GbmBufferedSurface::new( let target = GbmBufferedSurface::new(
drm_surface, drm_surface,
device.allocator.clone(), GbmAllocator::new(
device.gbm.clone(),
GbmBufferFlags::RENDERING | GbmBufferFlags::SCANOUT,
),
device.formats.clone(), device.formats.clone(),
None, None,
) )
@ -1051,7 +1107,7 @@ impl KmsState {
{ {
return self return self
.api .api
.renderer::<Gles2Renderbuffer>(&device.render_node, &device.render_node)? .single_renderer(&device.render_node)?
.import_dmabuf(&dmabuf, None) .import_dmabuf(&dmabuf, None)
.map(|_| ()) .map(|_| ())
.map_err(Into::into); .map_err(Into::into);
@ -1100,28 +1156,59 @@ impl KmsState {
}, },
move |_time, _, data| { move |_time, _, data| {
let backend = data.state.backend.kms(); let backend = data.state.backend.kms();
if let Some(device) = backend.devices.get_mut(&device) { let (mut device, mut other) = backend
if let Some(surface) = device.surfaces.get_mut(&crtc) { .devices
match surface.render_output( .iter_mut()
&data.display.handle(), .partition::<Vec<_>, _>(|(key, _val)| *key == &device);
let target_device = &mut device[0].1;
if let Some(surface) = target_device.surfaces.get_mut(&crtc) {
let target_node = target_device.render_node;
let render_node = render_node_for_output(
&data.display.handle(),
&surface.output,
target_node,
&data.state.common.shell,
);
let state = &mut data.state.common;
let result = if render_node != target_node {
let render_device = &mut other
.iter_mut()
.find(|(_, val)| val.render_node == render_node)
.unwrap()
.1;
surface.render_output(
&mut backend.api, &mut backend.api,
&device.render_node, Some((
&mut data.state.common, &render_device.render_node,
render_device.allocator.as_mut(),
)),
&target_node,
state,
screencopy_sessions.as_deref(), screencopy_sessions.as_deref(),
) { )
Ok(_) => return TimeoutAction::Drop, } else {
Err(err) => { surface.render_output(
if backend.session.is_active() { &mut backend.api,
slog_scope::error!("Error rendering: {}", err); None,
return TimeoutAction::ToDuration( &target_node,
Duration::from_secs_f64( state,
(1000.0 / surface.refresh_rate as f64) - 0.003, screencopy_sessions.as_deref(),
), )
); };
}
match result {
Ok(_) => return TimeoutAction::Drop,
Err(err) => {
if backend.session.is_active() {
slog_scope::error!("Error rendering: {}", err);
return TimeoutAction::ToDuration(Duration::from_secs_f64(
(1000.0 / surface.refresh_rate as f64) - 0.003,
));
} }
}; }
} };
} }
if let Some(sessions) = screencopy_sessions.as_mut() { if let Some(sessions) = screencopy_sessions.as_mut() {

View file

@ -154,15 +154,15 @@ impl RenderElement<GlowRenderer> for CosmicElement<GlowRenderer> {
} }
} }
impl<'a> RenderElement<GlMultiRenderer<'a>> for CosmicElement<GlMultiRenderer<'a>> { impl<'a, 'b> RenderElement<GlMultiRenderer<'a, 'b>> for CosmicElement<GlMultiRenderer<'a, 'b>> {
fn draw<'frame>( fn draw<'frame>(
&self, &self,
frame: &mut GlMultiFrame<'a, 'frame>, frame: &mut GlMultiFrame<'a, 'b, 'frame>,
src: Rectangle<f64, BufferCoords>, src: Rectangle<f64, BufferCoords>,
dst: Rectangle<i32, Physical>, dst: Rectangle<i32, Physical>,
damage: &[Rectangle<i32, Physical>], damage: &[Rectangle<i32, Physical>],
log: &slog::Logger, log: &slog::Logger,
) -> Result<(), <GlMultiRenderer<'_> as Renderer>::Error> { ) -> Result<(), <GlMultiRenderer<'a, 'b> as Renderer>::Error> {
match self { match self {
CosmicElement::Workspace(elem) => elem.draw(frame, src, dst, damage, log), CosmicElement::Workspace(elem) => elem.draw(frame, src, dst, damage, log),
CosmicElement::Cursor(elem) => elem.draw(frame, src, dst, damage, log), CosmicElement::Cursor(elem) => elem.draw(frame, src, dst, damage, log),
@ -181,8 +181,8 @@ impl<'a> RenderElement<GlMultiRenderer<'a>> for CosmicElement<GlMultiRenderer<'a
fn underlying_storage( fn underlying_storage(
&self, &self,
renderer: &GlMultiRenderer<'a>, renderer: &GlMultiRenderer<'a, 'b>,
) -> Option<UnderlyingStorage<'_, GlMultiRenderer<'a>>> { ) -> Option<UnderlyingStorage<'_, GlMultiRenderer<'a, 'b>>> {
match self { match self {
CosmicElement::Workspace(elem) => elem.underlying_storage(renderer), CosmicElement::Workspace(elem) => elem.underlying_storage(renderer),
CosmicElement::Cursor(elem) => elem.underlying_storage(renderer), CosmicElement::Cursor(elem) => elem.underlying_storage(renderer),
@ -263,7 +263,7 @@ impl AsGlowRenderer for GlowRenderer {
} }
} }
impl<'a> AsGlowRenderer for GlMultiRenderer<'a> { impl<'a, 'b> AsGlowRenderer for GlMultiRenderer<'a, 'b> {
fn glow_renderer(&self) -> &GlowRenderer { fn glow_renderer(&self) -> &GlowRenderer {
self.as_ref() self.as_ref()
} }
@ -289,7 +289,7 @@ impl<'frame> AsGlowFrame<'frame> for GlowFrame<'frame> {
} }
} }
impl<'renderer, 'frame> AsGlowFrame<'frame> for GlMultiFrame<'renderer, 'frame> { impl<'renderer, 'alloc, 'frame> AsGlowFrame<'frame> for GlMultiFrame<'renderer, 'alloc, 'frame> {
fn glow_frame(&self) -> &GlowFrame<'frame> { fn glow_frame(&self) -> &GlowFrame<'frame> {
self.as_ref() self.as_ref()
} }

View file

@ -27,9 +27,9 @@ use smithay::{
DamageTrackedRenderer, DamageTrackedRendererError as RenderError, OutputNoMode, DamageTrackedRenderer, DamageTrackedRendererError as RenderError, OutputNoMode,
}, },
element::{RenderElement, RenderElementStates}, element::{RenderElement, RenderElementStates},
gles2::{Gles2Error, Gles2Renderbuffer}, gles2::Gles2Error,
glow::GlowRenderer, glow::GlowRenderer,
multigpu::{egl::EglGlesBackend, MultiFrame, MultiRenderer}, multigpu::{gbm::GbmGlesBackend, MultiFrame, MultiRenderer},
Bind, Blit, ExportMem, ImportAll, ImportMem, Offscreen, Renderer, TextureFilter, Bind, Blit, ExportMem, ImportAll, ImportMem, Offscreen, Renderer, TextureFilter,
}, },
}, },
@ -43,21 +43,10 @@ use self::cursor::CursorRenderElement;
pub mod element; pub mod element;
use self::element::{AsGlowRenderer, CosmicElement}; use self::element::{AsGlowRenderer, CosmicElement};
pub type GlMultiRenderer<'a> = MultiRenderer< pub type GlMultiRenderer<'a, 'b> =
'a, MultiRenderer<'a, 'a, 'b, GbmGlesBackend<GlowRenderer>, GbmGlesBackend<GlowRenderer>>;
'a, pub type GlMultiFrame<'a, 'b, 'frame> =
EglGlesBackend<GlowRenderer>, MultiFrame<'a, 'a, 'b, 'frame, GbmGlesBackend<GlowRenderer>, GbmGlesBackend<GlowRenderer>>;
EglGlesBackend<GlowRenderer>,
Gles2Renderbuffer,
>;
pub type GlMultiFrame<'a, 'frame> = MultiFrame<
'a,
'a,
'frame,
EglGlesBackend<GlowRenderer>,
EglGlesBackend<GlowRenderer>,
Gles2Renderbuffer,
>;
pub static CLEAR_COLOR: [f32; 4] = [0.153, 0.161, 0.165, 1.0]; pub static CLEAR_COLOR: [f32; 4] = [0.153, 0.161, 0.165, 1.0];

View file

@ -11,14 +11,19 @@ use crate::{
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use smithay::{ use smithay::{
backend::{ backend::{
allocator::dmabuf::Dmabuf, allocator::{
drm::DrmDeviceFd, dmabuf::{Dmabuf, DmabufAllocator},
egl::{EGLContext, EGLDisplay}, gbm::{GbmAllocator, GbmBufferFlags},
vulkan::{ImageUsageFlags, VulkanAllocator},
},
drm::{DrmDeviceFd, DrmNode},
egl::{EGLContext, EGLDevice, EGLDisplay},
input::{Event, InputEvent}, input::{Event, InputEvent},
renderer::{ renderer::{
damage::DamageTrackedRenderer, gles2::Gles2Renderbuffer, glow::GlowRenderer, Bind, damage::DamageTrackedRenderer, gles2::Gles2Renderbuffer, glow::GlowRenderer, Bind,
ImportDma, ImportEgl, ImportDma, ImportEgl,
}, },
vulkan::{version::Version, Instance, PhysicalDevice},
x11::{Window, WindowBuilder, X11Backend, X11Event, X11Handle, X11Input, X11Surface}, x11::{Window, WindowBuilder, X11Backend, X11Event, X11Handle, X11Input, X11Surface},
}, },
desktop::layer_map_for_output, desktop::layer_map_for_output,
@ -31,13 +36,18 @@ use smithay::{
}, },
utils::{DeviceFd, Transform}, utils::{DeviceFd, Transform},
}; };
use std::cell::RefCell; use std::{cell::RefCell, os::unix::io::OwnedFd};
#[cfg(feature = "debug")] #[cfg(feature = "debug")]
use crate::state::Fps; use crate::state::Fps;
enum Allocator {
Gbm(GbmAllocator<DrmDeviceFd>),
Vulkan(PhysicalDevice),
}
pub struct X11State { pub struct X11State {
allocator: GbmDevice<DrmDeviceFd>, allocator: Allocator,
_egl: EGLDisplay, _egl: EGLDisplay,
pub renderer: GlowRenderer, pub renderer: GlowRenderer,
surfaces: Vec<Surface>, surfaces: Vec<Surface>,
@ -51,18 +61,28 @@ impl X11State {
.build(&self.handle) .build(&self.handle)
.with_context(|| "Failed to create window")?; .with_context(|| "Failed to create window")?;
let fourcc = window.format(); let fourcc = window.format();
let surface = self let modifiers = Bind::<Dmabuf>::supported_formats(&self.renderer).unwrap();
.handle let filtered_modifiers = modifiers
.create_surface( .iter()
&window, .filter(|format| format.code == fourcc)
self.allocator.clone(), .map(|format| format.modifier);
Bind::<Dmabuf>::supported_formats(&self.renderer) let surface = match &self.allocator {
.unwrap() Allocator::Gbm(gbm) => self
.iter() .handle
.filter(|format| format.code == fourcc) .create_surface(&window, DmabufAllocator(gbm.clone()), filtered_modifiers)
.map(|format| format.modifier), .with_context(|| "Failed to create surface")?,
) Allocator::Vulkan(vulkan) => self
.with_context(|| "Failed to create surface")?; .handle
.create_surface(
&window,
DmabufAllocator(
VulkanAllocator::new(vulkan, ImageUsageFlags::COLOR_ATTACHMENT)
.with_context(|| "Failed to create vulkan allocator for window")?,
),
filtered_modifiers,
)
.with_context(|| "Failed to create surface")?,
};
let name = format!("X11-{}", self.surfaces.len()); let name = format!("X11-{}", self.surfaces.len());
let size = window.size(); let size = window.size();
@ -251,6 +271,57 @@ impl Surface {
} }
} }
fn try_vulkan_allocator(node: &DrmNode) -> Option<Allocator> {
let instance = match Instance::new(Version::VERSION_1_2, None, None) {
Ok(instance) => instance,
Err(err) => {
slog_scope::warn!(
"Failed to instanciate vulkan, falling back to gbm allocator: {}",
err
);
return None;
}
};
let devices = match PhysicalDevice::enumerate(&instance) {
Ok(devices) => devices,
Err(err) => {
slog_scope::debug!("No vulkan devices, falling back to gbm: {}", err);
return None;
}
};
let Some(device) = devices
.filter(|phd| {
phd.has_device_extension(smithay::reexports::ash::extensions::ext::PhysicalDeviceDrm::name())
})
.find(|phd| {
phd.primary_node().unwrap() == Some(*node) || phd.render_node().unwrap() == Some(*node)
})
else {
slog_scope::debug!("No vulkan device for node {:?}, falling back to gbm", node);
return None;
};
Some(Allocator::Vulkan(device))
}
fn try_gbm_allocator(fd: OwnedFd) -> Option<Allocator> {
// Create the gbm device for buffer allocation.
let device = match GbmDevice::new(DrmDeviceFd::new(DeviceFd::from(fd), None)) {
Ok(gbm) => gbm,
Err(err) => {
slog_scope::error!("Failed to create GBM device: {}", err);
return None;
}
};
Some(Allocator::Gbm(GbmAllocator::new(
device,
GbmBufferFlags::RENDERING,
)))
}
pub fn init_backend( pub fn init_backend(
dh: &DisplayHandle, dh: &DisplayHandle,
event_loop: &mut EventLoop<Data>, event_loop: &mut EventLoop<Data>,
@ -260,16 +331,16 @@ pub fn init_backend(
let handle = backend.handle(); let handle = backend.handle();
// Obtain the DRM node the X server uses for direct rendering. // Obtain the DRM node the X server uses for direct rendering.
let (_drm_node, fd) = handle let (drm_node, fd) = handle
.drm_node() .drm_node()
.with_context(|| "Could not get DRM node used by X server")?; .with_context(|| "Could not get DRM node used by X server")?;
// Create the gbm device for buffer allocation. let device = EGLDevice::enumerate()
let device = GbmDevice::new(DrmDeviceFd::new(DeviceFd::from(fd), None)) .with_context(|| "Failed to enumerate EGL devices")?
.with_context(|| "Failed to create GBM device")?; .find(|device| device.try_get_render_node().ok().flatten() == Some(drm_node))
// Initialize EGL using the GBM device. .with_context(|| format!("Failed to find EGLDevice for node {}", drm_node))?;
let egl = // Initialize EGL
EGLDisplay::new(device.clone(), None).with_context(|| "Failed to create EGL display")?; let egl = EGLDisplay::new(device, None).with_context(|| "Failed to create EGL display")?;
// Create the OpenGL context // Create the OpenGL context
let context = EGLContext::new(&egl, None).with_context(|| "Failed to create EGL context")?; let context = EGLContext::new(&egl, None).with_context(|| "Failed to create EGL context")?;
// Create a renderer // Create a renderer
@ -280,7 +351,9 @@ pub fn init_backend(
state.backend = BackendData::X11(X11State { state.backend = BackendData::X11(X11State {
handle, handle,
allocator: device, allocator: try_vulkan_allocator(&drm_node)
.or_else(|| try_gbm_allocator(fd))
.expect("Failed to create allocator for x11"),
_egl: egl, _egl: egl,
renderer, renderer,
surfaces: Vec::new(), surfaces: Vec::new(),

View file

@ -775,15 +775,17 @@ impl RenderElement<GlowRenderer> for CosmicMappedRenderElement<GlowRenderer> {
} }
} }
impl<'a> RenderElement<GlMultiRenderer<'a>> for CosmicMappedRenderElement<GlMultiRenderer<'a>> { impl<'a, 'b> RenderElement<GlMultiRenderer<'a, 'b>>
for CosmicMappedRenderElement<GlMultiRenderer<'a, 'b>>
{
fn draw<'frame>( fn draw<'frame>(
&self, &self,
frame: &mut GlMultiFrame<'a, 'frame>, frame: &mut GlMultiFrame<'a, 'b, 'frame>,
src: Rectangle<f64, BufferCoords>, src: Rectangle<f64, BufferCoords>,
dst: Rectangle<i32, Physical>, dst: Rectangle<i32, Physical>,
damage: &[Rectangle<i32, Physical>], damage: &[Rectangle<i32, Physical>],
log: &slog::Logger, log: &slog::Logger,
) -> Result<(), <GlMultiRenderer<'_> as Renderer>::Error> { ) -> Result<(), <GlMultiRenderer<'a, 'b> as Renderer>::Error> {
match self { match self {
CosmicMappedRenderElement::Stack(elem) => elem.draw(frame, src, dst, damage, log), CosmicMappedRenderElement::Stack(elem) => elem.draw(frame, src, dst, damage, log),
CosmicMappedRenderElement::Window(elem) => elem.draw(frame, src, dst, damage, log), CosmicMappedRenderElement::Window(elem) => elem.draw(frame, src, dst, damage, log),
@ -798,8 +800,8 @@ impl<'a> RenderElement<GlMultiRenderer<'a>> for CosmicMappedRenderElement<GlMult
fn underlying_storage( fn underlying_storage(
&self, &self,
renderer: &GlMultiRenderer<'a>, renderer: &GlMultiRenderer<'a, 'b>,
) -> Option<UnderlyingStorage<'_, GlMultiRenderer<'a>>> { ) -> Option<UnderlyingStorage<'_, GlMultiRenderer<'a, 'b>>> {
match self { match self {
CosmicMappedRenderElement::Stack(elem) => elem.underlying_storage(renderer), CosmicMappedRenderElement::Stack(elem) => elem.underlying_storage(renderer),
CosmicMappedRenderElement::Window(elem) => elem.underlying_storage(renderer), CosmicMappedRenderElement::Window(elem) => elem.underlying_storage(renderer),

View file

@ -7,10 +7,12 @@ use smithay::{
reexports::wayland_server::protocol::{wl_data_source::WlDataSource, wl_surface::WlSurface}, reexports::wayland_server::protocol::{wl_data_source::WlDataSource, wl_surface::WlSurface},
utils::IsAlive, utils::IsAlive,
wayland::data_device::{ wayland::data_device::{
ClientDndGrabHandler, DataDeviceHandler, DataDeviceState, ServerDndGrabHandler, with_source_metadata, ClientDndGrabHandler, DataDeviceHandler, DataDeviceState,
ServerDndGrabHandler,
}, },
xwayland::xwm::{SelectionType, XwmId},
}; };
use std::cell::RefCell; use std::{cell::RefCell, os::unix::io::OwnedFd};
pub struct DnDIcon { pub struct DnDIcon {
surface: RefCell<Option<WlSurface>>, surface: RefCell<Option<WlSurface>>,
@ -48,9 +50,54 @@ impl ClientDndGrabHandler for State {
} }
impl ServerDndGrabHandler for State {} impl ServerDndGrabHandler for State {}
impl DataDeviceHandler for State { impl DataDeviceHandler for State {
type SelectionUserData = XwmId;
fn data_device_state(&self) -> &DataDeviceState { fn data_device_state(&self) -> &DataDeviceState {
&self.common.data_device_state &self.common.data_device_state
} }
fn new_selection(&mut self, source: Option<WlDataSource>) {
for xstate in self.common.xwayland_state.values_mut() {
if let Some(xwm) = xstate.xwm.as_mut() {
if let Some(source) = &source {
if let Ok(Err(err)) = with_source_metadata(source, |metadata| {
xwm.new_selection(
SelectionType::Clipboard,
Some(metadata.mime_types.clone()),
)
}) {
slog_scope::warn!("Failed to set Xwayland clipboard selection: {}", err);
}
} else if let Err(err) = xwm.new_selection(SelectionType::Clipboard, None) {
slog_scope::warn!("Failed to clear Xwayland clipboard selection: {}", err);
}
}
}
}
fn send_selection(
&mut self,
mime_type: String,
fd: OwnedFd,
user_data: &Self::SelectionUserData,
) {
if let Some(xwm) = self
.common
.xwayland_state
.values_mut()
.flat_map(|xstate| xstate.xwm.as_mut())
.find(|xwm| &xwm.id() == user_data)
{
if let Err(err) = xwm.send_selection(
SelectionType::Clipboard,
mime_type,
fd,
self.common.event_loop_handle.clone(),
) {
slog_scope::warn!("Failed to send clipboard (X11 -> Wayland): {}", err);
}
}
}
} }
delegate_data_device!(State); delegate_data_device!(State);

View file

@ -3,13 +3,57 @@
use crate::state::State; use crate::state::State;
use smithay::{ use smithay::{
delegate_primary_selection, delegate_primary_selection,
wayland::primary_selection::{PrimarySelectionHandler, PrimarySelectionState}, wayland::primary_selection::{PrimarySelectionHandler, PrimarySelectionState, with_source_metadata}, xwayland::xwm::{XwmId, SelectionType}, reexports::wayland_protocols::wp::primary_selection::zv1::server::zwp_primary_selection_source_v1::ZwpPrimarySelectionSourceV1,
}; };
use std::os::unix::io::OwnedFd;
impl PrimarySelectionHandler for State { impl PrimarySelectionHandler for State {
type SelectionUserData = XwmId;
fn primary_selection_state(&self) -> &PrimarySelectionState { fn primary_selection_state(&self) -> &PrimarySelectionState {
&self.common.primary_selection_state &self.common.primary_selection_state
} }
fn new_selection(&mut self, source: Option<ZwpPrimarySelectionSourceV1>) {
for xstate in self.common.xwayland_state.values_mut() {
if let Some(xwm) = xstate.xwm.as_mut() {
if let Some(source) = &source {
if let Ok(Err(err)) = with_source_metadata(source, |metadata| {
xwm.new_selection(SelectionType::Primary, Some(metadata.mime_types.clone()))
}) {
slog_scope::warn!("Failed to set Xwayland primary selection: {}", err);
}
} else if let Err(err) = xwm.new_selection(SelectionType::Primary, None) {
slog_scope::warn!("Failed to clear Xwayland primary selection: {}", err);
}
}
}
}
fn send_selection(
&mut self,
mime_type: String,
fd: OwnedFd,
user_data: &Self::SelectionUserData,
) {
if let Some(xwm) = self
.common
.xwayland_state
.values_mut()
.flat_map(|xstate| xstate.xwm.as_mut())
.find(|xwm| &xwm.id() == user_data)
{
if let Err(err) = xwm.send_selection(
SelectionType::Primary,
mime_type,
fd,
self.common.event_loop_handle.clone(),
) {
slog_scope::warn!("Failed to send primary selection (X11 -> Wayland): {}", err);
}
}
}
} }
delegate_primary_selection!(State); delegate_primary_selection!(State);

View file

@ -183,7 +183,7 @@ impl ScreencopyHandler for State {
None None
}) })
.unwrap_or(kms.primary.clone()); .unwrap_or(kms.primary.clone());
_kms_renderer = Some(kms.api.renderer::<Gles2Renderbuffer>(&node, &node).unwrap()); _kms_renderer = Some(kms.api.single_renderer(&node).unwrap());
_kms_renderer.as_mut().unwrap().as_mut() _kms_renderer.as_mut().unwrap().as_mut()
} }
BackendData::Winit(ref mut winit) => winit.backend.renderer(), BackendData::Winit(ref mut winit) => winit.backend.renderer(),
@ -423,7 +423,7 @@ fn formats_for_output(
let renderer = match backend { let renderer = match backend {
BackendData::Kms(ref mut kms) => { BackendData::Kms(ref mut kms) => {
let node = kms.target_node_for_output(&output).unwrap_or(kms.primary); let node = kms.target_node_for_output(&output).unwrap_or(kms.primary);
_kms_renderer = Some(kms.api.renderer::<Gles2Renderbuffer>(&node, &node).unwrap()); _kms_renderer = Some(kms.api.single_renderer(&node).unwrap());
_kms_renderer.as_mut().unwrap().as_mut() _kms_renderer.as_mut().unwrap().as_mut()
} }
BackendData::Winit(ref mut winit) => winit.backend.renderer(), BackendData::Winit(ref mut winit) => winit.backend.renderer(),
@ -664,7 +664,7 @@ pub fn render_output_to_buffer(
BackendData::Kms(kms) => { BackendData::Kms(kms) => {
let mut multirenderer = kms let mut multirenderer = kms
.api .api
.renderer::<Gles2Renderbuffer>(node.as_ref().unwrap(), node.as_ref().unwrap()) .single_renderer(node.as_ref().unwrap())
.map_err(|err| (FailureReason::Unspec, err.into()))?; .map_err(|err| (FailureReason::Unspec, err.into()))?;
render_session::<_, _>( render_session::<_, _>(
node, node,
@ -794,7 +794,7 @@ pub fn render_workspace_to_buffer(
BackendData::Kms(kms) => { BackendData::Kms(kms) => {
let mut multirenderer = kms let mut multirenderer = kms
.api .api
.renderer::<Gles2Renderbuffer>(node.as_ref().unwrap(), node.as_ref().unwrap()) .single_renderer(node.as_ref().unwrap())
.map_err(|err| (FailureReason::Unspec, err.into()))?; .map_err(|err| (FailureReason::Unspec, err.into()))?;
render_session::<_, _>( render_session::<_, _>(
node, node,
@ -959,7 +959,7 @@ pub fn render_window_to_buffer(
BackendData::Kms(kms) => { BackendData::Kms(kms) => {
let mut multirenderer = kms let mut multirenderer = kms
.api .api
.renderer::<Gles2Renderbuffer>(node.as_ref().unwrap(), node.as_ref().unwrap()) .single_renderer(node.as_ref().unwrap())
.map_err(|err| (FailureReason::Unspec, err.into()))?; .map_err(|err| (FailureReason::Unspec, err.into()))?;
render_session::<_, _>( render_session::<_, _>(
node, node,

View file

@ -1,8 +1,8 @@
use std::ffi::OsString; use std::{ffi::OsString, os::unix::io::OwnedFd};
use crate::{ use crate::{
backend::render::cursor::Cursor, backend::render::cursor::Cursor,
shell::{CosmicSurface, Shell}, shell::{focus::target::KeyboardFocusTarget, CosmicSurface, Shell},
state::{Data, State}, state::{Data, State},
utils::prelude::*, utils::prelude::*,
wayland::{handlers::screencopy::PendingScreencopyBuffers, protocols::screencopy::SessionType}, wayland::{handlers::screencopy::PendingScreencopyBuffers, protocols::screencopy::SessionType},
@ -12,8 +12,18 @@ use smithay::{
desktop::space::SpaceElement, desktop::space::SpaceElement,
reexports::x11rb::protocol::xproto::Window as X11Window, reexports::x11rb::protocol::xproto::Window as X11Window,
utils::{Logical, Point, Rectangle, Size}, utils::{Logical, Point, Rectangle, Size},
wayland::{
data_device::{
clear_data_device_selection, current_data_device_selection_userdata,
request_data_device_client_selection, set_data_device_selection,
},
primary_selection::{
clear_primary_selection, current_primary_selection_userdata,
request_primary_client_selection, set_primary_selection,
},
},
xwayland::{ xwayland::{
xwm::{Reorder, XwmId}, xwm::{Reorder, SelectionType, XwmId},
X11Surface, X11Wm, XWayland, XWaylandEvent, XwmHandler, X11Surface, X11Wm, XWayland, XWaylandEvent, XwmHandler,
}, },
}; };
@ -449,4 +459,86 @@ impl XwmHandler for Data {
} }
} }
} }
fn send_selection(
&mut self,
_xwm: XwmId,
selection: SelectionType,
mime_type: String,
fd: OwnedFd,
) {
let seat = self.state.common.last_active_seat();
match selection {
SelectionType::Clipboard => {
if let Err(err) = request_data_device_client_selection(seat, mime_type, fd) {
slog_scope::error!(
"Failed to request current wayland clipboard for Xwayland: {}",
err
);
}
}
SelectionType::Primary => {
if let Err(err) = request_primary_client_selection(seat, mime_type, fd) {
slog_scope::error!(
"Failed to request current wayland primary selection for Xwayland: {}",
err
);
}
}
}
}
fn allow_selection_access(&mut self, xwm: XwmId, _selection: SelectionType) -> bool {
self.state.common.is_x_focused(xwm)
}
fn new_selection(&mut self, xwm: XwmId, selection: SelectionType, mime_types: Vec<String>) {
slog_scope::info!("Got Selection {:?} from X11: {:?}", selection, mime_types);
if self.state.common.is_x_focused(xwm) {
let seat = self.state.common.last_active_seat();
match selection {
SelectionType::Clipboard => set_data_device_selection(
&self.state.common.display_handle,
&seat,
mime_types,
xwm,
),
SelectionType::Primary => {
set_primary_selection(&self.state.common.display_handle, &seat, mime_types, xwm)
}
}
}
}
fn cleared_selection(&mut self, xwm: XwmId, selection: SelectionType) {
for seat in self.state.common.seats() {
match selection {
SelectionType::Clipboard => {
if current_data_device_selection_userdata(seat).as_deref() == Some(&xwm) {
clear_data_device_selection(&self.state.common.display_handle, seat)
}
}
SelectionType::Primary => {
if current_primary_selection_userdata(seat).as_deref() == Some(&xwm) {
clear_primary_selection(&self.state.common.display_handle, seat)
}
}
}
}
}
}
impl Common {
fn is_x_focused(&self, xwm: XwmId) -> bool {
if let Some(keyboard) = self.last_active_seat().get_keyboard() {
if let Some(KeyboardFocusTarget::Element(mapped)) = keyboard.current_focus() {
if let CosmicSurface::X11(surface) = mapped.active_window() {
return surface.xwm_id().unwrap() == xwm;
}
}
}
false
}
} }