Improve mirroring size/scale comparison

To determine if `mirroring_state` is needed, we want to compare the
untransformed dimensions of the source output to the target outputs
mode. The fact the mode comparision previously compared refresh rate
(since it compared the whole `Mode`) seems unintended.

We also re-create the `MirroringState` when the source output
dimensions changes.
This commit is contained in:
Ian Douglas Scott 2024-12-23 16:18:45 -08:00 committed by Victoria Brekenfeld
parent 9963887ac5
commit a3714b036e

View file

@ -63,7 +63,7 @@ use smithay::{
}, },
wayland_server::protocol::wl_surface::WlSurface, wayland_server::protocol::wl_surface::WlSurface,
}, },
utils::{Buffer as BufferCoords, Clock, Monotonic, Physical, Rectangle, Transform}, utils::{Buffer as BufferCoords, Clock, Monotonic, Physical, Rectangle, Size, Transform},
wayland::{ wayland::{
dmabuf::{get_dmabuf, DmabufFeedbackBuilder}, dmabuf::{get_dmabuf, DmabufFeedbackBuilder},
presentation::Refresh, presentation::Refresh,
@ -147,26 +147,52 @@ pub struct SurfaceThreadState {
egui: EguiState, egui: EguiState,
} }
#[derive(Debug, PartialEq)]
struct MirroringOutputConfig {
size: Size<i32, Physical>,
fractional_scale: f64,
}
impl MirroringOutputConfig {
fn for_output_untransformed(output: &Output) -> Self {
Self {
// Apply inverse of output transform to mode size to get correct size
// for an untransformed render.
size: output.current_transform().invert().transform_size(
output
.current_mode()
.map(|mode| mode.size)
.unwrap_or_default(),
),
fractional_scale: output.current_scale().fractional_scale(),
}
}
fn for_output(output: &Output) -> Self {
Self {
size: output
.current_mode()
.map(|mode| mode.size)
.unwrap_or_default(),
fractional_scale: output.current_scale().fractional_scale(),
}
}
}
#[derive(Debug)] #[derive(Debug)]
struct MirroringState { struct MirroringState {
texture: TextureRenderBuffer<GlesTexture>, texture: TextureRenderBuffer<GlesTexture>,
damage_tracker: OutputDamageTracker, damage_tracker: OutputDamageTracker,
output_config: MirroringOutputConfig,
} }
impl MirroringState { impl MirroringState {
fn new_with_renderer( fn new_with_renderer(
renderer: &mut GlMultiRenderer, renderer: &mut GlMultiRenderer,
format: Fourcc, format: Fourcc,
output: &Output, output_config: MirroringOutputConfig,
) -> Result<Self> { ) -> Result<Self> {
// Apply inverse of output transform to mode size to get correct size let size = output_config.size;
// for an untransformed render.
let size = output.current_transform().invert().transform_size(
output
.current_mode()
.map(|mode| mode.size)
.unwrap_or_default(),
);
let buffer_size = size.to_logical(1).to_buffer(1, Transform::Normal); let buffer_size = size.to_logical(1).to_buffer(1, Transform::Normal);
let opaque_regions = vec![Rectangle::from_size(buffer_size)]; let opaque_regions = vec![Rectangle::from_size(buffer_size)];
@ -180,15 +206,13 @@ impl MirroringState {
); );
// Don't use `from_output` to avoid applying output transform // Don't use `from_output` to avoid applying output transform
let damage_tracker = OutputDamageTracker::new( let damage_tracker =
size, OutputDamageTracker::new(size, output_config.fractional_scale, Transform::Normal);
output.current_scale().fractional_scale(),
Transform::Normal,
);
Ok(MirroringState { Ok(MirroringState {
texture: texture_buffer, texture: texture_buffer,
damage_tracker, damage_tracker,
output_config,
}) })
} }
} }
@ -1053,20 +1077,29 @@ impl SurfaceThreadState {
// actual rendering // actual rendering
let res = if let Some(mirrored_output) = self.mirroring.as_ref().filter(|mirrored_output| { let res = if let Some(mirrored_output) = self.mirroring.as_ref().filter(|mirrored_output| {
mirrored_output.current_mode().is_some_and(|mirror_mode| { MirroringOutputConfig::for_output_untransformed(mirrored_output)
self.output != MirroringOutputConfig::for_output(&self.output)
.current_mode()
.is_some_and(|mode| mode != mirror_mode)
}) || mirrored_output.current_scale().fractional_scale()
!= self.output.current_scale().fractional_scale()
}) { }) {
let mirrored_output_config =
MirroringOutputConfig::for_output_untransformed(mirrored_output);
let mirroring_state = match self.mirroring_textures.entry(self.target_node) { let mirroring_state = match self.mirroring_textures.entry(self.target_node) {
hash_map::Entry::Occupied(occupied) => occupied.into_mut(), hash_map::Entry::Occupied(occupied) => {
let mirroring_state = occupied.into_mut();
// If output config is different, re-create offscreen state
if mirroring_state.output_config != mirrored_output_config {
*mirroring_state = MirroringState::new_with_renderer(
&mut renderer,
compositor.format(),
mirrored_output_config,
)?
}
mirroring_state
}
hash_map::Entry::Vacant(vacant) => { hash_map::Entry::Vacant(vacant) => {
vacant.insert(MirroringState::new_with_renderer( vacant.insert(MirroringState::new_with_renderer(
&mut renderer, &mut renderer,
compositor.format(), compositor.format(),
mirrored_output, mirrored_output_config,
)?) )?)
} }
}; };