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,68 +584,117 @@ 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),
DamageTrackedRendererError<R>,
>
where
R: Renderer
+ ImportAll
+ ImportMem
+ ExportMem
+ Bind<Dmabuf>
+ Offscreen<Gles2Renderbuffer>
+ Blit<Dmabuf>
+ AsGlowRenderer,
<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() {
ScreencopyCursorMode::Embedded => CursorMode::All,
ScreencopyCursorMode::Captured(_) | ScreencopyCursorMode::None => CursorMode::None,
};
if let Ok(dmabuf) = get_dmabuf(buffer) {
render_output::<_, _, Gles2Renderbuffer, Dmabuf>(
node,
renderer,
dmabuf,
dtr,
age,
common,
&output,
cursor_mode,
None,
None,
)
} else {
let size = buffer_dimensions(buffer).unwrap();
let render_buffer = Offscreen::<Gles2Renderbuffer>::create_buffer(renderer, size)
.map_err(DamageTrackedRendererError::Rendering)?;
render_output::<_, _, Gles2Renderbuffer, Dmabuf>(
node,
renderer,
render_buffer,
dtr,
age,
common,
&output,
cursor_mode,
None,
None,
)
} }
BackendData::Winit(winit) => winit.backend.renderer(), }
BackendData::X11(x11) => &mut x11.renderer,
_ => unreachable!(),
};
let common = &mut state.common; let common = &mut state.common;
render_session::<_, _>( let node = node_from_params(&params, &mut state.backend, Some(output));
node, match &mut state.backend {
renderer, BackendData::Kms(kms) => {
session, let mut multirenderer = kms
&params, .api
output.current_transform(), .renderer::<Gles2Renderbuffer>(node.as_ref().unwrap(), node.as_ref().unwrap())
|node, buffer, renderer, dtr, age| { .map_err(|err| (FailureReason::Unspec, err.into()))?;
let cursor_mode = match session.cursor_mode() { render_session::<_, _>(
ScreencopyCursorMode::Embedded => CursorMode::All, node,
ScreencopyCursorMode::Captured(_) | ScreencopyCursorMode::None => CursorMode::None, &mut multirenderer,
}; session,
&params,
if let Ok(dmabuf) = get_dmabuf(buffer) { output.current_transform(),
render_output::<_, _, Gles2Renderbuffer, Dmabuf>( |node, buffer, renderer, dtr, age| {
node, render_fn(node, buffer, renderer, dtr, age, common, session, output)
renderer, },
dmabuf, )
dtr, .map_err(|err| match err {
age, DamageTrackedRendererError::OutputNoMode(x) => (FailureReason::Unspec, x.into()),
common, DamageTrackedRendererError::Rendering(x) => (FailureReason::Unspec, x.into()),
&output, })
cursor_mode, }
None, BackendData::Winit(winit) => render_session::<_, _>(
None, node,
) winit.backend.renderer(),
} else { session,
let size = buffer_dimensions(buffer).unwrap(); &params,
let render_buffer = Offscreen::<Gles2Renderbuffer>::create_buffer(renderer, size) output.current_transform(),
.map_err(DamageTrackedRendererError::Rendering)?; |node, buffer, renderer, dtr, age| {
render_output::<_, _, Gles2Renderbuffer, Dmabuf>( render_fn(node, buffer, renderer, dtr, age, common, session, output)
node, },
renderer, )
render_buffer, .map_err(|err| (FailureReason::Unspec, err.into())),
dtr, BackendData::X11(x11) => render_session::<_, _>(
age, node,
common, &mut x11.renderer,
&output, session,
cursor_mode, &params,
None, output.current_transform(),
None, |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| (FailureReason::Unspec, err.into())) _ => unreachable!(),
}
} }
pub fn render_workspace_to_buffer( pub fn render_workspace_to_buffer(
@ -658,69 +712,125 @@ 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<
(Option<Vec<Rectangle<i32, Physical>>>, RenderElementStates),
DamageTrackedRendererError<R>,
>
where
R: Renderer
+ ImportAll
+ ImportMem
+ ExportMem
+ Bind<Dmabuf>
+ Offscreen<Gles2Renderbuffer>
+ Blit<Dmabuf>
+ AsGlowRenderer,
<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() {
ScreencopyCursorMode::Embedded => CursorMode::All,
ScreencopyCursorMode::Captured(_) | ScreencopyCursorMode::None => CursorMode::None,
};
if let Ok(dmabuf) = get_dmabuf(buffer) {
render_workspace::<_, _, Gles2Renderbuffer, Dmabuf>(
node,
renderer,
dmabuf,
dtr,
age,
common,
&output,
handle,
cursor_mode,
None,
None,
)
} else {
let size = buffer_dimensions(buffer).unwrap();
let render_buffer = Offscreen::<Gles2Renderbuffer>::create_buffer(renderer, size)
.map_err(DamageTrackedRendererError::Rendering)?;
render_workspace::<_, _, Gles2Renderbuffer, Dmabuf>(
node,
renderer,
render_buffer,
dtr,
age,
common,
&output,
handle,
cursor_mode,
None,
None,
)
} }
BackendData::Winit(winit) => winit.backend.renderer(), }
BackendData::X11(x11) => &mut x11.renderer,
_ => unreachable!(),
};
let node = node_from_params(&params, &mut state.backend, Some(output));
let common = &mut state.common; let common = &mut state.common;
render_session::<_, _>( match &mut state.backend {
node, BackendData::Kms(kms) => {
renderer, let mut multirenderer = kms
session, .api
&params, .renderer::<Gles2Renderbuffer>(node.as_ref().unwrap(), node.as_ref().unwrap())
output.current_transform(), .map_err(|err| (FailureReason::Unspec, err.into()))?;
|node, buffer, renderer, dtr, age| { render_session::<_, _>(
let cursor_mode = match session.cursor_mode() { node,
ScreencopyCursorMode::Embedded => CursorMode::All, &mut multirenderer,
ScreencopyCursorMode::Captured(_) | ScreencopyCursorMode::None => CursorMode::None, session,
}; &params,
if let Ok(dmabuf) = get_dmabuf(buffer) { output.current_transform(),
render_workspace::<_, _, Gles2Renderbuffer, Dmabuf>( |node, buffer, renderer, dtr, age| {
node, render_fn(
renderer, node, buffer, renderer, dtr, age, common, session, output, handle,
dmabuf, )
dtr, },
age, )
common, .map_err(|err| match err {
&output, DamageTrackedRendererError::OutputNoMode(x) => (FailureReason::Unspec, x.into()),
handle, DamageTrackedRendererError::Rendering(x) => (FailureReason::Unspec, x.into()),
cursor_mode, })
None, }
None, 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,
) )
} else { },
let size = buffer_dimensions(buffer).unwrap(); )
let render_buffer = Offscreen::<Gles2Renderbuffer>::create_buffer(renderer, size) .map_err(|err| (FailureReason::Unspec, err.into())),
.map_err(DamageTrackedRendererError::Rendering)?; BackendData::X11(x11) => render_session::<_, _>(
render_workspace::<_, _, Gles2Renderbuffer, Dmabuf>( node,
node, &mut x11.renderer,
renderer, session,
render_buffer, &params,
dtr, output.current_transform(),
age, |node, buffer, renderer, dtr, age| {
common, render_fn(
&output, node, buffer, renderer, dtr, age, common, session, output, handle,
handle,
cursor_mode,
None,
None,
) )
} },
}, )
) .map_err(|err| (FailureReason::Unspec, err.into())),
.map_err(|err| (FailureReason::Unspec, err.into())) _ => unreachable!(),
}
} }
smithay::render_elements! { smithay::render_elements! {
@ -741,106 +851,154 @@ 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
+ ImportMem
+ ExportMem
+ Bind<Dmabuf>
+ Offscreen<Gles2Renderbuffer>
+ Blit<Dmabuf>
+ AsGlowRenderer,
<R as Renderer>::TextureId: Clone + 'static,
<R as Renderer>::Error: From<Gles2Error>,
CosmicElement<R>: RenderElement<R>,
CosmicMappedRenderElement<R>: RenderElement<R>,
{
// TODO cursor elements!
let mut elements = AsRenderElements::<R>::render_elements::<WindowCaptureElement<R>>(
window,
renderer,
(-geometry.loc.x, -geometry.loc.y).into(),
Scale::from(1.0),
);
render_session::<_, _>( for seat in common.seats() {
node, if let Some(location) = {
renderer, // we need to find the mapped element in that case
session, if let Some(mapped) = common
&params, .shell
Transform::Normal, .element_for_surface(window.toplevel().wl_surface())
|_node, buffer, renderer, dtr, age| { {
// TODO cursor elements! mapped.cursor_position(seat).and_then(|mut p| {
let mut elements = AsRenderElements::<GlowRenderer>::render_elements::< p -= mapped.active_window_offset().loc.to_f64();
WindowCaptureElement<GlowRenderer>, if p.x < 0. || p.y < 0. {
>( None
window, } else {
renderer, Some(p)
(-geometry.loc.x, -geometry.loc.y).into(), }
Scale::from(1.0), })
); } else {
None
}
} {
if session.cursor_mode() == ScreencopyCursorMode::Embedded {
elements.extend(
cursor::draw_cursor(
renderer,
seat,
location,
1.0.into(),
common.clock.now(),
true,
)
.into_iter()
.map(WindowCaptureElement::from),
);
}
for seat in state.common.seats() { if let Some(wl_surface) = get_dnd_icon(seat) {
if let Some(location) = { elements.extend(
// we need to find the mapped element in that case cursor::draw_dnd_icon(renderer, &wl_surface, location.to_i32_round(), 1.0)
if let Some(mapped) = state
.common
.shell
.element_for_surface(window.toplevel().wl_surface())
{
mapped.cursor_position(seat).and_then(|mut p| {
p -= mapped.active_window_offset().loc.to_f64();
if p.x < 0. || p.y < 0. {
None
} else {
Some(p)
}
})
} else {
None
}
} {
if session.cursor_mode() == ScreencopyCursorMode::Embedded {
elements.extend(
cursor::draw_cursor(
renderer,
seat,
location,
1.0.into(),
state.common.clock.now(),
true,
)
.into_iter() .into_iter()
.map(WindowCaptureElement::from), .map(WindowCaptureElement::from),
); );
}
if let Some(wl_surface) = get_dnd_icon(seat) {
elements.extend(
cursor::draw_dnd_icon(
renderer,
&wl_surface,
location.to_i32_round(),
1.0,
)
.into_iter()
.map(WindowCaptureElement::from),
);
}
} }
} }
}
if let Ok(dmabuf) = get_dmabuf(buffer) { if let Ok(dmabuf) = get_dmabuf(buffer) {
renderer renderer
.bind(dmabuf) .bind(dmabuf)
.map_err(DamageTrackedRendererError::Rendering)?; .map_err(DamageTrackedRendererError::Rendering)?;
} else { } else {
let size = buffer_dimensions(buffer).unwrap(); let size = buffer_dimensions(buffer).unwrap();
let render_buffer = Offscreen::<Gles2Renderbuffer>::create_buffer(renderer, size) let render_buffer = Offscreen::<Gles2Renderbuffer>::create_buffer(renderer, size)
.map_err(DamageTrackedRendererError::Rendering)?; .map_err(DamageTrackedRendererError::Rendering)?;
renderer renderer
.bind(render_buffer) .bind(render_buffer)
.map_err(DamageTrackedRendererError::Rendering)?; .map_err(DamageTrackedRendererError::Rendering)?;
} }
dtr.render_output(renderer, age, &elements, CLEAR_COLOR, None) dtr.render_output(renderer, age, &elements, CLEAR_COLOR, None)
}, }
)
.map_err(|err| (FailureReason::Unspec, err.into())) 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| 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 {