mirror of
https://github.com/niri-wm/niri.git
synced 2026-06-22 02:01:55 +07:00
Refactor screencopy/screencast to render via the damage tracker, fix cursorless screencopy with damage
The damage tracker stores framebuffer effect cache, so we want anything that renders repeatedly to render through a reused damage tracker. This way, the cache persists and is reused across renders. This will be important for the non-xray background effects.
This commit is contained in:
+78
-74
@@ -1,4 +1,4 @@
|
||||
use std::cell::{Cell, OnceCell, RefCell};
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::ffi::OsString;
|
||||
use std::os::unix::net::UnixStream;
|
||||
@@ -28,7 +28,7 @@ use smithay::backend::renderer::element::utils::{
|
||||
RescaleRenderElement,
|
||||
};
|
||||
use smithay::backend::renderer::element::{
|
||||
default_primary_scanout_output_compare, Element, Id, Kind, PrimaryScanoutOutput,
|
||||
default_primary_scanout_output_compare, Element, Id, Kind, PrimaryScanoutOutput, RenderElement,
|
||||
RenderElementStates,
|
||||
};
|
||||
use smithay::backend::renderer::gles::GlesRenderer;
|
||||
@@ -5194,57 +5194,65 @@ impl Niri {
|
||||
let _span = tracy_client::span!("Niri::render_for_screencopy_with_damage");
|
||||
|
||||
let mut screencopy_state = mem::take(&mut self.screencopy_state);
|
||||
let elements = OnceCell::new();
|
||||
|
||||
screencopy_state.with_queues_mut(|queue| {
|
||||
let (damage_tracker, screencopy) = queue.split();
|
||||
if let Some(screencopy) = screencopy {
|
||||
if screencopy.output() == output {
|
||||
let elements = elements.get_or_init(|| {
|
||||
let ctx = RenderCtx {
|
||||
renderer,
|
||||
target: RenderTarget::ScreenCapture,
|
||||
xray: None,
|
||||
};
|
||||
self.render_to_vec(ctx, output, true)
|
||||
});
|
||||
// FIXME: skip elements if not including pointers
|
||||
let render_result = Self::render_for_screencopy_internal(
|
||||
let ctx = RenderCtx {
|
||||
renderer,
|
||||
target: RenderTarget::ScreenCapture,
|
||||
xray: None,
|
||||
};
|
||||
let offset = screencopy.region_loc().upscale(-1);
|
||||
let mut elements = Vec::new();
|
||||
self.render(ctx, output, screencopy.overlay_cursor(), &mut |elem| {
|
||||
let elem =
|
||||
RelocateRenderElement::from_element(elem, offset, Relocate::Relative);
|
||||
elements.push(elem);
|
||||
});
|
||||
|
||||
let (damages, states) = Self::damage_screencopy_internal(
|
||||
output,
|
||||
elements,
|
||||
true,
|
||||
&elements,
|
||||
damage_tracker,
|
||||
screencopy,
|
||||
);
|
||||
match render_result {
|
||||
Ok((sync, damages)) => {
|
||||
if let Some(damages) = damages {
|
||||
// Convert from Physical coordinates back to Buffer coordinates.
|
||||
let transform = output.current_transform();
|
||||
let physical_size =
|
||||
transform.transform_size(screencopy.buffer_size());
|
||||
let damages = damages.iter().map(|dmg| {
|
||||
dmg.to_logical(1).to_buffer(
|
||||
1,
|
||||
transform.invert(),
|
||||
&physical_size.to_logical(1),
|
||||
)
|
||||
});
|
||||
if let Some(damages) = damages {
|
||||
// Convert from Physical coordinates back to Buffer coordinates.
|
||||
let transform = output.current_transform();
|
||||
let physical_size = transform.transform_size(screencopy.buffer_size());
|
||||
let damages = damages.iter().map(|dmg| {
|
||||
dmg.to_logical(1).to_buffer(
|
||||
1,
|
||||
transform.invert(),
|
||||
&physical_size.to_logical(1),
|
||||
)
|
||||
});
|
||||
|
||||
screencopy.damage(damages);
|
||||
screencopy.damage(damages);
|
||||
|
||||
let render_result = Self::render_for_screencopy_internal(
|
||||
renderer,
|
||||
damage_tracker,
|
||||
&elements,
|
||||
states,
|
||||
screencopy,
|
||||
);
|
||||
match render_result {
|
||||
Ok(sync) => {
|
||||
queue.pop().submit_after_sync(false, sync, &self.event_loop);
|
||||
} else {
|
||||
trace!("no damage found, waiting till next redraw");
|
||||
}
|
||||
Err(err) => {
|
||||
// Recreate damage tracker to report full damage next check.
|
||||
*damage_tracker =
|
||||
OutputDamageTracker::new((0, 0), 1.0, Transform::Normal);
|
||||
queue.pop();
|
||||
warn!("error rendering for screencopy: {err:?}");
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
// Recreate damage tracker to report full damage next check.
|
||||
*damage_tracker =
|
||||
OutputDamageTracker::new((0, 0), 1.0, Transform::Normal);
|
||||
queue.pop();
|
||||
warn!("error rendering for screencopy: {err:?}");
|
||||
}
|
||||
} else {
|
||||
trace!("no damage found, waiting till next redraw");
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -5274,24 +5282,28 @@ impl Niri {
|
||||
target: RenderTarget::ScreenCapture,
|
||||
xray: None,
|
||||
};
|
||||
let elements = self.render_to_vec(ctx, output, screencopy.overlay_cursor());
|
||||
let offset = screencopy.region_loc().upscale(-1);
|
||||
let mut elements = Vec::new();
|
||||
self.render(ctx, output, screencopy.overlay_cursor(), &mut |elem| {
|
||||
let elem = RelocateRenderElement::from_element(elem, offset, Relocate::Relative);
|
||||
elements.push(elem);
|
||||
});
|
||||
|
||||
let Some(damage_tracker) = self.screencopy_state.damage_tracker(manager) else {
|
||||
error!("screencopy queue must not be deleted as long as frames exist");
|
||||
bail!("screencopy queue missing");
|
||||
};
|
||||
|
||||
let render_result = Self::render_for_screencopy_internal(
|
||||
let (_damages, states) =
|
||||
Self::damage_screencopy_internal(output, &elements, damage_tracker, &screencopy);
|
||||
let res = Self::render_for_screencopy_internal(
|
||||
renderer,
|
||||
output,
|
||||
&elements,
|
||||
false,
|
||||
damage_tracker,
|
||||
&elements,
|
||||
states,
|
||||
&screencopy,
|
||||
);
|
||||
|
||||
let res = render_result
|
||||
.map(|(sync, _damage)| screencopy.submit_after_sync(false, sync, &self.event_loop));
|
||||
let res = res.map(|sync| screencopy.submit_after_sync(false, sync, &self.event_loop));
|
||||
|
||||
if res.is_err() {
|
||||
// Recreate damage tracker to report full damage next check.
|
||||
@@ -5301,15 +5313,15 @@ impl Niri {
|
||||
res
|
||||
}
|
||||
|
||||
#[allow(clippy::type_complexity)]
|
||||
fn render_for_screencopy_internal<'a>(
|
||||
renderer: &mut GlesRenderer,
|
||||
fn damage_screencopy_internal<'a>(
|
||||
output: &Output,
|
||||
elements: &[OutputRenderElements<GlesRenderer>],
|
||||
with_damage: bool,
|
||||
elements: &[impl Element],
|
||||
damage_tracker: &'a mut OutputDamageTracker,
|
||||
screencopy: &Screencopy,
|
||||
) -> anyhow::Result<(Option<SyncPoint>, Option<&'a Vec<Rectangle<i32, Physical>>>)> {
|
||||
) -> (
|
||||
Option<&'a Vec<Rectangle<i32, Physical>>>,
|
||||
RenderElementStates,
|
||||
) {
|
||||
let OutputModeSource::Static {
|
||||
size: last_size,
|
||||
scale: last_scale,
|
||||
@@ -5327,41 +5339,33 @@ impl Niri {
|
||||
*damage_tracker = OutputDamageTracker::new(size, scale, transform);
|
||||
}
|
||||
|
||||
let region_loc = screencopy.region_loc();
|
||||
let elements = elements
|
||||
.iter()
|
||||
.map(|element| {
|
||||
RelocateRenderElement::from_element(
|
||||
element,
|
||||
region_loc.upscale(-1),
|
||||
Relocate::Relative,
|
||||
)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// Just checked damage tracker has static mode
|
||||
let damages = damage_tracker.damage_output(1, &elements).unwrap().0;
|
||||
if with_damage && damages.is_none() {
|
||||
return Ok((None, None));
|
||||
}
|
||||
|
||||
let elements = elements.iter().rev();
|
||||
damage_tracker.damage_output(1, elements).unwrap()
|
||||
}
|
||||
|
||||
#[allow(clippy::type_complexity)]
|
||||
fn render_for_screencopy_internal(
|
||||
renderer: &mut GlesRenderer,
|
||||
damage_tracker: &mut OutputDamageTracker,
|
||||
elements: &[impl RenderElement<GlesRenderer>],
|
||||
states: RenderElementStates,
|
||||
screencopy: &Screencopy,
|
||||
) -> anyhow::Result<Option<SyncPoint>> {
|
||||
let sync = match screencopy.buffer() {
|
||||
ScreencopyBuffer::Dmabuf(dmabuf) => {
|
||||
let sync =
|
||||
render_to_dmabuf(renderer, dmabuf.clone(), size, scale, transform, elements)
|
||||
render_to_dmabuf(renderer, damage_tracker, dmabuf.clone(), elements, states)
|
||||
.context("error rendering to screencopy dmabuf")?;
|
||||
Some(sync)
|
||||
}
|
||||
ScreencopyBuffer::Shm(wl_buffer) => {
|
||||
render_to_shm(renderer, wl_buffer, size, scale, transform, elements)
|
||||
render_to_shm(renderer, damage_tracker, wl_buffer, elements, states)
|
||||
.context("error rendering to screencopy shm buffer")?;
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
Ok((sync, damages))
|
||||
Ok(sync)
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "xdp-gnome-screencast"))]
|
||||
|
||||
+44
-15
@@ -4,8 +4,9 @@ use anyhow::{ensure, Context as _};
|
||||
use niri_config::BlockOutFrom;
|
||||
use smithay::backend::allocator::dmabuf::Dmabuf;
|
||||
use smithay::backend::allocator::{Buffer, Fourcc};
|
||||
use smithay::backend::renderer::damage::OutputDamageTracker;
|
||||
use smithay::backend::renderer::element::utils::{Relocate, RelocateRenderElement};
|
||||
use smithay::backend::renderer::element::{Element, Kind, RenderElement};
|
||||
use smithay::backend::renderer::element::{Element, Kind, RenderElement, RenderElementStates};
|
||||
use smithay::backend::renderer::gles::{
|
||||
GlesError, GlesMapping, GlesRenderer, GlesTarget, GlesTexture,
|
||||
};
|
||||
@@ -269,33 +270,44 @@ pub fn render_to_vec(
|
||||
|
||||
pub fn render_to_dmabuf(
|
||||
renderer: &mut GlesRenderer,
|
||||
damage_tracker: &mut OutputDamageTracker,
|
||||
mut dmabuf: Dmabuf,
|
||||
size: Size<i32, Physical>,
|
||||
scale: Scale<f64>,
|
||||
transform: Transform,
|
||||
elements: impl Iterator<Item = impl RenderElement<GlesRenderer>>,
|
||||
elements: &[impl RenderElement<GlesRenderer>],
|
||||
states: RenderElementStates,
|
||||
) -> anyhow::Result<SyncPoint> {
|
||||
let _span = tracy_client::span!();
|
||||
let (size, _scale, _transform) = damage_tracker.mode().try_into().unwrap();
|
||||
ensure!(
|
||||
dmabuf.width() == size.w as u32 && dmabuf.height() == size.h as u32,
|
||||
"invalid buffer size"
|
||||
);
|
||||
let mut target = renderer
|
||||
.bind(&mut dmabuf)
|
||||
.context("error binding texture")?;
|
||||
render_elements(renderer, &mut target, size, scale, transform, elements)
|
||||
|
||||
let mut target = renderer.bind(&mut dmabuf).context("error binding dmabuf")?;
|
||||
let res = damage_tracker
|
||||
.render_output_with_states(
|
||||
renderer,
|
||||
&mut target,
|
||||
0,
|
||||
elements,
|
||||
Color32F::TRANSPARENT,
|
||||
states,
|
||||
)
|
||||
.context("error rendering to dmabuf")?;
|
||||
Ok(res.sync)
|
||||
}
|
||||
|
||||
pub fn render_to_shm(
|
||||
renderer: &mut GlesRenderer,
|
||||
damage_tracker: &mut OutputDamageTracker,
|
||||
buffer: &WlBuffer,
|
||||
size: Size<i32, Physical>,
|
||||
scale: Scale<f64>,
|
||||
transform: Transform,
|
||||
elements: impl Iterator<Item = impl RenderElement<GlesRenderer>>,
|
||||
elements: &[impl RenderElement<GlesRenderer>],
|
||||
states: RenderElementStates,
|
||||
) -> anyhow::Result<()> {
|
||||
let _span = tracy_client::span!();
|
||||
shm::with_buffer_contents_mut(buffer, |shm_buffer, shm_len, buffer_data| {
|
||||
let (size, _scale, _transform) = damage_tracker.mode().try_into().unwrap();
|
||||
let fourcc = Fourcc::Xrgb8888;
|
||||
|
||||
ensure!(
|
||||
// The buffer prefers pixels in little endian ...
|
||||
buffer_data.format == wl_shm::Format::Xrgb8888
|
||||
@@ -305,9 +317,26 @@ pub fn render_to_shm(
|
||||
&& shm_len == buffer_data.stride as usize * buffer_data.height as usize,
|
||||
"invalid buffer format or size"
|
||||
);
|
||||
let mapping =
|
||||
render_and_download(renderer, size, scale, transform, Fourcc::Xrgb8888, elements)?;
|
||||
|
||||
let mut texture =
|
||||
create_texture(renderer, size, fourcc).context("error creating texture")?;
|
||||
let mut target = renderer
|
||||
.bind(&mut texture)
|
||||
.context("error binding texture")?;
|
||||
|
||||
let _res = damage_tracker
|
||||
.render_output_with_states(
|
||||
renderer,
|
||||
&mut target,
|
||||
0,
|
||||
elements,
|
||||
Color32F::TRANSPARENT,
|
||||
states,
|
||||
)
|
||||
.context("error rendering")?;
|
||||
|
||||
let mapping =
|
||||
copy_framebuffer(renderer, &target, fourcc).context("error copying framebuffer")?;
|
||||
let bytes = renderer
|
||||
.map_texture(&mapping)
|
||||
.context("error mapping texture")?;
|
||||
|
||||
+32
-24
@@ -201,11 +201,6 @@ impl State {
|
||||
|
||||
self.backend.with_primary_renderer(|renderer| {
|
||||
let mut elements = Vec::new();
|
||||
mapped.render_for_screen_cast(renderer, scale, &mut |elem| {
|
||||
elements.push(CastRenderElement::from(elem))
|
||||
});
|
||||
|
||||
let mut pointer_elements = Vec::new();
|
||||
let mut pointer_location = Point::default();
|
||||
|
||||
if self.niri.pointer_visibility.is_visible() {
|
||||
@@ -225,11 +220,18 @@ impl State {
|
||||
self.niri.render_pointer(renderer, output, &mut |elem| {
|
||||
let elem =
|
||||
RelocateRenderElement::from_element(elem, pos, Relocate::Relative);
|
||||
pointer_elements.push(CastRenderElement::from(elem));
|
||||
elements.push(CastRenderElement::from(elem));
|
||||
});
|
||||
}
|
||||
}
|
||||
let cursor_data = CursorData::compute(&pointer_elements, pointer_location, scale);
|
||||
|
||||
let main_start = elements.len();
|
||||
mapped.render_for_screen_cast(renderer, scale, &mut |elem| {
|
||||
elements.push(CastRenderElement::from(elem))
|
||||
});
|
||||
|
||||
let cursor_data =
|
||||
CursorData::compute(&elements, main_start, pointer_location, scale);
|
||||
|
||||
if cast.dequeue_buffer_and_render(
|
||||
renderer,
|
||||
@@ -546,7 +548,6 @@ impl Niri {
|
||||
let scale = Scale::from(output.current_scale().fractional_scale());
|
||||
|
||||
let mut elements = Vec::new();
|
||||
let mut pointer = Vec::new();
|
||||
let mut cursor_data = None;
|
||||
|
||||
let mut casts_to_stop = vec![];
|
||||
@@ -575,13 +576,6 @@ impl Niri {
|
||||
}
|
||||
|
||||
if cursor_data.is_none() {
|
||||
let ctx = RenderCtx {
|
||||
renderer,
|
||||
target: RenderTarget::Screencast,
|
||||
xray: None,
|
||||
};
|
||||
self.render(ctx, output, false, &mut |elem| elements.push(elem.into()));
|
||||
|
||||
let mut pointer_pos = Point::default();
|
||||
if self.pointer_visibility.is_visible() {
|
||||
let output_geo = self.global_space.output_geometry(output).unwrap().to_f64();
|
||||
@@ -593,12 +587,25 @@ impl Niri {
|
||||
if output_geo.contains(pointer_loc) {
|
||||
pointer_pos = pointer_loc - output_geo.loc;
|
||||
self.render_pointer(renderer, output, &mut |elem| {
|
||||
pointer.push(elem.into())
|
||||
elements.push(elem.into())
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
cursor_data = Some(CursorData::compute(&pointer, pointer_pos, scale));
|
||||
let main_start = elements.len();
|
||||
let ctx = RenderCtx {
|
||||
renderer,
|
||||
target: RenderTarget::Screencast,
|
||||
xray: None,
|
||||
};
|
||||
self.render(ctx, output, false, &mut |elem| elements.push(elem.into()));
|
||||
|
||||
cursor_data = Some(CursorData::compute(
|
||||
&elements,
|
||||
main_start,
|
||||
pointer_pos,
|
||||
scale,
|
||||
));
|
||||
}
|
||||
let cursor_data = cursor_data.as_ref().unwrap();
|
||||
|
||||
@@ -659,11 +666,6 @@ impl Niri {
|
||||
}
|
||||
|
||||
let mut elements = Vec::new();
|
||||
mapped.render_for_screen_cast(renderer, scale, &mut |elem| {
|
||||
elements.push(CastRenderElement::from(elem))
|
||||
});
|
||||
|
||||
let mut pointer_elements = Vec::new();
|
||||
let mut pointer_location = Point::default();
|
||||
|
||||
if self.pointer_visibility.is_visible() {
|
||||
@@ -680,11 +682,17 @@ impl Niri {
|
||||
self.render_pointer(renderer, output, &mut |elem| {
|
||||
let elem =
|
||||
RelocateRenderElement::from_element(elem, pos, Relocate::Relative);
|
||||
pointer_elements.push(CastRenderElement::from(elem));
|
||||
elements.push(CastRenderElement::from(elem));
|
||||
});
|
||||
}
|
||||
}
|
||||
let cursor_data = CursorData::compute(&pointer_elements, pointer_location, scale);
|
||||
|
||||
let main_start = elements.len();
|
||||
mapped.render_for_screen_cast(renderer, scale, &mut |elem| {
|
||||
elements.push(CastRenderElement::from(elem))
|
||||
});
|
||||
|
||||
let cursor_data = CursorData::compute(&elements, main_start, pointer_location, scale);
|
||||
|
||||
if cast.dequeue_buffer_and_render(renderer, &elements, &cursor_data, bbox.size, scale) {
|
||||
cast.last_frame_time = target_presentation_time;
|
||||
|
||||
@@ -153,15 +153,19 @@ pub enum CastSizeChange {
|
||||
|
||||
/// Data for drawing a cursor either as metadata or embedded.
|
||||
///
|
||||
/// The cursor elements are expected to be at the start of the main elements slice. `elem_count` is
|
||||
/// the count of the pointer elements. This way, the full slice includes both main and cursor
|
||||
/// elements for embedded mode, and `&elements[elem_count..]` gives just the main elements for
|
||||
/// metadata mode.
|
||||
///
|
||||
/// We have weird borrowed references here in order to support both metadata and embedded cases.
|
||||
/// The cursor damage tracker needs a slice of impl Element at (0, 0), so we pass it `relocated`
|
||||
/// (luckily, &impl Element also impls Element). Then, if we need to embed the cursor, we chain the
|
||||
/// elements to the main video buffer elements, so we need the same type. We use `original` for
|
||||
/// this; `E` is expected to match the type of the main video buffer elements.
|
||||
/// (luckily, &impl Element also impls Element). Then, if we need to embed the cursor, we use the
|
||||
/// full elements slice which starts with non-relocated pointer elements (that we borrow from).
|
||||
#[derive(Debug)]
|
||||
pub struct CursorData<'a, E> {
|
||||
/// Cursor elements at their original location.
|
||||
original: &'a [E],
|
||||
/// Count of the pointer elements in the slice (index of the first non-pointer element).
|
||||
elem_count: usize,
|
||||
/// Cursor elements relocated to (0, 0).
|
||||
relocated: Vec<RelocateRenderElement<&'a E>>,
|
||||
/// Location of the cursor's hotspot in the video buffer.
|
||||
@@ -175,16 +179,22 @@ pub struct CursorData<'a, E> {
|
||||
}
|
||||
|
||||
impl<'a, E: Element> CursorData<'a, E> {
|
||||
pub fn compute(elements: &'a [E], location: Point<f64, Logical>, scale: Scale<f64>) -> Self {
|
||||
pub fn compute(
|
||||
elements: &'a [E],
|
||||
elem_count: usize,
|
||||
location: Point<f64, Logical>,
|
||||
scale: Scale<f64>,
|
||||
) -> Self {
|
||||
let pointer_elements = &elements[..elem_count];
|
||||
let location = location.to_physical_precise_round(scale);
|
||||
|
||||
let geo = encompassing_geo(scale, elements.iter());
|
||||
let relocated = Vec::from_iter(elements.iter().map(|elem| {
|
||||
let geo = encompassing_geo(scale, pointer_elements.iter());
|
||||
let relocated = Vec::from_iter(pointer_elements.iter().map(|elem| {
|
||||
RelocateRenderElement::from_element(elem, geo.loc.upscale(-1), Relocate::Relative)
|
||||
}));
|
||||
|
||||
Self {
|
||||
original: elements,
|
||||
elem_count,
|
||||
relocated,
|
||||
location,
|
||||
hotspot: location - geo.loc,
|
||||
@@ -1052,7 +1062,7 @@ impl Cast {
|
||||
pub fn dequeue_buffer_and_render(
|
||||
&mut self,
|
||||
renderer: &mut GlesRenderer,
|
||||
elements: &[CastRenderElement<GlesRenderer>],
|
||||
mut elements: &[CastRenderElement<GlesRenderer>],
|
||||
cursor_data: &CursorData<CastRenderElement<GlesRenderer>>,
|
||||
size: Size<i32, Physical>,
|
||||
scale: Scale<f64>,
|
||||
@@ -1092,11 +1102,17 @@ impl Cast {
|
||||
);
|
||||
}
|
||||
|
||||
let (damage, _states) = damage_tracker.damage_output(1, elements).unwrap();
|
||||
|
||||
let mut has_cursor_update = false;
|
||||
let mut redraw_cursor = false;
|
||||
if self.cursor_mode != CursorMode::Hidden {
|
||||
|
||||
// For embedded cursor, pass the full slice (cursor + main) to the damage tracker.
|
||||
// For metadata or hidden cursor, pass only the main elements.
|
||||
if self.cursor_mode == CursorMode::Metadata || self.cursor_mode == CursorMode::Hidden {
|
||||
elements = &elements[cursor_data.elem_count..];
|
||||
}
|
||||
let (damage, states) = damage_tracker.damage_output(1, elements).unwrap();
|
||||
|
||||
if self.cursor_mode == CursorMode::Metadata {
|
||||
let (damage, _states) = cursor_damage_tracker
|
||||
.damage_output(1, &cursor_data.relocated)
|
||||
.unwrap();
|
||||
@@ -1118,33 +1134,30 @@ impl Cast {
|
||||
};
|
||||
let buffer = pw_buffer.as_ptr();
|
||||
|
||||
let mut inner = self.inner.borrow_mut();
|
||||
let inner_ = &mut *inner;
|
||||
let CastState::Ready { damage_tracker, .. } = &mut inner_.state else {
|
||||
unreachable!()
|
||||
};
|
||||
let damage_tracker = damage_tracker.as_mut().unwrap();
|
||||
|
||||
unsafe {
|
||||
let spa_buffer = (*buffer).buffer;
|
||||
|
||||
let mut pointer_elements = None;
|
||||
if self.cursor_mode == CursorMode::Metadata {
|
||||
add_cursor_metadata(renderer, spa_buffer, cursor_data, redraw_cursor);
|
||||
} else if self.cursor_mode != CursorMode::Hidden {
|
||||
// Embed the cursor into the main render.
|
||||
pointer_elements = Some(cursor_data.original.iter());
|
||||
}
|
||||
let pointer_elements = pointer_elements.into_iter().flatten();
|
||||
let elements = pointer_elements.chain(elements);
|
||||
|
||||
// FIXME: would be good to skip rendering the full frame if only the pointer changed.
|
||||
// Unfortunately, I think the OBS PipeWire code needs to be updated first to cleanly
|
||||
// allow for that codepath.
|
||||
let fd = (*(*spa_buffer).datas).fd;
|
||||
let dmabuf = self.inner.borrow().dmabufs[&fd].clone();
|
||||
let dmabuf = inner_.dmabufs[&fd].clone();
|
||||
|
||||
match render_to_dmabuf(
|
||||
renderer,
|
||||
dmabuf,
|
||||
size,
|
||||
scale,
|
||||
Transform::Normal,
|
||||
elements.rev(),
|
||||
) {
|
||||
let res = render_to_dmabuf(renderer, damage_tracker, dmabuf, elements, states);
|
||||
drop(inner);
|
||||
|
||||
match res {
|
||||
Ok(sync_point) => {
|
||||
mark_buffer_as_good(pw_buffer, &mut self.sequence_counter);
|
||||
trace!("queueing buffer with seq={}", self.sequence_counter);
|
||||
|
||||
Reference in New Issue
Block a user