mirror of
https://github.com/niri-wm/niri.git
synced 2026-06-24 02:01:18 +07:00
Add wait-for-frame-completion-in-pipewire debug flag for NVIDIA screencasts
This commit is contained in:
committed by
Ivan Molodetskikh
parent
e11af089aa
commit
5b6b6a5fe1
@@ -2039,6 +2039,8 @@ pub struct DebugConfig {
|
|||||||
#[knuffel(child)]
|
#[knuffel(child)]
|
||||||
pub wait_for_frame_completion_before_queueing: bool,
|
pub wait_for_frame_completion_before_queueing: bool,
|
||||||
#[knuffel(child)]
|
#[knuffel(child)]
|
||||||
|
pub wait_for_frame_completion_in_pipewire: bool,
|
||||||
|
#[knuffel(child)]
|
||||||
pub enable_overlay_planes: bool,
|
pub enable_overlay_planes: bool,
|
||||||
#[knuffel(child)]
|
#[knuffel(child)]
|
||||||
pub disable_cursor_plane: bool,
|
pub disable_cursor_plane: bool,
|
||||||
@@ -4837,6 +4839,7 @@ mod tests {
|
|||||||
preview_render: None,
|
preview_render: None,
|
||||||
dbus_interfaces_in_non_session_instances: false,
|
dbus_interfaces_in_non_session_instances: false,
|
||||||
wait_for_frame_completion_before_queueing: false,
|
wait_for_frame_completion_before_queueing: false,
|
||||||
|
wait_for_frame_completion_in_pipewire: false,
|
||||||
enable_overlay_planes: false,
|
enable_overlay_planes: false,
|
||||||
disable_cursor_plane: false,
|
disable_cursor_plane: false,
|
||||||
disable_direct_scanout: false,
|
disable_direct_scanout: false,
|
||||||
|
|||||||
+27
-4
@@ -1630,8 +1630,12 @@ impl State {
|
|||||||
|
|
||||||
match &cast.target {
|
match &cast.target {
|
||||||
CastTarget::Nothing => {
|
CastTarget::Nothing => {
|
||||||
|
let config = self.niri.config.borrow();
|
||||||
|
let wait_for_sync = config.debug.wait_for_frame_completion_in_pipewire;
|
||||||
|
drop(config);
|
||||||
|
|
||||||
self.backend.with_primary_renderer(|renderer| {
|
self.backend.with_primary_renderer(|renderer| {
|
||||||
if cast.dequeue_buffer_and_clear(renderer) {
|
if cast.dequeue_buffer_and_clear(renderer, wait_for_sync) {
|
||||||
cast.last_frame_time = get_monotonic_time();
|
cast.last_frame_time = get_monotonic_time();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -1671,6 +1675,10 @@ impl State {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let config = self.niri.config.borrow();
|
||||||
|
let wait_for_sync = config.debug.wait_for_frame_completion_in_pipewire;
|
||||||
|
drop(config);
|
||||||
|
|
||||||
self.backend.with_primary_renderer(|renderer| {
|
self.backend.with_primary_renderer(|renderer| {
|
||||||
// FIXME: pointer.
|
// FIXME: pointer.
|
||||||
let elements = mapped
|
let elements = mapped
|
||||||
@@ -1678,7 +1686,13 @@ impl State {
|
|||||||
.rev()
|
.rev()
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
if cast.dequeue_buffer_and_render(renderer, &elements, bbox.size, scale) {
|
if cast.dequeue_buffer_and_render(
|
||||||
|
renderer,
|
||||||
|
&elements,
|
||||||
|
bbox.size,
|
||||||
|
scale,
|
||||||
|
wait_for_sync,
|
||||||
|
) {
|
||||||
cast.last_frame_time = get_monotonic_time();
|
cast.last_frame_time = get_monotonic_time();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -4370,6 +4384,10 @@ impl Niri {
|
|||||||
|
|
||||||
let scale = Scale::from(output.current_scale().fractional_scale());
|
let scale = Scale::from(output.current_scale().fractional_scale());
|
||||||
|
|
||||||
|
let config = self.config.borrow();
|
||||||
|
let wait_for_sync = config.debug.wait_for_frame_completion_in_pipewire;
|
||||||
|
drop(config);
|
||||||
|
|
||||||
let mut elements = None;
|
let mut elements = None;
|
||||||
let mut casts_to_stop = vec![];
|
let mut casts_to_stop = vec![];
|
||||||
|
|
||||||
@@ -4401,7 +4419,7 @@ impl Niri {
|
|||||||
self.render(renderer, output, true, RenderTarget::Screencast)
|
self.render(renderer, output, true, RenderTarget::Screencast)
|
||||||
});
|
});
|
||||||
|
|
||||||
if cast.dequeue_buffer_and_render(renderer, elements, size, scale) {
|
if cast.dequeue_buffer_and_render(renderer, elements, size, scale, wait_for_sync) {
|
||||||
cast.last_frame_time = target_presentation_time;
|
cast.last_frame_time = target_presentation_time;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4423,6 +4441,10 @@ impl Niri {
|
|||||||
|
|
||||||
let scale = Scale::from(output.current_scale().fractional_scale());
|
let scale = Scale::from(output.current_scale().fractional_scale());
|
||||||
|
|
||||||
|
let config = self.config.borrow();
|
||||||
|
let wait_for_sync = config.debug.wait_for_frame_completion_in_pipewire;
|
||||||
|
drop(config);
|
||||||
|
|
||||||
let mut casts_to_stop = vec![];
|
let mut casts_to_stop = vec![];
|
||||||
|
|
||||||
let mut casts = mem::take(&mut self.casts);
|
let mut casts = mem::take(&mut self.casts);
|
||||||
@@ -4461,7 +4483,8 @@ impl Niri {
|
|||||||
// FIXME: pointer.
|
// FIXME: pointer.
|
||||||
let elements: Vec<_> = mapped.render_for_screen_cast(renderer, scale).collect();
|
let elements: Vec<_> = mapped.render_for_screen_cast(renderer, scale).collect();
|
||||||
|
|
||||||
if cast.dequeue_buffer_and_render(renderer, &elements, bbox.size, scale) {
|
if cast.dequeue_buffer_and_render(renderer, &elements, bbox.size, scale, wait_for_sync)
|
||||||
|
{
|
||||||
cast.last_frame_time = target_presentation_time;
|
cast.last_frame_time = target_presentation_time;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+30
-3
@@ -821,6 +821,7 @@ impl Cast {
|
|||||||
elements: &[impl RenderElement<GlesRenderer>],
|
elements: &[impl RenderElement<GlesRenderer>],
|
||||||
size: Size<i32, Physical>,
|
size: Size<i32, Physical>,
|
||||||
scale: Scale<f64>,
|
scale: Scale<f64>,
|
||||||
|
wait_for_sync: bool,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let CastState::Ready { damage_tracker, .. } = &mut *self.state.borrow_mut() else {
|
let CastState::Ready { damage_tracker, .. } = &mut *self.state.borrow_mut() else {
|
||||||
error!("cast must be in Ready state to render");
|
error!("cast must be in Ready state to render");
|
||||||
@@ -851,7 +852,7 @@ impl Cast {
|
|||||||
let fd = buffer.datas_mut()[0].as_raw().fd;
|
let fd = buffer.datas_mut()[0].as_raw().fd;
|
||||||
let dmabuf = &self.dmabufs.borrow()[&fd];
|
let dmabuf = &self.dmabufs.borrow()[&fd];
|
||||||
|
|
||||||
if let Err(err) = render_to_dmabuf(
|
match render_to_dmabuf(
|
||||||
renderer,
|
renderer,
|
||||||
dmabuf.clone(),
|
dmabuf.clone(),
|
||||||
size,
|
size,
|
||||||
@@ -859,9 +860,20 @@ impl Cast {
|
|||||||
Transform::Normal,
|
Transform::Normal,
|
||||||
elements.iter().rev(),
|
elements.iter().rev(),
|
||||||
) {
|
) {
|
||||||
|
Ok(sync_point) => {
|
||||||
|
// FIXME: implement PipeWire explicit sync, and at the very least async wait.
|
||||||
|
if wait_for_sync {
|
||||||
|
let _span = tracy_client::span!("wait for completion");
|
||||||
|
if let Err(err) = sync_point.wait() {
|
||||||
|
warn!("error waiting for pw frame completion: {err:?}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
warn!("error rendering to dmabuf: {err:?}");
|
warn!("error rendering to dmabuf: {err:?}");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (data, (stride, offset)) in
|
for (data, (stride, offset)) in
|
||||||
zip(buffer.datas_mut(), zip(dmabuf.strides(), dmabuf.offsets()))
|
zip(buffer.datas_mut(), zip(dmabuf.strides(), dmabuf.offsets()))
|
||||||
@@ -880,7 +892,11 @@ impl Cast {
|
|||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dequeue_buffer_and_clear(&mut self, renderer: &mut GlesRenderer) -> bool {
|
pub fn dequeue_buffer_and_clear(
|
||||||
|
&mut self,
|
||||||
|
renderer: &mut GlesRenderer,
|
||||||
|
wait_for_sync: bool,
|
||||||
|
) -> bool {
|
||||||
// Clear out the damage tracker if we're in Ready state.
|
// Clear out the damage tracker if we're in Ready state.
|
||||||
if let CastState::Ready { damage_tracker, .. } = &mut *self.state.borrow_mut() {
|
if let CastState::Ready { damage_tracker, .. } = &mut *self.state.borrow_mut() {
|
||||||
*damage_tracker = None;
|
*damage_tracker = None;
|
||||||
@@ -894,10 +910,21 @@ impl Cast {
|
|||||||
let fd = buffer.datas_mut()[0].as_raw().fd;
|
let fd = buffer.datas_mut()[0].as_raw().fd;
|
||||||
let dmabuf = &self.dmabufs.borrow()[&fd];
|
let dmabuf = &self.dmabufs.borrow()[&fd];
|
||||||
|
|
||||||
if let Err(err) = clear_dmabuf(renderer, dmabuf.clone()) {
|
match clear_dmabuf(renderer, dmabuf.clone()) {
|
||||||
|
Ok(sync_point) => {
|
||||||
|
// FIXME: implement PipeWire explicit sync, and at the very least async wait.
|
||||||
|
if wait_for_sync {
|
||||||
|
let _span = tracy_client::span!("wait for completion");
|
||||||
|
if let Err(err) = sync_point.wait() {
|
||||||
|
warn!("error waiting for pw frame completion: {err:?}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
warn!("error clearing dmabuf: {err:?}");
|
warn!("error clearing dmabuf: {err:?}");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (data, (stride, offset)) in
|
for (data, (stride, offset)) in
|
||||||
zip(buffer.datas_mut(), zip(dmabuf.strides(), dmabuf.offsets()))
|
zip(buffer.datas_mut(), zip(dmabuf.strides(), dmabuf.offsets()))
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ debug {
|
|||||||
force-pipewire-invalid-modifier
|
force-pipewire-invalid-modifier
|
||||||
dbus-interfaces-in-non-session-instances
|
dbus-interfaces-in-non-session-instances
|
||||||
wait-for-frame-completion-before-queueing
|
wait-for-frame-completion-before-queueing
|
||||||
|
wait-for-frame-completion-in-pipewire
|
||||||
emulate-zero-presentation-time
|
emulate-zero-presentation-time
|
||||||
disable-resize-throttling
|
disable-resize-throttling
|
||||||
disable-transactions
|
disable-transactions
|
||||||
@@ -152,6 +153,22 @@ debug {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### `wait-for-frame-completion-in-pipewire`
|
||||||
|
|
||||||
|
<sup>Since: next release</sup>
|
||||||
|
|
||||||
|
Wait until every screencast frame is done rendering before handing it over to PipeWire.
|
||||||
|
|
||||||
|
Sometimes helps on NVIDIA to prevent glitched frames when screencasting.
|
||||||
|
|
||||||
|
This debug flag will eventually be removed once we handle this properly (via explicit sync in PipeWire).
|
||||||
|
|
||||||
|
```kdl
|
||||||
|
debug {
|
||||||
|
wait-for-frame-completion-in-pipewire
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### `emulate-zero-presentation-time`
|
### `emulate-zero-presentation-time`
|
||||||
|
|
||||||
Emulate zero (unknown) presentation time returned from DRM.
|
Emulate zero (unknown) presentation time returned from DRM.
|
||||||
|
|||||||
Reference in New Issue
Block a user