backend: Adopt to new wayland-display handling
This commit is contained in:
parent
b126dfaf77
commit
270f06182e
7 changed files with 351 additions and 379 deletions
|
|
@ -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(
|
||||||
|
|
|
||||||
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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())
|
||||||
|
|
|
||||||
|
|
@ -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(),
|
||||||
)?;
|
)?;
|
||||||
|
|
|
||||||
|
|
@ -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),
|
||||||
_ => {}
|
_ => {}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue