image-copy: Hold references to Buffers to block release
The `wl_buffer` now won't be released until sync fence polls ready.
This commit is contained in:
parent
d84d5d46ce
commit
dd6ebd03c9
3 changed files with 103 additions and 43 deletions
|
|
@ -1674,7 +1674,7 @@ fn send_screencopy_result<'a>(
|
||||||
pre_postprocess_data: &mut PrePostprocessData,
|
pre_postprocess_data: &mut PrePostprocessData,
|
||||||
tx: &std::sync::mpsc::Sender<PendingImageCopyData>,
|
tx: &std::sync::mpsc::Sender<PendingImageCopyData>,
|
||||||
frame_result: &RenderFrameResult<GbmBuffer, GbmFramebuffer, CosmicElement<GlMultiRenderer<'a>>>,
|
frame_result: &RenderFrameResult<GbmBuffer, GbmFramebuffer, CosmicElement<GlMultiRenderer<'a>>>,
|
||||||
elements: &[CosmicElement<GlMultiRenderer>],
|
elements: &[CosmicElement<GlMultiRenderer<'a>>],
|
||||||
(session, frame, res): (
|
(session, frame, res): (
|
||||||
&ScreencopySessionRef,
|
&ScreencopySessionRef,
|
||||||
ScreencopyFrame,
|
ScreencopyFrame,
|
||||||
|
|
@ -1855,6 +1855,8 @@ fn send_screencopy_result<'a>(
|
||||||
transform,
|
transform,
|
||||||
damage.as_deref(),
|
damage.as_deref(),
|
||||||
sync,
|
sync,
|
||||||
|
// Don't reference `Buffer`s since we blit from framebuffer/postprocess buffer
|
||||||
|
vec![],
|
||||||
)? {
|
)? {
|
||||||
if frame_result.is_empty {
|
if frame_result.is_empty {
|
||||||
data.frame
|
data.frame
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,9 @@ use crate::{
|
||||||
compositor::FRAME_TIME_FILTER,
|
compositor::FRAME_TIME_FILTER,
|
||||||
corner_radius::{pad_rect, surface_corners, surface_padding},
|
corner_radius::{pad_rect, surface_corners, surface_padding},
|
||||||
data_device::get_dnd_icon,
|
data_device::get_dnd_icon,
|
||||||
image_copy_capture::{FrameHolder, SessionData, render_session},
|
image_copy_capture::{
|
||||||
|
FrameHolder, SessionData, render_element_buffers, render_session,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
protocols::workspace::WorkspaceHandle,
|
protocols::workspace::WorkspaceHandle,
|
||||||
},
|
},
|
||||||
|
|
@ -1505,11 +1507,16 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(RenderOutputResult {
|
let buffers = render_element_buffers(renderer, &elements);
|
||||||
damage: res.0,
|
|
||||||
sync,
|
Ok((
|
||||||
states: res.1,
|
RenderOutputResult {
|
||||||
})
|
damage: res.0,
|
||||||
|
sync,
|
||||||
|
states: res.1,
|
||||||
|
},
|
||||||
|
buffers,
|
||||||
|
))
|
||||||
},
|
},
|
||||||
)? {
|
)? {
|
||||||
pending_image_copy_data.send_success_when_ready(
|
pending_image_copy_data.send_success_when_ready(
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ use smithay::{
|
||||||
buffer_dimensions, buffer_type,
|
buffer_dimensions, buffer_type,
|
||||||
damage::{Error as DTError, OutputDamageTracker, RenderOutputResult},
|
damage::{Error as DTError, OutputDamageTracker, RenderOutputResult},
|
||||||
element::{
|
element::{
|
||||||
RenderElement,
|
RenderElement, UnderlyingStorage,
|
||||||
utils::{Relocate, RelocateRenderElement},
|
utils::{Relocate, RelocateRenderElement},
|
||||||
},
|
},
|
||||||
gles::{GlesError, GlesRenderbuffer},
|
gles::{GlesError, GlesRenderbuffer},
|
||||||
|
|
@ -58,10 +58,30 @@ use crate::{
|
||||||
|
|
||||||
use super::{super::data_device::get_dnd_icon, user_data::SessionHolder};
|
use super::{super::data_device::get_dnd_icon, user_data::SessionHolder};
|
||||||
|
|
||||||
|
pub fn render_element_buffers<R, E>(
|
||||||
|
renderer: &mut R,
|
||||||
|
elements: &[E],
|
||||||
|
) -> Vec<smithay::backend::renderer::utils::Buffer>
|
||||||
|
where
|
||||||
|
R: AsGlowRenderer,
|
||||||
|
E: RenderElement<R>,
|
||||||
|
{
|
||||||
|
elements
|
||||||
|
.iter()
|
||||||
|
.filter_map(|elem| match elem.underlying_storage(renderer) {
|
||||||
|
Some(UnderlyingStorage::Wayland(buffer)) => Some(buffer.clone()),
|
||||||
|
Some(UnderlyingStorage::Memory(_)) | None => None,
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
pub struct PendingImageCopyData {
|
pub struct PendingImageCopyData {
|
||||||
pub frame: Frame,
|
pub frame: Frame,
|
||||||
pub damage: Vec<smithay::utils::Rectangle<i32, BufferCoords>>,
|
pub damage: Vec<smithay::utils::Rectangle<i32, BufferCoords>>,
|
||||||
pub sync: SyncPoint,
|
pub sync: SyncPoint,
|
||||||
|
// Hold reference so `wl_buffer` isn't released and sync point isn't signaled
|
||||||
|
// until image copy completes.
|
||||||
|
_buffers: Vec<smithay::backend::renderer::utils::Buffer>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PendingImageCopyData {
|
impl PendingImageCopyData {
|
||||||
|
|
@ -104,6 +124,7 @@ pub fn submit_buffer<R>(
|
||||||
transform: Transform,
|
transform: Transform,
|
||||||
damage: Option<&[Rectangle<i32, Physical>]>,
|
damage: Option<&[Rectangle<i32, Physical>]>,
|
||||||
mut sync: SyncPoint,
|
mut sync: SyncPoint,
|
||||||
|
buffers: Vec<smithay::backend::renderer::utils::Buffer>,
|
||||||
) -> Result<Option<PendingImageCopyData>, R::Error>
|
) -> Result<Option<PendingImageCopyData>, R::Error>
|
||||||
where
|
where
|
||||||
R: ExportMem + AsGlowRenderer,
|
R: ExportMem + AsGlowRenderer,
|
||||||
|
|
@ -182,6 +203,7 @@ where
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
sync,
|
sync,
|
||||||
|
_buffers: buffers,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -201,7 +223,13 @@ where
|
||||||
&'d mut OutputDamageTracker,
|
&'d mut OutputDamageTracker,
|
||||||
usize,
|
usize,
|
||||||
Vec<Rectangle<i32, BufferCoords>>,
|
Vec<Rectangle<i32, BufferCoords>>,
|
||||||
) -> Result<RenderOutputResult<'d>, DTError<R::Error>>,
|
) -> Result<
|
||||||
|
(
|
||||||
|
RenderOutputResult<'d>,
|
||||||
|
Vec<smithay::backend::renderer::utils::Buffer>,
|
||||||
|
),
|
||||||
|
DTError<R::Error>,
|
||||||
|
>,
|
||||||
{
|
{
|
||||||
let mut session_user_data = session.lock().unwrap();
|
let mut session_user_data = session.lock().unwrap();
|
||||||
|
|
||||||
|
|
@ -245,30 +273,25 @@ where
|
||||||
.as_mut()
|
.as_mut()
|
||||||
.map(|(_, tex)| renderer.bind(tex).map_err(DTError::Rendering))
|
.map(|(_, tex)| renderer.bind(tex).map_err(DTError::Rendering))
|
||||||
.transpose()?;
|
.transpose()?;
|
||||||
let res = render_fn(
|
let (result, buffers) = render_fn(
|
||||||
&frame.buffer(),
|
&frame.buffer(),
|
||||||
renderer,
|
renderer,
|
||||||
fb.as_mut(),
|
fb.as_mut(),
|
||||||
dt,
|
dt,
|
||||||
age,
|
age,
|
||||||
frame.damage(),
|
frame.damage(),
|
||||||
);
|
)?;
|
||||||
|
|
||||||
match res {
|
submit_buffer(
|
||||||
Ok(result) => submit_buffer(
|
frame,
|
||||||
frame,
|
renderer,
|
||||||
renderer,
|
fb.as_mut(),
|
||||||
fb.as_mut(),
|
transform,
|
||||||
transform,
|
result.damage.map(|x| x.as_slice()),
|
||||||
result.damage.map(|x| x.as_slice()),
|
result.sync,
|
||||||
result.sync,
|
buffers,
|
||||||
)
|
)
|
||||||
.map_err(DTError::Rendering),
|
.map_err(DTError::Rendering)
|
||||||
Err(err) => {
|
|
||||||
frame.fail(CaptureFailureReason::Unknown);
|
|
||||||
Err(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render_workspace_to_buffer(
|
pub fn render_workspace_to_buffer(
|
||||||
|
|
@ -316,7 +339,13 @@ pub fn render_workspace_to_buffer(
|
||||||
common: &mut Common,
|
common: &mut Common,
|
||||||
output: &Output,
|
output: &Output,
|
||||||
handle: (WorkspaceHandle, usize),
|
handle: (WorkspaceHandle, usize),
|
||||||
) -> Result<RenderOutputResult<'d>, DTError<R::Error>>
|
) -> Result<
|
||||||
|
(
|
||||||
|
RenderOutputResult<'d>,
|
||||||
|
Vec<smithay::backend::renderer::utils::Buffer>,
|
||||||
|
),
|
||||||
|
DTError<R::Error>,
|
||||||
|
>
|
||||||
where
|
where
|
||||||
R: AsGlowRenderer,
|
R: AsGlowRenderer,
|
||||||
R::TextureId: Send + Clone + 'static,
|
R::TextureId: Send + Clone + 'static,
|
||||||
|
|
@ -356,7 +385,7 @@ pub fn render_workspace_to_buffer(
|
||||||
.collect()
|
.collect()
|
||||||
});
|
});
|
||||||
|
|
||||||
if let Ok(dmabuf) = get_dmabuf(buffer) {
|
let (res, elements) = if let Ok(dmabuf) = get_dmabuf(buffer) {
|
||||||
let mut dmabuf = dmabuf.clone();
|
let mut dmabuf = dmabuf.clone();
|
||||||
let mut fb = renderer.bind(&mut dmabuf).map_err(DTError::Rendering)?;
|
let mut fb = renderer.bind(&mut dmabuf).map_err(DTError::Rendering)?;
|
||||||
render_workspace(
|
render_workspace(
|
||||||
|
|
@ -374,8 +403,7 @@ pub fn render_workspace_to_buffer(
|
||||||
handle,
|
handle,
|
||||||
cursor_mode,
|
cursor_mode,
|
||||||
ElementFilter::ExcludeWorkspaceOverview,
|
ElementFilter::ExcludeWorkspaceOverview,
|
||||||
)
|
)?
|
||||||
.map(|res| res.0)
|
|
||||||
} else {
|
} else {
|
||||||
let target = offscreen.expect("shm buffers should have an offscreen target");
|
let target = offscreen.expect("shm buffers should have an offscreen target");
|
||||||
render_workspace(
|
render_workspace(
|
||||||
|
|
@ -393,9 +421,12 @@ pub fn render_workspace_to_buffer(
|
||||||
handle,
|
handle,
|
||||||
cursor_mode,
|
cursor_mode,
|
||||||
ElementFilter::ExcludeWorkspaceOverview,
|
ElementFilter::ExcludeWorkspaceOverview,
|
||||||
)
|
)?
|
||||||
.map(|res| res.0)
|
};
|
||||||
}
|
|
||||||
|
let buffers = render_element_buffers(renderer, &elements);
|
||||||
|
|
||||||
|
Ok((res, buffers))
|
||||||
}
|
}
|
||||||
|
|
||||||
let draw_cursor = session.draw_cursor();
|
let draw_cursor = session.draw_cursor();
|
||||||
|
|
@ -549,7 +580,13 @@ pub fn render_window_to_buffer(
|
||||||
common: &mut Common,
|
common: &mut Common,
|
||||||
toplevel: &CosmicSurface,
|
toplevel: &CosmicSurface,
|
||||||
geometry: Rectangle<i32, Logical>,
|
geometry: Rectangle<i32, Logical>,
|
||||||
) -> Result<RenderOutputResult<'d>, DTError<R::Error>>
|
) -> Result<
|
||||||
|
(
|
||||||
|
RenderOutputResult<'d>,
|
||||||
|
Vec<smithay::backend::renderer::utils::Buffer>,
|
||||||
|
),
|
||||||
|
DTError<R::Error>,
|
||||||
|
>
|
||||||
where
|
where
|
||||||
R: AsGlowRenderer,
|
R: AsGlowRenderer,
|
||||||
R::TextureId: Send + Clone + 'static,
|
R::TextureId: Send + Clone + 'static,
|
||||||
|
|
@ -650,16 +687,20 @@ pub fn render_window_to_buffer(
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
if let Ok(dmabuf) = get_dmabuf(buffer) {
|
let res = if let Ok(dmabuf) = get_dmabuf(buffer) {
|
||||||
let mut dmabuf_clone = dmabuf.clone();
|
let mut dmabuf_clone = dmabuf.clone();
|
||||||
let mut fb = renderer
|
let mut fb = renderer
|
||||||
.bind(&mut dmabuf_clone)
|
.bind(&mut dmabuf_clone)
|
||||||
.map_err(DTError::Rendering)?;
|
.map_err(DTError::Rendering)?;
|
||||||
dt.render_output(renderer, &mut fb, age, &elements, Color32F::TRANSPARENT)
|
dt.render_output(renderer, &mut fb, age, &elements, Color32F::TRANSPARENT)?
|
||||||
} else {
|
} else {
|
||||||
let fb = offscreen.expect("shm buffer should have an offscreen target");
|
let fb = offscreen.expect("shm buffer should have an offscreen target");
|
||||||
dt.render_output(renderer, fb, age, &elements, Color32F::TRANSPARENT)
|
dt.render_output(renderer, fb, age, &elements, Color32F::TRANSPARENT)?
|
||||||
}
|
};
|
||||||
|
|
||||||
|
let buffers = render_element_buffers(renderer, &elements);
|
||||||
|
|
||||||
|
Ok((res, buffers))
|
||||||
}
|
}
|
||||||
|
|
||||||
let common = &mut state.common;
|
let common = &mut state.common;
|
||||||
|
|
@ -797,7 +838,13 @@ pub fn render_cursor_to_buffer(
|
||||||
additional_damage: Vec<Rectangle<i32, BufferCoords>>,
|
additional_damage: Vec<Rectangle<i32, BufferCoords>>,
|
||||||
common: &mut Common,
|
common: &mut Common,
|
||||||
seat: &Seat<State>,
|
seat: &Seat<State>,
|
||||||
) -> Result<RenderOutputResult<'d>, DTError<R::Error>>
|
) -> Result<
|
||||||
|
(
|
||||||
|
RenderOutputResult<'d>,
|
||||||
|
Vec<smithay::backend::renderer::utils::Buffer>,
|
||||||
|
),
|
||||||
|
DTError<R::Error>,
|
||||||
|
>
|
||||||
where
|
where
|
||||||
R: AsGlowRenderer,
|
R: AsGlowRenderer,
|
||||||
R::TextureId: Send + Clone + 'static,
|
R::TextureId: Send + Clone + 'static,
|
||||||
|
|
@ -830,16 +877,20 @@ pub fn render_cursor_to_buffer(
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
if let Ok(dmabuf) = get_dmabuf(buffer) {
|
let res = if let Ok(dmabuf) = get_dmabuf(buffer) {
|
||||||
let mut dmabuf_clone = dmabuf.clone();
|
let mut dmabuf_clone = dmabuf.clone();
|
||||||
let mut fb = renderer
|
let mut fb = renderer
|
||||||
.bind(&mut dmabuf_clone)
|
.bind(&mut dmabuf_clone)
|
||||||
.map_err(DTError::Rendering)?;
|
.map_err(DTError::Rendering)?;
|
||||||
dt.render_output(renderer, &mut fb, age, &elements, [0.0, 0.0, 0.0, 0.0])
|
dt.render_output(renderer, &mut fb, age, &elements, [0.0, 0.0, 0.0, 0.0])?
|
||||||
} else {
|
} else {
|
||||||
let fb = offscreen.expect("shm buffers should have offscreen target");
|
let fb = offscreen.expect("shm buffers should have offscreen target");
|
||||||
dt.render_output(renderer, fb, age, &elements, [0.0, 0.0, 0.0, 0.0])
|
dt.render_output(renderer, fb, age, &elements, [0.0, 0.0, 0.0, 0.0])?
|
||||||
}
|
};
|
||||||
|
|
||||||
|
let buffers = render_element_buffers(renderer, &elements);
|
||||||
|
|
||||||
|
Ok((res, buffers))
|
||||||
}
|
}
|
||||||
|
|
||||||
let common = &mut state.common;
|
let common = &mut state.common;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue