kms: Use new DrmOutput api
This commit is contained in:
parent
e356e3c589
commit
8b87d6524e
10 changed files with 347 additions and 217 deletions
|
|
@ -1,28 +1,40 @@
|
||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
backend::render::{output_elements, CursorMode, GlMultiRenderer, CLEAR_COLOR},
|
||||||
config::{AdaptiveSync, OutputConfig, OutputState},
|
config::{AdaptiveSync, OutputConfig, OutputState},
|
||||||
shell::Shell,
|
shell::Shell,
|
||||||
utils::prelude::*,
|
utils::prelude::*,
|
||||||
|
wayland::protocols::screencopy::Frame as ScreencopyFrame,
|
||||||
};
|
};
|
||||||
|
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
use libc::dev_t;
|
use libc::dev_t;
|
||||||
use smithay::{
|
use smithay::{
|
||||||
backend::{
|
backend::{
|
||||||
allocator::gbm::GbmDevice,
|
allocator::{
|
||||||
drm::{DrmDevice, DrmDeviceFd, DrmEvent, DrmNode},
|
gbm::{GbmAllocator, GbmDevice},
|
||||||
|
Fourcc,
|
||||||
|
},
|
||||||
|
drm::{
|
||||||
|
compositor::FrameFlags, output::DrmOutputManager, DrmDevice, DrmDeviceFd, DrmEvent,
|
||||||
|
DrmNode,
|
||||||
|
},
|
||||||
egl::{context::ContextPriority, EGLContext, EGLDevice, EGLDisplay},
|
egl::{context::ContextPriority, EGLContext, EGLDevice, EGLDisplay},
|
||||||
session::Session,
|
session::Session,
|
||||||
},
|
},
|
||||||
|
desktop::utils::OutputPresentationFeedback,
|
||||||
output::{Mode as OutputMode, Output, PhysicalProperties, Scale, Subpixel},
|
output::{Mode as OutputMode, Output, PhysicalProperties, Scale, Subpixel},
|
||||||
reexports::{
|
reexports::{
|
||||||
calloop::{LoopHandle, RegistrationToken},
|
calloop::{LoopHandle, RegistrationToken},
|
||||||
drm::control::{connector, crtc, Device as ControlDevice, ModeTypeFlags},
|
drm::control::{connector, crtc, Device as ControlDevice, ModeTypeFlags},
|
||||||
|
gbm::BufferObjectFlags as GbmBufferFlags,
|
||||||
rustix::fs::OFlags,
|
rustix::fs::OFlags,
|
||||||
wayland_server::{protocol::wl_buffer::WlBuffer, DisplayHandle, Weak},
|
wayland_server::{protocol::wl_buffer::WlBuffer, DisplayHandle, Weak},
|
||||||
},
|
},
|
||||||
utils::{DevPath, DeviceFd, Point, Transform},
|
utils::{
|
||||||
|
Buffer as BufferCoords, Clock, DevPath, DeviceFd, Monotonic, Point, Rectangle, Transform,
|
||||||
|
},
|
||||||
wayland::drm_lease::{DrmLease, DrmLeaseState},
|
wayland::drm_lease::{DrmLease, DrmLeaseState},
|
||||||
};
|
};
|
||||||
use tracing::{error, info, warn};
|
use tracing::{error, info, warn};
|
||||||
|
|
@ -32,7 +44,7 @@ use std::{
|
||||||
collections::{HashMap, HashSet},
|
collections::{HashMap, HashSet},
|
||||||
fmt,
|
fmt,
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
sync::{atomic::AtomicBool, Arc, RwLock},
|
sync::{atomic::AtomicBool, mpsc::Receiver, Arc, RwLock},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{drm_helpers, socket::Socket, surface::Surface};
|
use super::{drm_helpers, socket::Socket, surface::Surface};
|
||||||
|
|
@ -44,6 +56,16 @@ pub struct EGLInternals {
|
||||||
pub context: EGLContext,
|
pub context: EGLContext,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub type GbmDrmOutputManager = DrmOutputManager<
|
||||||
|
GbmAllocator<DrmDeviceFd>,
|
||||||
|
GbmDevice<DrmDeviceFd>,
|
||||||
|
Option<(
|
||||||
|
OutputPresentationFeedback,
|
||||||
|
Receiver<(ScreencopyFrame, Vec<Rectangle<i32, BufferCoords>>)>,
|
||||||
|
)>,
|
||||||
|
DrmDeviceFd,
|
||||||
|
>;
|
||||||
|
|
||||||
pub struct Device {
|
pub struct Device {
|
||||||
pub dev_node: DrmNode,
|
pub dev_node: DrmNode,
|
||||||
pub render_node: DrmNode,
|
pub render_node: DrmNode,
|
||||||
|
|
@ -51,8 +73,8 @@ pub struct Device {
|
||||||
|
|
||||||
pub outputs: HashMap<connector::Handle, Output>,
|
pub outputs: HashMap<connector::Handle, Output>,
|
||||||
pub surfaces: HashMap<crtc::Handle, Surface>,
|
pub surfaces: HashMap<crtc::Handle, Surface>,
|
||||||
|
pub drm: GbmDrmOutputManager,
|
||||||
pub gbm: GbmDevice<DrmDeviceFd>,
|
pub gbm: GbmDevice<DrmDeviceFd>,
|
||||||
pub drm: DrmDevice,
|
|
||||||
|
|
||||||
supports_atomic: bool,
|
supports_atomic: bool,
|
||||||
|
|
||||||
|
|
@ -72,8 +94,7 @@ impl fmt::Debug for Device {
|
||||||
.field("render_node", &self.render_node)
|
.field("render_node", &self.render_node)
|
||||||
.field("outputs", &self.outputs)
|
.field("outputs", &self.outputs)
|
||||||
.field("surfaces", &self.surfaces)
|
.field("surfaces", &self.surfaces)
|
||||||
.field("drm", &self.drm)
|
.field("drm", &"..")
|
||||||
.field("gbm", &self.gbm)
|
|
||||||
.field("egl", &self.egl)
|
.field("egl", &self.egl)
|
||||||
.field("supports_atomic", &self.supports_atomic)
|
.field("supports_atomic", &self.supports_atomic)
|
||||||
.field("leased_connectors", &self.leased_connectors)
|
.field("leased_connectors", &self.leased_connectors)
|
||||||
|
|
@ -190,6 +211,23 @@ impl State {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let drm = GbmDrmOutputManager::new(
|
||||||
|
drm,
|
||||||
|
GbmAllocator::new(
|
||||||
|
gbm.clone(),
|
||||||
|
GbmBufferFlags::RENDERING | GbmBufferFlags::SCANOUT,
|
||||||
|
),
|
||||||
|
gbm.clone(),
|
||||||
|
Some(gbm.clone()),
|
||||||
|
[
|
||||||
|
Fourcc::Abgr2101010,
|
||||||
|
Fourcc::Argb2101010,
|
||||||
|
Fourcc::Abgr8888,
|
||||||
|
Fourcc::Argb8888,
|
||||||
|
],
|
||||||
|
render_formats,
|
||||||
|
);
|
||||||
|
|
||||||
let mut device = Device {
|
let mut device = Device {
|
||||||
dev_node: drm_node,
|
dev_node: drm_node,
|
||||||
render_node,
|
render_node,
|
||||||
|
|
@ -197,8 +235,8 @@ impl State {
|
||||||
|
|
||||||
outputs: HashMap::new(),
|
outputs: HashMap::new(),
|
||||||
surfaces: HashMap::new(),
|
surfaces: HashMap::new(),
|
||||||
gbm: gbm.clone(),
|
|
||||||
drm,
|
drm,
|
||||||
|
gbm,
|
||||||
|
|
||||||
supports_atomic,
|
supports_atomic,
|
||||||
|
|
||||||
|
|
@ -264,6 +302,7 @@ impl State {
|
||||||
&mut self.common.workspace_state.update(),
|
&mut self.common.workspace_state.update(),
|
||||||
&self.common.xdg_activation_state,
|
&self.common.xdg_activation_state,
|
||||||
self.common.startup_done.clone(),
|
self.common.startup_done.clone(),
|
||||||
|
&self.common.clock,
|
||||||
);
|
);
|
||||||
|
|
||||||
self.backend.kms().refresh_used_devices()?;
|
self.backend.kms().refresh_used_devices()?;
|
||||||
|
|
@ -364,6 +403,7 @@ impl State {
|
||||||
&mut self.common.workspace_state.update(),
|
&mut self.common.workspace_state.update(),
|
||||||
&self.common.xdg_activation_state,
|
&self.common.xdg_activation_state,
|
||||||
self.common.startup_done.clone(),
|
self.common.startup_done.clone(),
|
||||||
|
&self.common.clock,
|
||||||
);
|
);
|
||||||
// Don't remove the outputs, before potentially new ones have been initialized.
|
// Don't remove the outputs, before potentially new ones have been initialized.
|
||||||
// reading a new config means outputs might become enabled, that were previously disabled.
|
// reading a new config means outputs might become enabled, that were previously disabled.
|
||||||
|
|
@ -417,6 +457,7 @@ impl State {
|
||||||
&mut self.common.workspace_state.update(),
|
&mut self.common.workspace_state.update(),
|
||||||
&self.common.xdg_activation_state,
|
&self.common.xdg_activation_state,
|
||||||
self.common.startup_done.clone(),
|
self.common.startup_done.clone(),
|
||||||
|
&self.common.clock,
|
||||||
);
|
);
|
||||||
self.common.refresh();
|
self.common.refresh();
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -435,7 +476,8 @@ pub struct OutputChanges {
|
||||||
impl Device {
|
impl Device {
|
||||||
pub fn enumerate_surfaces(&mut self) -> Result<OutputChanges> {
|
pub fn enumerate_surfaces(&mut self) -> Result<OutputChanges> {
|
||||||
// enumerate our outputs
|
// enumerate our outputs
|
||||||
let config = drm_helpers::display_configuration(&mut self.drm, self.supports_atomic)?;
|
let config =
|
||||||
|
drm_helpers::display_configuration(self.drm.device_mut(), self.supports_atomic)?;
|
||||||
|
|
||||||
let surfaces = self
|
let surfaces = self
|
||||||
.surfaces
|
.surfaces
|
||||||
|
|
@ -486,19 +528,20 @@ impl Device {
|
||||||
.get(&conn)
|
.get(&conn)
|
||||||
.cloned()
|
.cloned()
|
||||||
.map(|output| Ok(output))
|
.map(|output| Ok(output))
|
||||||
.unwrap_or_else(|| create_output_for_conn(&mut self.drm, conn))
|
.unwrap_or_else(|| create_output_for_conn(self.drm.device_mut(), conn))
|
||||||
.context("Failed to create `Output`")?;
|
.context("Failed to create `Output`")?;
|
||||||
|
|
||||||
let non_desktop = match drm_helpers::get_property_val(&self.drm, conn, "non-desktop") {
|
let non_desktop =
|
||||||
Ok((val_type, value)) => val_type.convert_value(value).as_boolean().unwrap(),
|
match drm_helpers::get_property_val(self.drm.device_mut(), conn, "non-desktop") {
|
||||||
Err(err) => {
|
Ok((val_type, value)) => val_type.convert_value(value).as_boolean().unwrap(),
|
||||||
warn!(
|
Err(err) => {
|
||||||
?err,
|
warn!(
|
||||||
"Failed to determine if connector is meant desktop usage, assuming so."
|
?err,
|
||||||
);
|
"Failed to determine if connector is meant desktop usage, assuming so."
|
||||||
false
|
);
|
||||||
}
|
false
|
||||||
};
|
}
|
||||||
|
};
|
||||||
|
|
||||||
if non_desktop {
|
if non_desktop {
|
||||||
if let Some(crtc) = maybe_crtc {
|
if let Some(crtc) = maybe_crtc {
|
||||||
|
|
@ -528,7 +571,7 @@ impl Device {
|
||||||
.user_data()
|
.user_data()
|
||||||
.insert_if_missing(|| RefCell::new(OutputConfig::default()));
|
.insert_if_missing(|| RefCell::new(OutputConfig::default()));
|
||||||
|
|
||||||
populate_modes(&mut self.drm, &output, conn, position)
|
populate_modes(self.drm.device_mut(), &output, conn, position)
|
||||||
.with_context(|| "Failed to enumerate connector modes")?;
|
.with_context(|| "Failed to enumerate connector modes")?;
|
||||||
|
|
||||||
let has_surface = if let Some(crtc) = maybe_crtc {
|
let has_surface = if let Some(crtc) = maybe_crtc {
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ use smithay::{
|
||||||
dmabuf::Dmabuf,
|
dmabuf::Dmabuf,
|
||||||
gbm::{GbmAllocator, GbmBufferFlags},
|
gbm::{GbmAllocator, GbmBufferFlags},
|
||||||
},
|
},
|
||||||
drm::{DrmDeviceFd, DrmNode, NodeType},
|
drm::{output::DrmOutputRenderElements, DrmDeviceFd, DrmNode, NodeType},
|
||||||
egl::{context::ContextPriority, EGLContext, EGLDevice, EGLDisplay},
|
egl::{context::ContextPriority, EGLContext, EGLDevice, EGLDisplay},
|
||||||
input::InputEvent,
|
input::InputEvent,
|
||||||
libinput::{LibinputInputBackend, LibinputSessionInterface},
|
libinput::{LibinputInputBackend, LibinputSessionInterface},
|
||||||
|
|
@ -27,13 +27,17 @@ use smithay::{
|
||||||
output::Output,
|
output::Output,
|
||||||
reexports::{
|
reexports::{
|
||||||
calloop::{Dispatcher, EventLoop, LoopHandle},
|
calloop::{Dispatcher, EventLoop, LoopHandle},
|
||||||
drm::control::{crtc, Device as _},
|
drm::{
|
||||||
|
control::{crtc, Device as _},
|
||||||
|
Device as _,
|
||||||
|
},
|
||||||
input::{self, Libinput},
|
input::{self, Libinput},
|
||||||
wayland_server::{Client, DisplayHandle},
|
wayland_server::{Client, DisplayHandle},
|
||||||
},
|
},
|
||||||
utils::{DevPath, Size},
|
utils::{Clock, DevPath, Monotonic, Size},
|
||||||
wayland::{dmabuf::DmabufGlobal, relative_pointer::RelativePointerManagerState},
|
wayland::{dmabuf::DmabufGlobal, relative_pointer::RelativePointerManagerState},
|
||||||
};
|
};
|
||||||
|
use surface::GbmDrmOutput;
|
||||||
use tracing::{error, info, trace, warn};
|
use tracing::{error, info, trace, warn};
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
|
|
@ -53,7 +57,7 @@ pub(crate) use surface::Surface;
|
||||||
use device::*;
|
use device::*;
|
||||||
pub use surface::Timings;
|
pub use surface::Timings;
|
||||||
|
|
||||||
use super::render::init_shaders;
|
use super::render::{init_shaders, output_elements, CursorMode, CLEAR_COLOR};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct KmsState {
|
pub struct KmsState {
|
||||||
|
|
@ -321,6 +325,7 @@ impl State {
|
||||||
&mut state.common.workspace_state.update(),
|
&mut state.common.workspace_state.update(),
|
||||||
&state.common.xdg_activation_state,
|
&state.common.xdg_activation_state,
|
||||||
state.common.startup_done.clone(),
|
state.common.startup_done.clone(),
|
||||||
|
&state.common.clock,
|
||||||
);
|
);
|
||||||
state.common.refresh();
|
state.common.refresh();
|
||||||
});
|
});
|
||||||
|
|
@ -528,6 +533,7 @@ impl KmsState {
|
||||||
loop_handle: &LoopHandle<'static, State>,
|
loop_handle: &LoopHandle<'static, State>,
|
||||||
shell: Arc<RwLock<Shell>>,
|
shell: Arc<RwLock<Shell>>,
|
||||||
startup_done: Arc<AtomicBool>,
|
startup_done: Arc<AtomicBool>,
|
||||||
|
clock: &Clock<Monotonic>,
|
||||||
) -> Result<Vec<Output>, anyhow::Error> {
|
) -> Result<Vec<Output>, anyhow::Error> {
|
||||||
if !self.session.is_active() {
|
if !self.session.is_active() {
|
||||||
return Ok(Vec::new());
|
return Ok(Vec::new());
|
||||||
|
|
@ -554,7 +560,7 @@ impl KmsState {
|
||||||
// TODO: Right now we always keep crtcs of already enabled outputs,
|
// TODO: Right now we always keep crtcs of already enabled outputs,
|
||||||
// even if another configuration could potentially enable more outputs
|
// even if another configuration could potentially enable more outputs
|
||||||
|
|
||||||
let res_handles = device.drm.resource_handles()?;
|
let res_handles = device.drm.device().resource_handles()?;
|
||||||
let free_crtcs = res_handles
|
let free_crtcs = res_handles
|
||||||
.crtcs()
|
.crtcs()
|
||||||
.iter()
|
.iter()
|
||||||
|
|
@ -579,16 +585,20 @@ impl KmsState {
|
||||||
});
|
});
|
||||||
|
|
||||||
for conn in open_conns {
|
for conn in open_conns {
|
||||||
let conn_info = device.drm.get_connector(conn, false).with_context(|| {
|
let conn_info = device
|
||||||
format!(
|
.drm
|
||||||
"Failed to query drm device: {:?}",
|
.device()
|
||||||
device.drm.dev_path().as_deref().map(Path::display),
|
.get_connector(conn, false)
|
||||||
)
|
.with_context(|| {
|
||||||
})?;
|
format!(
|
||||||
|
"Failed to query drm device: {:?}",
|
||||||
|
device.drm.device().dev_path().as_deref().map(Path::display),
|
||||||
|
)
|
||||||
|
})?;
|
||||||
'outer: for encoder_info in conn_info
|
'outer: for encoder_info in conn_info
|
||||||
.encoders()
|
.encoders()
|
||||||
.iter()
|
.iter()
|
||||||
.flat_map(|encoder_handle| device.drm.get_encoder(*encoder_handle))
|
.flat_map(|encoder_handle| device.drm.device().get_encoder(*encoder_handle))
|
||||||
{
|
{
|
||||||
for crtc in res_handles.filter_crtcs(encoder_info.possible_crtcs()) {
|
for crtc in res_handles.filter_crtcs(encoder_info.possible_crtcs()) {
|
||||||
if free_crtcs.contains(&crtc) {
|
if free_crtcs.contains(&crtc) {
|
||||||
|
|
@ -638,13 +648,20 @@ impl KmsState {
|
||||||
|
|
||||||
let mut all_outputs = Vec::new();
|
let mut all_outputs = Vec::new();
|
||||||
for device in self.drm_devices.values_mut() {
|
for device in self.drm_devices.values_mut() {
|
||||||
// reconfigure
|
// reconfigure existing
|
||||||
|
let now = clock.now();
|
||||||
|
let output_map = device
|
||||||
|
.surfaces
|
||||||
|
.iter()
|
||||||
|
.map(|(crtc, surface)| (*crtc, surface.output.clone()))
|
||||||
|
.collect::<HashMap<_, _>>();
|
||||||
|
|
||||||
for (crtc, surface) in device.surfaces.iter_mut() {
|
for (crtc, surface) in device.surfaces.iter_mut() {
|
||||||
let output_config = surface.output.config();
|
let output_config = surface.output.config();
|
||||||
|
|
||||||
let drm = &mut device.drm;
|
let drm = &mut device.drm;
|
||||||
let conn = surface.connector;
|
let conn = surface.connector;
|
||||||
let conn_info = drm.get_connector(conn, false)?;
|
let conn_info = drm.device().get_connector(conn, false)?;
|
||||||
let mode = conn_info
|
let mode = conn_info
|
||||||
.modes()
|
.modes()
|
||||||
.iter()
|
.iter()
|
||||||
|
|
@ -662,14 +679,64 @@ impl KmsState {
|
||||||
|
|
||||||
if !test_only {
|
if !test_only {
|
||||||
if !surface.is_active() {
|
if !surface.is_active() {
|
||||||
let drm_surface = drm
|
let compositor: GbmDrmOutput = {
|
||||||
.create_surface(*crtc, *mode, &[conn])
|
let mut planes = drm
|
||||||
.with_context(|| "Failed to create drm surface")?;
|
.device()
|
||||||
let gbm = device.gbm.clone();
|
.planes(crtc)
|
||||||
let cursor_size = drm.cursor_size();
|
.with_context(|| "Failed to enumerate planes")?;
|
||||||
|
let driver = drm.device().get_driver().ok();
|
||||||
|
|
||||||
|
// 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 mut renderer = self
|
||||||
|
.api
|
||||||
|
.single_renderer(&device.render_node)
|
||||||
|
.with_context(|| "Failed to create renderer")?;
|
||||||
|
|
||||||
|
let mut elements = DrmOutputRenderElements::default();
|
||||||
|
for (crtc, output) in output_map.iter() {
|
||||||
|
let output_elements = output_elements(
|
||||||
|
Some(&device.render_node),
|
||||||
|
&mut renderer,
|
||||||
|
&shell,
|
||||||
|
now,
|
||||||
|
&output,
|
||||||
|
CursorMode::All,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.with_context(|| "Failed to render outputs")?;
|
||||||
|
|
||||||
|
elements.add_output(crtc, CLEAR_COLOR, output_elements);
|
||||||
|
}
|
||||||
|
|
||||||
|
let compositor = drm
|
||||||
|
.initialize_output(
|
||||||
|
*crtc,
|
||||||
|
*mode,
|
||||||
|
&[conn],
|
||||||
|
&surface.output,
|
||||||
|
Some(planes),
|
||||||
|
&mut renderer,
|
||||||
|
&elements,
|
||||||
|
)
|
||||||
|
.with_context(|| "Failed to create drm surface")?;
|
||||||
|
|
||||||
|
let _ = renderer;
|
||||||
|
|
||||||
|
compositor
|
||||||
|
};
|
||||||
|
|
||||||
if let Some(bpc) = output_config.max_bpc {
|
if let Some(bpc) = output_config.max_bpc {
|
||||||
if let Err(err) = drm_helpers::set_max_bpc(drm, conn, bpc) {
|
if let Err(err) = drm_helpers::set_max_bpc(drm.device(), conn, bpc) {
|
||||||
warn!(
|
warn!(
|
||||||
?bpc,
|
?bpc,
|
||||||
?err,
|
?err,
|
||||||
|
|
@ -682,7 +749,7 @@ impl KmsState {
|
||||||
let vrr = output_config.vrr;
|
let vrr = output_config.vrr;
|
||||||
std::mem::drop(output_config);
|
std::mem::drop(output_config);
|
||||||
|
|
||||||
match surface.resume(drm_surface, gbm, cursor_size) {
|
match surface.resume(compositor) {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
surface.output.set_adaptive_sync_support(
|
surface.output.set_adaptive_sync_support(
|
||||||
surface.adaptive_sync_support().ok(),
|
surface.adaptive_sync_support().ok(),
|
||||||
|
|
@ -711,8 +778,29 @@ impl KmsState {
|
||||||
surface.output.set_adaptive_sync(AdaptiveSync::Disabled);
|
surface.output.set_adaptive_sync(AdaptiveSync::Disabled);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
surface
|
|
||||||
.set_mode(*mode)
|
let mut renderer = self
|
||||||
|
.api
|
||||||
|
.single_renderer(&device.render_node)
|
||||||
|
.with_context(|| "Failed to create renderer")?;
|
||||||
|
|
||||||
|
let mut elements = DrmOutputRenderElements::default();
|
||||||
|
for (crtc, output) in output_map.iter() {
|
||||||
|
let output_elements = output_elements(
|
||||||
|
Some(&device.render_node),
|
||||||
|
&mut renderer,
|
||||||
|
&shell,
|
||||||
|
now,
|
||||||
|
&output,
|
||||||
|
CursorMode::All,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.with_context(|| "Failed to render outputs")?;
|
||||||
|
|
||||||
|
elements.add_output(crtc, CLEAR_COLOR, output_elements);
|
||||||
|
}
|
||||||
|
|
||||||
|
drm.use_mode(&surface.crtc, *mode, &mut renderer, &elements)
|
||||||
.context("Failed to apply new mode")?;
|
.context("Failed to apply new mode")?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -731,6 +819,36 @@ impl KmsState {
|
||||||
.map(|(_, output)| output.clone())
|
.map(|(_, output)| output.clone())
|
||||||
.collect::<Vec<_>>(),
|
.collect::<Vec<_>>(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut renderer = self
|
||||||
|
.api
|
||||||
|
.single_renderer(&device.render_node)
|
||||||
|
.with_context(|| "Failed to create renderer")?;
|
||||||
|
|
||||||
|
let mut elements = DrmOutputRenderElements::default();
|
||||||
|
for (crtc, output) in output_map.iter() {
|
||||||
|
let output_elements = output_elements(
|
||||||
|
Some(&device.render_node),
|
||||||
|
&mut renderer,
|
||||||
|
&shell,
|
||||||
|
now,
|
||||||
|
&output,
|
||||||
|
CursorMode::All,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.with_context(|| "Failed to render outputs")?;
|
||||||
|
|
||||||
|
elements.add_output(crtc, CLEAR_COLOR, output_elements);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Err(err) = device
|
||||||
|
.drm
|
||||||
|
.try_to_restore_modifiers(&mut renderer, &elements)
|
||||||
|
{
|
||||||
|
warn!(?err, "Failed to restore modifiers");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// we need to handle mirroring, after all outputs have been enabled
|
// we need to handle mirroring, after all outputs have been enabled
|
||||||
|
|
|
||||||
|
|
@ -3,12 +3,12 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
backend::render::{
|
backend::render::{
|
||||||
element::{CosmicElement, DamageElement},
|
element::{CosmicElement, DamageElement},
|
||||||
init_shaders, workspace_elements, CursorMode, ElementFilter, GlMultiRenderer, CLEAR_COLOR,
|
init_shaders, output_elements, CursorMode, GlMultiRenderer, CLEAR_COLOR,
|
||||||
},
|
},
|
||||||
config::AdaptiveSync,
|
config::AdaptiveSync,
|
||||||
shell::Shell,
|
shell::Shell,
|
||||||
state::SurfaceDmabufFeedback,
|
state::SurfaceDmabufFeedback,
|
||||||
utils::{prelude::*, quirks::workspace_overview_is_open},
|
utils::prelude::*,
|
||||||
wayland::{
|
wayland::{
|
||||||
handlers::screencopy::{submit_buffer, FrameHolder, SessionData},
|
handlers::screencopy::{submit_buffer, FrameHolder, SessionData},
|
||||||
protocols::screencopy::{
|
protocols::screencopy::{
|
||||||
|
|
@ -23,14 +23,13 @@ use smithay::{
|
||||||
backend::{
|
backend::{
|
||||||
allocator::{
|
allocator::{
|
||||||
format::FormatSet,
|
format::FormatSet,
|
||||||
gbm::{GbmAllocator, GbmBufferFlags, GbmDevice},
|
gbm::{GbmAllocator, GbmDevice},
|
||||||
Fourcc,
|
Fourcc,
|
||||||
},
|
},
|
||||||
drm::{
|
drm::{
|
||||||
compositor::{
|
compositor::{BlitFrameResultError, FrameError, FrameFlags, PrimaryPlaneElement},
|
||||||
BlitFrameResultError, DrmCompositor, FrameError, FrameFlags, PrimaryPlaneElement,
|
output::DrmOutput,
|
||||||
},
|
DrmDeviceFd, DrmEventMetadata, DrmEventTime, DrmNode, VrrSupport,
|
||||||
DrmDeviceFd, DrmEventMetadata, DrmEventTime, DrmNode, DrmSurface, VrrSupport,
|
|
||||||
},
|
},
|
||||||
egl::EGLContext,
|
egl::EGLContext,
|
||||||
renderer::{
|
renderer::{
|
||||||
|
|
@ -57,17 +56,14 @@ use smithay::{
|
||||||
timer::{TimeoutAction, Timer},
|
timer::{TimeoutAction, Timer},
|
||||||
EventLoop, LoopHandle, RegistrationToken,
|
EventLoop, LoopHandle, RegistrationToken,
|
||||||
},
|
},
|
||||||
drm::{
|
drm::control::{connector, crtc},
|
||||||
control::{connector, crtc, Mode},
|
|
||||||
Device as _,
|
|
||||||
},
|
|
||||||
wayland_protocols::wp::{
|
wayland_protocols::wp::{
|
||||||
linux_dmabuf::zv1::server::zwp_linux_dmabuf_feedback_v1,
|
linux_dmabuf::zv1::server::zwp_linux_dmabuf_feedback_v1,
|
||||||
presentation_time::server::wp_presentation_feedback,
|
presentation_time::server::wp_presentation_feedback,
|
||||||
},
|
},
|
||||||
wayland_server::protocol::wl_surface::WlSurface,
|
wayland_server::protocol::wl_surface::WlSurface,
|
||||||
},
|
},
|
||||||
utils::{Buffer as BufferCoords, Clock, Monotonic, Physical, Rectangle, Size, Transform},
|
utils::{Buffer as BufferCoords, Clock, Monotonic, Physical, Rectangle, Transform},
|
||||||
wayland::{
|
wayland::{
|
||||||
dmabuf::{get_dmabuf, DmabufFeedbackBuilder},
|
dmabuf::{get_dmabuf, DmabufFeedbackBuilder},
|
||||||
presentation::Refresh,
|
presentation::Refresh,
|
||||||
|
|
@ -107,7 +103,7 @@ static NVIDIA_LOGO: &'static [u8] = include_bytes!("../../../../resources/icons/
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Surface {
|
pub struct Surface {
|
||||||
pub(crate) connector: connector::Handle,
|
pub(crate) connector: connector::Handle,
|
||||||
pub(super) _crtc: crtc::Handle,
|
pub(super) crtc: crtc::Handle,
|
||||||
pub(crate) output: Output,
|
pub(crate) output: Output,
|
||||||
known_nodes: HashSet<DrmNode>,
|
known_nodes: HashSet<DrmNode>,
|
||||||
|
|
||||||
|
|
@ -130,7 +126,7 @@ pub struct SurfaceThreadState {
|
||||||
active: Arc<AtomicBool>,
|
active: Arc<AtomicBool>,
|
||||||
vrr_mode: AdaptiveSync,
|
vrr_mode: AdaptiveSync,
|
||||||
frame_flags: FrameFlags,
|
frame_flags: FrameFlags,
|
||||||
compositor: Option<GbmDrmCompositor>,
|
compositor: Option<GbmDrmOutput>,
|
||||||
|
|
||||||
state: QueueState,
|
state: QueueState,
|
||||||
timings: Timings,
|
timings: Timings,
|
||||||
|
|
@ -189,7 +185,7 @@ impl MirroringState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type GbmDrmCompositor = DrmCompositor<
|
pub type GbmDrmOutput = DrmOutput<
|
||||||
GbmAllocator<DrmDeviceFd>,
|
GbmAllocator<DrmDeviceFd>,
|
||||||
GbmDevice<DrmDeviceFd>,
|
GbmDevice<DrmDeviceFd>,
|
||||||
Option<(
|
Option<(
|
||||||
|
|
@ -227,9 +223,7 @@ impl Default for QueueState {
|
||||||
pub enum ThreadCommand {
|
pub enum ThreadCommand {
|
||||||
Suspend(SyncSender<()>),
|
Suspend(SyncSender<()>),
|
||||||
Resume {
|
Resume {
|
||||||
surface: DrmSurface,
|
compositor: GbmDrmOutput,
|
||||||
gbm: GbmDevice<DrmDeviceFd>,
|
|
||||||
cursor_size: Size<u32, BufferCoords>,
|
|
||||||
result: SyncSender<Result<()>>,
|
result: SyncSender<Result<()>>,
|
||||||
},
|
},
|
||||||
NodeAdded {
|
NodeAdded {
|
||||||
|
|
@ -243,9 +237,9 @@ pub enum ThreadCommand {
|
||||||
UpdateMirroring(Option<Output>),
|
UpdateMirroring(Option<Output>),
|
||||||
VBlank(Option<DrmEventMetadata>),
|
VBlank(Option<DrmEventMetadata>),
|
||||||
ScheduleRender,
|
ScheduleRender,
|
||||||
SetMode(Mode, SyncSender<Result<()>>),
|
|
||||||
AdaptiveSyncAvailable(SyncSender<Result<VrrSupport>>),
|
AdaptiveSyncAvailable(SyncSender<Result<VrrSupport>>),
|
||||||
UseAdaptiveSync(AdaptiveSync),
|
UseAdaptiveSync(AdaptiveSync),
|
||||||
|
AllowOverlayScanout(bool, SyncSender<()>),
|
||||||
End,
|
End,
|
||||||
DpmsOff,
|
DpmsOff,
|
||||||
}
|
}
|
||||||
|
|
@ -351,7 +345,7 @@ impl Surface {
|
||||||
|
|
||||||
Ok(Surface {
|
Ok(Surface {
|
||||||
connector,
|
connector,
|
||||||
_crtc: crtc,
|
crtc,
|
||||||
output: output.clone(),
|
output: output.clone(),
|
||||||
known_nodes: HashSet::new(),
|
known_nodes: HashSet::new(),
|
||||||
active,
|
active,
|
||||||
|
|
@ -402,12 +396,6 @@ impl Surface {
|
||||||
.send(ThreadCommand::UpdateMirroring(output));
|
.send(ThreadCommand::UpdateMirroring(output));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_mode(&mut self, mode: Mode) -> Result<()> {
|
|
||||||
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 adaptive_sync_support(&self) -> Result<VrrSupport> {
|
pub fn adaptive_sync_support(&self) -> Result<VrrSupport> {
|
||||||
let (tx, rx) = std::sync::mpsc::sync_channel(1);
|
let (tx, rx) = std::sync::mpsc::sync_channel(1);
|
||||||
let _ = self
|
let _ = self
|
||||||
|
|
@ -441,31 +429,26 @@ impl Surface {
|
||||||
let _ = rx.recv();
|
let _ = rx.recv();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn resume(
|
pub fn resume(&mut self, compositor: GbmDrmOutput) -> Result<()> {
|
||||||
&mut self,
|
|
||||||
surface: DrmSurface,
|
|
||||||
gbm: GbmDevice<DrmDeviceFd>,
|
|
||||||
cursor_size: Size<u32, BufferCoords>,
|
|
||||||
) -> Result<()> {
|
|
||||||
let (tx, rx) = std::sync::mpsc::sync_channel(1);
|
let (tx, rx) = std::sync::mpsc::sync_channel(1);
|
||||||
self.plane_formats = surface
|
self.plane_formats = compositor.with_compositor(|c| {
|
||||||
.plane_info()
|
c.surface()
|
||||||
.formats
|
.plane_info()
|
||||||
.iter()
|
.formats
|
||||||
.copied()
|
.iter()
|
||||||
.chain(
|
.copied()
|
||||||
surface
|
.chain(
|
||||||
.planes()
|
c.surface()
|
||||||
.overlay
|
.planes()
|
||||||
.iter()
|
.overlay
|
||||||
.flat_map(|p| p.formats.iter().cloned()),
|
.iter()
|
||||||
)
|
.flat_map(|p| p.formats.iter().cloned()),
|
||||||
.collect::<FormatSet>();
|
)
|
||||||
|
.collect::<FormatSet>()
|
||||||
|
});
|
||||||
|
|
||||||
let _ = self.thread_command.send(ThreadCommand::Resume {
|
let _ = self.thread_command.send(ThreadCommand::Resume {
|
||||||
surface,
|
compositor,
|
||||||
gbm,
|
|
||||||
cursor_size,
|
|
||||||
result: tx,
|
result: tx,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -560,13 +543,8 @@ fn surface_thread(
|
||||||
.handle()
|
.handle()
|
||||||
.insert_source(thread_receiver, move |command, _, state| match command {
|
.insert_source(thread_receiver, move |command, _, state| match command {
|
||||||
Event::Msg(ThreadCommand::Suspend(tx)) => state.suspend(tx),
|
Event::Msg(ThreadCommand::Suspend(tx)) => state.suspend(tx),
|
||||||
Event::Msg(ThreadCommand::Resume {
|
Event::Msg(ThreadCommand::Resume { compositor, result }) => {
|
||||||
surface,
|
let _ = result.send(state.resume(compositor));
|
||||||
gbm,
|
|
||||||
cursor_size,
|
|
||||||
result,
|
|
||||||
}) => {
|
|
||||||
let _ = result.send(state.resume(surface, gbm, cursor_size));
|
|
||||||
}
|
}
|
||||||
Event::Msg(ThreadCommand::NodeAdded { node, gbm, egl }) => {
|
Event::Msg(ThreadCommand::NodeAdded { node, gbm, egl }) => {
|
||||||
if let Err(err) = state.node_added(node, gbm, egl) {
|
if let Err(err) = state.node_added(node, gbm, egl) {
|
||||||
|
|
@ -589,20 +567,13 @@ fn surface_thread(
|
||||||
Event::Msg(ThreadCommand::UpdateMirroring(mirroring_output)) => {
|
Event::Msg(ThreadCommand::UpdateMirroring(mirroring_output)) => {
|
||||||
state.update_mirroring(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));
|
|
||||||
} else {
|
|
||||||
let _ = result.send(Err(anyhow::anyhow!("Set mode with inactive surface")));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Event::Msg(ThreadCommand::AdaptiveSyncAvailable(result)) => {
|
Event::Msg(ThreadCommand::AdaptiveSyncAvailable(result)) => {
|
||||||
if let Some(compositor) = state.compositor.as_mut() {
|
if let Some(compositor) = state.compositor.as_mut() {
|
||||||
let _ = result.send(
|
let _ = result.send(
|
||||||
compositor
|
compositor
|
||||||
.vrr_supported(
|
.with_compositor(|c| {
|
||||||
compositor.pending_connectors().into_iter().next().unwrap(),
|
c.vrr_supported(c.pending_connectors().into_iter().next().unwrap())
|
||||||
)
|
})
|
||||||
.map_err(Into::into),
|
.map_err(Into::into),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -614,7 +585,7 @@ fn surface_thread(
|
||||||
}
|
}
|
||||||
Event::Msg(ThreadCommand::DpmsOff) => {
|
Event::Msg(ThreadCommand::DpmsOff) => {
|
||||||
if let Some(compositor) = state.compositor.as_mut() {
|
if let Some(compositor) = state.compositor.as_mut() {
|
||||||
if let Err(err) = compositor.clear() {
|
if let Err(err) = compositor.with_compositor(|c| c.clear()) {
|
||||||
error!("Failed to set DPMS off: {:?}", err);
|
error!("Failed to set DPMS off: {:?}", err);
|
||||||
}
|
}
|
||||||
match std::mem::replace(&mut state.state, QueueState::Idle) {
|
match std::mem::replace(&mut state.state, QueueState::Idle) {
|
||||||
|
|
@ -670,69 +641,22 @@ impl SurfaceThreadState {
|
||||||
let _ = tx.send(());
|
let _ = tx.send(());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resume(
|
fn resume(&mut self, compositor: GbmDrmOutput) -> Result<()> {
|
||||||
&mut self,
|
let mode = compositor.with_compositor(|c| c.surface().pending_mode());
|
||||||
surface: DrmSurface,
|
|
||||||
gbm: GbmDevice<DrmDeviceFd>,
|
|
||||||
cursor_size: Size<u32, BufferCoords>,
|
|
||||||
) -> 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();
|
|
||||||
|
|
||||||
self.timings
|
self.timings
|
||||||
.set_refresh_interval(Some(Duration::from_secs_f64(
|
.set_refresh_interval(Some(Duration::from_secs_f64(
|
||||||
1_000.0 / drm_helpers::calculate_refresh_rate(surface.pending_mode()) as f64,
|
1_000.0 / drm_helpers::calculate_refresh_rate(mode) as f64,
|
||||||
)));
|
)));
|
||||||
|
|
||||||
match DrmCompositor::new(
|
if crate::utils::env::bool_var("COSMIC_DISABLE_DIRECT_SCANOUT").unwrap_or(false) {
|
||||||
&self.output,
|
self.frame_flags.remove(FrameFlags::ALLOW_SCANOUT);
|
||||||
surface,
|
} else if crate::utils::env::bool_var("COSMIC_DISABLE_OVERLAY_SCANOUT").unwrap_or(false) {
|
||||||
Some(planes),
|
self.frame_flags
|
||||||
GbmAllocator::new(
|
.remove(FrameFlags::ALLOW_OVERLAY_PLANE_SCANOUT);
|
||||||
gbm.clone(),
|
|
||||||
GbmBufferFlags::RENDERING | GbmBufferFlags::SCANOUT,
|
|
||||||
),
|
|
||||||
gbm.clone(),
|
|
||||||
[
|
|
||||||
Fourcc::Abgr2101010,
|
|
||||||
Fourcc::Argb2101010,
|
|
||||||
Fourcc::Abgr8888,
|
|
||||||
Fourcc::Argb8888,
|
|
||||||
],
|
|
||||||
render_formats,
|
|
||||||
cursor_size,
|
|
||||||
Some(gbm),
|
|
||||||
) {
|
|
||||||
Ok(compositor) => {
|
|
||||||
if crate::utils::env::bool_var("COSMIC_DISABLE_DIRECT_SCANOUT").unwrap_or(false) {
|
|
||||||
self.frame_flags.remove(FrameFlags::ALLOW_SCANOUT);
|
|
||||||
}
|
|
||||||
self.active.store(true, Ordering::SeqCst);
|
|
||||||
self.compositor = Some(compositor);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
Err(err) => {
|
|
||||||
self.active.store(false, Ordering::SeqCst);
|
|
||||||
Err(err.into())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
self.active.store(true, Ordering::SeqCst);
|
||||||
|
self.compositor = Some(compositor);
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn node_added(
|
fn node_added(
|
||||||
|
|
@ -817,7 +741,7 @@ impl SurfaceThreadState {
|
||||||
if self
|
if self
|
||||||
.compositor
|
.compositor
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.is_some_and(|comp| comp.vrr_enabled()) =>
|
.is_some_and(|comp| comp.with_compositor(|c| c.vrr_enabled())) =>
|
||||||
{
|
{
|
||||||
Refresh::Variable(rate)
|
Refresh::Variable(rate)
|
||||||
}
|
}
|
||||||
|
|
@ -975,47 +899,27 @@ impl SurfaceThreadState {
|
||||||
_ => false,
|
_ => false,
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut elements = {
|
if self.vrr_mode == AdaptiveSync::Enabled {
|
||||||
let shell = self.shell.read().unwrap();
|
let shell = self.shell.read().unwrap();
|
||||||
let output = self.mirroring.as_ref().unwrap_or(&self.output);
|
let output = self.mirroring.as_ref().unwrap_or(&self.output);
|
||||||
|
vrr = shell.workspaces.active(output).1.get_fullscreen().is_some();
|
||||||
|
}
|
||||||
|
|
||||||
let (previous_workspace, workspace) = shell.workspaces.active(output);
|
let mut elements = output_elements(
|
||||||
let (previous_idx, idx) = shell.workspaces.active_num(&output);
|
Some(&render_node),
|
||||||
let previous_workspace = previous_workspace
|
&mut renderer,
|
||||||
.zip(previous_idx)
|
&self.shell,
|
||||||
.map(|((w, start), idx)| (w.handle, idx, start));
|
self.clock.now(),
|
||||||
if self.vrr_mode == AdaptiveSync::Enabled {
|
self.mirroring.as_ref().unwrap_or(&self.output),
|
||||||
vrr = workspace.get_fullscreen().is_some();
|
CursorMode::All,
|
||||||
}
|
#[cfg(not(feature = "debug"))]
|
||||||
let workspace = (workspace.handle, idx);
|
None,
|
||||||
|
#[cfg(feature = "debug")]
|
||||||
std::mem::drop(shell);
|
Some((&self.egui, &self.timings)),
|
||||||
|
)
|
||||||
let element_filter = if workspace_overview_is_open(output) {
|
.map_err(|err| {
|
||||||
ElementFilter::LayerShellOnly
|
anyhow::format_err!("Failed to accumulate elements for rendering: {:?}", err)
|
||||||
} else {
|
})?;
|
||||||
ElementFilter::All
|
|
||||||
};
|
|
||||||
|
|
||||||
workspace_elements(
|
|
||||||
Some(&render_node),
|
|
||||||
&mut renderer,
|
|
||||||
&self.shell,
|
|
||||||
self.clock.now(),
|
|
||||||
output,
|
|
||||||
previous_workspace,
|
|
||||||
workspace,
|
|
||||||
CursorMode::All,
|
|
||||||
element_filter,
|
|
||||||
#[cfg(not(feature = "debug"))]
|
|
||||||
None,
|
|
||||||
#[cfg(feature = "debug")]
|
|
||||||
Some((&self.egui, &self.timings)),
|
|
||||||
)
|
|
||||||
.map_err(|err| {
|
|
||||||
anyhow::format_err!("Failed to accumulate elements for rendering: {:?}", err)
|
|
||||||
})?
|
|
||||||
};
|
|
||||||
self.timings.set_vrr(vrr);
|
self.timings.set_vrr(vrr);
|
||||||
self.timings.elements_done(&self.clock);
|
self.timings.elements_done(&self.clock);
|
||||||
|
|
||||||
|
|
@ -1172,24 +1076,24 @@ impl SurfaceThreadState {
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
renderer = self.api.single_renderer(&self.target_node).unwrap();
|
renderer = self.api.single_renderer(&self.target_node).unwrap();
|
||||||
if let Err(err) = compositor.use_vrr(false) {
|
if let Err(err) = compositor.with_compositor(|c| c.use_vrr(vrr)) {
|
||||||
warn!("Unable to set adaptive VRR state: {}", err);
|
warn!("Unable to set adaptive VRR state: {}", err);
|
||||||
}
|
}
|
||||||
compositor.render_frame(
|
compositor.render_frame(
|
||||||
&mut renderer,
|
&mut renderer,
|
||||||
&elements,
|
&elements,
|
||||||
[0.0, 0.0, 0.0, 1.0],
|
[0.0, 0.0, 0.0, 1.0],
|
||||||
FrameFlags::DEFAULT,
|
self.frame_flags,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
if let Err(err) = compositor.use_vrr(vrr) {
|
if let Err(err) = compositor.with_compositor(|c| c.use_vrr(vrr)) {
|
||||||
warn!("Unable to set adaptive VRR state: {}", err);
|
warn!("Unable to set adaptive VRR state: {}", err);
|
||||||
}
|
}
|
||||||
compositor.render_frame(
|
compositor.render_frame(
|
||||||
&mut renderer,
|
&mut renderer,
|
||||||
&elements,
|
&elements,
|
||||||
CLEAR_COLOR, // TODO use a theme neutral color
|
CLEAR_COLOR, // TODO use a theme neutral color
|
||||||
FrameFlags::DEFAULT,
|
self.frame_flags,
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
self.timings.draw_done(&self.clock);
|
self.timings.draw_done(&self.clock);
|
||||||
|
|
|
||||||
|
|
@ -499,6 +499,53 @@ pub enum ElementFilter {
|
||||||
LayerShellOnly,
|
LayerShellOnly,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn output_elements<R>(
|
||||||
|
_gpu: Option<&DrmNode>,
|
||||||
|
renderer: &mut R,
|
||||||
|
shell: &Arc<RwLock<Shell>>,
|
||||||
|
now: Time<Monotonic>,
|
||||||
|
output: &Output,
|
||||||
|
cursor_mode: CursorMode,
|
||||||
|
_fps: Option<(&EguiState, &Timings)>,
|
||||||
|
) -> Result<Vec<CosmicElement<R>>, RenderError<R::Error>>
|
||||||
|
where
|
||||||
|
R: Renderer + ImportAll + ImportMem + AsGlowRenderer,
|
||||||
|
<R as Renderer>::TextureId: Send + Clone + 'static,
|
||||||
|
<R as Renderer>::Error: FromGlesError,
|
||||||
|
CosmicMappedRenderElement<R>: RenderElement<R>,
|
||||||
|
WorkspaceRenderElement<R>: RenderElement<R>,
|
||||||
|
{
|
||||||
|
let shell_guard = shell.read().unwrap();
|
||||||
|
|
||||||
|
let (previous_workspace, workspace) = shell_guard.workspaces.active(output);
|
||||||
|
let (previous_idx, idx) = shell_guard.workspaces.active_num(&output);
|
||||||
|
let previous_workspace = previous_workspace
|
||||||
|
.zip(previous_idx)
|
||||||
|
.map(|((w, start), idx)| (w.handle, idx, start));
|
||||||
|
let workspace = (workspace.handle, idx);
|
||||||
|
|
||||||
|
std::mem::drop(shell_guard);
|
||||||
|
|
||||||
|
let element_filter = if workspace_overview_is_open(output) {
|
||||||
|
ElementFilter::LayerShellOnly
|
||||||
|
} else {
|
||||||
|
ElementFilter::All
|
||||||
|
};
|
||||||
|
|
||||||
|
workspace_elements(
|
||||||
|
_gpu,
|
||||||
|
renderer,
|
||||||
|
shell,
|
||||||
|
now,
|
||||||
|
output,
|
||||||
|
previous_workspace,
|
||||||
|
workspace,
|
||||||
|
cursor_mode,
|
||||||
|
element_filter,
|
||||||
|
_fps,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
#[profiling::function]
|
#[profiling::function]
|
||||||
pub fn workspace_elements<R>(
|
pub fn workspace_elements<R>(
|
||||||
_gpu: Option<&DrmNode>,
|
_gpu: Option<&DrmNode>,
|
||||||
|
|
|
||||||
|
|
@ -228,6 +228,7 @@ pub fn init_backend(
|
||||||
&mut state.common.workspace_state.update(),
|
&mut state.common.workspace_state.update(),
|
||||||
&state.common.xdg_activation_state,
|
&state.common.xdg_activation_state,
|
||||||
state.common.startup_done.clone(),
|
state.common.startup_done.clone(),
|
||||||
|
&state.common.clock,
|
||||||
);
|
);
|
||||||
state.common.refresh();
|
state.common.refresh();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -363,6 +363,7 @@ pub fn init_backend(
|
||||||
&mut state.common.workspace_state.update(),
|
&mut state.common.workspace_state.update(),
|
||||||
&state.common.xdg_activation_state,
|
&state.common.xdg_activation_state,
|
||||||
state.common.startup_done.clone(),
|
state.common.startup_done.clone(),
|
||||||
|
&state.common.clock,
|
||||||
);
|
);
|
||||||
state.common.refresh();
|
state.common.refresh();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,6 @@ use cosmic_config::{ConfigGet, CosmicConfigEntry};
|
||||||
use cosmic_settings_config::window_rules::ApplicationException;
|
use cosmic_settings_config::window_rules::ApplicationException;
|
||||||
use cosmic_settings_config::{shortcuts, window_rules, Shortcuts};
|
use cosmic_settings_config::{shortcuts, window_rules, Shortcuts};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use smithay::wayland::xdg_activation::XdgActivationState;
|
|
||||||
pub use smithay::{
|
pub use smithay::{
|
||||||
backend::input::KeyState,
|
backend::input::KeyState,
|
||||||
input::keyboard::{keysyms as KeySyms, Keysym, ModifiersState},
|
input::keyboard::{keysyms as KeySyms, Keysym, ModifiersState},
|
||||||
|
|
@ -25,6 +24,10 @@ pub use smithay::{
|
||||||
},
|
},
|
||||||
utils::{Logical, Physical, Point, Size, Transform},
|
utils::{Logical, Physical, Point, Size, Transform},
|
||||||
};
|
};
|
||||||
|
use smithay::{
|
||||||
|
utils::{Clock, Monotonic},
|
||||||
|
wayland::xdg_activation::XdgActivationState,
|
||||||
|
};
|
||||||
use std::{
|
use std::{
|
||||||
cell::RefCell,
|
cell::RefCell,
|
||||||
collections::{BTreeMap, HashMap},
|
collections::{BTreeMap, HashMap},
|
||||||
|
|
@ -381,6 +384,7 @@ impl Config {
|
||||||
workspace_state: &mut WorkspaceUpdateGuard<'_, State>,
|
workspace_state: &mut WorkspaceUpdateGuard<'_, State>,
|
||||||
xdg_activation_state: &XdgActivationState,
|
xdg_activation_state: &XdgActivationState,
|
||||||
startup_done: Arc<AtomicBool>,
|
startup_done: Arc<AtomicBool>,
|
||||||
|
clock: &Clock<Monotonic>,
|
||||||
) {
|
) {
|
||||||
let outputs = output_state.outputs().collect::<Vec<_>>();
|
let outputs = output_state.outputs().collect::<Vec<_>>();
|
||||||
let mut infos = outputs
|
let mut infos = outputs
|
||||||
|
|
@ -422,6 +426,7 @@ impl Config {
|
||||||
workspace_state,
|
workspace_state,
|
||||||
xdg_activation_state,
|
xdg_activation_state,
|
||||||
startup_done.clone(),
|
startup_done.clone(),
|
||||||
|
clock,
|
||||||
) {
|
) {
|
||||||
warn!(?err, "Failed to set new config.");
|
warn!(?err, "Failed to set new config.");
|
||||||
found_outputs.clear();
|
found_outputs.clear();
|
||||||
|
|
@ -446,6 +451,7 @@ impl Config {
|
||||||
workspace_state,
|
workspace_state,
|
||||||
xdg_activation_state,
|
xdg_activation_state,
|
||||||
startup_done,
|
startup_done,
|
||||||
|
clock,
|
||||||
) {
|
) {
|
||||||
error!(?err, "Failed to reset config.");
|
error!(?err, "Failed to reset config.");
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -477,6 +483,7 @@ impl Config {
|
||||||
workspace_state,
|
workspace_state,
|
||||||
xdg_activation_state,
|
xdg_activation_state,
|
||||||
startup_done,
|
startup_done,
|
||||||
|
clock,
|
||||||
) {
|
) {
|
||||||
warn!(?err, "Failed to set new config.",);
|
warn!(?err, "Failed to set new config.",);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
11
src/state.rs
11
src/state.rs
|
|
@ -297,11 +297,16 @@ impl BackendData {
|
||||||
workspace_state: &mut WorkspaceUpdateGuard<'_, State>,
|
workspace_state: &mut WorkspaceUpdateGuard<'_, State>,
|
||||||
xdg_activation_state: &XdgActivationState,
|
xdg_activation_state: &XdgActivationState,
|
||||||
startup_done: Arc<AtomicBool>,
|
startup_done: Arc<AtomicBool>,
|
||||||
|
clock: &Clock<Monotonic>,
|
||||||
) -> Result<(), anyhow::Error> {
|
) -> Result<(), anyhow::Error> {
|
||||||
let result = match self {
|
let result = match self {
|
||||||
BackendData::Kms(ref mut state) => {
|
BackendData::Kms(ref mut state) => state.apply_config_for_outputs(
|
||||||
state.apply_config_for_outputs(test_only, loop_handle, shell.clone(), startup_done)
|
test_only,
|
||||||
}
|
loop_handle,
|
||||||
|
shell.clone(),
|
||||||
|
startup_done,
|
||||||
|
clock,
|
||||||
|
),
|
||||||
BackendData::Winit(ref mut state) => state.apply_config_for_outputs(test_only),
|
BackendData::Winit(ref mut state) => state.apply_config_for_outputs(test_only),
|
||||||
BackendData::X11(ref mut state) => state.apply_config_for_outputs(test_only),
|
BackendData::X11(ref mut state) => state.apply_config_for_outputs(test_only),
|
||||||
_ => unreachable!("No backend set when applying output config"),
|
_ => unreachable!("No backend set when applying output config"),
|
||||||
|
|
|
||||||
|
|
@ -32,8 +32,7 @@ impl DrmLeaseHandler for State {
|
||||||
.drm_devices
|
.drm_devices
|
||||||
.get_mut(&node)
|
.get_mut(&node)
|
||||||
.ok_or(LeaseRejected::default())?;
|
.ok_or(LeaseRejected::default())?;
|
||||||
|
let mut builder = DrmLeaseBuilder::new(backend.drm.device());
|
||||||
let mut builder = DrmLeaseBuilder::new(&backend.drm);
|
|
||||||
for conn in request.connectors {
|
for conn in request.connectors {
|
||||||
if let Some((_, crtc)) = backend
|
if let Some((_, crtc)) = backend
|
||||||
.leased_connectors
|
.leased_connectors
|
||||||
|
|
@ -44,6 +43,7 @@ impl DrmLeaseHandler for State {
|
||||||
builder.add_crtc(*crtc);
|
builder.add_crtc(*crtc);
|
||||||
let planes = backend
|
let planes = backend
|
||||||
.drm
|
.drm
|
||||||
|
.device()
|
||||||
.planes(crtc)
|
.planes(crtc)
|
||||||
.map_err(LeaseRejected::with_cause)?;
|
.map_err(LeaseRejected::with_cause)?;
|
||||||
let (primary_plane, primary_plane_claim) = planes
|
let (primary_plane, primary_plane_claim) = planes
|
||||||
|
|
@ -52,6 +52,7 @@ impl DrmLeaseHandler for State {
|
||||||
.find_map(|plane| {
|
.find_map(|plane| {
|
||||||
backend
|
backend
|
||||||
.drm
|
.drm
|
||||||
|
.device_mut()
|
||||||
.claim_plane(plane.handle, *crtc)
|
.claim_plane(plane.handle, *crtc)
|
||||||
.map(|claim| (plane, claim))
|
.map(|claim| (plane, claim))
|
||||||
})
|
})
|
||||||
|
|
@ -60,6 +61,7 @@ impl DrmLeaseHandler for State {
|
||||||
if let Some((cursor, claim)) = planes.cursor.into_iter().find_map(|plane| {
|
if let Some((cursor, claim)) = planes.cursor.into_iter().find_map(|plane| {
|
||||||
backend
|
backend
|
||||||
.drm
|
.drm
|
||||||
|
.device_mut()
|
||||||
.claim_plane(plane.handle, *crtc)
|
.claim_plane(plane.handle, *crtc)
|
||||||
.map(|claim| (plane, claim))
|
.map(|claim| (plane, claim))
|
||||||
}) {
|
}) {
|
||||||
|
|
|
||||||
|
|
@ -140,6 +140,7 @@ impl State {
|
||||||
&mut self.common.workspace_state.update(),
|
&mut self.common.workspace_state.update(),
|
||||||
&self.common.xdg_activation_state,
|
&self.common.xdg_activation_state,
|
||||||
self.common.startup_done.clone(),
|
self.common.startup_done.clone(),
|
||||||
|
&self.common.clock,
|
||||||
);
|
);
|
||||||
if let Err(err) = res {
|
if let Err(err) = res {
|
||||||
warn!(?err, "Failed to apply config. Resetting");
|
warn!(?err, "Failed to apply config. Resetting");
|
||||||
|
|
@ -161,6 +162,7 @@ impl State {
|
||||||
&mut self.common.workspace_state.update(),
|
&mut self.common.workspace_state.update(),
|
||||||
&self.common.xdg_activation_state,
|
&self.common.xdg_activation_state,
|
||||||
self.common.startup_done.clone(),
|
self.common.startup_done.clone(),
|
||||||
|
&self.common.clock,
|
||||||
) {
|
) {
|
||||||
error!(?err, "Failed to reset output config.");
|
error!(?err, "Failed to reset output config.");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue