screencopy: Fix missing contents on multigpu setups

This commit is contained in:
Victoria Brekenfeld 2022-12-02 14:09:23 +01:00
parent 010faf3789
commit 69646f1c95

View file

@ -17,11 +17,11 @@ use smithay::{
buffer_dimensions, buffer_type, buffer_dimensions, buffer_type,
damage::{DamageTrackedRenderer, DamageTrackedRendererError}, damage::{DamageTrackedRenderer, DamageTrackedRendererError},
element::{ element::{
surface::WaylandSurfaceRenderElement, AsRenderElements, RenderElementStates, surface::WaylandSurfaceRenderElement, AsRenderElements, RenderElement,
RenderElementStates,
}, },
gles2::Gles2Renderbuffer, gles2::{Gles2Error, Gles2Renderbuffer},
glow::GlowRenderer, Bind, Blit, BufferType, ExportMem, ImportAll, ImportMem, Offscreen, Renderer,
Bind, BufferType, ExportMem, ImportAll, Offscreen, Renderer,
}, },
}, },
desktop::Window, desktop::Window,
@ -30,7 +30,7 @@ use smithay::{
protocol::{wl_buffer::WlBuffer, wl_shm::Format as ShmFormat, wl_surface::WlSurface}, protocol::{wl_buffer::WlBuffer, wl_shm::Format as ShmFormat, wl_surface::WlSurface},
Resource, Resource,
}, },
utils::{IsAlive, Physical, Rectangle, Scale, Transform}, utils::{IsAlive, Logical, Physical, Rectangle, Scale, Transform},
wayland::{ wayland::{
dmabuf::get_dmabuf, dmabuf::get_dmabuf,
shm::{with_buffer_contents, with_buffer_contents_mut}, shm::{with_buffer_contents, with_buffer_contents_mut},
@ -38,7 +38,12 @@ use smithay::{
}; };
use crate::{ use crate::{
backend::render::{cursor, render_output, render_workspace, CursorMode, CLEAR_COLOR}, backend::render::{
cursor,
element::{AsGlowRenderer, CosmicElement},
render_output, render_workspace, CursorMode, CLEAR_COLOR,
},
shell::CosmicMappedRenderElement,
state::{BackendData, ClientState, Common, State}, state::{BackendData, ClientState, Common, State},
utils::prelude::OutputExt, utils::prelude::OutputExt,
wayland::protocols::{ wayland::protocols::{
@ -579,30 +584,33 @@ pub fn render_output_to_buffer(
return Err((FailureReason::InvalidSize, anyhow!("Output changed mode"))); return Err((FailureReason::InvalidSize, anyhow!("Output changed mode")));
} }
let node = node_from_params(&params, &mut state.backend, Some(output)); fn render_fn<R>(
let mut _tmp_multirenderer = None; node: Option<&DrmNode>,
let renderer = match &mut state.backend { buffer: &WlBuffer,
BackendData::Kms(kms) => { renderer: &mut R,
_tmp_multirenderer = Some( dtr: &mut DamageTrackedRenderer,
kms.api age: usize,
.renderer::<Gles2Renderbuffer>(node.as_ref().unwrap(), node.as_ref().unwrap()) common: &mut Common,
.map_err(|err| (FailureReason::Unspec, err.into()))?, session: &Session,
); output: &Output,
_tmp_multirenderer.as_mut().unwrap().as_mut() ) -> Result<
} (Option<Vec<Rectangle<i32, Physical>>>, RenderElementStates),
BackendData::Winit(winit) => winit.backend.renderer(), DamageTrackedRendererError<R>,
BackendData::X11(x11) => &mut x11.renderer, >
_ => unreachable!(), where
}; R: Renderer
+ ImportAll
let common = &mut state.common; + ImportMem
render_session::<_, _>( + ExportMem
node, + Bind<Dmabuf>
renderer, + Offscreen<Gles2Renderbuffer>
session, + Blit<Dmabuf>
&params, + AsGlowRenderer,
output.current_transform(), <R as Renderer>::TextureId: Clone + 'static,
|node, buffer, renderer, dtr, age| { <R as Renderer>::Error: From<Gles2Error>,
CosmicElement<R>: RenderElement<R>,
CosmicMappedRenderElement<R>: RenderElement<R>,
{
let cursor_mode = match session.cursor_mode() { let cursor_mode = match session.cursor_mode() {
ScreencopyCursorMode::Embedded => CursorMode::All, ScreencopyCursorMode::Embedded => CursorMode::All,
ScreencopyCursorMode::Captured(_) | ScreencopyCursorMode::None => CursorMode::None, ScreencopyCursorMode::Captured(_) | ScreencopyCursorMode::None => CursorMode::None,
@ -638,9 +646,55 @@ pub fn render_output_to_buffer(
None, None,
) )
} }
}
let common = &mut state.common;
let node = node_from_params(&params, &mut state.backend, Some(output));
match &mut state.backend {
BackendData::Kms(kms) => {
let mut multirenderer = kms
.api
.renderer::<Gles2Renderbuffer>(node.as_ref().unwrap(), node.as_ref().unwrap())
.map_err(|err| (FailureReason::Unspec, err.into()))?;
render_session::<_, _>(
node,
&mut multirenderer,
session,
&params,
output.current_transform(),
|node, buffer, renderer, dtr, age| {
render_fn(node, buffer, renderer, dtr, age, common, session, output)
}, },
) )
.map_err(|err| (FailureReason::Unspec, err.into())) .map_err(|err| match err {
DamageTrackedRendererError::OutputNoMode(x) => (FailureReason::Unspec, x.into()),
DamageTrackedRendererError::Rendering(x) => (FailureReason::Unspec, x.into()),
})
}
BackendData::Winit(winit) => render_session::<_, _>(
node,
winit.backend.renderer(),
session,
&params,
output.current_transform(),
|node, buffer, renderer, dtr, age| {
render_fn(node, buffer, renderer, dtr, age, common, session, output)
},
)
.map_err(|err| (FailureReason::Unspec, err.into())),
BackendData::X11(x11) => render_session::<_, _>(
node,
&mut x11.renderer,
session,
&params,
output.current_transform(),
|node, buffer, renderer, dtr, age| {
render_fn(node, buffer, renderer, dtr, age, common, session, output)
},
)
.map_err(|err| (FailureReason::Unspec, err.into())),
_ => unreachable!(),
}
} }
pub fn render_workspace_to_buffer( pub fn render_workspace_to_buffer(
@ -658,30 +712,34 @@ pub fn render_workspace_to_buffer(
return Err((FailureReason::InvalidSize, anyhow!("Output changed mode"))); return Err((FailureReason::InvalidSize, anyhow!("Output changed mode")));
} }
let node = node_from_params(&params, &mut state.backend, Some(output)); fn render_fn<R>(
let mut _tmp_multirenderer = None; node: Option<&DrmNode>,
let renderer = match &mut state.backend { buffer: &WlBuffer,
BackendData::Kms(kms) => { renderer: &mut R,
_tmp_multirenderer = Some( dtr: &mut DamageTrackedRenderer,
kms.api age: usize,
.renderer::<Gles2Renderbuffer>(node.as_ref().unwrap(), node.as_ref().unwrap()) common: &mut Common,
.map_err(|err| (FailureReason::Unspec, err.into()))?, session: &Session,
); output: &Output,
_tmp_multirenderer.as_mut().unwrap().as_mut() handle: &WorkspaceHandle,
} ) -> Result<
BackendData::Winit(winit) => winit.backend.renderer(), (Option<Vec<Rectangle<i32, Physical>>>, RenderElementStates),
BackendData::X11(x11) => &mut x11.renderer, DamageTrackedRendererError<R>,
_ => unreachable!(), >
}; where
R: Renderer
let common = &mut state.common; + ImportAll
render_session::<_, _>( + ImportMem
node, + ExportMem
renderer, + Bind<Dmabuf>
session, + Offscreen<Gles2Renderbuffer>
&params, + Blit<Dmabuf>
output.current_transform(), + AsGlowRenderer,
|node, buffer, renderer, dtr, age| { <R as Renderer>::TextureId: Clone + 'static,
<R as Renderer>::Error: From<Gles2Error>,
CosmicElement<R>: RenderElement<R>,
CosmicMappedRenderElement<R>: RenderElement<R>,
{
let cursor_mode = match session.cursor_mode() { let cursor_mode = match session.cursor_mode() {
ScreencopyCursorMode::Embedded => CursorMode::All, ScreencopyCursorMode::Embedded => CursorMode::All,
ScreencopyCursorMode::Captured(_) | ScreencopyCursorMode::None => CursorMode::None, ScreencopyCursorMode::Captured(_) | ScreencopyCursorMode::None => CursorMode::None,
@ -718,9 +776,61 @@ pub fn render_workspace_to_buffer(
None, None,
) )
} }
}
let node = node_from_params(&params, &mut state.backend, Some(output));
let common = &mut state.common;
match &mut state.backend {
BackendData::Kms(kms) => {
let mut multirenderer = kms
.api
.renderer::<Gles2Renderbuffer>(node.as_ref().unwrap(), node.as_ref().unwrap())
.map_err(|err| (FailureReason::Unspec, err.into()))?;
render_session::<_, _>(
node,
&mut multirenderer,
session,
&params,
output.current_transform(),
|node, buffer, renderer, dtr, age| {
render_fn(
node, buffer, renderer, dtr, age, common, session, output, handle,
)
}, },
) )
.map_err(|err| (FailureReason::Unspec, err.into())) .map_err(|err| match err {
DamageTrackedRendererError::OutputNoMode(x) => (FailureReason::Unspec, x.into()),
DamageTrackedRendererError::Rendering(x) => (FailureReason::Unspec, x.into()),
})
}
BackendData::Winit(winit) => render_session::<_, _>(
node,
winit.backend.renderer(),
session,
&params,
output.current_transform(),
|node, buffer, renderer, dtr, age| {
render_fn(
node, buffer, renderer, dtr, age, common, session, output, handle,
)
},
)
.map_err(|err| (FailureReason::Unspec, err.into())),
BackendData::X11(x11) => render_session::<_, _>(
node,
&mut x11.renderer,
session,
&params,
output.current_transform(),
|node, buffer, renderer, dtr, age| {
render_fn(
node, buffer, renderer, dtr, age, common, session, output, handle,
)
},
)
.map_err(|err| (FailureReason::Unspec, err.into())),
_ => unreachable!(),
}
} }
smithay::render_elements! { smithay::render_elements! {
@ -741,44 +851,45 @@ pub fn render_window_to_buffer(
return Err((FailureReason::InvalidSize, anyhow!("Window changed size"))); return Err((FailureReason::InvalidSize, anyhow!("Window changed size")));
} }
let node = node_from_params(&params, &mut state.backend, None); fn render_fn<R>(
let mut _tmp_multirenderer = None; buffer: &WlBuffer,
let renderer = match &mut state.backend { renderer: &mut R,
BackendData::Kms(kms) => { dtr: &mut DamageTrackedRenderer,
_tmp_multirenderer = Some( age: usize,
kms.api session: &Session,
.renderer::<Gles2Renderbuffer>(node.as_ref().unwrap(), node.as_ref().unwrap()) common: &mut Common,
.map_err(|err| (FailureReason::Unspec, err.into()))?, window: &Window,
); geometry: Rectangle<i32, Logical>,
_tmp_multirenderer.as_mut().unwrap().as_mut() ) -> Result<
} (Option<Vec<Rectangle<i32, Physical>>>, RenderElementStates),
BackendData::Winit(winit) => winit.backend.renderer(), DamageTrackedRendererError<R>,
BackendData::X11(x11) => &mut x11.renderer, >
_ => unreachable!(), where
}; R: Renderer
+ ImportAll
render_session::<_, _>( + ImportMem
node, + ExportMem
renderer, + Bind<Dmabuf>
session, + Offscreen<Gles2Renderbuffer>
&params, + Blit<Dmabuf>
Transform::Normal, + AsGlowRenderer,
|_node, buffer, renderer, dtr, age| { <R as Renderer>::TextureId: Clone + 'static,
<R as Renderer>::Error: From<Gles2Error>,
CosmicElement<R>: RenderElement<R>,
CosmicMappedRenderElement<R>: RenderElement<R>,
{
// TODO cursor elements! // TODO cursor elements!
let mut elements = AsRenderElements::<GlowRenderer>::render_elements::< let mut elements = AsRenderElements::<R>::render_elements::<WindowCaptureElement<R>>(
WindowCaptureElement<GlowRenderer>,
>(
window, window,
renderer, renderer,
(-geometry.loc.x, -geometry.loc.y).into(), (-geometry.loc.x, -geometry.loc.y).into(),
Scale::from(1.0), Scale::from(1.0),
); );
for seat in state.common.seats() { for seat in common.seats() {
if let Some(location) = { if let Some(location) = {
// we need to find the mapped element in that case // we need to find the mapped element in that case
if let Some(mapped) = state if let Some(mapped) = common
.common
.shell .shell
.element_for_surface(window.toplevel().wl_surface()) .element_for_surface(window.toplevel().wl_surface())
{ {
@ -801,7 +912,7 @@ pub fn render_window_to_buffer(
seat, seat,
location, location,
1.0.into(), 1.0.into(),
state.common.clock.now(), common.clock.now(),
true, true,
) )
.into_iter() .into_iter()
@ -811,12 +922,7 @@ pub fn render_window_to_buffer(
if let Some(wl_surface) = get_dnd_icon(seat) { if let Some(wl_surface) = get_dnd_icon(seat) {
elements.extend( elements.extend(
cursor::draw_dnd_icon( cursor::draw_dnd_icon(renderer, &wl_surface, location.to_i32_round(), 1.0)
renderer,
&wl_surface,
location.to_i32_round(),
1.0,
)
.into_iter() .into_iter()
.map(WindowCaptureElement::from), .map(WindowCaptureElement::from),
); );
@ -838,9 +944,61 @@ pub fn render_window_to_buffer(
} }
dtr.render_output(renderer, age, &elements, CLEAR_COLOR, None) dtr.render_output(renderer, age, &elements, CLEAR_COLOR, None)
}
let node = node_from_params(&params, &mut state.backend, None);
let common = &mut state.common;
match &mut state.backend {
BackendData::Kms(kms) => {
let mut multirenderer = kms
.api
.renderer::<Gles2Renderbuffer>(node.as_ref().unwrap(), node.as_ref().unwrap())
.map_err(|err| (FailureReason::Unspec, err.into()))?;
render_session::<_, _>(
node,
&mut multirenderer,
session,
&params,
Transform::Normal,
|_node, buffer, renderer, dtr, age| {
render_fn(
buffer, renderer, dtr, age, session, common, window, geometry,
)
}, },
) )
.map_err(|err| (FailureReason::Unspec, err.into())) .map_err(|err| match err {
DamageTrackedRendererError::OutputNoMode(x) => (FailureReason::Unspec, x.into()),
DamageTrackedRendererError::Rendering(x) => (FailureReason::Unspec, x.into()),
})
}
BackendData::Winit(winit) => render_session::<_, _>(
node,
winit.backend.renderer(),
session,
&params,
Transform::Normal,
|_node, buffer, renderer, dtr, age| {
render_fn(
buffer, renderer, dtr, age, session, common, window, geometry,
)
},
)
.map_err(|err| (FailureReason::Unspec, err.into())),
BackendData::X11(x11) => render_session::<_, _>(
node,
&mut x11.renderer,
session,
&params,
Transform::Normal,
|_node, buffer, renderer, dtr, age| {
render_fn(
buffer, renderer, dtr, age, session, common, window, geometry,
)
},
)
.map_err(|err| (FailureReason::Unspec, err.into())),
_ => unreachable!(),
}
} }
impl Common { impl Common {