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