kms: Optimize buffer imports to secondary gpus
This commit is contained in:
parent
7de8d6e979
commit
46e679ec92
3 changed files with 76 additions and 41 deletions
|
|
@ -33,7 +33,7 @@ use smithay::{
|
||||||
drm::control::{connector, crtc, Device as ControlDevice, ModeTypeFlags},
|
drm::control::{connector, crtc, Device as ControlDevice, ModeTypeFlags},
|
||||||
input::Libinput,
|
input::Libinput,
|
||||||
nix::{fcntl::OFlag, sys::stat::dev_t},
|
nix::{fcntl::OFlag, sys::stat::dev_t},
|
||||||
wayland_server::protocol::wl_output,
|
wayland_server::protocol::{wl_output, wl_surface::WlSurface},
|
||||||
},
|
},
|
||||||
utils::signaling::{Linkable, SignalToken, Signaler},
|
utils::signaling::{Linkable, SignalToken, Signaler},
|
||||||
wayland::output::{Mode as OutputMode, Output, PhysicalProperties},
|
wayland::output::{Mode as OutputMode, Output, PhysicalProperties},
|
||||||
|
|
@ -658,6 +658,40 @@ impl Device {
|
||||||
|
|
||||||
const MAX_CPU_COPIES: usize = 3;
|
const MAX_CPU_COPIES: usize = 3;
|
||||||
|
|
||||||
|
fn render_node_for_output(output: &Output, target_node: DrmNode, shell: &Shell) -> DrmNode {
|
||||||
|
let workspace = shell.active_space(output);
|
||||||
|
let nodes = workspace
|
||||||
|
.get_fullscreen(output)
|
||||||
|
.map(|w| vec![w])
|
||||||
|
.unwrap_or_else(|| workspace.space.windows().collect::<Vec<_>>())
|
||||||
|
.into_iter()
|
||||||
|
.flat_map(|w| {
|
||||||
|
w.toplevel()
|
||||||
|
.get_surface()?
|
||||||
|
.as_ref()
|
||||||
|
.client()?
|
||||||
|
.data_map()
|
||||||
|
.get::<DrmNode>()
|
||||||
|
.cloned()
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
if nodes.contains(&target_node) || nodes.len() < MAX_CPU_COPIES {
|
||||||
|
target_node
|
||||||
|
} else {
|
||||||
|
nodes
|
||||||
|
.iter()
|
||||||
|
.fold(HashMap::new(), |mut count_map, node| {
|
||||||
|
let count = count_map.entry(node).or_insert(0);
|
||||||
|
*count += 1;
|
||||||
|
count_map
|
||||||
|
})
|
||||||
|
.into_iter()
|
||||||
|
.reduce(|a, b| if a.1 > b.1 { a } else { b })
|
||||||
|
.map(|(node, _)| *node)
|
||||||
|
.unwrap_or(target_node)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Surface {
|
impl Surface {
|
||||||
pub fn render_output(
|
pub fn render_output(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
|
@ -673,39 +707,8 @@ impl Surface {
|
||||||
self.surface.as_mut().unwrap().reset_buffers();
|
self.surface.as_mut().unwrap().reset_buffers();
|
||||||
}
|
}
|
||||||
|
|
||||||
let workspace = state.shell.active_space(&self.output);
|
let render_node = render_node_for_output(&self.output, *target_node, &state.shell);
|
||||||
let nodes = workspace
|
let mut renderer = api.renderer(&render_node, &target_node).unwrap();
|
||||||
.get_fullscreen(&self.output)
|
|
||||||
.map(|w| vec![w])
|
|
||||||
.unwrap_or_else(|| workspace.space.windows().collect::<Vec<_>>())
|
|
||||||
.into_iter()
|
|
||||||
.flat_map(|w| {
|
|
||||||
w.toplevel()
|
|
||||||
.get_surface()?
|
|
||||||
.as_ref()
|
|
||||||
.client()?
|
|
||||||
.data_map()
|
|
||||||
.get::<DrmNode>()
|
|
||||||
.cloned()
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
let render_node = if nodes.contains(&target_node) || nodes.len() < MAX_CPU_COPIES {
|
|
||||||
&target_node
|
|
||||||
} else {
|
|
||||||
nodes
|
|
||||||
.iter()
|
|
||||||
.fold(HashMap::new(), |mut count_map, node| {
|
|
||||||
let count = count_map.entry(node).or_insert(0);
|
|
||||||
*count += 1;
|
|
||||||
count_map
|
|
||||||
})
|
|
||||||
.into_iter()
|
|
||||||
.reduce(|a, b| if a.1 > b.1 { a } else { b })
|
|
||||||
.map(|(node, _)| node)
|
|
||||||
.unwrap_or(&target_node)
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut renderer = api.renderer(render_node, &target_node).unwrap();
|
|
||||||
|
|
||||||
let surface = self.surface.as_mut().unwrap();
|
let surface = self.surface.as_mut().unwrap();
|
||||||
let (buffer, age) = surface
|
let (buffer, age) = surface
|
||||||
|
|
@ -841,6 +844,20 @@ impl KmsState {
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
pub fn target_node_for_output(&self, output: &Output) -> Option<DrmNode> {
|
||||||
|
self.devices.iter().find(|(_, dev)| dev.surfaces.values().any(|s| s.output == *output)).map(|(target, _)| target).copied()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn try_early_import(&mut self, surface: &WlSurface, output: &Output, target: DrmNode, shell: &Shell) {
|
||||||
|
let render = render_node_for_output(&output, target, &shell);
|
||||||
|
if let Err(err) = self.api.early_import(
|
||||||
|
surface.as_ref().client().and_then(|c| c.data_map().get::<DrmNode>().cloned()),
|
||||||
|
render,
|
||||||
|
surface,
|
||||||
|
) {
|
||||||
|
slog_scope::debug!("Early import failed: {}", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn schedule_render(
|
pub fn schedule_render(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,11 @@
|
||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
use crate::{config::Config, input::active_output, state::State, utils::SurfaceDropNotifier};
|
use crate::{
|
||||||
|
config::Config,
|
||||||
|
input::active_output,
|
||||||
|
state::{BackendData, State},
|
||||||
|
utils::SurfaceDropNotifier,
|
||||||
|
};
|
||||||
use smithay::{
|
use smithay::{
|
||||||
backend::renderer::utils::on_commit_buffer_handler,
|
backend::renderer::utils::on_commit_buffer_handler,
|
||||||
desktop::{
|
desktop::{
|
||||||
|
|
@ -309,14 +314,18 @@ fn check_grab_preconditions(
|
||||||
}
|
}
|
||||||
|
|
||||||
fn commit(surface: &WlSurface, state: &mut State) {
|
fn commit(surface: &WlSurface, state: &mut State) {
|
||||||
// TODO figure out which output the surface is on.
|
let mut import_nodes = std::collections::HashSet::new();
|
||||||
for output in state.common.shell.outputs() {
|
for output in state.common.shell.outputs_for_surface(&surface) {
|
||||||
//.cloned().collect::<Vec<_>>().into_iter() {
|
if let BackendData::Kms(ref mut kms_state) = &mut state.backend {
|
||||||
|
if let Some(target) = kms_state.target_node_for_output(&output) {
|
||||||
|
if import_nodes.insert(target) {
|
||||||
|
kms_state.try_early_import(surface, &output, target, &state.common.shell);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
state
|
state
|
||||||
.backend
|
.backend
|
||||||
.schedule_render(&state.common.event_loop_handle, output);
|
.schedule_render(&state.common.event_loop_handle, &output);
|
||||||
// let space = state.common.spaces.active_space(output);
|
|
||||||
// get output for surface
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let state = &mut state.common;
|
let state = &mut state.common;
|
||||||
|
|
|
||||||
|
|
@ -598,6 +598,15 @@ impl Shell {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn outputs_for_surface(&self, surface: &WlSurface) -> impl Iterator<Item=Output> {
|
||||||
|
self.space_for_surface(surface)
|
||||||
|
.and_then(|w| if let Some(window) = w.space.window_for_surface(surface, WindowSurfaceType::ALL) {
|
||||||
|
Some(w.space.outputs_for_window(&window).into_iter())
|
||||||
|
} else { None })
|
||||||
|
.into_iter()
|
||||||
|
.flatten()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn space_for_surface(&self, surface: &WlSurface) -> Option<&Workspace> {
|
pub fn space_for_surface(&self, surface: &WlSurface) -> Option<&Workspace> {
|
||||||
self.spaces.iter().find(|workspace| {
|
self.spaces.iter().find(|workspace| {
|
||||||
workspace
|
workspace
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue