kms: Allow updating the primary node
Add more sophisticated code to handle the primary node disappearing. Also overhaul the selection logic to respect our allow/deny-list and prefer devices with built-in connectors before using the boot gpu. This will also allow triggering a primary node switch at runtime for debugging purposes in the future.
This commit is contained in:
parent
4c0c61e94b
commit
8194be30c6
8 changed files with 153 additions and 93 deletions
|
|
@ -4,7 +4,7 @@ use crate::{
|
||||||
backend::render::{output_elements, CursorMode, GlMultiRenderer, CLEAR_COLOR},
|
backend::render::{output_elements, CursorMode, GlMultiRenderer, CLEAR_COLOR},
|
||||||
config::{AdaptiveSync, EdidProduct, OutputConfig, OutputState, ScreenFilter},
|
config::{AdaptiveSync, EdidProduct, OutputConfig, OutputState, ScreenFilter},
|
||||||
shell::Shell,
|
shell::Shell,
|
||||||
utils::prelude::*,
|
utils::{env::dev_list_var, prelude::*},
|
||||||
wayland::protocols::screencopy::Frame,
|
wayland::protocols::screencopy::Frame,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -21,7 +21,7 @@ use smithay::{
|
||||||
compositor::{FrameError, FrameFlags},
|
compositor::{FrameError, FrameFlags},
|
||||||
exporter::gbm::GbmFramebufferExporter,
|
exporter::gbm::GbmFramebufferExporter,
|
||||||
output::DrmOutputManager,
|
output::DrmOutputManager,
|
||||||
DrmDevice, DrmDeviceFd, DrmEvent, DrmNode,
|
DrmDevice, DrmDeviceFd, DrmEvent, DrmNode, NodeType,
|
||||||
},
|
},
|
||||||
egl::{context::ContextPriority, EGLContext, EGLDevice, EGLDisplay},
|
egl::{context::ContextPriority, EGLContext, EGLDevice, EGLDisplay},
|
||||||
session::Session,
|
session::Session,
|
||||||
|
|
@ -312,7 +312,7 @@ impl State {
|
||||||
{
|
{
|
||||||
for (conn, maybe_crtc) in connectors {
|
for (conn, maybe_crtc) in connectors {
|
||||||
match device.connector_added(
|
match device.connector_added(
|
||||||
self.backend.kms().primary_node.as_ref(),
|
self.backend.kms().primary_node.clone(),
|
||||||
conn,
|
conn,
|
||||||
maybe_crtc,
|
maybe_crtc,
|
||||||
(w, 0),
|
(w, 0),
|
||||||
|
|
@ -336,7 +336,14 @@ impl State {
|
||||||
|
|
||||||
// TODO atomic commit all surfaces together and drop surfaces, if it fails due to bandwidth
|
// TODO atomic commit all surfaces together and drop surfaces, if it fails due to bandwidth
|
||||||
|
|
||||||
self.backend.kms().drm_devices.insert(drm_node, device);
|
let kms = self.backend.kms();
|
||||||
|
let was_empty = kms.drm_devices.is_empty();
|
||||||
|
kms.drm_devices.insert(drm_node, device);
|
||||||
|
if was_empty {
|
||||||
|
if let Err(err) = kms.select_primary_gpu(dh) {
|
||||||
|
warn!("Failed to determine a new primary gpu: {}", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.common
|
self.common
|
||||||
|
|
@ -406,7 +413,7 @@ impl State {
|
||||||
|
|
||||||
for (conn, maybe_crtc) in changes.added {
|
for (conn, maybe_crtc) in changes.added {
|
||||||
match device.connector_added(
|
match device.connector_added(
|
||||||
backend.primary_node.as_ref(),
|
backend.primary_node.clone(),
|
||||||
conn,
|
conn,
|
||||||
maybe_crtc,
|
maybe_crtc,
|
||||||
(w, 0),
|
(w, 0),
|
||||||
|
|
@ -466,7 +473,7 @@ impl State {
|
||||||
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();
|
||||||
let backend = self.backend.kms();
|
let backend = self.backend.kms();
|
||||||
if let Some(mut device) = backend.drm_devices.remove(&drm_node) {
|
if let Some(mut device) = backend.drm_devices.shift_remove(&drm_node) {
|
||||||
if let Some(mut leasing_global) = device.leasing_global.take() {
|
if let Some(mut leasing_global) = device.leasing_global.take() {
|
||||||
leasing_global.disable_global::<State>();
|
leasing_global.disable_global::<State>();
|
||||||
}
|
}
|
||||||
|
|
@ -483,6 +490,12 @@ impl State {
|
||||||
.destroy_global::<State>(dh, socket.dmabuf_global);
|
.destroy_global::<State>(dh, socket.dmabuf_global);
|
||||||
dh.remove_global::<State>(socket.drm_global);
|
dh.remove_global::<State>(socket.drm_global);
|
||||||
}
|
}
|
||||||
|
let was_primary = *backend.primary_node.read().unwrap() == Some(device.render_node);
|
||||||
|
if was_primary {
|
||||||
|
if let Err(err) = backend.select_primary_gpu(dh) {
|
||||||
|
warn!("Failed to determine a new primary gpu: {}", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
self.common
|
self.common
|
||||||
.output_configuration_state
|
.output_configuration_state
|
||||||
|
|
@ -558,7 +571,7 @@ impl Device {
|
||||||
|
|
||||||
pub fn connector_added(
|
pub fn connector_added(
|
||||||
&mut self,
|
&mut self,
|
||||||
primary_node: Option<&DrmNode>,
|
primary_node: Arc<RwLock<Option<DrmNode>>>,
|
||||||
conn: connector::Handle,
|
conn: connector::Handle,
|
||||||
maybe_crtc: Option<crtc::Handle>,
|
maybe_crtc: Option<crtc::Handle>,
|
||||||
position: (u32, u32),
|
position: (u32, u32),
|
||||||
|
|
@ -623,7 +636,7 @@ impl Device {
|
||||||
&output,
|
&output,
|
||||||
crtc,
|
crtc,
|
||||||
conn,
|
conn,
|
||||||
primary_node.copied().unwrap_or(self.render_node),
|
primary_node,
|
||||||
self.dev_node,
|
self.dev_node,
|
||||||
self.render_node,
|
self.render_node,
|
||||||
evlh,
|
evlh,
|
||||||
|
|
|
||||||
|
|
@ -4,11 +4,12 @@ use crate::{
|
||||||
config::{AdaptiveSync, OutputState, ScreenFilter},
|
config::{AdaptiveSync, OutputState, ScreenFilter},
|
||||||
shell::Shell,
|
shell::Shell,
|
||||||
state::BackendData,
|
state::BackendData,
|
||||||
utils::prelude::*,
|
utils::{env::dev_var, prelude::*},
|
||||||
};
|
};
|
||||||
|
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
use calloop::LoopSignal;
|
use calloop::LoopSignal;
|
||||||
|
use indexmap::IndexMap;
|
||||||
use render::gles::GbmGlowBackend;
|
use render::gles::GbmGlowBackend;
|
||||||
use smithay::{
|
use smithay::{
|
||||||
backend::{
|
backend::{
|
||||||
|
|
@ -22,13 +23,13 @@ use smithay::{
|
||||||
libinput::{LibinputInputBackend, LibinputSessionInterface},
|
libinput::{LibinputInputBackend, LibinputSessionInterface},
|
||||||
renderer::{glow::GlowRenderer, multigpu::GpuManager},
|
renderer::{glow::GlowRenderer, multigpu::GpuManager},
|
||||||
session::{libseat::LibSeatSession, Event as SessionEvent, Session},
|
session::{libseat::LibSeatSession, Event as SessionEvent, Session},
|
||||||
udev::{all_gpus, primary_gpu, UdevBackend, UdevEvent},
|
udev::{primary_gpu, UdevBackend, UdevEvent},
|
||||||
},
|
},
|
||||||
output::Output,
|
output::Output,
|
||||||
reexports::{
|
reexports::{
|
||||||
calloop::{Dispatcher, EventLoop, LoopHandle},
|
calloop::{Dispatcher, EventLoop, LoopHandle},
|
||||||
drm::{
|
drm::{
|
||||||
control::{crtc, Device as _},
|
control::{connector::Interface, crtc, Device as _},
|
||||||
Device as _,
|
Device as _,
|
||||||
},
|
},
|
||||||
input::{self, Libinput},
|
input::{self, Libinput},
|
||||||
|
|
@ -65,9 +66,9 @@ use super::render::{init_shaders, output_elements, CursorMode, CLEAR_COLOR};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct KmsState {
|
pub struct KmsState {
|
||||||
pub drm_devices: HashMap<DrmNode, Device>,
|
pub drm_devices: IndexMap<DrmNode, Device>,
|
||||||
pub input_devices: HashMap<String, input::Device>,
|
pub input_devices: HashMap<String, input::Device>,
|
||||||
pub primary_node: Option<DrmNode>,
|
pub primary_node: Arc<RwLock<Option<DrmNode>>>,
|
||||||
// Mesa llvmpipe renderer, if supported and there are no render nodes
|
// Mesa llvmpipe renderer, if supported and there are no render nodes
|
||||||
pub software_renderer: Option<GlowRenderer>,
|
pub software_renderer: Option<GlowRenderer>,
|
||||||
pub api: GpuManager<GbmGlowBackend<DrmDeviceFd>>,
|
pub api: GpuManager<GbmGlowBackend<DrmDeviceFd>>,
|
||||||
|
|
@ -90,24 +91,6 @@ pub fn init_backend(
|
||||||
let libinput_context = init_libinput(dh, &session, &event_loop.handle())
|
let libinput_context = init_libinput(dh, &session, &event_loop.handle())
|
||||||
.context("Failed to initialize libinput backend")?;
|
.context("Failed to initialize libinput backend")?;
|
||||||
|
|
||||||
// get our primary gpu
|
|
||||||
let primary = determine_primary_gpu(session.seat());
|
|
||||||
if let Some(primary) = primary.as_ref() {
|
|
||||||
info!("Using {} as primary gpu for rendering.", primary);
|
|
||||||
}
|
|
||||||
|
|
||||||
let software_renderer = if primary.is_none() {
|
|
||||||
match software_renderer() {
|
|
||||||
Ok(renderer) => Some(renderer),
|
|
||||||
Err(err) => {
|
|
||||||
error!(?err, "Failed to initialize software EGL renderer.");
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
// watch for gpu events
|
// watch for gpu events
|
||||||
let udev_dispatcher = init_udev(session.seat(), &event_loop.handle())
|
let udev_dispatcher = init_udev(session.seat(), &event_loop.handle())
|
||||||
.context("Failed to initialize udev connection")?;
|
.context("Failed to initialize udev connection")?;
|
||||||
|
|
@ -134,10 +117,10 @@ pub fn init_backend(
|
||||||
|
|
||||||
// finish backend initialization
|
// finish backend initialization
|
||||||
state.backend = BackendData::Kms(KmsState {
|
state.backend = BackendData::Kms(KmsState {
|
||||||
drm_devices: HashMap::new(),
|
drm_devices: IndexMap::new(),
|
||||||
input_devices: HashMap::new(),
|
input_devices: HashMap::new(),
|
||||||
primary_node: primary,
|
primary_node: Arc::new(RwLock::new(None)),
|
||||||
software_renderer,
|
software_renderer: None,
|
||||||
api: GpuManager::new(GbmGlowBackend::new()).context("Failed to initialize gpu backend")?,
|
api: GpuManager::new(GbmGlowBackend::new()).context("Failed to initialize gpu backend")?,
|
||||||
|
|
||||||
session,
|
session,
|
||||||
|
|
@ -146,9 +129,6 @@ pub fn init_backend(
|
||||||
syncobj_state: None,
|
syncobj_state: None,
|
||||||
});
|
});
|
||||||
|
|
||||||
// start x11
|
|
||||||
state.launch_xwayland(primary);
|
|
||||||
|
|
||||||
// manually add already present gpus
|
// manually add already present gpus
|
||||||
for (dev, path) in udev_dispatcher.as_source_ref().device_list() {
|
for (dev, path) in udev_dispatcher.as_source_ref().device_list() {
|
||||||
if let Err(err) = state.device_added(dev, path.into(), dh) {
|
if let Err(err) = state.device_added(dev, path.into(), dh) {
|
||||||
|
|
@ -156,24 +136,9 @@ pub fn init_backend(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !crate::utils::env::bool_var("COSMIC_DISABLE_SYNCOBJ").unwrap_or(false) {
|
// start x11
|
||||||
let kms = match &mut state.backend {
|
let primary = state.backend.kms().primary_node.read().unwrap().clone();
|
||||||
BackendData::Kms(kms) => kms,
|
state.launch_xwayland(primary);
|
||||||
_ => unreachable!(),
|
|
||||||
};
|
|
||||||
if let Some(primary_node) = kms
|
|
||||||
.primary_node
|
|
||||||
.and_then(|node| node.node_with_type(NodeType::Primary).and_then(|x| x.ok()))
|
|
||||||
{
|
|
||||||
if let Some(device) = kms.drm_devices.get(&primary_node) {
|
|
||||||
let import_device = device.drm.device().device_fd().clone();
|
|
||||||
if supports_syncobj_eventfd(&import_device) {
|
|
||||||
let syncobj_state = DrmSyncobjState::new::<State>(&dh, import_device);
|
|
||||||
kms.syncobj_state = Some(syncobj_state);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
@ -217,32 +182,51 @@ fn init_libinput(
|
||||||
Ok(libinput_context)
|
Ok(libinput_context)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn determine_primary_gpu(seat: String) -> Option<DrmNode> {
|
fn determine_boot_gpu(seat: String) -> Option<DrmNode> {
|
||||||
if let Some(node) = std::env::var("COSMIC_RENDER_DEVICE")
|
let primary_node = primary_gpu(&seat)
|
||||||
.ok()
|
.ok()
|
||||||
.and_then(|x| DrmNode::from_path(x).ok())
|
.flatten()
|
||||||
{
|
.and_then(|x| DrmNode::from_path(x).ok());
|
||||||
Some(node)
|
primary_node.and_then(|x| x.node_with_type(NodeType::Render).and_then(Result::ok))
|
||||||
} else {
|
}
|
||||||
let primary_node = primary_gpu(&seat)
|
|
||||||
.ok()
|
|
||||||
.flatten()
|
|
||||||
.and_then(|x| DrmNode::from_path(x).ok());
|
|
||||||
primary_node
|
|
||||||
.and_then(|x| x.node_with_type(NodeType::Render).and_then(Result::ok))
|
|
||||||
.or_else(|| {
|
|
||||||
for dev in all_gpus(&seat).expect("Failed to query gpus") {
|
|
||||||
if let Some(node) = DrmNode::from_path(dev)
|
|
||||||
.ok()
|
|
||||||
.and_then(|x| x.node_with_type(NodeType::Render).and_then(Result::ok))
|
|
||||||
{
|
|
||||||
return Some(node);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
None
|
fn determine_primary_gpu(
|
||||||
})
|
drm_devices: &IndexMap<DrmNode, Device>,
|
||||||
|
seat: String,
|
||||||
|
) -> Result<Option<DrmNode>> {
|
||||||
|
if let Some(device) = dev_var("COSMIC_RENDER_DEVICE") {
|
||||||
|
if let Some(node) = drm_devices
|
||||||
|
.values()
|
||||||
|
.find_map(|dev| device.matches(&dev.render_node).then_some(dev.render_node))
|
||||||
|
{
|
||||||
|
return Ok(Some(node));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// try to find builtin display
|
||||||
|
for dev in drm_devices.values() {
|
||||||
|
if dev.surfaces.values().any(|s| {
|
||||||
|
if let Some(conn_info) = dev.drm.device().get_connector(s.connector, false).ok() {
|
||||||
|
let i = conn_info.interface();
|
||||||
|
i == Interface::EmbeddedDisplayPort || i == Interface::LVDS || i == Interface::DSI
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}) {
|
||||||
|
return Ok(Some(dev.render_node));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// else try to find the boot gpu
|
||||||
|
let boot = determine_boot_gpu(seat);
|
||||||
|
if let Some(boot) = boot {
|
||||||
|
if drm_devices.values().any(|dev| dev.render_node == boot) {
|
||||||
|
return Ok(Some(boot));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// else just take the first
|
||||||
|
Ok(drm_devices.values().next().map(|dev| dev.render_node))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create `GlowRenderer` for `EGL_MESA_device_software` device, if present
|
/// Create `GlowRenderer` for `EGL_MESA_device_software` device, if present
|
||||||
|
|
@ -375,6 +359,55 @@ impl State {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl KmsState {
|
impl KmsState {
|
||||||
|
fn select_primary_gpu(&mut self, dh: &DisplayHandle) -> Result<()> {
|
||||||
|
// We don't have to check the allow/blocklist here,
|
||||||
|
// as any disallowed devices won't be in `self.drm_devices`.
|
||||||
|
|
||||||
|
let mut primary_node = self.primary_node.write().unwrap();
|
||||||
|
let _ = primary_node.take(); // if we error don't leave an old node in place
|
||||||
|
*primary_node = determine_primary_gpu(&self.drm_devices, self.session.seat())?;
|
||||||
|
|
||||||
|
if let Some(node) = *primary_node {
|
||||||
|
info!("Using {} as primary gpu for rendering.", node);
|
||||||
|
self.software_renderer.take();
|
||||||
|
} else if self.software_renderer.is_none() {
|
||||||
|
info!("Failed to find a suitable gpu, using software renderingr");
|
||||||
|
self.software_renderer = match software_renderer() {
|
||||||
|
Ok(renderer) => Some(renderer),
|
||||||
|
Err(err) => {
|
||||||
|
error!(?err, "Failed to initialize software EGL renderer.");
|
||||||
|
None
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if !crate::utils::env::bool_var("COSMIC_DISABLE_SYNCOBJ").unwrap_or(false) {
|
||||||
|
if let Some(primary_node) = primary_node
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|node| node.node_with_type(NodeType::Primary).and_then(|x| x.ok()))
|
||||||
|
{
|
||||||
|
if let Some(device) = self.drm_devices.get(&primary_node) {
|
||||||
|
let import_device = device.drm.device().device_fd().clone();
|
||||||
|
if supports_syncobj_eventfd(&import_device) {
|
||||||
|
if let Some(state) = self.syncobj_state.as_mut() {
|
||||||
|
state.update_device(import_device);
|
||||||
|
} else {
|
||||||
|
let syncobj_state = DrmSyncobjState::new::<State>(&dh, import_device);
|
||||||
|
self.syncobj_state = Some(syncobj_state);
|
||||||
|
}
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(old_state) = self.syncobj_state.take() {
|
||||||
|
dh.remove_global::<State>(old_state.into_global());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn switch_vt(&mut self, num: i32) -> Result<(), anyhow::Error> {
|
pub fn switch_vt(&mut self, num: i32) -> Result<(), anyhow::Error> {
|
||||||
self.session.change_vt(num).map_err(Into::into)
|
self.session.change_vt(num).map_err(Into::into)
|
||||||
}
|
}
|
||||||
|
|
@ -459,7 +492,7 @@ impl KmsState {
|
||||||
let mut used_devices = HashSet::new();
|
let mut used_devices = HashSet::new();
|
||||||
|
|
||||||
for device in self.drm_devices.values_mut() {
|
for device in self.drm_devices.values_mut() {
|
||||||
if device.in_use(self.primary_node.as_ref()) {
|
if device.in_use(self.primary_node.read().unwrap().as_ref()) {
|
||||||
if device.egl.is_none() {
|
if device.egl.is_none() {
|
||||||
let egl = init_egl(&device.gbm).context("Failed to create EGL context")?;
|
let egl = init_egl(&device.gbm).context("Failed to create EGL context")?;
|
||||||
let mut renderer = unsafe {
|
let mut renderer = unsafe {
|
||||||
|
|
@ -495,7 +528,7 @@ impl KmsState {
|
||||||
}
|
}
|
||||||
|
|
||||||
// trigger re-evaluation... urgh
|
// trigger re-evaluation... urgh
|
||||||
if let Some(primary_node) = self.primary_node.as_ref() {
|
if let Some(primary_node) = self.primary_node.read().unwrap().as_ref() {
|
||||||
let _ = self.api.single_renderer(primary_node);
|
let _ = self.api.single_renderer(primary_node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -654,7 +687,7 @@ impl KmsState {
|
||||||
if !test_only {
|
if !test_only {
|
||||||
for (conn, crtc) in new_pairings {
|
for (conn, crtc) in new_pairings {
|
||||||
let (output, _) = device.connector_added(
|
let (output, _) = device.connector_added(
|
||||||
self.primary_node.as_ref(),
|
self.primary_node.clone(),
|
||||||
conn,
|
conn,
|
||||||
Some(crtc),
|
Some(crtc),
|
||||||
(w, 0),
|
(w, 0),
|
||||||
|
|
|
||||||
|
|
@ -119,7 +119,7 @@ pub struct Surface {
|
||||||
pub struct SurfaceThreadState {
|
pub struct SurfaceThreadState {
|
||||||
// rendering
|
// rendering
|
||||||
api: GpuManager<GbmGlowBackend<DrmDeviceFd>>,
|
api: GpuManager<GbmGlowBackend<DrmDeviceFd>>,
|
||||||
primary_node: DrmNode,
|
primary_node: Arc<RwLock<Option<DrmNode>>>,
|
||||||
target_node: DrmNode,
|
target_node: DrmNode,
|
||||||
active: Arc<AtomicBool>,
|
active: Arc<AtomicBool>,
|
||||||
vrr_mode: AdaptiveSync,
|
vrr_mode: AdaptiveSync,
|
||||||
|
|
@ -228,7 +228,7 @@ impl Surface {
|
||||||
output: &Output,
|
output: &Output,
|
||||||
crtc: crtc::Handle,
|
crtc: crtc::Handle,
|
||||||
connector: connector::Handle,
|
connector: connector::Handle,
|
||||||
primary_node: DrmNode,
|
primary_node: Arc<RwLock<Option<DrmNode>>>,
|
||||||
dev_node: DrmNode,
|
dev_node: DrmNode,
|
||||||
target_node: DrmNode,
|
target_node: DrmNode,
|
||||||
evlh: &LoopHandle<'static, State>,
|
evlh: &LoopHandle<'static, State>,
|
||||||
|
|
@ -469,7 +469,7 @@ impl Drop for Surface {
|
||||||
|
|
||||||
fn surface_thread(
|
fn surface_thread(
|
||||||
output: Output,
|
output: Output,
|
||||||
primary_node: DrmNode,
|
primary_node: Arc<RwLock<Option<DrmNode>>>,
|
||||||
target_node: DrmNode,
|
target_node: DrmNode,
|
||||||
shell: Arc<RwLock<Shell>>,
|
shell: Arc<RwLock<Shell>>,
|
||||||
active: Arc<AtomicBool>,
|
active: Arc<AtomicBool>,
|
||||||
|
|
@ -956,7 +956,11 @@ impl SurfaceThreadState {
|
||||||
|
|
||||||
let render_node = render_node_for_output(
|
let render_node = render_node_for_output(
|
||||||
self.mirroring.as_ref().unwrap_or(&self.output),
|
self.mirroring.as_ref().unwrap_or(&self.output),
|
||||||
&self.primary_node,
|
self.primary_node
|
||||||
|
.read()
|
||||||
|
.unwrap()
|
||||||
|
.as_ref()
|
||||||
|
.unwrap_or(&self.target_node),
|
||||||
&self.target_node,
|
&self.target_node,
|
||||||
&*self.shell.read().unwrap(),
|
&*self.shell.read().unwrap(),
|
||||||
);
|
);
|
||||||
|
|
@ -1821,6 +1825,8 @@ fn source_node_for_surface(w: &WlSurface) -> Option<DrmNode> {
|
||||||
.flatten()
|
.flatten()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Introduce can_shared_dmabuf_framebuffer for cases where we might select another gpu
|
||||||
|
// and composite on target if not possible to finally get rid of "primary"
|
||||||
fn render_node_for_output(
|
fn render_node_for_output(
|
||||||
output: &Output,
|
output: &Output,
|
||||||
primary_node: &DrmNode,
|
primary_node: &DrmNode,
|
||||||
|
|
|
||||||
|
|
@ -671,7 +671,7 @@ impl State {
|
||||||
ClientState {
|
ClientState {
|
||||||
compositor_client_state: CompositorClientState::default(),
|
compositor_client_state: CompositorClientState::default(),
|
||||||
advertised_drm_node: match &self.backend {
|
advertised_drm_node: match &self.backend {
|
||||||
BackendData::Kms(kms_state) => kms_state.primary_node,
|
BackendData::Kms(kms_state) => *kms_state.primary_node.read().unwrap(),
|
||||||
_ => None,
|
_ => None,
|
||||||
},
|
},
|
||||||
privileged: !enable_wayland_security(),
|
privileged: !enable_wayland_security(),
|
||||||
|
|
|
||||||
|
|
@ -104,7 +104,7 @@ pub fn screenshot_window(state: &mut State, surface: &CosmicSurface) {
|
||||||
.backend
|
.backend
|
||||||
.offscreen_renderer(|kms| {
|
.offscreen_renderer(|kms| {
|
||||||
advertised_node_for_surface(&wl_surface, &state.common.display_handle)
|
advertised_node_for_surface(&wl_surface, &state.common.display_handle)
|
||||||
.or(kms.primary_node)
|
.or(*kms.primary_node.read().unwrap())
|
||||||
})
|
})
|
||||||
.with_context(|| "Failed to get renderer for screenshot")
|
.with_context(|| "Failed to get renderer for screenshot")
|
||||||
.and_then(|renderer| match renderer {
|
.and_then(|renderer| match renderer {
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ impl BufferHandler for State {
|
||||||
if let BackendData::Kms(kms_state) = &mut self.backend {
|
if let BackendData::Kms(kms_state) = &mut self.backend {
|
||||||
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.read().unwrap().as_ref()) {
|
||||||
if let Err(err) = kms_state.refresh_used_devices() {
|
if let Err(err) = kms_state.refresh_used_devices() {
|
||||||
warn!(?err, "Failed to init devices.");
|
warn!(?err, "Failed to init devices.");
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -355,7 +355,10 @@ fn constraints_for_output(output: &Output, backend: &mut BackendData) -> Option<
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut renderer = backend
|
let mut renderer = backend
|
||||||
.offscreen_renderer(|kms| kms.target_node_for_output(&output).or(kms.primary_node))
|
.offscreen_renderer(|kms| {
|
||||||
|
kms.target_node_for_output(&output)
|
||||||
|
.or(*kms.primary_node.read().unwrap())
|
||||||
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
Some(constraints_for_renderer(mode, renderer.as_mut()))
|
Some(constraints_for_renderer(mode, renderer.as_mut()))
|
||||||
}
|
}
|
||||||
|
|
@ -376,7 +379,7 @@ fn constraints_for_toplevel(
|
||||||
})
|
})
|
||||||
.flatten();
|
.flatten();
|
||||||
|
|
||||||
dma_node.or(kms.primary_node)
|
dma_node.or(*kms.primary_node.read().unwrap())
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -337,7 +337,9 @@ pub fn render_workspace_to_buffer(
|
||||||
let common = &mut state.common;
|
let common = &mut state.common;
|
||||||
|
|
||||||
let renderer = match state.backend.offscreen_renderer(|kms| {
|
let renderer = match state.backend.offscreen_renderer(|kms| {
|
||||||
let render_node = kms.target_node_for_output(&output).or(kms.primary_node)?;
|
let render_node = kms
|
||||||
|
.target_node_for_output(&output)
|
||||||
|
.or(*kms.primary_node.read().unwrap())?;
|
||||||
let target_node = get_dmabuf(&buffer)
|
let target_node = get_dmabuf(&buffer)
|
||||||
.ok()
|
.ok()
|
||||||
.and_then(|dma| dma.node())
|
.and_then(|dma| dma.node())
|
||||||
|
|
@ -591,7 +593,7 @@ pub fn render_window_to_buffer(
|
||||||
})
|
})
|
||||||
.flatten()
|
.flatten()
|
||||||
})
|
})
|
||||||
.or(kms.primary_node)
|
.or(*kms.primary_node.read().unwrap())
|
||||||
}) {
|
}) {
|
||||||
Ok(renderer) => renderer,
|
Ok(renderer) => renderer,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
|
|
@ -745,7 +747,10 @@ pub fn render_cursor_to_buffer(
|
||||||
}
|
}
|
||||||
|
|
||||||
let common = &mut state.common;
|
let common = &mut state.common;
|
||||||
let renderer = match state.backend.offscreen_renderer(|kms| kms.primary_node) {
|
let renderer = match state
|
||||||
|
.backend
|
||||||
|
.offscreen_renderer(|kms| *kms.primary_node.read().unwrap())
|
||||||
|
{
|
||||||
Ok(renderer) => renderer,
|
Ok(renderer) => renderer,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
warn!(?err, "Couldn't use node for screencopy");
|
warn!(?err, "Couldn't use node for screencopy");
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue