Fix fractional-scale capture sizing and release idle capture caches
This commit is contained in:
1 parent
07a8e50f47
commit
a5e8ba65e2
5 files changed
+57
-4
No files matched your search
@@ -3,12 +3,51 @@ use smithay::backend::renderer::element::RenderElement;
|
|||||||
use smithay::backend::renderer::gles::{GlesError, GlesRenderer, GlesTarget, GlesTexture};
|
use smithay::backend::renderer::gles::{GlesError, GlesRenderer, GlesTarget, GlesTexture};
|
||||||
use smithay::backend::renderer::{Bind, Offscreen, Texture};
|
use smithay::backend::renderer::{Bind, Offscreen, Texture};
|
||||||
use smithay::output::Output;
|
use smithay::output::Output;
|
||||||
|
use smithay::reexports::calloop::timer::{TimeoutAction, Timer};
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
use crate::Ferese;
|
use crate::Ferese;
|
||||||
use crate::render::{capture_output_elements, redraw_output};
|
use crate::render::{capture_output_elements, redraw_output};
|
||||||
use crate::state::FrameScene;
|
use crate::state::FrameScene;
|
||||||
|
|
||||||
|
const CACHE_IDLE: Duration = Duration::from_secs(2);
|
||||||
|
|
||||||
|
pub(crate) fn touch_cache(state: &mut Ferese) {
|
||||||
|
if state.capture_last_used.replace(Instant::now()).is_some() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if let Err(error) = state
|
||||||
|
.loop_handle
|
||||||
|
.insert_source(Timer::from_duration(CACHE_IDLE), |_, _, state| {
|
||||||
|
let Some(last_used) = state.capture_last_used else {
|
||||||
|
return TimeoutAction::Drop;
|
||||||
|
};
|
||||||
|
let idle = last_used.elapsed();
|
||||||
|
if idle < CACHE_IDLE {
|
||||||
|
return TimeoutAction::ToDuration(CACHE_IDLE - idle);
|
||||||
|
}
|
||||||
|
// A stream can pause or fail without another repaint. Release its
|
||||||
|
// offscreen targets and filtered-scene caches from the event loop.
|
||||||
|
state.capture_last_used = None;
|
||||||
|
state.capture_render = Default::default();
|
||||||
|
state.nested_capture_texture = None;
|
||||||
|
if let Some(backend) = state.direct_backend.as_mut() {
|
||||||
|
for device in backend.devices.values_mut() {
|
||||||
|
for output in device.outputs.values_mut() {
|
||||||
|
output.capture_texture = None;
|
||||||
|
output.mirror_capture_texture = None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TimeoutAction::Drop
|
||||||
|
})
|
||||||
|
{
|
||||||
|
state.capture_last_used = None;
|
||||||
|
tracing::warn!(%error, "could not schedule capture cache cleanup");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn capture_output(
|
pub(crate) fn capture_output(
|
||||||
state: &mut Ferese,
|
state: &mut Ferese,
|
||||||
renderer: &mut GlesRenderer,
|
renderer: &mut GlesRenderer,
|
||||||
|
|||||||
@@ -447,6 +447,15 @@ pub(crate) fn capture_region_for_geometry(
|
|||||||
transform: smithay::utils::Transform,
|
transform: smithay::utils::Transform,
|
||||||
requested: Option<Rectangle<i32, Logical>>,
|
requested: Option<Rectangle<i32, Logical>>,
|
||||||
) -> Option<Rectangle<i32, Buffer>> {
|
) -> Option<Rectangle<i32, Buffer>> {
|
||||||
|
let buffer_bounds = Rectangle::from_size(Size::<i32, Buffer>::from((mode_size.w, mode_size.h)));
|
||||||
|
if mode_size.w <= 0 || mode_size.h <= 0 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
// Full-output captures must match the framebuffer exactly. Rounding the
|
||||||
|
// logical size and scaling it back can add a pixel at fractional scales.
|
||||||
|
if requested.is_none() {
|
||||||
|
return Some(buffer_bounds);
|
||||||
|
}
|
||||||
let logical_size = output_logical_size(mode_size, scale, transform);
|
let logical_size = output_logical_size(mode_size, scale, transform);
|
||||||
let output_region = Rectangle::from_size(logical_size);
|
let output_region = Rectangle::from_size(logical_size);
|
||||||
let logical_region = requested.unwrap_or(output_region).intersection(output_region)?;
|
let logical_region = requested.unwrap_or(output_region).intersection(output_region)?;
|
||||||
@@ -455,12 +464,11 @@ pub(crate) fn capture_region_for_geometry(
|
|||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(
|
|
||||||
logical_region
|
logical_region
|
||||||
.to_f64()
|
.to_f64()
|
||||||
.to_buffer(scale, transform, &logical_size.to_f64())
|
.to_buffer(scale, transform, &logical_size.to_f64())
|
||||||
.to_i32_round(),
|
.to_i32_round()
|
||||||
)
|
.intersection(buffer_bounds)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn valid_shm_buffer(buffer: &WlBuffer, expected: Size<i32, Buffer>) -> bool {
|
pub(super) fn valid_shm_buffer(buffer: &WlBuffer, expected: Size<i32, Buffer>) -> bool {
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ pub(crate) fn capture_output_elements(
|
|||||||
) -> Vec<AnimatedWindowRenderElement> {
|
) -> Vec<AnimatedWindowRenderElement> {
|
||||||
// Blur textures and resize handoff snapshots must never be shared with
|
// Blur textures and resize handoff snapshots must never be shared with
|
||||||
// display rendering. Only the capture scene can populate these caches.
|
// display rendering. Only the capture scene can populate these caches.
|
||||||
|
crate::backends::direct::capture::touch_cache(state);
|
||||||
std::mem::swap(&mut state.render, &mut state.capture_render);
|
std::mem::swap(&mut state.render, &mut state.capture_render);
|
||||||
let elements = scene_elements(state, renderer, output, include_cursor, frame, true);
|
let elements = scene_elements(state, renderer, output, include_cursor, frame, true);
|
||||||
std::mem::swap(&mut state.render, &mut state.capture_render);
|
std::mem::swap(&mut state.render, &mut state.capture_render);
|
||||||
|
|||||||
@@ -440,6 +440,8 @@ pub struct Ferese {
|
|||||||
pub(crate) windows: WindowRegistry<Window>,
|
pub(crate) windows: WindowRegistry<Window>,
|
||||||
pub(crate) render: crate::render::RenderResources,
|
pub(crate) render: crate::render::RenderResources,
|
||||||
pub(crate) capture_render: crate::render::RenderResources,
|
pub(crate) capture_render: crate::render::RenderResources,
|
||||||
|
pub(crate) capture_last_used: Option<Instant>,
|
||||||
|
pub(crate) nested_capture_texture: Option<smithay::backend::renderer::gles::GlesTexture>,
|
||||||
pub(crate) capture_epoch: u64,
|
pub(crate) capture_epoch: u64,
|
||||||
capture_protected_windows: HashSet<WindowId>,
|
capture_protected_windows: HashSet<WindowId>,
|
||||||
capture_protected_cursor: Option<WlSurface>,
|
capture_protected_cursor: Option<WlSurface>,
|
||||||
@@ -742,6 +744,8 @@ impl Ferese {
|
|||||||
windows: WindowRegistry::default(),
|
windows: WindowRegistry::default(),
|
||||||
render: Default::default(),
|
render: Default::default(),
|
||||||
capture_render: Default::default(),
|
capture_render: Default::default(),
|
||||||
|
capture_last_used: None,
|
||||||
|
nested_capture_texture: None,
|
||||||
capture_epoch: 0,
|
capture_epoch: 0,
|
||||||
capture_protected_windows: HashSet::new(),
|
capture_protected_windows: HashSet::new(),
|
||||||
capture_protected_cursor: None,
|
capture_protected_cursor: None,
|
||||||
|
|||||||
@@ -94,7 +94,6 @@ pub fn init(event_loop: &mut EventLoop<Ferese>, state: &mut Ferese) -> Result<()
|
|||||||
}
|
}
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let mut capture_texture = None;
|
|
||||||
event_loop
|
event_loop
|
||||||
.handle()
|
.handle()
|
||||||
.insert_source(event_source, move |event, _, state| {
|
.insert_source(event_source, move |event, _, state| {
|
||||||
@@ -157,6 +156,7 @@ pub fn init(event_loop: &mut EventLoop<Ferese>, state: &mut Ferese) -> Result<()
|
|||||||
|| state.has_pending_screencopy(&output, true)
|
|| state.has_pending_screencopy(&output, true)
|
||||||
{
|
{
|
||||||
let scene = state.sample_frame(&output, Duration::ZERO);
|
let scene = state.sample_frame(&output, Duration::ZERO);
|
||||||
|
let mut capture_texture = state.nested_capture_texture.take();
|
||||||
crate::backends::direct::capture::capture_output(
|
crate::backends::direct::capture::capture_output(
|
||||||
state,
|
state,
|
||||||
renderer,
|
renderer,
|
||||||
@@ -164,6 +164,7 @@ pub fn init(event_loop: &mut EventLoop<Ferese>, state: &mut Ferese) -> Result<()
|
|||||||
&output,
|
&output,
|
||||||
&scene,
|
&scene,
|
||||||
);
|
);
|
||||||
|
state.nested_capture_texture = capture_texture;
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user