chore: Cleanup
This commit is contained in:
parent
800e01a484
commit
92f3dbce01
16 changed files with 329 additions and 277 deletions
|
|
@ -253,7 +253,7 @@ impl State {
|
||||||
self.backend.kms().drm_devices.insert(drm_node, device);
|
self.backend.kms().drm_devices.insert(drm_node, device);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.backend.kms().refresh_used_devices();
|
self.backend.kms().refresh_used_devices()?;
|
||||||
|
|
||||||
self.common
|
self.common
|
||||||
.output_configuration_state
|
.output_configuration_state
|
||||||
|
|
@ -345,7 +345,7 @@ impl State {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.backend.kms().refresh_used_devices();
|
self.backend.kms().refresh_used_devices()?;
|
||||||
|
|
||||||
self.common
|
self.common
|
||||||
.output_configuration_state
|
.output_configuration_state
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,10 @@
|
||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
use crate::{
|
use crate::{config::OutputState, shell::Shell, state::BackendData, utils::prelude::*};
|
||||||
config::OutputState, shell::Shell, state::BackendData, utils::prelude::*,
|
|
||||||
wayland::handlers::output,
|
|
||||||
};
|
|
||||||
|
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
use calloop::LoopSignal;
|
use calloop::LoopSignal;
|
||||||
use render::gles::GbmGlowBackend;
|
use render::gles::GbmGlowBackend;
|
||||||
use smallvec::SmallVec;
|
|
||||||
use smithay::{
|
use smithay::{
|
||||||
backend::{
|
backend::{
|
||||||
allocator::{
|
allocator::{
|
||||||
|
|
@ -87,10 +83,9 @@ pub fn init_backend(
|
||||||
.context("Failed to initialize udev connection")?;
|
.context("Failed to initialize udev connection")?;
|
||||||
|
|
||||||
// handle session events
|
// handle session events
|
||||||
let handle = event_loop.handle();
|
|
||||||
let loop_signal = event_loop.get_signal();
|
let loop_signal = event_loop.get_signal();
|
||||||
let dispatcher = udev_dispatcher.clone();
|
let dispatcher = udev_dispatcher.clone();
|
||||||
let session_event_source = event_loop
|
event_loop
|
||||||
.handle()
|
.handle()
|
||||||
.insert_source(notifier, move |event, &mut (), state| match event {
|
.insert_source(notifier, move |event, &mut (), state| match event {
|
||||||
SessionEvent::ActivateSession => {
|
SessionEvent::ActivateSession => {
|
||||||
|
|
@ -226,7 +221,8 @@ fn init_udev(
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let udev_event_source = evlh.register_dispatcher(dispatcher.clone()).unwrap();
|
evlh.register_dispatcher(dispatcher.clone())
|
||||||
|
.context("Failed to register udev event source")?;
|
||||||
|
|
||||||
Ok(dispatcher)
|
Ok(dispatcher)
|
||||||
}
|
}
|
||||||
|
|
@ -622,8 +618,9 @@ impl KmsState {
|
||||||
)?);
|
)?);
|
||||||
}
|
}
|
||||||
std::mem::drop(output_config);
|
std::mem::drop(output_config);
|
||||||
surface.set_mode(*mode);
|
surface
|
||||||
// TODO: .context("Failed to apply new mode")?;
|
.set_mode(*mode)
|
||||||
|
.context("Failed to apply new mode")?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ use crate::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
|
use calloop::channel::Channel;
|
||||||
use smithay::{
|
use smithay::{
|
||||||
backend::{
|
backend::{
|
||||||
allocator::{
|
allocator::{
|
||||||
|
|
@ -80,7 +81,6 @@ use std::{
|
||||||
mpsc::{Receiver, SyncSender},
|
mpsc::{Receiver, SyncSender},
|
||||||
Arc, Condvar, Mutex, RwLock,
|
Arc, Condvar, Mutex, RwLock,
|
||||||
},
|
},
|
||||||
thread::JoinHandle,
|
|
||||||
time::Duration,
|
time::Duration,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -110,7 +110,6 @@ pub struct Surface {
|
||||||
|
|
||||||
loop_handle: LoopHandle<'static, State>,
|
loop_handle: LoopHandle<'static, State>,
|
||||||
thread_command: Sender<ThreadCommand>,
|
thread_command: Sender<ThreadCommand>,
|
||||||
thread_handle: JoinHandle<()>,
|
|
||||||
thread_token: RegistrationToken,
|
thread_token: RegistrationToken,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -234,8 +233,7 @@ pub enum ThreadCommand {
|
||||||
UpdateMirroring(Option<Output>),
|
UpdateMirroring(Option<Output>),
|
||||||
VBlank(Option<DrmEventMetadata>),
|
VBlank(Option<DrmEventMetadata>),
|
||||||
ScheduleRender,
|
ScheduleRender,
|
||||||
// TODO: Error handling
|
SetMode(Mode, SyncSender<Result<()>>),
|
||||||
SetMode(Mode),
|
|
||||||
End,
|
End,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -262,220 +260,29 @@ impl Surface {
|
||||||
let (tx, rx) = channel::<ThreadCommand>();
|
let (tx, rx) = channel::<ThreadCommand>();
|
||||||
let (tx2, rx2) = channel::<SurfaceCommand>();
|
let (tx2, rx2) = channel::<SurfaceCommand>();
|
||||||
let active = Arc::new(AtomicBool::new(false));
|
let active = Arc::new(AtomicBool::new(false));
|
||||||
let active_clone = active.clone();
|
|
||||||
|
|
||||||
|
let active_clone = active.clone();
|
||||||
let frame_callback_seq_clone = frame_callback_seq.clone();
|
let frame_callback_seq_clone = frame_callback_seq.clone();
|
||||||
let output_clone = output.clone();
|
let output_clone = output.clone();
|
||||||
let thread_handle = std::thread::spawn(move || {
|
|
||||||
profiling::register_thread!(format!("Surface Thread {}", output.name()));
|
|
||||||
|
|
||||||
let mut event_loop = EventLoop::try_new().unwrap();
|
std::thread::Builder::new()
|
||||||
|
.name(format!("surface-{}", output.name()))
|
||||||
let api = GpuManager::new(GbmGlowBackend::<DrmDeviceFd>::default())
|
.spawn(move || {
|
||||||
.expect("Failed to initialize rendering");
|
if let Err(err) = surface_thread(
|
||||||
/*
|
output_clone,
|
||||||
let software_api = GpuManager::new(GbmPixmanBackend::<DrmDeviceFd>::with_allocator_flags(
|
primary_node,
|
||||||
gbm_flags,
|
target_node,
|
||||||
))
|
shell,
|
||||||
.context("Failed to initialize software rendering");
|
active_clone,
|
||||||
*/
|
frame_callback_seq_clone,
|
||||||
|
tx2,
|
||||||
#[cfg(feature = "debug")]
|
rx,
|
||||||
let egui = {
|
startup_done,
|
||||||
let state = smithay_egui::EguiState::new(
|
) {
|
||||||
smithay::utils::Rectangle::from_loc_and_size((0, 0), (400, 800)),
|
error!("Surface thread crashed: {}", err);
|
||||||
);
|
}
|
||||||
let mut visuals: egui::style::Visuals = Default::default();
|
})
|
||||||
visuals.window_shadow.extrusion = 0.0;
|
.context("Failed to spawn surface thread")?;
|
||||||
state.context().set_visuals(visuals);
|
|
||||||
state
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut state = SurfaceThreadState {
|
|
||||||
api,
|
|
||||||
primary_node,
|
|
||||||
target_node,
|
|
||||||
active: active_clone,
|
|
||||||
compositor: None,
|
|
||||||
|
|
||||||
state: QueueState::Idle,
|
|
||||||
timings: Timings::new(None, false),
|
|
||||||
frame_callback_seq: frame_callback_seq_clone,
|
|
||||||
thread_sender: tx2,
|
|
||||||
|
|
||||||
output: output_clone,
|
|
||||||
mirroring: None,
|
|
||||||
mirroring_textures: HashMap::new(),
|
|
||||||
|
|
||||||
shell,
|
|
||||||
loop_handle: event_loop.handle(),
|
|
||||||
clock: Clock::new(),
|
|
||||||
#[cfg(feature = "debug")]
|
|
||||||
egui,
|
|
||||||
};
|
|
||||||
|
|
||||||
let signal = event_loop.get_signal();
|
|
||||||
event_loop
|
|
||||||
.handle()
|
|
||||||
.insert_source(rx, move |command, _, state| match command {
|
|
||||||
Event::Msg(ThreadCommand::Suspend) => {
|
|
||||||
state.active.store(false, Ordering::SeqCst);
|
|
||||||
let _ = state.compositor.take();
|
|
||||||
|
|
||||||
match std::mem::replace(&mut state.state, QueueState::Idle) {
|
|
||||||
QueueState::Idle => {}
|
|
||||||
QueueState::Queued(token)
|
|
||||||
| QueueState::WaitingForEstimatedVBlank(token) => {
|
|
||||||
state.loop_handle.remove(token);
|
|
||||||
}
|
|
||||||
QueueState::WaitingForVBlank { .. } => {
|
|
||||||
state.timings.discard_current_frame()
|
|
||||||
}
|
|
||||||
QueueState::WaitingForEstimatedVBlankAndQueued {
|
|
||||||
estimated_vblank,
|
|
||||||
queued_render,
|
|
||||||
} => {
|
|
||||||
state.loop_handle.remove(estimated_vblank);
|
|
||||||
state.loop_handle.remove(queued_render);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
Event::Msg(ThreadCommand::Resume {
|
|
||||||
surface,
|
|
||||||
gbm,
|
|
||||||
cursor_size,
|
|
||||||
vrr,
|
|
||||||
result,
|
|
||||||
}) => {
|
|
||||||
let driver = surface.get_driver().ok();
|
|
||||||
let mut planes = surface.planes().clone();
|
|
||||||
|
|
||||||
// QUIRK: Using an overlay plane on a nvidia card breaks the display controller (wtf...)
|
|
||||||
if driver.is_some_and(|driver| {
|
|
||||||
driver
|
|
||||||
.name()
|
|
||||||
.to_string_lossy()
|
|
||||||
.to_lowercase()
|
|
||||||
.contains("nvidia")
|
|
||||||
}) {
|
|
||||||
planes.overlay = vec![];
|
|
||||||
}
|
|
||||||
|
|
||||||
let render_formats = state
|
|
||||||
.api
|
|
||||||
.single_renderer(&state.target_node)
|
|
||||||
.unwrap()
|
|
||||||
.dmabuf_formats()
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
state
|
|
||||||
.timings
|
|
||||||
.set_refresh_interval(Some(Duration::from_nanos(
|
|
||||||
drm_helpers::calculate_refresh_rate(surface.pending_mode()) as u64,
|
|
||||||
)));
|
|
||||||
state.timings.set_vrr(vrr);
|
|
||||||
|
|
||||||
match DrmCompositor::new(
|
|
||||||
&state.output,
|
|
||||||
surface,
|
|
||||||
Some(planes),
|
|
||||||
GbmAllocator::new(
|
|
||||||
gbm.clone(),
|
|
||||||
GbmBufferFlags::RENDERING | GbmBufferFlags::SCANOUT,
|
|
||||||
),
|
|
||||||
gbm.clone(),
|
|
||||||
&[
|
|
||||||
Fourcc::Abgr2101010,
|
|
||||||
Fourcc::Argb2101010,
|
|
||||||
Fourcc::Abgr8888,
|
|
||||||
Fourcc::Argb8888,
|
|
||||||
],
|
|
||||||
render_formats,
|
|
||||||
cursor_size,
|
|
||||||
Some(gbm),
|
|
||||||
) {
|
|
||||||
Ok(compositor) => {
|
|
||||||
state.active.store(true, Ordering::SeqCst);
|
|
||||||
state.compositor = Some(compositor);
|
|
||||||
let _ = result.send(Ok(()));
|
|
||||||
}
|
|
||||||
Err(err) => {
|
|
||||||
state.active.store(false, Ordering::SeqCst);
|
|
||||||
let _ = result.send(Err(err.into()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Event::Msg(ThreadCommand::NodeAdded { node, gbm, egl }) => {
|
|
||||||
//if let Some(egl) = egl {
|
|
||||||
let mut renderer =
|
|
||||||
unsafe { GlowRenderer::new(egl) }.expect("Failed to create renderer");
|
|
||||||
init_shaders(renderer.borrow_mut());
|
|
||||||
|
|
||||||
state.api.as_mut().add_node(node, gbm, renderer);
|
|
||||||
/*
|
|
||||||
} else {
|
|
||||||
state.software_api.as_mut().add_node(node, gbm);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
#[cfg(feature = "debug")]
|
|
||||||
{
|
|
||||||
let renderer = state.api.single_renderer(node);
|
|
||||||
state
|
|
||||||
.egui
|
|
||||||
.load_svg(renderer, String::from("intel"), INTEL_LOGO)
|
|
||||||
.unwrap();
|
|
||||||
state
|
|
||||||
.egui
|
|
||||||
.load_svg(renderer, String::from("amd"), AMD_LOGO)
|
|
||||||
.unwrap();
|
|
||||||
state
|
|
||||||
.egui
|
|
||||||
.load_svg(renderer, String::from("nvidia"), NVIDIA_LOGO)
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Event::Msg(ThreadCommand::NodeRemoved { node }) => {
|
|
||||||
state.api.as_mut().remove_node(&node);
|
|
||||||
//state.software_api.as_mut().remove_node(node);
|
|
||||||
}
|
|
||||||
Event::Msg(ThreadCommand::VBlank(metadata)) => {
|
|
||||||
state.on_vblank(metadata);
|
|
||||||
}
|
|
||||||
Event::Msg(ThreadCommand::ScheduleRender) => {
|
|
||||||
{
|
|
||||||
// Wait for start up.
|
|
||||||
let (lock, cvar) = &*startup_done;
|
|
||||||
// As long as the value inside the `Mutex<bool>` is `false`, we wait.
|
|
||||||
let _guard = cvar
|
|
||||||
.wait_while(lock.lock().unwrap(), |startup_done| !*startup_done)
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
state.queue_redraw(false);
|
|
||||||
}
|
|
||||||
Event::Msg(ThreadCommand::UpdateMirroring(mirroring)) => {
|
|
||||||
state.mirroring = mirroring;
|
|
||||||
state.mirroring_textures.clear();
|
|
||||||
}
|
|
||||||
Event::Msg(ThreadCommand::SetMode(mode)) => {
|
|
||||||
if let Some(compositor) = state.compositor.as_mut() {
|
|
||||||
compositor.use_mode(mode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Event::Closed | Event::Msg(ThreadCommand::End) => {
|
|
||||||
signal.stop();
|
|
||||||
signal.wakeup();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
if let Err(err) = event_loop.run(None, &mut state, |_| {
|
|
||||||
// TODO: if queued, but token invalid, schedule redraw timer again
|
|
||||||
}) {
|
|
||||||
error!("Surface thread crashed: {}", err);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let output_clone = output.clone();
|
let output_clone = output.clone();
|
||||||
let thread_token = evlh
|
let thread_token = evlh
|
||||||
|
|
@ -540,46 +347,54 @@ impl Surface {
|
||||||
plane_formats: HashSet::new(),
|
plane_formats: HashSet::new(),
|
||||||
loop_handle: evlh.clone(),
|
loop_handle: evlh.clone(),
|
||||||
thread_command: tx,
|
thread_command: tx,
|
||||||
thread_handle,
|
|
||||||
thread_token,
|
thread_token,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_node(&mut self, node: DrmNode, gbm: GbmAllocator<DrmDeviceFd>, egl: EGLContext) {
|
|
||||||
self.known_nodes.insert(node);
|
|
||||||
self.thread_command
|
|
||||||
.send(ThreadCommand::NodeAdded { node, gbm, egl });
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn remove_node(&mut self, node: DrmNode) {
|
|
||||||
self.known_nodes.remove(&node);
|
|
||||||
self.thread_command
|
|
||||||
.send(ThreadCommand::NodeRemoved { node });
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn known_nodes(&self) -> &HashSet<DrmNode> {
|
pub fn known_nodes(&self) -> &HashSet<DrmNode> {
|
||||||
&self.known_nodes
|
&self.known_nodes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_active(&self) -> bool {
|
||||||
|
self.active.load(Ordering::SeqCst)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_node(&mut self, node: DrmNode, gbm: GbmAllocator<DrmDeviceFd>, egl: EGLContext) {
|
||||||
|
self.known_nodes.insert(node);
|
||||||
|
let _ = self
|
||||||
|
.thread_command
|
||||||
|
.send(ThreadCommand::NodeAdded { node, gbm, egl });
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn remove_node(&mut self, node: DrmNode) {
|
||||||
|
self.known_nodes.remove(&node);
|
||||||
|
let _ = self
|
||||||
|
.thread_command
|
||||||
|
.send(ThreadCommand::NodeRemoved { node });
|
||||||
|
}
|
||||||
|
|
||||||
pub fn on_vblank(&self, metadata: Option<DrmEventMetadata>) {
|
pub fn on_vblank(&self, metadata: Option<DrmEventMetadata>) {
|
||||||
self.thread_command.send(ThreadCommand::VBlank(metadata));
|
let _ = self.thread_command.send(ThreadCommand::VBlank(metadata));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn schedule_render(&self) {
|
pub fn schedule_render(&self) {
|
||||||
self.thread_command.send(ThreadCommand::ScheduleRender);
|
let _ = self.thread_command.send(ThreadCommand::ScheduleRender);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_mirroring(&mut self, output: Option<Output>) {
|
pub fn set_mirroring(&mut self, output: Option<Output>) {
|
||||||
self.thread_command
|
let _ = self
|
||||||
|
.thread_command
|
||||||
.send(ThreadCommand::UpdateMirroring(output));
|
.send(ThreadCommand::UpdateMirroring(output));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_mode(&mut self, mode: Mode) {
|
pub fn set_mode(&mut self, mode: Mode) -> Result<()> {
|
||||||
self.thread_command.send(ThreadCommand::SetMode(mode));
|
let (tx, rx) = std::sync::mpsc::sync_channel(1);
|
||||||
|
let _ = self.thread_command.send(ThreadCommand::SetMode(mode, tx));
|
||||||
|
rx.recv().context("Surface thread died")?
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn suspend(&mut self) {
|
pub fn suspend(&mut self) {
|
||||||
self.thread_command.send(ThreadCommand::Suspend);
|
let _ = self.thread_command.send(ThreadCommand::Suspend);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn resume(
|
pub fn resume(
|
||||||
|
|
@ -615,10 +430,6 @@ impl Surface {
|
||||||
|
|
||||||
rx.recv().context("Surface thread died")?
|
rx.recv().context("Surface thread died")?
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_active(&self) -> bool {
|
|
||||||
self.active.load(Ordering::SeqCst)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for Surface {
|
impl Drop for Surface {
|
||||||
|
|
@ -628,7 +439,246 @@ impl Drop for Surface {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn surface_thread(
|
||||||
|
output: Output,
|
||||||
|
primary_node: DrmNode,
|
||||||
|
target_node: DrmNode,
|
||||||
|
shell: Arc<RwLock<Shell>>,
|
||||||
|
active: Arc<AtomicBool>,
|
||||||
|
frame_callback_seq: Arc<AtomicUsize>,
|
||||||
|
thread_sender: Sender<SurfaceCommand>,
|
||||||
|
thread_receiver: Channel<ThreadCommand>,
|
||||||
|
startup_done: Arc<(Mutex<bool>, Condvar)>,
|
||||||
|
) -> Result<()> {
|
||||||
|
profiling::register_thread!(format!("Surface Thread {}", output.name()));
|
||||||
|
|
||||||
|
let mut event_loop = EventLoop::try_new().unwrap();
|
||||||
|
|
||||||
|
let api = GpuManager::new(GbmGlowBackend::<DrmDeviceFd>::default())
|
||||||
|
.context("Failed to initialize rendering api")?;
|
||||||
|
/*
|
||||||
|
let software_api = GpuManager::new(GbmPixmanBackend::<DrmDeviceFd>::with_allocator_flags(
|
||||||
|
gbm_flags,
|
||||||
|
))
|
||||||
|
.context("Failed to initialize software rendering");
|
||||||
|
*/
|
||||||
|
|
||||||
|
#[cfg(feature = "debug")]
|
||||||
|
let egui = {
|
||||||
|
let state = smithay_egui::EguiState::new(smithay::utils::Rectangle::from_loc_and_size(
|
||||||
|
(0, 0),
|
||||||
|
(400, 800),
|
||||||
|
));
|
||||||
|
let mut visuals: egui::style::Visuals = Default::default();
|
||||||
|
visuals.window_shadow.extrusion = 0.0;
|
||||||
|
state.context().set_visuals(visuals);
|
||||||
|
state
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut state = SurfaceThreadState {
|
||||||
|
api,
|
||||||
|
primary_node,
|
||||||
|
target_node,
|
||||||
|
active,
|
||||||
|
compositor: None,
|
||||||
|
|
||||||
|
state: QueueState::Idle,
|
||||||
|
timings: Timings::new(None, false),
|
||||||
|
frame_callback_seq,
|
||||||
|
thread_sender,
|
||||||
|
|
||||||
|
output,
|
||||||
|
mirroring: None,
|
||||||
|
mirroring_textures: HashMap::new(),
|
||||||
|
|
||||||
|
shell,
|
||||||
|
loop_handle: event_loop.handle(),
|
||||||
|
clock: Clock::new(),
|
||||||
|
#[cfg(feature = "debug")]
|
||||||
|
egui,
|
||||||
|
};
|
||||||
|
|
||||||
|
let signal = event_loop.get_signal();
|
||||||
|
event_loop
|
||||||
|
.handle()
|
||||||
|
.insert_source(thread_receiver, move |command, _, state| match command {
|
||||||
|
Event::Msg(ThreadCommand::Suspend) => state.suspend(),
|
||||||
|
Event::Msg(ThreadCommand::Resume {
|
||||||
|
surface,
|
||||||
|
gbm,
|
||||||
|
cursor_size,
|
||||||
|
vrr,
|
||||||
|
result,
|
||||||
|
}) => {
|
||||||
|
let _ = result.send(state.resume(surface, gbm, cursor_size, vrr));
|
||||||
|
}
|
||||||
|
Event::Msg(ThreadCommand::NodeAdded { node, gbm, egl }) => {
|
||||||
|
if let Err(err) = state.node_added(node, gbm, egl) {
|
||||||
|
warn!(?err, ?node, "Failed to add node to surface-thread");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Event::Msg(ThreadCommand::NodeRemoved { node }) => {
|
||||||
|
state.node_removed(node);
|
||||||
|
}
|
||||||
|
Event::Msg(ThreadCommand::VBlank(metadata)) => {
|
||||||
|
state.on_vblank(metadata);
|
||||||
|
}
|
||||||
|
Event::Msg(ThreadCommand::ScheduleRender) => {
|
||||||
|
{
|
||||||
|
// Wait for start up.
|
||||||
|
let (lock, cvar) = &*startup_done;
|
||||||
|
// As long as the value inside the `Mutex<bool>` is `false`, we wait.
|
||||||
|
let _guard = cvar
|
||||||
|
.wait_while(lock.lock().unwrap(), |startup_done| !*startup_done)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
state.queue_redraw(false);
|
||||||
|
}
|
||||||
|
Event::Msg(ThreadCommand::UpdateMirroring(mirroring_output)) => {
|
||||||
|
state.update_mirroring(mirroring_output);
|
||||||
|
}
|
||||||
|
Event::Msg(ThreadCommand::SetMode(mode, result)) => {
|
||||||
|
if let Some(compositor) = state.compositor.as_mut() {
|
||||||
|
let _ = result.send(compositor.use_mode(mode).map_err(Into::into));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Event::Closed | Event::Msg(ThreadCommand::End) => {
|
||||||
|
signal.stop();
|
||||||
|
signal.wakeup();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.map_err(|insert_error| insert_error.error)
|
||||||
|
.context("Failed to listen for events")?;
|
||||||
|
|
||||||
|
event_loop.run(None, &mut state, |_| {}).map_err(Into::into)
|
||||||
|
}
|
||||||
|
|
||||||
impl SurfaceThreadState {
|
impl SurfaceThreadState {
|
||||||
|
fn suspend(&mut self) {
|
||||||
|
self.active.store(false, Ordering::SeqCst);
|
||||||
|
let _ = self.compositor.take();
|
||||||
|
|
||||||
|
match std::mem::replace(&mut self.state, QueueState::Idle) {
|
||||||
|
QueueState::Idle => {}
|
||||||
|
QueueState::Queued(token) | QueueState::WaitingForEstimatedVBlank(token) => {
|
||||||
|
self.loop_handle.remove(token);
|
||||||
|
}
|
||||||
|
QueueState::WaitingForVBlank { .. } => self.timings.discard_current_frame(),
|
||||||
|
QueueState::WaitingForEstimatedVBlankAndQueued {
|
||||||
|
estimated_vblank,
|
||||||
|
queued_render,
|
||||||
|
} => {
|
||||||
|
self.loop_handle.remove(estimated_vblank);
|
||||||
|
self.loop_handle.remove(queued_render);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resume(
|
||||||
|
&mut self,
|
||||||
|
surface: DrmSurface,
|
||||||
|
gbm: GbmDevice<DrmDeviceFd>,
|
||||||
|
cursor_size: Size<u32, BufferCoords>,
|
||||||
|
vrr: bool,
|
||||||
|
) -> Result<()> {
|
||||||
|
let driver = surface.get_driver().ok();
|
||||||
|
let mut planes = surface.planes().clone();
|
||||||
|
|
||||||
|
// QUIRK: Using an overlay plane on a nvidia card breaks the display controller (wtf...)
|
||||||
|
if driver.is_some_and(|driver| {
|
||||||
|
driver
|
||||||
|
.name()
|
||||||
|
.to_string_lossy()
|
||||||
|
.to_lowercase()
|
||||||
|
.contains("nvidia")
|
||||||
|
}) {
|
||||||
|
planes.overlay = vec![];
|
||||||
|
}
|
||||||
|
|
||||||
|
let render_formats = self
|
||||||
|
.api
|
||||||
|
.single_renderer(&self.target_node)
|
||||||
|
.unwrap()
|
||||||
|
.dmabuf_formats()
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
self.timings.set_refresh_interval(Some(Duration::from_nanos(
|
||||||
|
drm_helpers::calculate_refresh_rate(surface.pending_mode()) as u64,
|
||||||
|
)));
|
||||||
|
self.timings.set_vrr(vrr);
|
||||||
|
|
||||||
|
match DrmCompositor::new(
|
||||||
|
&self.output,
|
||||||
|
surface,
|
||||||
|
Some(planes),
|
||||||
|
GbmAllocator::new(
|
||||||
|
gbm.clone(),
|
||||||
|
GbmBufferFlags::RENDERING | GbmBufferFlags::SCANOUT,
|
||||||
|
),
|
||||||
|
gbm.clone(),
|
||||||
|
&[
|
||||||
|
Fourcc::Abgr2101010,
|
||||||
|
Fourcc::Argb2101010,
|
||||||
|
Fourcc::Abgr8888,
|
||||||
|
Fourcc::Argb8888,
|
||||||
|
],
|
||||||
|
render_formats,
|
||||||
|
cursor_size,
|
||||||
|
Some(gbm),
|
||||||
|
) {
|
||||||
|
Ok(compositor) => {
|
||||||
|
self.active.store(true, Ordering::SeqCst);
|
||||||
|
self.compositor = Some(compositor);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
self.active.store(false, Ordering::SeqCst);
|
||||||
|
Err(err.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn node_added(
|
||||||
|
&mut self,
|
||||||
|
node: DrmNode,
|
||||||
|
gbm: GbmAllocator<DrmDeviceFd>,
|
||||||
|
egl: EGLContext,
|
||||||
|
) -> Result<()> {
|
||||||
|
//if let Some(egl) = egl {
|
||||||
|
let mut renderer =
|
||||||
|
unsafe { GlowRenderer::new(egl) }.context("Failed to create renderer")?;
|
||||||
|
init_shaders(renderer.borrow_mut()).context("Failed to initialize shaders")?;
|
||||||
|
|
||||||
|
self.api.as_mut().add_node(node, gbm, renderer);
|
||||||
|
/*
|
||||||
|
} else {
|
||||||
|
self.software_api.as_mut().add_node(node, gbm);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
#[cfg(feature = "debug")]
|
||||||
|
{
|
||||||
|
let renderer = self.api.single_renderer(node);
|
||||||
|
self.egui
|
||||||
|
.load_svg(renderer, String::from("intel"), INTEL_LOGO)
|
||||||
|
.unwrap();
|
||||||
|
self.egui
|
||||||
|
.load_svg(renderer, String::from("amd"), AMD_LOGO)
|
||||||
|
.unwrap();
|
||||||
|
self.egui
|
||||||
|
.load_svg(renderer, String::from("nvidia"), NVIDIA_LOGO)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn node_removed(&mut self, node: DrmNode) {
|
||||||
|
self.api.as_mut().remove_node(&node);
|
||||||
|
//self.software_api.as_mut().remove_node(node);
|
||||||
|
}
|
||||||
|
|
||||||
fn on_vblank(&mut self, metadata: Option<DrmEventMetadata>) {
|
fn on_vblank(&mut self, metadata: Option<DrmEventMetadata>) {
|
||||||
let Some(compositor) = self.compositor.as_mut() else {
|
let Some(compositor) = self.compositor.as_mut() else {
|
||||||
return;
|
return;
|
||||||
|
|
@ -1254,14 +1304,20 @@ impl SurfaceThreadState {
|
||||||
self.state = QueueState::WaitingForEstimatedVBlank(token);
|
self.state = QueueState::WaitingForEstimatedVBlank(token);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn update_mirroring(&mut self, mirroring_output: Option<Output>) {
|
||||||
|
self.mirroring = mirroring_output;
|
||||||
|
self.mirroring_textures.clear();
|
||||||
|
}
|
||||||
|
|
||||||
fn send_frame_callbacks(&mut self) {
|
fn send_frame_callbacks(&mut self) {
|
||||||
if self.mirroring.is_none() {
|
if self.mirroring.is_none() {
|
||||||
self.thread_sender.send(SurfaceCommand::SendFrames);
|
let _ = self.thread_sender.send(SurfaceCommand::SendFrames);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_dmabuf_feedback(&mut self, states: RenderElementStates) {
|
fn send_dmabuf_feedback(&mut self, states: RenderElementStates) {
|
||||||
self.thread_sender
|
let _ = self
|
||||||
|
.thread_sender
|
||||||
.send(SurfaceCommand::RenderStates(states));
|
.send(SurfaceCommand::RenderStates(states));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -146,9 +146,7 @@ fn main() -> Result<()> {
|
||||||
let shell = state.common.shell.read().unwrap();
|
let shell = state.common.shell.read().unwrap();
|
||||||
if shell.animations_going() {
|
if shell.animations_going() {
|
||||||
for output in shell.outputs().cloned().collect::<Vec<_>>().into_iter() {
|
for output in shell.outputs().cloned().collect::<Vec<_>>().into_iter() {
|
||||||
state
|
state.backend.schedule_render(&output);
|
||||||
.backend
|
|
||||||
.schedule_render(&state.common.event_loop_handle, &output);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,6 @@ use smithay::{
|
||||||
};
|
};
|
||||||
use std::{
|
use std::{
|
||||||
borrow::Cow,
|
borrow::Cow,
|
||||||
cell::RefCell,
|
|
||||||
fmt,
|
fmt,
|
||||||
hash::Hash,
|
hash::Hash,
|
||||||
sync::{
|
sync::{
|
||||||
|
|
|
||||||
|
|
@ -649,7 +649,7 @@ impl Workspaces {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(set) = self.sets.remove(output) {
|
if let Some(set) = self.sets.shift_remove(output) {
|
||||||
{
|
{
|
||||||
let map = layer_map_for_output(output);
|
let map = layer_map_for_output(output);
|
||||||
for surface in map.layers() {
|
for surface in map.layers() {
|
||||||
|
|
|
||||||
|
|
@ -98,11 +98,11 @@ use time::UtcOffset;
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
cell::RefCell,
|
cell::RefCell,
|
||||||
collections::{HashSet, VecDeque},
|
collections::HashSet,
|
||||||
ffi::OsString,
|
ffi::OsString,
|
||||||
process::Child,
|
process::Child,
|
||||||
sync::{Arc, Condvar, Mutex, Once, RwLock},
|
sync::{Arc, Condvar, Mutex, Once, RwLock},
|
||||||
time::{Duration, Instant},
|
time::Duration,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(RustEmbed)]
|
#[derive(RustEmbed)]
|
||||||
|
|
@ -326,13 +326,13 @@ impl BackendData {
|
||||||
|
|
||||||
layer_map_for_output(&output).arrange();
|
layer_map_for_output(&output).arrange();
|
||||||
|
|
||||||
self.schedule_render(loop_handle, &output);
|
self.schedule_render(&output);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn schedule_render(&mut self, loop_handle: &LoopHandle<'_, State>, output: &Output) {
|
pub fn schedule_render(&mut self, output: &Output) {
|
||||||
match self {
|
match self {
|
||||||
BackendData::Winit(_) => {} // We cannot do this on the winit backend.
|
BackendData::Winit(_) => {} // We cannot do this on the winit backend.
|
||||||
// Winit has a very strict render-loop and skipping frames breaks atleast the wayland winit-backend.
|
// Winit has a very strict render-loop and skipping frames breaks atleast the wayland winit-backend.
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ use smithay::{
|
||||||
reexports::wayland_server::{protocol::wl_buffer::WlBuffer, Resource},
|
reexports::wayland_server::{protocol::wl_buffer::WlBuffer, Resource},
|
||||||
wayland::buffer::BufferHandler,
|
wayland::buffer::BufferHandler,
|
||||||
};
|
};
|
||||||
|
use tracing::warn;
|
||||||
|
|
||||||
impl BufferHandler for State {
|
impl BufferHandler for State {
|
||||||
fn buffer_destroyed(&mut self, buffer: &WlBuffer) {
|
fn buffer_destroyed(&mut self, buffer: &WlBuffer) {
|
||||||
|
|
@ -12,7 +13,9 @@ impl BufferHandler for State {
|
||||||
for device in kms_state.drm_devices.values_mut() {
|
for device in kms_state.drm_devices.values_mut() {
|
||||||
if device.active_buffers.remove(&buffer.downgrade()) {
|
if device.active_buffers.remove(&buffer.downgrade()) {
|
||||||
if !device.in_use(kms_state.primary_node.as_ref()) {
|
if !device.in_use(kms_state.primary_node.as_ref()) {
|
||||||
kms_state.refresh_used_devices();
|
if let Err(err) = kms_state.refresh_used_devices() {
|
||||||
|
warn!(?err, "Failed to init devices.");
|
||||||
|
};
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -148,8 +148,7 @@ impl CompositorHandler for State {
|
||||||
|
|
||||||
// schedule a new render
|
// schedule a new render
|
||||||
if let Some(output) = shell.visible_output_for_surface(surface) {
|
if let Some(output) = shell.visible_output_for_surface(surface) {
|
||||||
self.backend
|
self.backend.schedule_render(&output);
|
||||||
.schedule_render(&self.common.event_loop_handle, &output);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if mapped {
|
if mapped {
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ use smithay::{
|
||||||
reexports::wayland_server::Resource,
|
reexports::wayland_server::Resource,
|
||||||
wayland::dmabuf::{DmabufGlobal, DmabufHandler, DmabufState, ImportNotifier},
|
wayland::dmabuf::{DmabufGlobal, DmabufHandler, DmabufState, ImportNotifier},
|
||||||
};
|
};
|
||||||
|
use tracing::warn;
|
||||||
|
|
||||||
impl DmabufHandler for State {
|
impl DmabufHandler for State {
|
||||||
fn dmabuf_state(&mut self) -> &mut DmabufState {
|
fn dmabuf_state(&mut self) -> &mut DmabufState {
|
||||||
|
|
@ -41,7 +42,9 @@ impl DmabufHandler for State {
|
||||||
{
|
{
|
||||||
device.active_buffers.insert(buffer.downgrade());
|
device.active_buffers.insert(buffer.downgrade());
|
||||||
}
|
}
|
||||||
kms_state.refresh_used_devices();
|
if let Err(err) = kms_state.refresh_used_devices() {
|
||||||
|
warn!(?err, "Failed to init devices.");
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(None) => {
|
Ok(None) => {
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ use smithay::{
|
||||||
reexports::wayland_server::{protocol::wl_buffer::WlBuffer, Resource},
|
reexports::wayland_server::{protocol::wl_buffer::WlBuffer, Resource},
|
||||||
wayland::dmabuf::DmabufGlobal,
|
wayland::dmabuf::DmabufGlobal,
|
||||||
};
|
};
|
||||||
|
use tracing::warn;
|
||||||
|
|
||||||
impl DrmHandler<Option<DrmNode>> for State {
|
impl DrmHandler<Option<DrmNode>> for State {
|
||||||
fn dmabuf_imported(
|
fn dmabuf_imported(
|
||||||
|
|
@ -33,7 +34,9 @@ impl DrmHandler<Option<DrmNode>> for State {
|
||||||
device.active_buffers.insert(buffer.downgrade());
|
device.active_buffers.insert(buffer.downgrade());
|
||||||
}
|
}
|
||||||
|
|
||||||
kms_state.refresh_used_devices();
|
if let Err(err) = kms_state.refresh_used_devices() {
|
||||||
|
warn!(?err, "Failed to init devices.");
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -71,8 +71,7 @@ impl WlrLayerShellHandler for State {
|
||||||
|
|
||||||
shell.workspaces.recalculate();
|
shell.workspaces.recalculate();
|
||||||
|
|
||||||
self.backend
|
self.backend.schedule_render(&output);
|
||||||
.schedule_render(&self.common.event_loop_handle, &output);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -260,8 +260,7 @@ impl ScreencopyHandler for State {
|
||||||
};
|
};
|
||||||
|
|
||||||
output.add_frame(session, frame);
|
output.add_frame(session, frame);
|
||||||
self.backend
|
self.backend.schedule_render(&output);
|
||||||
.schedule_render(&self.common.event_loop_handle, &output);
|
|
||||||
}
|
}
|
||||||
ImageSourceData::Workspace(handle) => {
|
ImageSourceData::Workspace(handle) => {
|
||||||
render_workspace_to_buffer(self, session, frame, handle)
|
render_workspace_to_buffer(self, session, frame, handle)
|
||||||
|
|
|
||||||
|
|
@ -40,8 +40,7 @@ impl SessionLockHandler for State {
|
||||||
});
|
});
|
||||||
|
|
||||||
for output in shell.outputs() {
|
for output in shell.outputs() {
|
||||||
self.backend
|
self.backend.schedule_render(&output);
|
||||||
.schedule_render(&self.common.event_loop_handle, &output);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -50,8 +49,7 @@ impl SessionLockHandler for State {
|
||||||
shell.session_lock = None;
|
shell.session_lock = None;
|
||||||
|
|
||||||
for output in shell.outputs() {
|
for output in shell.outputs() {
|
||||||
self.backend
|
self.backend.schedule_render(&output);
|
||||||
.schedule_render(&self.common.event_loop_handle, &output);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -399,8 +399,7 @@ impl XdgShellHandler for State {
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(output) = output.as_ref() {
|
if let Some(output) = output.as_ref() {
|
||||||
self.backend
|
self.backend.schedule_render(&output);
|
||||||
.schedule_render(&self.common.event_loop_handle, &output);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -351,8 +351,7 @@ impl XwmHandler for State {
|
||||||
}
|
}
|
||||||
|
|
||||||
for output in outputs.into_iter() {
|
for output in outputs.into_iter() {
|
||||||
self.backend
|
self.backend.schedule_render(&output);
|
||||||
.schedule_render(&self.common.event_loop_handle, &output);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue