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:
parent
32762fb983
commit
4a9dfcead0
11 changed files with 450 additions and 115 deletions
7
Cargo.lock
generated
7
Cargo.lock
generated
|
|
@ -1753,9 +1753,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "input"
|
||||
version = "0.8.1"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d4669c07fe301ce2eb323ff23b9480e6a19d8e94520236862caca51b2b5c45e3"
|
||||
checksum = "eeb3afdf1f8137428002b354eaf87aa629178995683941d94b04c6d145ec8937"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"input-sys",
|
||||
|
|
@ -3292,9 +3292,10 @@ checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
|
|||
[[package]]
|
||||
name = "smithay"
|
||||
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 = [
|
||||
"appendlist",
|
||||
"ash",
|
||||
"bitflags",
|
||||
"calloop",
|
||||
"cc",
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ version = "0.3"
|
|||
git = "https://github.com/Smithay/smithay.git"
|
||||
rev = "2de946cf9e"
|
||||
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]
|
||||
git = "https://github.com/Smithay/smithay-egui.git"
|
||||
|
|
@ -70,4 +70,4 @@ debug = true
|
|||
lto = "fat"
|
||||
|
||||
[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" }
|
||||
|
|
|
|||
|
|
@ -15,7 +15,12 @@ use crate::{
|
|||
use anyhow::{Context, Result};
|
||||
use smithay::{
|
||||
backend::{
|
||||
allocator::{dmabuf::Dmabuf, gbm::GbmDevice, Format},
|
||||
allocator::{
|
||||
dmabuf::{AnyError, Dmabuf, DmabufAllocator},
|
||||
gbm::{GbmAllocator, GbmBufferFlags, GbmDevice},
|
||||
vulkan::{ImageUsageFlags, VulkanAllocator},
|
||||
Allocator, Format,
|
||||
},
|
||||
drm::{
|
||||
DrmDevice, DrmDeviceFd, DrmEvent, DrmEventTime, DrmNode, GbmBufferedSurface, NodeType,
|
||||
},
|
||||
|
|
@ -26,10 +31,11 @@ use smithay::{
|
|||
damage::DamageTrackedRenderer,
|
||||
gles2::Gles2Renderbuffer,
|
||||
glow::GlowRenderer,
|
||||
multigpu::{egl::EglGlesBackend, GpuManager},
|
||||
multigpu::{gbm::GbmGlesBackend, GpuManager},
|
||||
},
|
||||
session::{libseat::LibSeatSession, Event as SessionEvent, Session},
|
||||
udev::{all_gpus, primary_gpu, UdevBackend, UdevEvent},
|
||||
vulkan::{version::Version, Instance, PhysicalDevice},
|
||||
},
|
||||
desktop::utils::OutputPresentationFeedback,
|
||||
input::Seat,
|
||||
|
|
@ -53,6 +59,7 @@ use smithay::{
|
|||
use std::{
|
||||
cell::RefCell,
|
||||
collections::{HashMap, HashSet},
|
||||
ffi::CStr,
|
||||
os::unix::io::FromRawFd,
|
||||
path::PathBuf,
|
||||
time::Duration,
|
||||
|
|
@ -68,7 +75,7 @@ const MIN_RENDER_TIME: Duration = Duration::from_millis(3);
|
|||
|
||||
pub struct KmsState {
|
||||
devices: HashMap<DrmNode, Device>,
|
||||
pub api: GpuManager<EglGlesBackend<GlowRenderer>>,
|
||||
pub api: GpuManager<GbmGlesBackend<GlowRenderer>>,
|
||||
pub primary: DrmNode,
|
||||
session: LibSeatSession,
|
||||
_tokens: Vec<RegistrationToken>,
|
||||
|
|
@ -77,8 +84,9 @@ pub struct KmsState {
|
|||
pub struct Device {
|
||||
render_node: DrmNode,
|
||||
surfaces: HashMap<crtc::Handle, Surface>,
|
||||
allocator: GbmDevice<DrmDeviceFd>,
|
||||
drm: Dispatcher<'static, DrmDevice, Data>,
|
||||
gbm: GbmDevice<DrmDeviceFd>,
|
||||
allocator: Box<dyn Allocator<Buffer = Dmabuf, Error = AnyError>>,
|
||||
formats: HashSet<Format>,
|
||||
supports_atomic: bool,
|
||||
event_token: Option<RegistrationToken>,
|
||||
|
|
@ -86,7 +94,8 @@ pub struct Device {
|
|||
}
|
||||
|
||||
pub struct Surface {
|
||||
surface: Option<GbmBufferedSurface<GbmDevice<DrmDeviceFd>, Option<OutputPresentationFeedback>>>,
|
||||
surface:
|
||||
Option<GbmBufferedSurface<GbmAllocator<DrmDeviceFd>, Option<OutputPresentationFeedback>>>,
|
||||
damage_tracker: DamageTrackedRenderer,
|
||||
connector: connector::Handle,
|
||||
output: Output,
|
||||
|
|
@ -137,7 +146,7 @@ pub fn init_backend(
|
|||
})
|
||||
.map_err(|err| err.error)
|
||||
.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")?;
|
||||
|
||||
// TODO get this info from system76-power, if available and setup a watcher
|
||||
|
|
@ -359,12 +368,7 @@ impl State {
|
|||
.try_get_render_node()
|
||||
.ok()
|
||||
.and_then(std::convert::identity)
|
||||
.with_context(|| {
|
||||
format!(
|
||||
"Failed to determine path of egl device for {}",
|
||||
path.display()
|
||||
)
|
||||
})?;
|
||||
.unwrap_or(drm_node);
|
||||
let egl_context = EGLContext::new(&egl_display, None).with_context(|| {
|
||||
format!(
|
||||
"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 {
|
||||
render_node,
|
||||
surfaces: HashMap::new(),
|
||||
allocator: gbm,
|
||||
gbm,
|
||||
allocator,
|
||||
drm: dispatcher,
|
||||
formats,
|
||||
supports_atomic,
|
||||
|
|
@ -500,7 +509,7 @@ impl State {
|
|||
{
|
||||
let backend = self.backend.kms();
|
||||
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,
|
||||
Err(err) => {
|
||||
slog_scope::warn!("Failed to initialize output: {}", err);
|
||||
|
|
@ -536,6 +545,44 @@ impl State {
|
|||
&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(())
|
||||
}
|
||||
|
||||
|
|
@ -562,10 +609,7 @@ impl State {
|
|||
}
|
||||
}
|
||||
for (crtc, conn) in changes.added {
|
||||
let mut renderer = match backend
|
||||
.api
|
||||
.renderer(&device.render_node, &device.render_node)
|
||||
{
|
||||
let mut renderer = match backend.api.single_renderer(&device.render_node) {
|
||||
Ok(renderer) => renderer,
|
||||
Err(err) => {
|
||||
slog_scope::warn!("Failed to initialize output: {}", err);
|
||||
|
|
@ -701,7 +745,7 @@ impl Device {
|
|||
crtc: crtc::Handle,
|
||||
conn: connector::Handle,
|
||||
position: (i32, i32),
|
||||
renderer: &mut GlMultiRenderer<'_>,
|
||||
renderer: &mut GlMultiRenderer<'_, '_>,
|
||||
) -> Result<Output> {
|
||||
let drm = &mut *self.drm.as_source_mut();
|
||||
let crtc_info = drm.get_crtc(crtc)?;
|
||||
|
|
@ -828,8 +872,11 @@ fn render_node_for_output(
|
|||
impl Surface {
|
||||
pub fn render_output(
|
||||
&mut self,
|
||||
dh: &DisplayHandle,
|
||||
api: &mut GpuManager<EglGlesBackend<GlowRenderer>>,
|
||||
api: &mut GpuManager<GbmGlesBackend<GlowRenderer>>,
|
||||
render_node: Option<(
|
||||
&DrmNode,
|
||||
&mut dyn Allocator<Buffer = Dmabuf, Error = AnyError>,
|
||||
)>,
|
||||
target_node: &DrmNode,
|
||||
state: &mut Common,
|
||||
screencopy: Option<&[(ScreencopySession, BufferParams)]>,
|
||||
|
|
@ -838,10 +885,16 @@ impl Surface {
|
|||
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 (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
|
||||
.next_buffer()
|
||||
.with_context(|| "Failed to allocate buffer")?;
|
||||
|
|
@ -957,7 +1010,10 @@ impl KmsState {
|
|||
let drm_surface = drm.create_surface(*crtc, *mode, &[conn])?;
|
||||
let target = GbmBufferedSurface::new(
|
||||
drm_surface,
|
||||
device.allocator.clone(),
|
||||
GbmAllocator::new(
|
||||
device.gbm.clone(),
|
||||
GbmBufferFlags::RENDERING | GbmBufferFlags::SCANOUT,
|
||||
),
|
||||
device.formats.clone(),
|
||||
None,
|
||||
)
|
||||
|
|
@ -1051,7 +1107,7 @@ impl KmsState {
|
|||
{
|
||||
return self
|
||||
.api
|
||||
.renderer::<Gles2Renderbuffer>(&device.render_node, &device.render_node)?
|
||||
.single_renderer(&device.render_node)?
|
||||
.import_dmabuf(&dmabuf, None)
|
||||
.map(|_| ())
|
||||
.map_err(Into::into);
|
||||
|
|
@ -1100,28 +1156,59 @@ impl KmsState {
|
|||
},
|
||||
move |_time, _, data| {
|
||||
let backend = data.state.backend.kms();
|
||||
if let Some(device) = backend.devices.get_mut(&device) {
|
||||
if let Some(surface) = device.surfaces.get_mut(&crtc) {
|
||||
match surface.render_output(
|
||||
&data.display.handle(),
|
||||
let (mut device, mut other) = backend
|
||||
.devices
|
||||
.iter_mut()
|
||||
.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,
|
||||
&device.render_node,
|
||||
&mut data.state.common,
|
||||
Some((
|
||||
&render_device.render_node,
|
||||
render_device.allocator.as_mut(),
|
||||
)),
|
||||
&target_node,
|
||||
state,
|
||||
screencopy_sessions.as_deref(),
|
||||
) {
|
||||
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,
|
||||
),
|
||||
);
|
||||
}
|
||||
)
|
||||
} else {
|
||||
surface.render_output(
|
||||
&mut backend.api,
|
||||
None,
|
||||
&target_node,
|
||||
state,
|
||||
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() {
|
||||
|
|
|
|||
|
|
@ -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>(
|
||||
&self,
|
||||
frame: &mut GlMultiFrame<'a, 'frame>,
|
||||
frame: &mut GlMultiFrame<'a, 'b, 'frame>,
|
||||
src: Rectangle<f64, BufferCoords>,
|
||||
dst: Rectangle<i32, Physical>,
|
||||
damage: &[Rectangle<i32, Physical>],
|
||||
log: &slog::Logger,
|
||||
) -> Result<(), <GlMultiRenderer<'_> as Renderer>::Error> {
|
||||
) -> Result<(), <GlMultiRenderer<'a, 'b> as Renderer>::Error> {
|
||||
match self {
|
||||
CosmicElement::Workspace(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(
|
||||
&self,
|
||||
renderer: &GlMultiRenderer<'a>,
|
||||
) -> Option<UnderlyingStorage<'_, GlMultiRenderer<'a>>> {
|
||||
renderer: &GlMultiRenderer<'a, 'b>,
|
||||
) -> Option<UnderlyingStorage<'_, GlMultiRenderer<'a, 'b>>> {
|
||||
match self {
|
||||
CosmicElement::Workspace(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 {
|
||||
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> {
|
||||
self.as_ref()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,9 +27,9 @@ use smithay::{
|
|||
DamageTrackedRenderer, DamageTrackedRendererError as RenderError, OutputNoMode,
|
||||
},
|
||||
element::{RenderElement, RenderElementStates},
|
||||
gles2::{Gles2Error, Gles2Renderbuffer},
|
||||
gles2::Gles2Error,
|
||||
glow::GlowRenderer,
|
||||
multigpu::{egl::EglGlesBackend, MultiFrame, MultiRenderer},
|
||||
multigpu::{gbm::GbmGlesBackend, MultiFrame, MultiRenderer},
|
||||
Bind, Blit, ExportMem, ImportAll, ImportMem, Offscreen, Renderer, TextureFilter,
|
||||
},
|
||||
},
|
||||
|
|
@ -43,21 +43,10 @@ use self::cursor::CursorRenderElement;
|
|||
pub mod element;
|
||||
use self::element::{AsGlowRenderer, CosmicElement};
|
||||
|
||||
pub type GlMultiRenderer<'a> = MultiRenderer<
|
||||
'a,
|
||||
'a,
|
||||
EglGlesBackend<GlowRenderer>,
|
||||
EglGlesBackend<GlowRenderer>,
|
||||
Gles2Renderbuffer,
|
||||
>;
|
||||
pub type GlMultiFrame<'a, 'frame> = MultiFrame<
|
||||
'a,
|
||||
'a,
|
||||
'frame,
|
||||
EglGlesBackend<GlowRenderer>,
|
||||
EglGlesBackend<GlowRenderer>,
|
||||
Gles2Renderbuffer,
|
||||
>;
|
||||
pub type GlMultiRenderer<'a, 'b> =
|
||||
MultiRenderer<'a, 'a, 'b, GbmGlesBackend<GlowRenderer>, GbmGlesBackend<GlowRenderer>>;
|
||||
pub type GlMultiFrame<'a, 'b, 'frame> =
|
||||
MultiFrame<'a, 'a, 'b, 'frame, GbmGlesBackend<GlowRenderer>, GbmGlesBackend<GlowRenderer>>;
|
||||
|
||||
pub static CLEAR_COLOR: [f32; 4] = [0.153, 0.161, 0.165, 1.0];
|
||||
|
||||
|
|
|
|||
|
|
@ -11,14 +11,19 @@ use crate::{
|
|||
use anyhow::{Context, Result};
|
||||
use smithay::{
|
||||
backend::{
|
||||
allocator::dmabuf::Dmabuf,
|
||||
drm::DrmDeviceFd,
|
||||
egl::{EGLContext, EGLDisplay},
|
||||
allocator::{
|
||||
dmabuf::{Dmabuf, DmabufAllocator},
|
||||
gbm::{GbmAllocator, GbmBufferFlags},
|
||||
vulkan::{ImageUsageFlags, VulkanAllocator},
|
||||
},
|
||||
drm::{DrmDeviceFd, DrmNode},
|
||||
egl::{EGLContext, EGLDevice, EGLDisplay},
|
||||
input::{Event, InputEvent},
|
||||
renderer::{
|
||||
damage::DamageTrackedRenderer, gles2::Gles2Renderbuffer, glow::GlowRenderer, Bind,
|
||||
ImportDma, ImportEgl,
|
||||
},
|
||||
vulkan::{version::Version, Instance, PhysicalDevice},
|
||||
x11::{Window, WindowBuilder, X11Backend, X11Event, X11Handle, X11Input, X11Surface},
|
||||
},
|
||||
desktop::layer_map_for_output,
|
||||
|
|
@ -31,13 +36,18 @@ use smithay::{
|
|||
},
|
||||
utils::{DeviceFd, Transform},
|
||||
};
|
||||
use std::cell::RefCell;
|
||||
use std::{cell::RefCell, os::unix::io::OwnedFd};
|
||||
|
||||
#[cfg(feature = "debug")]
|
||||
use crate::state::Fps;
|
||||
|
||||
enum Allocator {
|
||||
Gbm(GbmAllocator<DrmDeviceFd>),
|
||||
Vulkan(PhysicalDevice),
|
||||
}
|
||||
|
||||
pub struct X11State {
|
||||
allocator: GbmDevice<DrmDeviceFd>,
|
||||
allocator: Allocator,
|
||||
_egl: EGLDisplay,
|
||||
pub renderer: GlowRenderer,
|
||||
surfaces: Vec<Surface>,
|
||||
|
|
@ -51,18 +61,28 @@ impl X11State {
|
|||
.build(&self.handle)
|
||||
.with_context(|| "Failed to create window")?;
|
||||
let fourcc = window.format();
|
||||
let surface = self
|
||||
.handle
|
||||
.create_surface(
|
||||
&window,
|
||||
self.allocator.clone(),
|
||||
Bind::<Dmabuf>::supported_formats(&self.renderer)
|
||||
.unwrap()
|
||||
.iter()
|
||||
.filter(|format| format.code == fourcc)
|
||||
.map(|format| format.modifier),
|
||||
)
|
||||
.with_context(|| "Failed to create surface")?;
|
||||
let modifiers = Bind::<Dmabuf>::supported_formats(&self.renderer).unwrap();
|
||||
let filtered_modifiers = modifiers
|
||||
.iter()
|
||||
.filter(|format| format.code == fourcc)
|
||||
.map(|format| format.modifier);
|
||||
let surface = match &self.allocator {
|
||||
Allocator::Gbm(gbm) => self
|
||||
.handle
|
||||
.create_surface(&window, DmabufAllocator(gbm.clone()), filtered_modifiers)
|
||||
.with_context(|| "Failed to create surface")?,
|
||||
Allocator::Vulkan(vulkan) => self
|
||||
.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 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(
|
||||
dh: &DisplayHandle,
|
||||
event_loop: &mut EventLoop<Data>,
|
||||
|
|
@ -260,16 +331,16 @@ pub fn init_backend(
|
|||
let handle = backend.handle();
|
||||
|
||||
// Obtain the DRM node the X server uses for direct rendering.
|
||||
let (_drm_node, fd) = handle
|
||||
let (drm_node, fd) = handle
|
||||
.drm_node()
|
||||
.with_context(|| "Could not get DRM node used by X server")?;
|
||||
|
||||
// Create the gbm device for buffer allocation.
|
||||
let device = GbmDevice::new(DrmDeviceFd::new(DeviceFd::from(fd), None))
|
||||
.with_context(|| "Failed to create GBM device")?;
|
||||
// Initialize EGL using the GBM device.
|
||||
let egl =
|
||||
EGLDisplay::new(device.clone(), None).with_context(|| "Failed to create EGL display")?;
|
||||
let device = EGLDevice::enumerate()
|
||||
.with_context(|| "Failed to enumerate EGL devices")?
|
||||
.find(|device| device.try_get_render_node().ok().flatten() == Some(drm_node))
|
||||
.with_context(|| format!("Failed to find EGLDevice for node {}", drm_node))?;
|
||||
// Initialize EGL
|
||||
let egl = EGLDisplay::new(device, None).with_context(|| "Failed to create EGL display")?;
|
||||
// Create the OpenGL context
|
||||
let context = EGLContext::new(&egl, None).with_context(|| "Failed to create EGL context")?;
|
||||
// Create a renderer
|
||||
|
|
@ -280,7 +351,9 @@ pub fn init_backend(
|
|||
|
||||
state.backend = BackendData::X11(X11State {
|
||||
handle,
|
||||
allocator: device,
|
||||
allocator: try_vulkan_allocator(&drm_node)
|
||||
.or_else(|| try_gbm_allocator(fd))
|
||||
.expect("Failed to create allocator for x11"),
|
||||
_egl: egl,
|
||||
renderer,
|
||||
surfaces: Vec::new(),
|
||||
|
|
|
|||
|
|
@ -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>(
|
||||
&self,
|
||||
frame: &mut GlMultiFrame<'a, 'frame>,
|
||||
frame: &mut GlMultiFrame<'a, 'b, 'frame>,
|
||||
src: Rectangle<f64, BufferCoords>,
|
||||
dst: Rectangle<i32, Physical>,
|
||||
damage: &[Rectangle<i32, Physical>],
|
||||
log: &slog::Logger,
|
||||
) -> Result<(), <GlMultiRenderer<'_> as Renderer>::Error> {
|
||||
) -> Result<(), <GlMultiRenderer<'a, 'b> as Renderer>::Error> {
|
||||
match self {
|
||||
CosmicMappedRenderElement::Stack(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(
|
||||
&self,
|
||||
renderer: &GlMultiRenderer<'a>,
|
||||
) -> Option<UnderlyingStorage<'_, GlMultiRenderer<'a>>> {
|
||||
renderer: &GlMultiRenderer<'a, 'b>,
|
||||
) -> Option<UnderlyingStorage<'_, GlMultiRenderer<'a, 'b>>> {
|
||||
match self {
|
||||
CosmicMappedRenderElement::Stack(elem) => elem.underlying_storage(renderer),
|
||||
CosmicMappedRenderElement::Window(elem) => elem.underlying_storage(renderer),
|
||||
|
|
|
|||
|
|
@ -7,10 +7,12 @@ use smithay::{
|
|||
reexports::wayland_server::protocol::{wl_data_source::WlDataSource, wl_surface::WlSurface},
|
||||
utils::IsAlive,
|
||||
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 {
|
||||
surface: RefCell<Option<WlSurface>>,
|
||||
|
|
@ -48,9 +50,54 @@ impl ClientDndGrabHandler for State {
|
|||
}
|
||||
impl ServerDndGrabHandler for State {}
|
||||
impl DataDeviceHandler for State {
|
||||
type SelectionUserData = XwmId;
|
||||
|
||||
fn data_device_state(&self) -> &DataDeviceState {
|
||||
&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);
|
||||
|
|
|
|||
|
|
@ -3,13 +3,57 @@
|
|||
use crate::state::State;
|
||||
use smithay::{
|
||||
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 {
|
||||
type SelectionUserData = XwmId;
|
||||
|
||||
fn primary_selection_state(&self) -> &PrimarySelectionState {
|
||||
&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);
|
||||
|
|
|
|||
|
|
@ -183,7 +183,7 @@ impl ScreencopyHandler for State {
|
|||
None
|
||||
})
|
||||
.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()
|
||||
}
|
||||
BackendData::Winit(ref mut winit) => winit.backend.renderer(),
|
||||
|
|
@ -423,7 +423,7 @@ fn formats_for_output(
|
|||
let renderer = match backend {
|
||||
BackendData::Kms(ref mut kms) => {
|
||||
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()
|
||||
}
|
||||
BackendData::Winit(ref mut winit) => winit.backend.renderer(),
|
||||
|
|
@ -664,7 +664,7 @@ pub fn render_output_to_buffer(
|
|||
BackendData::Kms(kms) => {
|
||||
let mut multirenderer = kms
|
||||
.api
|
||||
.renderer::<Gles2Renderbuffer>(node.as_ref().unwrap(), node.as_ref().unwrap())
|
||||
.single_renderer(node.as_ref().unwrap())
|
||||
.map_err(|err| (FailureReason::Unspec, err.into()))?;
|
||||
render_session::<_, _>(
|
||||
node,
|
||||
|
|
@ -794,7 +794,7 @@ pub fn render_workspace_to_buffer(
|
|||
BackendData::Kms(kms) => {
|
||||
let mut multirenderer = kms
|
||||
.api
|
||||
.renderer::<Gles2Renderbuffer>(node.as_ref().unwrap(), node.as_ref().unwrap())
|
||||
.single_renderer(node.as_ref().unwrap())
|
||||
.map_err(|err| (FailureReason::Unspec, err.into()))?;
|
||||
render_session::<_, _>(
|
||||
node,
|
||||
|
|
@ -959,7 +959,7 @@ pub fn render_window_to_buffer(
|
|||
BackendData::Kms(kms) => {
|
||||
let mut multirenderer = kms
|
||||
.api
|
||||
.renderer::<Gles2Renderbuffer>(node.as_ref().unwrap(), node.as_ref().unwrap())
|
||||
.single_renderer(node.as_ref().unwrap())
|
||||
.map_err(|err| (FailureReason::Unspec, err.into()))?;
|
||||
render_session::<_, _>(
|
||||
node,
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
use std::ffi::OsString;
|
||||
use std::{ffi::OsString, os::unix::io::OwnedFd};
|
||||
|
||||
use crate::{
|
||||
backend::render::cursor::Cursor,
|
||||
shell::{CosmicSurface, Shell},
|
||||
shell::{focus::target::KeyboardFocusTarget, CosmicSurface, Shell},
|
||||
state::{Data, State},
|
||||
utils::prelude::*,
|
||||
wayland::{handlers::screencopy::PendingScreencopyBuffers, protocols::screencopy::SessionType},
|
||||
|
|
@ -12,8 +12,18 @@ use smithay::{
|
|||
desktop::space::SpaceElement,
|
||||
reexports::x11rb::protocol::xproto::Window as X11Window,
|
||||
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::{
|
||||
xwm::{Reorder, XwmId},
|
||||
xwm::{Reorder, SelectionType, XwmId},
|
||||
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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue