backend: Adopt to new wayland-display handling

This commit is contained in:
Victoria Brekenfeld 2022-07-04 15:29:31 +02:00
parent b126dfaf77
commit 270f06182e
7 changed files with 351 additions and 379 deletions

View file

@ -7,19 +7,25 @@ use crate::{
backend::render, backend::render,
config::OutputConfig, config::OutputConfig,
shell::Shell, shell::Shell,
state::{BackendData, Common, State}, state::{BackendData, ClientState, Common, Data},
utils::prelude::*,
}; };
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use smithay::{ use smithay::{
backend::{ backend::{
allocator::{gbm::GbmDevice, Format}, allocator::{
dmabuf::Dmabuf,
gbm::GbmDevice,
Format,
},
drm::{DrmDevice, DrmEvent, DrmEventTime, DrmNode, GbmBufferedSurface, NodeType}, drm::{DrmDevice, DrmEvent, DrmEventTime, DrmNode, GbmBufferedSurface, NodeType},
egl::{EGLContext, EGLDevice, EGLDisplay}, egl::{EGLContext, EGLDevice, EGLDisplay},
input::InputEvent, input::InputEvent,
libinput::{LibinputInputBackend, LibinputSessionInterface}, libinput::{LibinputInputBackend, LibinputSessionInterface},
renderer::{ renderer::{
multigpu::{egl::EglGlesBackend, GpuManager}, multigpu::{egl::EglGlesBackend, GpuManager},
gles2::Gles2Renderbuffer,
Bind, Bind,
}, },
session::{auto::AutoSession, Session, Signal}, session::{auto::AutoSession, Session, Signal},
@ -33,10 +39,16 @@ use smithay::{
drm::control::{connector, crtc, Device as ControlDevice, ModeTypeFlags}, drm::control::{connector, crtc, Device as ControlDevice, ModeTypeFlags},
input::Libinput, input::Libinput,
nix::{fcntl::OFlag, sys::stat::dev_t}, nix::{fcntl::OFlag, sys::stat::dev_t},
wayland_server::protocol::{wl_output, wl_surface::WlSurface}, wayland_server::{
DisplayHandle, Resource,
protocol::{wl_output, wl_surface::WlSurface},
},
}, },
utils::signaling::{Linkable, SignalToken, Signaler}, utils::signaling::{Linkable, SignalToken, Signaler},
wayland::output::{Mode as OutputMode, Output, PhysicalProperties}, wayland::{
dmabuf::DmabufGlobal,
output::{Mode as OutputMode, Output, PhysicalProperties},
},
}; };
use std::{ use std::{
@ -56,7 +68,7 @@ use socket::*;
pub struct KmsState { pub struct KmsState {
devices: HashMap<DrmNode, Device>, devices: HashMap<DrmNode, Device>,
api: GpuManager<EglGlesBackend>, api: GpuManager<EglGlesBackend>,
primary: DrmNode, pub primary: DrmNode,
session: AutoSession, session: AutoSession,
signaler: Signaler<Signal>, signaler: Signaler<Signal>,
_restart_token: SignalToken, _restart_token: SignalToken,
@ -67,7 +79,7 @@ pub struct Device {
render_node: DrmNode, render_node: DrmNode,
surfaces: HashMap<crtc::Handle, Surface>, surfaces: HashMap<crtc::Handle, Surface>,
allocator: Rc<RefCell<GbmDevice<SessionFd>>>, allocator: Rc<RefCell<GbmDevice<SessionFd>>>,
drm: Dispatcher<'static, DrmDevice<SessionFd>, State>, drm: Dispatcher<'static, DrmDevice<SessionFd>, Data>,
formats: HashSet<Format>, formats: HashSet<Format>,
supports_atomic: bool, supports_atomic: bool,
event_token: Option<RegistrationToken>, event_token: Option<RegistrationToken>,
@ -87,7 +99,7 @@ pub struct Surface {
fps: Fps, fps: Fps,
} }
pub fn init_backend(event_loop: &mut EventLoop<'static, State>, state: &mut State) -> Result<()> { pub fn init_backend(dh: &DisplayHandle, event_loop: &mut EventLoop<'static, Data>, state: &mut State) -> Result<()> {
let (session, notifier) = AutoSession::new(None).context("Failed to acquire session")?; let (session, notifier) = AutoSession::new(None).context("Failed to acquire session")?;
let signaler = notifier.signaler(); let signaler = notifier.signaler();
@ -102,16 +114,16 @@ pub fn init_backend(event_loop: &mut EventLoop<'static, State>, state: &mut Stat
let libinput_event_source = event_loop let libinput_event_source = event_loop
.handle() .handle()
.insert_source(libinput_backend, move |mut event, _, state| { .insert_source(libinput_backend, move |mut event, _, data| {
if let &mut InputEvent::DeviceAdded { ref mut device } = &mut event { if let &mut InputEvent::DeviceAdded { ref mut device } = &mut event {
state.common.config.read_device(device); data.state.common.config.read_device(device);
} }
state.process_input_event(event); data.state.process_input_event(&data.display.handle(), event);
for output in state.common.shell.outputs() { for output in data.state.common.shell.outputs() {
if let Err(err) = state if let Err(err) = data.state
.backend .backend
.kms() .kms()
.schedule_render(&state.common.event_loop_handle, output) .schedule_render(&data.state.common.event_loop_handle, output)
{ {
slog_scope::crit!("Error scheduling event loop for output {}: {:?}", output.name(), err); slog_scope::crit!("Error scheduling event loop for output {}: {:?}", output.name(), err);
} }
@ -153,16 +165,16 @@ pub fn init_backend(event_loop: &mut EventLoop<'static, State>, state: &mut Stat
}; };
slog_scope::info!("Using {} as primary gpu for rendering", primary); slog_scope::info!("Using {} as primary gpu for rendering", primary);
let udev_dispatcher = Dispatcher::new(udev_backend, move |event, _, state: &mut State| { let udev_dispatcher = Dispatcher::new(udev_backend, move |event, _, data: &mut Data| {
match match event { match match event {
UdevEvent::Added { device_id, path } => state UdevEvent::Added { device_id, path } => data.state
.device_added(device_id, path) .device_added(device_id, path, &data.display.handle())
.with_context(|| format!("Failed to add drm device: {}", device_id)), .with_context(|| format!("Failed to add drm device: {}", device_id)),
UdevEvent::Changed { device_id } => state UdevEvent::Changed { device_id } => data.state
.device_changed(device_id) .device_changed(device_id)
.with_context(|| format!("Failed to update drm device: {}", device_id)), .with_context(|| format!("Failed to update drm device: {}", device_id)),
UdevEvent::Removed { device_id } => state UdevEvent::Removed { device_id } => data.state
.device_removed(device_id) .device_removed(device_id, &data.display.handle())
.with_context(|| format!("Failed to remove drm device: {}", device_id)), .with_context(|| format!("Failed to remove drm device: {}", device_id)),
} { } {
Ok(()) => { Ok(()) => {
@ -184,7 +196,7 @@ pub fn init_backend(event_loop: &mut EventLoop<'static, State>, state: &mut Stat
let _restart_token = signaler.register(move |signal| { let _restart_token = signaler.register(move |signal| {
if let Signal::ActivateSession = signal { if let Signal::ActivateSession = signal {
let dispatcher = dispatcher.clone(); let dispatcher = dispatcher.clone();
handle.insert_idle(move |state| { handle.insert_idle(move |data| {
for (dev, path) in dispatcher.as_source_ref().device_list() { for (dev, path) in dispatcher.as_source_ref().device_list() {
let drm_node = match DrmNode::from_dev_id(dev) { let drm_node = match DrmNode::from_dev_id(dev) {
Ok(node) => node, Ok(node) => node,
@ -197,8 +209,8 @@ pub fn init_backend(event_loop: &mut EventLoop<'static, State>, state: &mut Stat
continue; continue;
} }
}; };
if state.backend.kms().devices.contains_key(&drm_node) { if data.state.backend.kms().devices.contains_key(&drm_node) {
if let Err(err) = state.device_changed(dev) { if let Err(err) = data.state.device_changed(dev) {
slog_scope::error!( slog_scope::error!(
"Failed to update drm device {}: {}", "Failed to update drm device {}: {}",
path.display(), path.display(),
@ -206,7 +218,7 @@ pub fn init_backend(event_loop: &mut EventLoop<'static, State>, state: &mut Stat
); );
} }
} else { } else {
if let Err(err) = state.device_added(dev, path.into()) { if let Err(err) = data.state.device_added(dev, path.into(), &data.display.handle()) {
slog_scope::error!( slog_scope::error!(
"Failed to add drm device {}: {}", "Failed to add drm device {}: {}",
path.display(), path.display(),
@ -215,24 +227,24 @@ pub fn init_backend(event_loop: &mut EventLoop<'static, State>, state: &mut Stat
} }
} }
} }
state data.state
.common .common
.output_conf .output_configuration_state
.update(&mut *state.common.display.borrow_mut()); .update();
state.common.config.read_outputs( data.state.common.config.read_outputs(
state.common.output_conf.outputs(), data.state.common.output_configuration_state.outputs(),
&mut state.backend, &mut data.state.backend,
&mut state.common.shell, &mut data.state.common.shell,
&state.common.event_loop_handle, &data.state.common.event_loop_handle,
); );
state.common.shell.refresh_outputs(); data.state.common.shell.refresh_outputs();
state data.state
.common .common
.config .config
.write_outputs(state.common.output_conf.outputs()); .write_outputs(data.state.common.output_configuration_state.outputs());
for surface in state for surface in data.state
.backend .backend
.kms() .kms()
.devices .devices
@ -241,11 +253,11 @@ pub fn init_backend(event_loop: &mut EventLoop<'static, State>, state: &mut Stat
{ {
surface.pending = false; surface.pending = false;
} }
for output in state.common.shell.outputs() { for output in data.state.common.shell.outputs() {
if let Err(err) = state if let Err(err) = data.state
.backend .backend
.kms() .kms()
.schedule_render(&state.common.event_loop_handle, output) .schedule_render(&data.state.common.event_loop_handle, output)
{ {
slog_scope::crit!("Error scheduling event loop for output {}: {:?}", output.name(), err); slog_scope::crit!("Error scheduling event loop for output {}: {:?}", output.name(), err);
} }
@ -271,14 +283,14 @@ pub fn init_backend(event_loop: &mut EventLoop<'static, State>, state: &mut Stat
for (dev, path) in udev_dispatcher.as_source_ref().device_list() { for (dev, path) in udev_dispatcher.as_source_ref().device_list() {
state state
.device_added(dev, path.into()) .device_added(dev, path.into(), dh)
.with_context(|| format!("Failed to add drm device: {}", path.display()))?; .with_context(|| format!("Failed to add drm device: {}", path.display()))?;
} }
Ok(()) Ok(())
} }
impl State { impl State {
fn device_added(&mut self, dev: dev_t, path: PathBuf) -> Result<()> { fn device_added(&mut self, dev: dev_t, path: PathBuf, dh: &DisplayHandle) -> Result<()> {
if !self.backend.kms().session.is_active() { if !self.backend.kms().session.is_active() {
return Ok(()); return Ok(());
} }
@ -332,21 +344,21 @@ impl State {
drm.link(self.backend.kms().signaler.clone()); drm.link(self.backend.kms().signaler.clone());
let dispatcher = let dispatcher =
Dispatcher::new(drm, move |event, metadata, state: &mut State| match event { Dispatcher::new(drm, move |event, metadata, data: &mut Data| match event {
DrmEvent::VBlank(crtc) => { DrmEvent::VBlank(crtc) => {
if let Some(device) = state.backend.kms().devices.get_mut(&drm_node) { if let Some(device) = data.state.backend.kms().devices.get_mut(&drm_node) {
if let Some(surface) = device.surfaces.get_mut(&crtc) { if let Some(surface) = device.surfaces.get_mut(&crtc) {
match surface.surface.as_mut().map(|x| x.frame_submitted()) { match surface.surface.as_mut().map(|x| x.frame_submitted()) {
Some(Ok(_)) => { Some(Ok(_)) => {
surface.last_submit = metadata.take().map(|data| data.time); surface.last_submit = metadata.take().map(|data| data.time);
surface.pending = false; surface.pending = false;
state data.state
.common .common
.shell .shell
.active_space_mut(&surface.output) .active_space_mut(&surface.output)
.space .space
.send_frames( .send_frames(
state.common.start_time.elapsed().as_millis() as u32 data.state.common.start_time.elapsed().as_millis() as u32
); );
} }
Some(Err(err)) => { Some(Err(err)) => {
@ -367,7 +379,7 @@ impl State {
.register_dispatcher(dispatcher.clone()) .register_dispatcher(dispatcher.clone())
.with_context(|| format!("Failed to add drm device to event loop: {}", dev))?; .with_context(|| format!("Failed to add drm device to event loop: {}", dev))?;
let socket = match self.create_socket(render_node, formats.clone().into_iter()) { let socket = match self.create_socket(dh, render_node, formats.clone().into_iter()) {
Ok(socket) => Some(socket), Ok(socket) => Some(socket),
Err(err) => { Err(err) => {
slog_scope::warn!( slog_scope::warn!(
@ -410,10 +422,10 @@ impl State {
} }
self.backend.kms().devices.insert(drm_node, device); self.backend.kms().devices.insert(drm_node, device);
self.common.output_conf.add_heads(wl_outputs.iter()); self.common.output_configuration_state.add_heads(wl_outputs.iter());
self.common self.common
.output_conf .output_configuration_state
.update(&mut *self.common.display.borrow_mut()); .update();
for output in wl_outputs { for output in wl_outputs {
if let Err(err) = self.backend.kms().apply_config_for_output( if let Err(err) = self.backend.kms().apply_config_for_output(
&output, &output,
@ -425,7 +437,7 @@ impl State {
} }
} }
self.common.config.read_outputs( self.common.config.read_outputs(
self.common.output_conf.outputs(), self.common.output_configuration_state.outputs(),
&mut self.backend, &mut self.backend,
&mut self.common.shell, &mut self.common.shell,
&self.common.event_loop_handle, &self.common.event_loop_handle,
@ -433,7 +445,7 @@ impl State {
self.common.shell.refresh_outputs(); self.common.shell.refresh_outputs();
self.common self.common
.config .config
.write_outputs(self.common.output_conf.outputs()); .write_outputs(self.common.output_configuration_state.outputs());
Ok(()) Ok(())
} }
@ -475,8 +487,8 @@ impl State {
} }
} }
self.common.output_conf.remove_heads(outputs_removed.iter()); self.common.output_configuration_state.remove_heads(outputs_removed.iter());
self.common.output_conf.add_heads(outputs_added.iter()); self.common.output_configuration_state.add_heads(outputs_added.iter());
for output in outputs_added { for output in outputs_added {
if let Err(err) = self.backend.kms().apply_config_for_output( if let Err(err) = self.backend.kms().apply_config_for_output(
&output, &output,
@ -488,10 +500,10 @@ impl State {
} }
} }
self.common self.common
.output_conf .output_configuration_state
.update(&mut self.common.display.borrow_mut()); .update();
self.common.config.read_outputs( self.common.config.read_outputs(
self.common.output_conf.outputs(), self.common.output_configuration_state.outputs(),
&mut self.backend, &mut self.backend,
&mut self.common.shell, &mut self.common.shell,
&self.common.event_loop_handle, &self.common.event_loop_handle,
@ -499,12 +511,12 @@ impl State {
self.common.shell.refresh_outputs(); self.common.shell.refresh_outputs();
self.common self.common
.config .config
.write_outputs(self.common.output_conf.outputs()); .write_outputs(self.common.output_configuration_state.outputs());
Ok(()) Ok(())
} }
fn device_removed(&mut self, dev: dev_t) -> Result<()> { fn device_removed(&mut self, dev: dev_t, dh: &DisplayHandle) -> Result<()> {
let drm_node = DrmNode::from_dev_id(dev)?; let drm_node = DrmNode::from_dev_id(dev)?;
let mut outputs_removed = Vec::new(); let mut outputs_removed = Vec::new();
if let Some(mut device) = self.backend.kms().devices.remove(&drm_node) { if let Some(mut device) = self.backend.kms().devices.remove(&drm_node) {
@ -519,16 +531,18 @@ impl State {
} }
if let Some(socket) = device.socket.take() { if let Some(socket) = device.socket.take() {
self.common.event_loop_handle.remove(socket.token); self.common.event_loop_handle.remove(socket.token);
self.common.dmabuf_state.destroy_global::<State>(dh, socket.dmabuf_global);
dh.remove_global(socket.drm_global);
} }
} }
self.common.output_conf.remove_heads(outputs_removed.iter()); self.common.output_configuration_state.remove_heads(outputs_removed.iter());
self.common self.common
.output_conf .output_configuration_state
.update(&mut *self.common.display.borrow_mut()); .update();
if self.backend.kms().session.is_active() { if self.backend.kms().session.is_active() {
self.common.config.read_outputs( self.common.config.read_outputs(
self.common.output_conf.outputs(), self.common.output_configuration_state.outputs(),
&mut self.backend, &mut self.backend,
&mut self.common.shell, &mut self.common.shell,
&self.common.event_loop_handle, &self.common.event_loop_handle,
@ -536,7 +550,7 @@ impl State {
self.common.shell.refresh_outputs(); self.common.shell.refresh_outputs();
self.common self.common
.config .config
.write_outputs(self.common.output_conf.outputs()); .write_outputs(self.common.output_configuration_state.outputs());
} }
Ok(()) Ok(())
@ -658,7 +672,7 @@ impl Device {
const MAX_CPU_COPIES: usize = 3; const MAX_CPU_COPIES: usize = 3;
fn render_node_for_output(output: &Output, target_node: DrmNode, shell: &Shell) -> DrmNode { fn render_node_for_output(dh: &DisplayHandle, output: &Output, target_node: DrmNode, shell: &Shell) -> DrmNode {
let workspace = shell.active_space(output); let workspace = shell.active_space(output);
let nodes = workspace let nodes = workspace
.get_fullscreen(output) .get_fullscreen(output)
@ -666,13 +680,10 @@ fn render_node_for_output(output: &Output, target_node: DrmNode, shell: &Shell)
.unwrap_or_else(|| workspace.space.windows().collect::<Vec<_>>()) .unwrap_or_else(|| workspace.space.windows().collect::<Vec<_>>())
.into_iter() .into_iter()
.flat_map(|w| { .flat_map(|w| {
w.toplevel() dh.get_client(w.toplevel().wl_surface().id()).ok()?
.get_surface()? .get_data::<ClientState>().unwrap()
.as_ref() .drm_node
.client()? .clone()
.data_map()
.get::<DrmNode>()
.cloned()
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
if nodes.contains(&target_node) || nodes.len() < MAX_CPU_COPIES { if nodes.contains(&target_node) || nodes.len() < MAX_CPU_COPIES {
@ -695,6 +706,7 @@ fn render_node_for_output(output: &Output, target_node: DrmNode, shell: &Shell)
impl Surface { impl Surface {
pub fn render_output( pub fn render_output(
&mut self, &mut self,
dh: &DisplayHandle,
api: &mut GpuManager<EglGlesBackend>, api: &mut GpuManager<EglGlesBackend>,
target_node: &DrmNode, target_node: &DrmNode,
state: &mut Common, state: &mut Common,
@ -707,7 +719,7 @@ impl Surface {
self.surface.as_mut().unwrap().reset_buffers(); self.surface.as_mut().unwrap().reset_buffers();
} }
let render_node = render_node_for_output(&self.output, *target_node, &state.shell); let render_node = render_node_for_output(dh, &self.output, *target_node, &state.shell);
let mut renderer = api.renderer(&render_node, &target_node).unwrap(); let mut renderer = api.renderer(&render_node, &target_node).unwrap();
let surface = self.surface.as_mut().unwrap(); let surface = self.surface.as_mut().unwrap();
@ -753,7 +765,7 @@ impl KmsState {
output: &Output, output: &Output,
shell: &mut Shell, shell: &mut Shell,
test_only: bool, test_only: bool,
loop_handle: &LoopHandle<'_, State>, loop_handle: &LoopHandle<'_, Data>,
) -> Result<(), anyhow::Error> { ) -> Result<(), anyhow::Error> {
let recreated = if let Some(device) = self let recreated = if let Some(device) = self
.devices .devices
@ -848,10 +860,10 @@ impl KmsState {
self.devices.iter().find(|(_, dev)| dev.surfaces.values().any(|s| s.output == *output)).map(|(target, _)| target).copied() self.devices.iter().find(|(_, dev)| dev.surfaces.values().any(|s| s.output == *output)).map(|(target, _)| target).copied()
} }
pub fn try_early_import(&mut self, surface: &WlSurface, output: &Output, target: DrmNode, shell: &Shell) { pub fn try_early_import(&mut self, dh: &DisplayHandle, surface: &WlSurface, output: &Output, target: DrmNode, shell: &Shell) {
let render = render_node_for_output(&output, target, &shell); let render = render_node_for_output(dh, &output, target, &shell);
if let Err(err) = self.api.early_import( if let Err(err) = self.api.early_import(
surface.as_ref().client().and_then(|c| c.data_map().get::<DrmNode>().cloned()), dh.get_client(surface.id()).ok().and_then(|c| c.get_data::<ClientState>().unwrap().drm_node.clone()),
render, render,
surface, surface,
) { ) {
@ -859,9 +871,23 @@ impl KmsState {
} }
} }
pub fn dmabuf_imported(&mut self, _dh: &DisplayHandle, global: &DmabufGlobal, dmabuf: Dmabuf) -> Result<()> {
use smithay::backend::renderer::ImportDma;
for device in self.devices.values() {
if device.socket.as_ref().map(|s| &s.dmabuf_global == global).unwrap_or(false) {
return self.api.renderer::<Gles2Renderbuffer>(&device.render_node, &device.render_node)?
.import_dmabuf(&dmabuf, None)
.map(|_| ())
.map_err(Into::into);
}
}
unreachable!()
}
pub fn schedule_render( pub fn schedule_render(
&mut self, &mut self,
loop_handle: &LoopHandle<'_, State>, loop_handle: &LoopHandle<'_, Data>,
output: &Output, output: &Output,
) -> Result<(), InsertError<Timer>> { ) -> Result<(), InsertError<Timer>> {
if let Some((device, crtc, surface)) = self if let Some((device, crtc, surface)) = self
@ -897,14 +923,15 @@ impl KmsState {
/*} else { /*} else {
Timer::from_deadline(instant.unwrap()) Timer::from_deadline(instant.unwrap())
}*/, }*/,
move |_time, _, state| { move |_time, _, data| {
let backend = state.backend.kms(); let backend = data.state.backend.kms();
if let Some(device) = backend.devices.get_mut(&device) { if let Some(device) = backend.devices.get_mut(&device) {
if let Some(surface) = device.surfaces.get_mut(&crtc) { if let Some(surface) = device.surfaces.get_mut(&crtc) {
if let Err(err) = surface.render_output( if let Err(err) = surface.render_output(
&data.display.handle(),
&mut backend.api, &mut backend.api,
&device.render_node, &device.render_node,
&mut state.common, &mut data.state.common,
) { ) {
slog_scope::error!("Error rendering: {}", err); slog_scope::error!("Error rendering: {}", err);
return TimeoutAction::ToDuration(Duration::from_secs_f64( return TimeoutAction::ToDuration(Duration::from_secs_f64(

View file

@ -1,46 +1,42 @@
// SPDX-License-Identifier: GPL-3.0-only // SPDX-License-Identifier: GPL-3.0-only
use anyhow::{Context, Result}; use anyhow::{anyhow, Context, Result};
use smithay::{ use smithay::{
backend::{ backend::{
allocator::Format, allocator::Format,
drm::DrmNode, drm::{DrmNode, NodeType},
renderer::{gles2::Gles2Renderbuffer, ImportDma},
}, },
reexports::{ reexports::{
calloop::{generic::Generic, Interest, Mode, PostAction, RegistrationToken}, calloop::RegistrationToken,
wayland_protocols::unstable::linux_dmabuf, wayland_server::{Client, DisplayHandle, backend::GlobalId},
wayland_server::Client,
}, },
wayland::dmabuf::init_dmabuf_global_with_filter, wayland::{
}; dmabuf::DmabufGlobal,
socket::ListeningSocketSource,
use std::{
env,
os::unix::{
io::{AsRawFd, IntoRawFd, RawFd},
net::UnixListener,
}, },
path::PathBuf,
}; };
use std::sync::Arc;
use crate::{state::State, utils::GlobalDrop, wayland::init_wl_drm_global}; use crate::{
state::{ClientState, Data},
utils::prelude::*,
};
pub struct Socket { pub struct Socket {
pub token: RegistrationToken, pub token: RegistrationToken,
pub drm_global: GlobalDrop<crate::wayland::wl_drm::WlDrm>, pub drm_global: GlobalId,
pub dmabuf_global: GlobalDrop<linux_dmabuf::v1::server::zwp_linux_dmabuf_v1::ZwpLinuxDmabufV1>, pub dmabuf_global: DmabufGlobal,
} }
impl State { impl State {
pub(super) fn create_socket( pub(super) fn create_socket(
&mut self, &mut self,
dh: &DisplayHandle,
render_node: DrmNode, render_node: DrmNode,
formats: impl Iterator<Item = Format>, formats: impl Iterator<Item = Format>,
) -> Result<Socket> { ) -> Result<Socket> {
let formats = formats.collect::<Vec<_>>(); let formats = formats.collect::<Vec<_>>();
let is_primary = self.backend.kms().primary == render_node; let socket_name = format!(
let socket_path = PathBuf::from(env::var("XDG_RUNTIME_DIR").unwrap()).join(format!(
"{}-{}", "{}-{}",
&self.common.socket.to_string_lossy(), &self.common.socket.to_string_lossy(),
render_node render_node
@ -49,125 +45,63 @@ impl State {
.file_name() .file_name()
.unwrap() .unwrap()
.to_string_lossy() .to_string_lossy()
)); );
// HACK!
let _ = std::fs::remove_file(&socket_path);
let listener = UnixListener::bind(socket_path.clone())
.with_context(|| format!("Failed to bind socket to {}", socket_path.display()))?;
listener.set_nonblocking(true)?;
let listener = WaylandListener(listener);
let token = self
.common
.event_loop_handle
.insert_source(
Generic::new(listener, Interest::READ, Mode::Edge),
move |_, listener, state: &mut State| {
loop {
match listener.0.accept() {
Ok((stream, _)) => {
let display = state.common.display.clone();
let client = unsafe {
display
.borrow_mut()
.create_client(stream.into_raw_fd(), state)
};
client
.data_map()
.insert_if_missing_threadsafe(|| render_node);
}
Err(ref e) if e.kind() == std::io::ErrorKind::WouldBlock => {
// we have exhausted all the pending connections
break;
}
Err(e) => {
// this is a legitimate error
if let Ok(addr) = listener.0.local_addr() {
if let Some(path) = addr.as_pathname() {
slog_scope::error!(
"Error accepting connection on listening socket {} : {}",
path.display(),
e
);
return Err(e);
}
}
slog_scope::error!(
"Error accepting connection on listening socket <unnamed> : {}",
e
);
return Err(e);
}
}
}
Ok(PostAction::Continue)
},
)
.context("Failed to add gpu-wayland socket to the event loop")?;
// initialize globals // initialize globals
let filter = move |client: Client| { let filter = move |client: &Client| {
let dev_id = client.data_map().get::<DrmNode>(); let dev_id = client.get_data::<ClientState>().unwrap().drm_node.unwrap();
if dev_id.is_none() && is_primary { dev_id == render_node
client
.data_map()
.insert_if_missing_threadsafe(|| render_node);
}
dev_id.map(|x| *x == render_node).unwrap_or(is_primary)
}; };
let drm_global = init_wl_drm_global( let dmabuf_global = self.common.dmabuf_state.create_global_with_filter::<State, _, _>(
&mut *self.common.display.borrow_mut(), dh,
render_node.dev_path().unwrap(),
formats.clone(), formats.clone(),
filter.clone(),
);
let dmabuf_global = init_dmabuf_global_with_filter(
&mut *self.common.display.borrow_mut(),
formats,
move |buf, mut ddata| {
let state = ddata.get::<State>().unwrap();
state
.backend
.kms()
.api
.renderer::<Gles2Renderbuffer>(&render_node, &render_node)
.map(|mut renderer| renderer.import_dmabuf(buf, None).is_ok())
.unwrap_or(false)
},
filter, filter,
None, None,
); );
slog_scope::info!( let drm_global_id = self.common.wl_drm_state.create_global_with_filter::<State, _>(
"Adding socket at {} for gpu {}", dh,
socket_path.display(),
render_node render_node
.dev_path_with_type(NodeType::Render)
.or_else(|| render_node.dev_path())
.ok_or(anyhow!("Could not determine path for gpu node: {}", render_node))?,
formats,
&dmabuf_global,
filter,
);
// add a special socket for the gpu
let listener = ListeningSocketSource::with_name(&socket_name, None)
.with_context(|| format!("Failed to bind socket to {}", socket_name))?;
let token = self
.common
.event_loop_handle
.insert_source(
listener,
move |client_stream, _, data: &mut Data| {
if let Err(err) = data
.display
.handle()
.insert_client(client_stream, Arc::new(data.state.new_client_state_with_node(render_node)))
{
slog_scope::warn!("Error adding wayland client ({}): {}", render_node, err);
}
}
)
.context("Failed to add gpu-wayland socket to the event loop")?;
slog_scope::info!(
"Added socket at {} for gpu {}",
socket_name,
render_node,
); );
Ok(Socket { Ok(Socket {
token, token,
drm_global: GlobalDrop::from(drm_global), drm_global: drm_global_id,
dmabuf_global: GlobalDrop::from(dmabuf_global), dmabuf_global,
}) })
} }
} }
struct WaylandListener(UnixListener);
impl AsRawFd for WaylandListener {
fn as_raw_fd(&self) -> RawFd {
self.0.as_raw_fd()
}
}
impl Drop for WaylandListener {
fn drop(&mut self) {
if let Ok(socketaddr) = self.0.local_addr() {
if let Some(path) = socketaddr.as_pathname() {
let _ = ::std::fs::remove_file(path);
}
}
}
}

View file

@ -1,8 +1,11 @@
// SPDX-License-Identifier: GPL-3.0-only // SPDX-License-Identifier: GPL-3.0-only
use crate::state::State; use crate::state::{Data, State};
use anyhow::Result; use anyhow::Result;
use smithay::reexports::calloop::EventLoop; use smithay::reexports::{
calloop::EventLoop,
wayland_server::DisplayHandle,
};
pub mod render; pub mod render;
@ -13,28 +16,29 @@ pub mod x11;
// pub mod wayland; // tbd in smithay // pub mod wayland; // tbd in smithay
pub fn init_backend_auto( pub fn init_backend_auto(
event_loop: &mut EventLoop<'static, State>, dh: &DisplayHandle,
event_loop: &mut EventLoop<'static, Data>,
state: &mut State, state: &mut State,
) -> Result<()> { ) -> Result<()> {
match std::env::var("COSMIC_BACKEND") { match std::env::var("COSMIC_BACKEND") {
Ok(x) if x == "x11" => x11::init_backend(event_loop, state), Ok(x) if x == "x11" => x11::init_backend(dh, event_loop, state),
Ok(x) if x == "winit" => winit::init_backend(event_loop, state), Ok(x) if x == "winit" => winit::init_backend(dh, event_loop, state),
Ok(x) if x == "kms" => kms::init_backend(event_loop, state), Ok(x) if x == "kms" => kms::init_backend(dh, event_loop, state),
Ok(_) => unimplemented!("There is no backend with this identifier"), Ok(_) => unimplemented!("There is no backend with this identifier"),
Err(_) => { Err(_) => {
if std::env::var_os("DISPLAY").is_some() if std::env::var_os("DISPLAY").is_some()
|| std::env::var_os("WAYLAND_DISPLAY").is_some() || std::env::var_os("WAYLAND_DISPLAY").is_some()
{ {
match x11::init_backend(event_loop, state) { match x11::init_backend(dh, event_loop, state) {
Ok(_) => Ok(()), Ok(_) => Ok(()),
Err(err) => { Err(err) => {
slog_scope::warn!("X11 Backend failed with error: {}", err); slog_scope::warn!("X11 Backend failed with error: {}", err);
slog_scope::info!("Falling back to winit backend."); slog_scope::info!("Falling back to winit backend.");
winit::init_backend(event_loop, state) winit::init_backend(dh, event_loop, state)
} }
} }
} else { } else {
kms::init_backend(event_loop, state) kms::init_backend(dh, event_loop, state)
} }
} }
} }

View file

@ -1,11 +1,14 @@
// SPDX-License-Identifier: GPL-3.0-only // SPDX-License-Identifier: GPL-3.0-only
use crate::state::get_dnd_icon; use crate::{
wayland::handlers::data_device::get_dnd_icon,
utils::prelude::*,
};
use smithay::{ use smithay::{
backend::renderer::{Frame, ImportAll, ImportMem, Renderer, Texture}, backend::renderer::{Frame, ImportAll, ImportMem, Renderer, Texture},
desktop::space::{RenderElement, SpaceOutputTuple, SurfaceTree}, desktop::space::{RenderElement, SpaceOutputTuple, SurfaceTree},
reexports::wayland_server::protocol::wl_surface, reexports::wayland_server::protocol::wl_surface,
utils::{Logical, Point, Rectangle, Size, Transform}, utils::{IsAlive, Logical, Physical, Point, Rectangle, Size, Scale, Transform},
wayland::{ wayland::{
compositor::{get_role, with_states}, compositor::{get_role, with_states},
seat::{CursorImageAttributes, CursorImageStatus, Seat}, seat::{CursorImageAttributes, CursorImageStatus, Seat},
@ -125,27 +128,16 @@ pub fn draw_surface_cursor(
where where
{ {
let mut position = location.into(); let mut position = location.into();
let ret = with_states(&surface, |states| { let h = with_states(&surface, |states| {
Some( states
states .data_map
.data_map .get::<Mutex<CursorImageAttributes>>()
.get::<Mutex<CursorImageAttributes>>() .unwrap()
.unwrap() .lock()
.lock() .unwrap()
.unwrap() .hotspot
.hotspot, });
) position -= h;
})
.unwrap_or(None);
position -= match ret {
Some(h) => h,
None => {
slog_scope::warn!(
"Trying to display as a cursor a surface that does not have the CursorImage role."
);
(0, 0).into()
}
};
SurfaceTree { SurfaceTree {
surface, surface,
position, position,
@ -171,7 +163,7 @@ pub fn draw_dnd_icon(
pub struct PointerElement<T: Texture> { pub struct PointerElement<T: Texture> {
texture: T, texture: T,
position: Point<i32, Logical>, position: Point<f64, Logical>,
size: Size<i32, Logical>, size: Size<i32, Logical>,
new_frame: bool, new_frame: bool,
} }
@ -179,7 +171,7 @@ pub struct PointerElement<T: Texture> {
impl<T: Texture> PointerElement<T> { impl<T: Texture> PointerElement<T> {
pub fn new( pub fn new(
texture: T, texture: T,
relative_pointer_pos: Point<i32, Logical>, relative_pointer_pos: Point<f64, Logical>,
new_frame: bool, new_frame: bool,
) -> PointerElement<T> { ) -> PointerElement<T> {
let size = texture.size().to_logical(1, Transform::Normal); let size = texture.size().to_logical(1, Transform::Normal);
@ -201,16 +193,21 @@ where
0 0
} }
fn geometry(&self) -> Rectangle<i32, Logical> { fn location(&self, scale: impl Into<Scale<f64>>) -> Point<f64, Physical> {
Rectangle::from_loc_and_size(self.position, self.size) self.position.to_physical(scale)
}
fn geometry(&self, scale: impl Into<Scale<f64>>) -> Rectangle<i32, Physical> {
Rectangle::from_loc_and_size(self.position, self.size.to_f64()).to_physical(scale).to_i32_round()
} }
fn accumulated_damage( fn accumulated_damage(
&self, &self,
scale: impl Into<Scale<f64>>,
_: Option<SpaceOutputTuple<'_, '_>>, _: Option<SpaceOutputTuple<'_, '_>>,
) -> Vec<Rectangle<i32, Logical>> { ) -> Vec<Rectangle<i32, Physical>> {
if self.new_frame { if self.new_frame {
vec![Rectangle::from_loc_and_size((0, 0), self.size)] vec![Rectangle::from_loc_and_size((0, 0), self.size.to_physical_precise_round(scale))]
} else { } else {
vec![] vec![]
} }
@ -220,21 +217,18 @@ where
&self, &self,
_renderer: &mut R, _renderer: &mut R,
frame: &mut <R as Renderer>::Frame, frame: &mut <R as Renderer>::Frame,
scale: f64, scale: impl Into<Scale<f64>>,
position: Point<i32, Logical>, position: Point<f64, Physical>,
damage: &[Rectangle<i32, Logical>], damage: &[Rectangle<i32, Physical>],
_log: &slog::Logger, _log: &slog::Logger,
) -> Result<(), <R as Renderer>::Error> { ) -> Result<(), <R as Renderer>::Error> {
frame.render_texture_at( frame.render_texture_at(
&self.texture, &self.texture,
position.to_f64().to_physical(scale as f64).to_i32_round(), position.to_i32_round(),
1, 1,
scale as f64, scale,
Transform::Normal, Transform::Normal,
&*damage damage,
.iter()
.map(|rect| rect.to_physical(1).to_f64())
.collect::<Vec<_>>(),
1.0, 1.0,
)?; )?;
Ok(()) Ok(())
@ -259,8 +253,8 @@ impl Default for CursorState {
pub fn draw_cursor<R, I>( pub fn draw_cursor<R, I>(
renderer: &mut R, renderer: &mut R,
seat: &Seat, seat: &Seat<State>,
location: Point<i32, Logical>, location: Point<f64, Logical>,
start_time: &std::time::Instant, start_time: &std::time::Instant,
draw_default: bool, draw_default: bool,
) -> Option<I> ) -> Option<I>
@ -272,8 +266,8 @@ where
// draw the dnd icon if applicable // draw the dnd icon if applicable
{ {
if let Some(wl_surface) = get_dnd_icon(seat) { if let Some(wl_surface) = get_dnd_icon(seat) {
if wl_surface.as_ref().is_alive() { if wl_surface.alive() {
return Some(draw_dnd_icon(wl_surface, location).into()); return Some(draw_dnd_icon(wl_surface, location.to_i32_round()).into());
} }
} }
} }
@ -287,7 +281,7 @@ where
.map(|cell| { .map(|cell| {
let mut cursor_status = cell.borrow_mut(); let mut cursor_status = cell.borrow_mut();
if let CursorImageStatus::Image(ref surface) = *cursor_status { if let CursorImageStatus::Image(ref surface) = *cursor_status {
if !surface.as_ref().is_alive() { if !surface.alive() {
*cursor_status = CursorImageStatus::Default; *cursor_status = CursorImageStatus::Default;
} }
} }
@ -296,7 +290,7 @@ where
.unwrap_or(CursorImageStatus::Default); .unwrap_or(CursorImageStatus::Default);
if let CursorImageStatus::Image(wl_surface) = cursor_status { if let CursorImageStatus::Image(wl_surface) = cursor_status {
Some(draw_surface_cursor(wl_surface.clone(), location).into()) Some(draw_surface_cursor(wl_surface.clone(), location.to_i32_round()).into())
} else if draw_default { } else if draw_default {
let seat_userdata = seat.user_data(); let seat_userdata = seat.user_data();
seat_userdata.insert_if_missing(CursorState::default); seat_userdata.insert_if_missing(CursorState::default);
@ -329,7 +323,7 @@ where
pointer_images.push((frame.clone(), Box::new(texture.clone()))); pointer_images.push((frame.clone(), Box::new(texture.clone())));
texture texture
}); });
let hotspot = Point::<i32, Logical>::from((frame.xhot as i32, frame.yhot as i32)); let hotspot = Point::<i32, Logical>::from((frame.xhot as i32, frame.yhot as i32)).to_f64();
*state.current_image.borrow_mut() = Some(frame); *state.current_image.borrow_mut() = Some(frame);
Some(PointerElement::new(pointer_image.clone(), location - hotspot, new_frame).into()) Some(PointerElement::new(pointer_image.clone(), location - hotspot, new_frame).into())

View file

@ -18,12 +18,12 @@ use smithay::{
}, },
}, },
desktop::{ desktop::{
draw_layer_surface, draw_window, layer_map_for_output, draw_layer_surface, draw_layer_popups, draw_window, draw_window_popups, layer_map_for_output,
space::{RenderElement, RenderError, SpaceOutputTuple, SurfaceTree}, space::{RenderElement, RenderError, SpaceOutputTuple, SurfaceTree},
utils::damage_from_surface_tree, utils::damage_from_surface_tree,
Window, Window,
}, },
utils::{Logical, Point, Rectangle, Transform}, utils::{Physical, Point, Rectangle, Scale, Transform},
wayland::{output::Output, shell::wlr_layer::Layer as WlrLayer}, wayland::{output::Output, shell::wlr_layer::Layer as WlrLayer},
}; };
@ -44,7 +44,7 @@ smithay::custom_elements! {
EguiFrame=EguiFrame, EguiFrame=EguiFrame,
} }
// TODO: due to the lifetime, we cannot be generic over CustomElem's renderer // TODO: due to the lifetime of MultiRenderer, we cannot be generic over CustomElem's renderer
// util after GATs land. So we generate with the macro for Gles2 and then // util after GATs land. So we generate with the macro for Gles2 and then
// do a manual impl for MultiRenderer. // do a manual impl for MultiRenderer.
impl RenderElement<GlMultiRenderer<'_>> for CustomElem { impl RenderElement<GlMultiRenderer<'_>> for CustomElem {
@ -52,24 +52,29 @@ impl RenderElement<GlMultiRenderer<'_>> for CustomElem {
RenderElement::<Gles2Renderer>::id(self) RenderElement::<Gles2Renderer>::id(self)
} }
fn geometry(&self) -> Rectangle<i32, Logical> { fn location(&self, scale: impl Into<Scale<f64>>) -> Point<f64, Physical> {
RenderElement::<Gles2Renderer>::geometry(self) RenderElement::<Gles2Renderer>::location(self, scale)
}
fn geometry(&self, scale: impl Into<Scale<f64>>) -> Rectangle<i32, Physical> {
RenderElement::<Gles2Renderer>::geometry(self, scale)
} }
fn accumulated_damage( fn accumulated_damage(
&self, &self,
scale: impl Into<Scale<f64>>,
for_values: Option<SpaceOutputTuple<'_, '_>>, for_values: Option<SpaceOutputTuple<'_, '_>>,
) -> Vec<Rectangle<i32, Logical>> { ) -> Vec<Rectangle<i32, Physical>> {
RenderElement::<Gles2Renderer>::accumulated_damage(self, for_values) RenderElement::<Gles2Renderer>::accumulated_damage(self, scale, for_values)
} }
fn draw( fn draw(
&self, &self,
renderer: &mut GlMultiRenderer<'_>, renderer: &mut GlMultiRenderer<'_>,
frame: &mut GlMultiFrame, frame: &mut GlMultiFrame,
scale: f64, scale: impl Into<Scale<f64>>,
location: Point<i32, Logical>, location: Point<f64, Physical>,
damage: &[Rectangle<i32, Logical>], damage: &[Rectangle<i32, Physical>],
log: &Logger, log: &Logger,
) -> Result<(), MultiError<EglGlesBackend, EglGlesBackend>> { ) -> Result<(), MultiError<EglGlesBackend, EglGlesBackend>> {
RenderElement::<Gles2Renderer>::draw( RenderElement::<Gles2Renderer>::draw(
@ -130,7 +135,7 @@ pub fn render_output<R>(
output: &Output, output: &Output,
hardware_cursor: bool, hardware_cursor: bool,
#[cfg(feature = "debug")] fps: &mut Fps, #[cfg(feature = "debug")] fps: &mut Fps,
) -> Result<Option<Vec<Rectangle<i32, Logical>>>, RenderError<R>> ) -> Result<Option<Vec<Rectangle<i32, Physical>>>, RenderError<R>>
where where
R: Renderer + ImportAll + AsGles2Renderer, R: Renderer + ImportAll + AsGles2Renderer,
<R as Renderer>::TextureId: Clone + 'static, <R as Renderer>::TextureId: Clone + 'static,
@ -140,7 +145,6 @@ where
{ {
fps.start(); fps.start();
} }
let workspace = state.shell.active_space(output); let workspace = state.shell.active_space(output);
let maybe_fullscreen_window = workspace.get_fullscreen(output).cloned(); let maybe_fullscreen_window = workspace.get_fullscreen(output).cloned();
let res = if let Some(window) = maybe_fullscreen_window { let res = if let Some(window) = maybe_fullscreen_window {
@ -179,7 +183,7 @@ fn render_desktop<R>(
output: &Output, output: &Output,
hardware_cursor: bool, hardware_cursor: bool,
#[cfg(feature = "debug")] fps: &mut Fps, #[cfg(feature = "debug")] fps: &mut Fps,
) -> Result<Option<Vec<Rectangle<i32, Logical>>>, RenderError<R>> ) -> Result<Option<Vec<Rectangle<i32, Physical>>>, RenderError<R>>
where where
R: Renderer + ImportAll + AsGles2Renderer, R: Renderer + ImportAll + AsGles2Renderer,
<R as Renderer>::TextureId: Clone + 'static, <R as Renderer>::TextureId: Clone + 'static,
@ -246,7 +250,7 @@ fn render_fullscreen<R>(
output: &Output, output: &Output,
hardware_cursor: bool, hardware_cursor: bool,
#[cfg(feature = "debug")] fps: &mut Fps, #[cfg(feature = "debug")] fps: &mut Fps,
) -> Result<Option<Vec<Rectangle<i32, Logical>>>, RenderError<R>> ) -> Result<Option<Vec<Rectangle<i32, Physical>>>, RenderError<R>>
where where
R: Renderer + ImportAll + AsGles2Renderer, R: Renderer + ImportAll + AsGles2Renderer,
<R as Renderer>::TextureId: Clone + 'static, <R as Renderer>::TextureId: Clone + 'static,
@ -293,20 +297,32 @@ where
renderer renderer
.render(mode.size, transform, |renderer, frame| { .render(mode.size, transform, |renderer, frame| {
let mut damage = window.accumulated_damage(None); let mut damage = window.accumulated_damage((0.0, 0.0), scale, None);
frame.clear( frame.clear(
CLEAR_COLOR, CLEAR_COLOR,
&[Rectangle::from_loc_and_size((0, 0), mode.size).to_f64()], &[Rectangle::from_loc_and_size((0, 0), mode.size)],
)?; )?;
draw_window( draw_window(
renderer, renderer,
frame, frame,
&window, &window,
scale, scale,
(0, 0), (0.0, 0.0),
&[Rectangle::from_loc_and_size( &[Rectangle::from_loc_and_size(
(0, 0), (0, 0),
mode.size.to_f64().to_logical(scale).to_i32_round(), mode.size,
)],
&slog_scope::logger(),
)?;
draw_window_popups(
renderer,
frame,
&window,
scale,
(0.0, 0.0),
&[Rectangle::from_loc_and_size(
(0, 0),
mode.size,
)], )],
&slog_scope::logger(), &slog_scope::logger(),
)?; )?;
@ -318,22 +334,30 @@ where
frame, frame,
layer_surface, layer_surface,
scale, scale,
geo.loc, geo.loc.to_f64().to_physical(scale),
&[Rectangle::from_loc_and_size((0, 0), geo.size)], &[Rectangle::from_loc_and_size((0, 0), geo.size.to_physical_precise_round(scale))],
&slog_scope::logger(), &slog_scope::logger(),
)?; )?;
if let Some(surface) = layer_surface.get_surface() { draw_layer_popups(
damage.extend(damage_from_surface_tree(surface, geo.loc, None)); renderer,
} frame,
layer_surface,
scale,
geo.loc.to_f64().to_physical(scale),
&[Rectangle::from_loc_and_size((0, 0), geo.size.to_physical_precise_round(scale))],
&slog_scope::logger(),
)?;
damage.extend(damage_from_surface_tree(layer_surface.wl_surface(), geo.loc.to_f64().to_physical(scale), scale, None));
} }
for elem in custom_elements { for elem in custom_elements {
let geo = elem.geometry(); let loc = elem.location(scale);
let elem_damage = elem.accumulated_damage(None); let geo = elem.geometry(scale);
let elem_damage = elem.accumulated_damage(scale, None);
elem.draw( elem.draw(
renderer, renderer,
frame, frame,
scale, scale,
geo.loc, loc,
&[Rectangle::from_loc_and_size((0, 0), geo.size)], &[Rectangle::from_loc_and_size((0, 0), geo.size)],
&slog_scope::logger(), &slog_scope::logger(),
)?; )?;

View file

@ -3,10 +3,11 @@
use crate::{ use crate::{
backend::render, backend::render,
config::OutputConfig, config::OutputConfig,
input::{set_active_output, Devices}, input::Devices,
state::{BackendData, Common, State}, state::{BackendData, Common, Data},
utils::prelude::*,
}; };
use anyhow::{Context, Result}; use anyhow::{anyhow, Context, Result};
use smithay::{ use smithay::{
backend::{ backend::{
renderer::{ImportDma, ImportEgl}, renderer::{ImportDma, ImportEgl},
@ -17,23 +18,19 @@ use smithay::{
calloop::{ping, EventLoop}, calloop::{ping, EventLoop},
wayland_server::{ wayland_server::{
protocol::wl_output::{Subpixel, Transform}, protocol::wl_output::{Subpixel, Transform},
Display, DisplayHandle,
}, },
}, },
wayland::{ wayland::output::{Mode, Output, PhysicalProperties},
dmabuf::init_dmabuf_global,
output::{Mode, Output, PhysicalProperties},
},
}; };
use std::{cell::RefCell, rc::Rc}; use std::cell::RefCell;
#[cfg(feature = "debug")] #[cfg(feature = "debug")]
use crate::state::Fps; use crate::state::Fps;
pub struct WinitState { pub struct WinitState {
// The winit backend currently has no notion of multiple windows // The winit backend currently has no notion of multiple windows
backend: Rc<RefCell<WinitGraphicsBackend>>, pub backend: WinitGraphicsBackend,
//_global: GlobalDrop<WlOutput>,
output: Output, output: Output,
age_reset: u8, age_reset: u8,
#[cfg(feature = "debug")] #[cfg(feature = "debug")]
@ -46,18 +43,17 @@ impl WinitState {
self.reset_buffers(); self.reset_buffers();
} }
let backend = &mut *self.backend.borrow_mut(); self.backend.bind().with_context(|| "Failed to bind buffer")?;
backend.bind().with_context(|| "Failed to bind buffer")?;
let age = if self.age_reset > 0 { let age = if self.age_reset > 0 {
self.age_reset -= 1; self.age_reset -= 1;
0 0
} else { } else {
backend.buffer_age().unwrap_or(0) self.backend.buffer_age().unwrap_or(0)
}; };
match render::render_output( match render::render_output(
None, None,
backend.renderer(), self.backend.renderer(),
age as u8, age as u8,
state, state,
&self.output, &self.output,
@ -71,8 +67,8 @@ impl WinitState {
.active_space_mut(&self.output) .active_space_mut(&self.output)
.space .space
.send_frames(state.start_time.elapsed().as_millis() as u32); .send_frames(state.start_time.elapsed().as_millis() as u32);
backend self.backend
.submit(damage.as_ref().map(|x| &**x), 1.0) .submit(damage.as_ref().map(|x| &**x))
.with_context(|| "Failed to submit buffer for display")?; .with_context(|| "Failed to submit buffer for display")?;
} }
Err(err) => { Err(err) => {
@ -90,7 +86,7 @@ impl WinitState {
) -> Result<(), anyhow::Error> { ) -> Result<(), anyhow::Error> {
// TODO: if we ever have multiple winit outputs, don't ignore config.enabled // TODO: if we ever have multiple winit outputs, don't ignore config.enabled
// reset size // reset size
let size = self.backend.borrow().window_size(); let size = self.backend.window_size();
let mut config = output let mut config = output
.user_data() .user_data()
.get::<RefCell<OutputConfig>>() .get::<RefCell<OutputConfig>>()
@ -114,15 +110,14 @@ impl WinitState {
} }
} }
pub fn init_backend(event_loop: &mut EventLoop<State>, state: &mut State) -> Result<()> { pub fn init_backend(dh: &DisplayHandle, event_loop: &mut EventLoop<Data>, state: &mut State) -> Result<()> {
let (backend, mut input) = let (mut backend, mut input) =
winit::init(None).with_context(|| "Failed to initilize winit backend")?; winit::init(None).map_err(|_| anyhow!("Failed to initilize winit backend"))?;
let backend = Rc::new(RefCell::new(backend));
init_egl_client_side(&mut *state.common.display.borrow_mut(), backend.clone())?; init_egl_client_side(dh, state, &mut backend)?;
let name = format!("WINIT-0"); let name = format!("WINIT-0");
let size = backend.borrow().window_size(); let size = backend.window_size();
let props = PhysicalProperties { let props = PhysicalProperties {
size: (0, 0).into(), size: (0, 0).into(),
subpixel: Subpixel::Unknown, subpixel: Subpixel::Unknown,
@ -134,7 +129,7 @@ pub fn init_backend(event_loop: &mut EventLoop<State>, state: &mut State) -> Res
refresh: 60_000, refresh: 60_000,
}; };
let output = Output::new(name, props, None); let output = Output::new(name, props, None);
//let _global = global.into(); let _global = output.create_global::<State>(dh);
output.change_current_state( output.change_current_state(
Some(mode), Some(mode),
Some(Transform::Flipped180), Some(Transform::Flipped180),
@ -162,8 +157,10 @@ pub fn init_backend(event_loop: &mut EventLoop<State>, state: &mut State) -> Res
let mut token = Some( let mut token = Some(
event_loop event_loop
.handle() .handle()
.insert_source(render_source, move |_, _, state| { .insert_source(render_source, move |_, _, data| {
if let Err(err) = state.backend.winit().render_output(&mut state.common) { if let Err(err) = data.state.backend.winit().render_output(
&mut data.state.common
) {
slog_scope::error!("Failed to render frame: {}", err); slog_scope::error!("Failed to render frame: {}", err);
render_ping.ping(); render_ping.ping();
} }
@ -173,17 +170,21 @@ pub fn init_backend(event_loop: &mut EventLoop<State>, state: &mut State) -> Res
let event_loop_handle = event_loop.handle(); let event_loop_handle = event_loop.handle();
event_loop event_loop
.handle() .handle()
.insert_source(event_source, move |_, _, state| { .insert_source(event_source, move |_, _, data| {
match input match input
.dispatch_new_events(|event| state.process_winit_event(event, &render_ping_handle)) .dispatch_new_events(|event| data.state.process_winit_event(
&data.display.handle(),
event,
&render_ping_handle
))
{ {
Ok(_) => { Ok(_) => {
event_ping_handle.ping(); event_ping_handle.ping();
render_ping_handle.ping(); render_ping_handle.ping();
} }
Err(winit::WinitError::WindowClosed) => { Err(winit::WinitError::WindowClosed) => {
let output = state.backend.winit().output.clone(); let output = data.state.backend.winit().output.clone();
state.common.shell.remove_output(&output); data.state.common.shell.remove_output(&output);
if let Some(token) = token.take() { if let Some(token) = token.take() {
event_loop_handle.remove(token); event_loop_handle.remove(token);
} }
@ -200,11 +201,11 @@ pub fn init_backend(event_loop: &mut EventLoop<State>, state: &mut State) -> Res
fps: Fps::default(), fps: Fps::default(),
age_reset: 0, age_reset: 0,
}); });
state.common.output_conf.add_heads(std::iter::once(&output)); state.common.output_configuration_state.add_heads(std::iter::once(&output));
state state
.common .common
.output_conf .output_configuration_state
.update(&mut *state.common.display.borrow_mut()); .update();
state.common.shell.add_output(&output); state.common.shell.add_output(&output);
state.common.config.read_outputs( state.common.config.read_outputs(
std::iter::once(&output), std::iter::once(&output),
@ -219,29 +220,22 @@ pub fn init_backend(event_loop: &mut EventLoop<State>, state: &mut State) -> Res
} }
fn init_egl_client_side( fn init_egl_client_side(
display: &mut Display, dh: &DisplayHandle,
renderer: Rc<RefCell<WinitGraphicsBackend>>, state: &mut State,
renderer: &mut WinitGraphicsBackend,
) -> Result<()> { ) -> Result<()> {
let bind_result = renderer.borrow_mut().renderer().bind_wl_display(display); let bind_result = renderer.renderer().bind_wl_display(dh);
match bind_result { match bind_result {
Ok(_) => { Ok(_) => {
slog_scope::info!("EGL hardware-acceleration enabled"); slog_scope::info!("EGL hardware-acceleration enabled");
let dmabuf_formats = renderer let dmabuf_formats = renderer
.borrow_mut()
.renderer() .renderer()
.dmabuf_formats() .dmabuf_formats()
.cloned() .cloned()
.collect::<Vec<_>>(); .collect::<Vec<_>>();
init_dmabuf_global( state.common.dmabuf_state.create_global::<State, _>(
display, dh,
dmabuf_formats, dmabuf_formats,
move |buffer, _| {
renderer
.borrow_mut()
.renderer()
.import_dmabuf(buffer, None)
.is_ok()
},
None, None,
); );
} }
@ -252,7 +246,7 @@ fn init_egl_client_side(
} }
impl State { impl State {
pub fn process_winit_event(&mut self, event: WinitEvent, render_ping: &ping::Ping) { pub fn process_winit_event(&mut self, dh: &DisplayHandle, event: WinitEvent, render_ping: &ping::Ping) {
// here we can handle special cases for winit inputs // here we can handle special cases for winit inputs
match event { match event {
WinitEvent::Focus(true) => { WinitEvent::Focus(true) => {
@ -283,15 +277,15 @@ impl State {
output.delete_mode(output.current_mode().unwrap()); output.delete_mode(output.current_mode().unwrap());
output.set_preferred(mode); output.set_preferred(mode);
output.change_current_state(Some(mode), None, None, None); output.change_current_state(Some(mode), None, None, None);
layer_map_for_output(output).arrange(); layer_map_for_output(output).arrange(dh);
self.common self.common
.output_conf .output_configuration_state
.update(&mut *self.common.display.borrow_mut()); .update();
self.common.shell.refresh_outputs(); self.common.shell.refresh_outputs();
render_ping.ping(); render_ping.ping();
} }
WinitEvent::Refresh => render_ping.ping(), WinitEvent::Refresh => render_ping.ping(),
WinitEvent::Input(event) => self.process_input_event(event), WinitEvent::Input(event) => self.process_input_event(dh, event),
_ => {} _ => {}
}; };
} }

View file

@ -3,8 +3,9 @@
use crate::{ use crate::{
backend::render, backend::render,
config::OutputConfig, config::OutputConfig,
input::{set_active_output, Devices}, input::Devices,
state::{BackendData, Common, State}, state::{BackendData, Common, Data},
utils::prelude::*,
}; };
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use smithay::{ use smithay::{
@ -19,16 +20,12 @@ use smithay::{
reexports::{ reexports::{
calloop::{ping, EventLoop, LoopHandle}, calloop::{ping, EventLoop, LoopHandle},
gbm::{Device as GbmDevice, FdWrapper}, gbm::{Device as GbmDevice, FdWrapper},
wayland_server::{protocol::wl_output::Subpixel, Display}, wayland_server::{protocol::wl_output::Subpixel, DisplayHandle},
},
wayland::{
dmabuf::init_dmabuf_global,
output::{Mode, Output, PhysicalProperties},
}, },
wayland::output::{Mode, Output, PhysicalProperties},
}; };
use std::{ use std::{
cell::RefCell, cell::RefCell,
rc::Rc,
sync::{Arc, Mutex}, sync::{Arc, Mutex},
}; };
@ -38,13 +35,13 @@ use crate::state::Fps;
pub struct X11State { pub struct X11State {
allocator: Arc<Mutex<GbmDevice<FdWrapper>>>, allocator: Arc<Mutex<GbmDevice<FdWrapper>>>,
_egl: EGLDisplay, _egl: EGLDisplay,
renderer: Rc<RefCell<Gles2Renderer>>, pub renderer: Gles2Renderer,
surfaces: Vec<Surface>, surfaces: Vec<Surface>,
handle: X11Handle, handle: X11Handle,
} }
impl X11State { impl X11State {
pub fn add_window(&mut self, handle: LoopHandle<'_, State>) -> Result<Output> { pub fn add_window(&mut self, handle: LoopHandle<'_, Data>) -> Result<Output> {
let window = WindowBuilder::new() let window = WindowBuilder::new()
.title("COSMIC") .title("COSMIC")
.build(&self.handle) .build(&self.handle)
@ -55,7 +52,7 @@ impl X11State {
.create_surface( .create_surface(
&window, &window,
self.allocator.clone(), self.allocator.clone(),
Bind::<Dmabuf>::supported_formats(&*self.renderer.borrow()) Bind::<Dmabuf>::supported_formats(&self.renderer)
.unwrap() .unwrap()
.iter() .iter()
.filter(|format| format.code == fourcc) .filter(|format| format.code == fourcc)
@ -89,15 +86,15 @@ impl X11State {
let (ping, source) = let (ping, source) =
ping::make_ping().with_context(|| "Failed to create output event loop source")?; ping::make_ping().with_context(|| "Failed to create output event loop source")?;
let _token = handle let _token = handle
.insert_source(source, move |_, _, state| { .insert_source(source, move |_, _, data| {
let x11_state = state.backend.x11(); let x11_state = data.state.backend.x11();
if let Some(surface) = x11_state if let Some(surface) = x11_state
.surfaces .surfaces
.iter_mut() .iter_mut()
.find(|s| s.output == output_ref) .find(|s| s.output == output_ref)
{ {
if let Err(err) = surface if let Err(err) = surface
.render_output(&mut *x11_state.renderer.borrow_mut(), &mut state.common) .render_output(&mut x11_state.renderer, &mut data.state.common)
{ {
slog_scope::error!("Error rendering: {}", err); slog_scope::error!("Error rendering: {}", err);
} }
@ -221,7 +218,7 @@ impl Surface {
} }
} }
pub fn init_backend(event_loop: &mut EventLoop<State>, state: &mut State) -> Result<()> { pub fn init_backend(dh: &DisplayHandle, event_loop: &mut EventLoop<Data>, state: &mut State) -> Result<()> {
let backend = X11Backend::new(None).with_context(|| "Failed to initilize X11 backend")?; let backend = X11Backend::new(None).with_context(|| "Failed to initilize X11 backend")?;
let handle = backend.handle(); let handle = backend.handle();
@ -238,12 +235,10 @@ pub fn init_backend(event_loop: &mut EventLoop<State>, state: &mut State) -> Res
// 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
let renderer = Rc::new(RefCell::new( let mut renderer = unsafe { Gles2Renderer::new(context, None) }
unsafe { Gles2Renderer::new(context, None) } .with_context(|| "Failed to initialize renderer")?;
.with_context(|| "Failed to initialize renderer")?,
));
init_egl_client_side(&mut *state.common.display.borrow_mut(), renderer.clone())?; init_egl_client_side(dh, state, &mut renderer)?;
state.backend = BackendData::X11(X11State { state.backend = BackendData::X11(X11State {
handle, handle,
@ -258,11 +253,11 @@ pub fn init_backend(event_loop: &mut EventLoop<State>, state: &mut State) -> Res
.x11() .x11()
.add_window(event_loop.handle()) .add_window(event_loop.handle())
.with_context(|| "Failed to create wl_output")?; .with_context(|| "Failed to create wl_output")?;
state.common.output_conf.add_heads(std::iter::once(&output)); state.common.output_configuration_state.add_heads(std::iter::once(&output));
state state
.common .common
.output_conf .output_configuration_state
.update(&mut *state.common.display.borrow_mut()); .update();
state.common.shell.add_output(&output); state.common.shell.add_output(&output);
state.common.config.read_outputs( state.common.config.read_outputs(
std::iter::once(&output), std::iter::once(&output),
@ -275,11 +270,12 @@ pub fn init_backend(event_loop: &mut EventLoop<State>, state: &mut State) -> Res
event_loop event_loop
.handle() .handle()
.insert_source(backend, |event, _, state| match event { .insert_source(backend, |event, _, data| match event {
X11Event::CloseRequested { window_id } => { X11Event::CloseRequested { window_id } => {
// TODO: drain_filter // TODO: drain_filter
let mut outputs_removed = Vec::new(); let mut outputs_removed = Vec::new();
for surface in state for surface in data
.state
.backend .backend
.x11() .x11()
.surfaces .surfaces
@ -289,13 +285,13 @@ pub fn init_backend(event_loop: &mut EventLoop<State>, state: &mut State) -> Res
surface.window.unmap(); surface.window.unmap();
outputs_removed.push(surface.output.clone()); outputs_removed.push(surface.output.clone());
} }
state data.state
.backend .backend
.x11() .x11()
.surfaces .surfaces
.retain(|s| s.window.id() != window_id); .retain(|s| s.window.id() != window_id);
for output in outputs_removed.into_iter() { for output in outputs_removed.into_iter() {
state.common.shell.remove_output(&output); data.state.common.shell.remove_output(&output);
} }
} }
X11Event::Resized { X11Event::Resized {
@ -307,7 +303,7 @@ pub fn init_backend(event_loop: &mut EventLoop<State>, state: &mut State) -> Res
size, size,
refresh: 60_000, refresh: 60_000,
}; };
if let Some(surface) = state if let Some(surface) = data.state
.backend .backend
.x11() .x11()
.surfaces .surfaces
@ -327,12 +323,12 @@ pub fn init_backend(event_loop: &mut EventLoop<State>, state: &mut State) -> Res
output.delete_mode(output.current_mode().unwrap()); output.delete_mode(output.current_mode().unwrap());
output.change_current_state(Some(mode), None, None, None); output.change_current_state(Some(mode), None, None, None);
output.set_preferred(mode); output.set_preferred(mode);
layer_map_for_output(output).arrange(); layer_map_for_output(output).arrange(&data.display.handle());
state data.state
.common .common
.output_conf .output_configuration_state
.update(&mut *state.common.display.borrow_mut()); .update();
state.common.shell.refresh_outputs(); data.state.common.shell.refresh_outputs();
surface.dirty = true; surface.dirty = true;
if !surface.pending { if !surface.pending {
surface.render.ping(); surface.render.ping();
@ -340,7 +336,8 @@ pub fn init_backend(event_loop: &mut EventLoop<State>, state: &mut State) -> Res
} }
} }
X11Event::Refresh { window_id } | X11Event::PresentCompleted { window_id } => { X11Event::Refresh { window_id } | X11Event::PresentCompleted { window_id } => {
if let Some(surface) = state if let Some(surface) = data
.state
.backend .backend
.x11() .x11()
.surfaces .surfaces
@ -354,27 +351,25 @@ pub fn init_backend(event_loop: &mut EventLoop<State>, state: &mut State) -> Res
} }
} }
} }
X11Event::Input(event) => state.process_x11_event(event), X11Event::Input(event) => data.state.process_x11_event(&data.display.handle(), event),
}) })
.map_err(|_| anyhow::anyhow!("Failed to insert X11 Backend into event loop"))?; .map_err(|_| anyhow::anyhow!("Failed to insert X11 Backend into event loop"))?;
Ok(()) Ok(())
} }
fn init_egl_client_side(display: &mut Display, renderer: Rc<RefCell<Gles2Renderer>>) -> Result<()> { fn init_egl_client_side(dh: &DisplayHandle, state: &mut State, renderer: &mut Gles2Renderer) -> Result<()> {
let bind_result = renderer.borrow_mut().bind_wl_display(display); let bind_result = renderer.bind_wl_display(dh);
match bind_result { match bind_result {
Ok(_) => { Ok(_) => {
slog_scope::info!("EGL hardware-acceleration enabled"); slog_scope::info!("EGL hardware-acceleration enabled");
let dmabuf_formats = renderer let dmabuf_formats = renderer
.borrow()
.dmabuf_formats() .dmabuf_formats()
.cloned() .cloned()
.collect::<Vec<_>>(); .collect::<Vec<_>>();
init_dmabuf_global( state.common.dmabuf_state.create_global::<State, _>(
display, dh,
dmabuf_formats, dmabuf_formats,
move |buffer, _| renderer.borrow_mut().import_dmabuf(buffer, None).is_ok(),
None, None,
); );
} }
@ -385,7 +380,7 @@ fn init_egl_client_side(display: &mut Display, renderer: Rc<RefCell<Gles2Rendere
} }
impl State { impl State {
pub fn process_x11_event(&mut self, event: InputEvent<X11Input>) { pub fn process_x11_event(&mut self, dh: &DisplayHandle, event: InputEvent<X11Input>) {
// here we can handle special cases for x11 inputs, like mapping them to windows // here we can handle special cases for x11 inputs, like mapping them to windows
match &event { match &event {
InputEvent::PointerMotionAbsolute { event } => { InputEvent::PointerMotionAbsolute { event } => {
@ -412,7 +407,7 @@ impl State {
_ => {} _ => {}
}; };
self.process_input_event(event); self.process_input_event(dh, event);
// TODO actually figure out the output // TODO actually figure out the output
for output in self.common.shell.outputs() { for output in self.common.shell.outputs() {
self.backend self.backend