kms: Support screencopy cursor modes with active filters
This commit is contained in:
parent
7373b3f513
commit
7a8577592d
2 changed files with 326 additions and 46 deletions
|
|
@ -3,8 +3,8 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
backend::render::{
|
backend::render::{
|
||||||
element::{CosmicElement, DamageElement},
|
element::{CosmicElement, DamageElement},
|
||||||
init_shaders, output_elements, CursorMode, GlMultiRenderer, PostprocessOutputConfig,
|
init_shaders, output_elements, CursorMode, GlMultiError, GlMultiRenderer,
|
||||||
PostprocessShader, PostprocessState, CLEAR_COLOR,
|
PostprocessOutputConfig, PostprocessShader, PostprocessState, CLEAR_COLOR,
|
||||||
},
|
},
|
||||||
config::{AdaptiveSync, ScreenFilter},
|
config::{AdaptiveSync, ScreenFilter},
|
||||||
shell::Shell,
|
shell::Shell,
|
||||||
|
|
@ -25,6 +25,7 @@ use smithay::{
|
||||||
allocator::{
|
allocator::{
|
||||||
format::FormatSet,
|
format::FormatSet,
|
||||||
gbm::{GbmAllocator, GbmDevice},
|
gbm::{GbmAllocator, GbmDevice},
|
||||||
|
Fourcc,
|
||||||
},
|
},
|
||||||
drm::{
|
drm::{
|
||||||
compositor::{BlitFrameResultError, FrameError, FrameFlags, PrimaryPlaneElement},
|
compositor::{BlitFrameResultError, FrameError, FrameFlags, PrimaryPlaneElement},
|
||||||
|
|
@ -37,15 +38,21 @@ use smithay::{
|
||||||
damage::Error as RenderError,
|
damage::Error as RenderError,
|
||||||
element::{
|
element::{
|
||||||
texture::TextureRenderElement,
|
texture::TextureRenderElement,
|
||||||
utils::{constrain_render_elements, ConstrainAlign, ConstrainScaleBehavior},
|
utils::{
|
||||||
|
constrain_render_elements, ConstrainAlign, ConstrainScaleBehavior, Relocate,
|
||||||
|
RelocateRenderElement,
|
||||||
|
},
|
||||||
Element, Kind, RenderElementStates,
|
Element, Kind, RenderElementStates,
|
||||||
},
|
},
|
||||||
gles::{element::TextureShaderElement, GlesRenderbuffer, GlesRenderer, Uniform},
|
gles::{
|
||||||
|
element::TextureShaderElement, GlesRenderbuffer, GlesRenderer, GlesTexture, Uniform,
|
||||||
|
},
|
||||||
glow::GlowRenderer,
|
glow::GlowRenderer,
|
||||||
multigpu::{Error as MultiError, GpuManager},
|
multigpu::{Error as MultiError, GpuManager},
|
||||||
sync::SyncPoint,
|
sync::SyncPoint,
|
||||||
utils::with_renderer_surface_state,
|
utils::with_renderer_surface_state,
|
||||||
Bind, Blit, ImportDma, Offscreen, Renderer, RendererSuper, Texture, TextureFilter,
|
Bind, Blit, Frame, ImportDma, Offscreen, Renderer, RendererSuper, Texture,
|
||||||
|
TextureFilter,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
desktop::utils::OutputPresentationFeedback,
|
desktop::utils::OutputPresentationFeedback,
|
||||||
|
|
@ -63,7 +70,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, Point, Rectangle, Transform},
|
||||||
wayland::{
|
wayland::{
|
||||||
dmabuf::{get_dmabuf, DmabufFeedbackBuilder},
|
dmabuf::{get_dmabuf, DmabufFeedbackBuilder},
|
||||||
presentation::Refresh,
|
presentation::Refresh,
|
||||||
|
|
@ -936,6 +943,7 @@ impl SurfaceThreadState {
|
||||||
|
|
||||||
// we can't use the elements after `compositor.render_frame`,
|
// we can't use the elements after `compositor.render_frame`,
|
||||||
// so let's collect everything we need for screencopy now
|
// so let's collect everything we need for screencopy now
|
||||||
|
let mut has_cursor_mode_none = false;
|
||||||
let frames: Vec<(
|
let frames: Vec<(
|
||||||
ScreencopySession,
|
ScreencopySession,
|
||||||
ScreencopyFrame,
|
ScreencopyFrame,
|
||||||
|
|
@ -993,6 +1001,10 @@ impl SurfaceThreadState {
|
||||||
elements.truncate(old_len);
|
elements.truncate(old_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !session.draw_cursor() {
|
||||||
|
has_cursor_mode_none = true;
|
||||||
|
}
|
||||||
|
|
||||||
let res = res.map(|(a, b)| (a.cloned(), b));
|
let res = res.map(|(a, b)| (a.cloned(), b));
|
||||||
std::mem::drop(damage_tracking);
|
std::mem::drop(damage_tracking);
|
||||||
(session, frame, res)
|
(session, frame, res)
|
||||||
|
|
@ -1011,8 +1023,16 @@ impl SurfaceThreadState {
|
||||||
|| !self.screen_filter.is_noop()
|
|| !self.screen_filter.is_noop()
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut pre_postprocess_states = None;
|
#[derive(Debug, Default)]
|
||||||
let mut pre_postprocess_texture = None;
|
struct PrePostprocessData {
|
||||||
|
states: Option<RenderElementStates>,
|
||||||
|
texture: Option<GlesTexture>,
|
||||||
|
cursor_texture: Option<GlesTexture>,
|
||||||
|
cursor_geometry: Option<Rectangle<i32, Physical>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut pre_postprocess_data = PrePostprocessData::default();
|
||||||
|
|
||||||
let res = if let Some(source_output) = source_output {
|
let res = if let Some(source_output) = source_output {
|
||||||
let offscreen_output_config =
|
let offscreen_output_config =
|
||||||
PostprocessOutputConfig::for_output_untransformed(source_output);
|
PostprocessOutputConfig::for_output_untransformed(source_output);
|
||||||
|
|
@ -1038,12 +1058,104 @@ impl SurfaceThreadState {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if has_cursor_mode_none && self.mirroring.is_none() {
|
||||||
|
// TODO: use `extract_if` once stablized
|
||||||
|
let cursor_element_count = elements
|
||||||
|
.iter()
|
||||||
|
.take_while(|elem| elem.kind() == Kind::Cursor)
|
||||||
|
.count();
|
||||||
|
let cursor_elements = elements.drain(..cursor_element_count).collect::<Vec<_>>();
|
||||||
|
let scale = source_output.current_scale().fractional_scale().into();
|
||||||
|
|
||||||
|
let geometry: Option<Rectangle<i32, Physical>> =
|
||||||
|
cursor_elements.iter().fold(None, |acc, elem| {
|
||||||
|
let geometry = elem.geometry(scale);
|
||||||
|
if let Some(acc) = acc {
|
||||||
|
Some(acc.merge(geometry))
|
||||||
|
} else {
|
||||||
|
Some(geometry)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if let Some(geometry) = geometry {
|
||||||
|
let cursor_elements = cursor_elements
|
||||||
|
.into_iter()
|
||||||
|
.map(|elem| {
|
||||||
|
RelocateRenderElement::from_element(
|
||||||
|
elem,
|
||||||
|
Point::from((-geometry.loc.x, -geometry.loc.y)),
|
||||||
|
Relocate::Relative,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
postprocess_state.track_cursor(
|
||||||
|
&mut renderer,
|
||||||
|
Fourcc::Abgr8888,
|
||||||
|
geometry.size,
|
||||||
|
scale,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
postprocess_state
|
||||||
|
.cursor_texture
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.render()
|
||||||
|
.draw::<_, <GlMultiRenderer as RendererSuper>::Error>(|tex| {
|
||||||
|
if self.mirroring.is_none() {
|
||||||
|
pre_postprocess_data.cursor_geometry = Some(geometry);
|
||||||
|
pre_postprocess_data.cursor_texture = Some(tex.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut fb = renderer.bind(tex)?;
|
||||||
|
let res = match postprocess_state
|
||||||
|
.cursor_damage_tracker
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.render_output(
|
||||||
|
&mut renderer,
|
||||||
|
&mut fb,
|
||||||
|
1,
|
||||||
|
&cursor_elements,
|
||||||
|
[0.0, 0.0, 0.0, 0.0],
|
||||||
|
) {
|
||||||
|
Ok(res) => res,
|
||||||
|
Err(RenderError::Rendering(err)) => return Err(err),
|
||||||
|
Err(RenderError::OutputNoMode(_)) => unreachable!(),
|
||||||
|
};
|
||||||
|
|
||||||
|
if self.mirroring.is_none() {
|
||||||
|
pre_postprocess_data.states = Some(res.states);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderer.wait(&res.sync)?;
|
||||||
|
std::mem::drop(fb);
|
||||||
|
|
||||||
|
let transform = source_output.current_transform();
|
||||||
|
let area = tex.size().to_logical(1, transform);
|
||||||
|
|
||||||
|
Ok(res
|
||||||
|
.damage
|
||||||
|
.cloned()
|
||||||
|
.map(|v| {
|
||||||
|
v.into_iter()
|
||||||
|
.map(|r| r.to_logical(1).to_buffer(1, transform, &area))
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
})
|
||||||
|
.unwrap_or_default())
|
||||||
|
})
|
||||||
|
.context("Failed to draw to offscreen render target")?;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
postprocess_state.remove_cursor();
|
||||||
|
}
|
||||||
|
|
||||||
postprocess_state
|
postprocess_state
|
||||||
.texture
|
.texture
|
||||||
.render()
|
.render()
|
||||||
.draw::<_, <GlMultiRenderer as RendererSuper>::Error>(|tex| {
|
.draw::<_, <GlMultiRenderer as RendererSuper>::Error>(|tex| {
|
||||||
if self.mirroring.is_none() {
|
if self.mirroring.is_none() {
|
||||||
pre_postprocess_texture = Some(tex.clone());
|
pre_postprocess_data.texture = Some(tex.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut fb = renderer.bind(tex)?;
|
let mut fb = renderer.bind(tex)?;
|
||||||
|
|
@ -1060,7 +1172,11 @@ impl SurfaceThreadState {
|
||||||
};
|
};
|
||||||
|
|
||||||
if self.mirroring.is_none() {
|
if self.mirroring.is_none() {
|
||||||
pre_postprocess_states = Some(res.states);
|
if let Some(states) = pre_postprocess_data.states.as_mut() {
|
||||||
|
states.states.extend(res.states.states);
|
||||||
|
} else {
|
||||||
|
pre_postprocess_data.states = Some(res.states);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
renderer.wait(&res.sync)?;
|
renderer.wait(&res.sync)?;
|
||||||
|
|
@ -1081,26 +1197,73 @@ impl SurfaceThreadState {
|
||||||
})
|
})
|
||||||
.context("Failed to draw to offscreen render target")?;
|
.context("Failed to draw to offscreen render target")?;
|
||||||
|
|
||||||
let texture_elem = TextureRenderElement::from_texture_render_buffer(
|
|
||||||
(0., 0.),
|
|
||||||
&postprocess_state.texture,
|
|
||||||
Some(1.0),
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
Kind::Unspecified,
|
|
||||||
);
|
|
||||||
|
|
||||||
renderer = self.api.single_renderer(&self.target_node).unwrap();
|
renderer = self.api.single_renderer(&self.target_node).unwrap();
|
||||||
|
let postprocess_texture_shader = Borrow::<GlesRenderer>::borrow(renderer.as_ref())
|
||||||
let postprocess_texture_shader = Borrow::<GlesRenderer>::borrow(renderer.as_mut())
|
|
||||||
.egl_context()
|
.egl_context()
|
||||||
.user_data()
|
.user_data()
|
||||||
.get::<PostprocessShader>()
|
.get::<PostprocessShader>()
|
||||||
.expect("OffscreenShader should be available through `init_shaders`");
|
.expect("OffscreenShader should be available through `init_shaders`");
|
||||||
let texture_geometry =
|
|
||||||
texture_elem.geometry(self.output.current_scale().fractional_scale().into());
|
|
||||||
elements = {
|
elements = {
|
||||||
let texture_elem = TextureShaderElement::new(
|
let mut elements: [Option<TextureShaderElement>; 2] = [None, None];
|
||||||
|
if let Some(cursor_texture) = postprocess_state.cursor_texture.as_ref() {
|
||||||
|
let cursor_geometry = pre_postprocess_data.cursor_geometry.unwrap();
|
||||||
|
let texture_elem = TextureRenderElement::from_texture_render_buffer(
|
||||||
|
cursor_geometry.loc.to_f64(),
|
||||||
|
cursor_texture,
|
||||||
|
None,
|
||||||
|
Some(Rectangle::new(
|
||||||
|
Point::from((0., 0.)),
|
||||||
|
cursor_geometry.size.to_logical(1).to_f64(),
|
||||||
|
)),
|
||||||
|
Some(
|
||||||
|
cursor_geometry
|
||||||
|
.size
|
||||||
|
.to_f64()
|
||||||
|
.to_logical(self.output.current_scale().fractional_scale())
|
||||||
|
.to_i32_round(),
|
||||||
|
),
|
||||||
|
Kind::Cursor,
|
||||||
|
);
|
||||||
|
|
||||||
|
elements[0] = Some(TextureShaderElement::new(
|
||||||
|
texture_elem,
|
||||||
|
postprocess_texture_shader.0.clone(),
|
||||||
|
vec![
|
||||||
|
Uniform::new(
|
||||||
|
"invert",
|
||||||
|
if self.screen_filter.inverted { 1. } else { 0. },
|
||||||
|
),
|
||||||
|
Uniform::new(
|
||||||
|
"color_mode",
|
||||||
|
self.screen_filter
|
||||||
|
.color_filter
|
||||||
|
.map(|val| val as u8 as f32)
|
||||||
|
.unwrap_or(0.),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
let texture_elem = TextureRenderElement::from_texture_render_buffer(
|
||||||
|
(0., 0.),
|
||||||
|
&postprocess_state.texture,
|
||||||
|
None,
|
||||||
|
Some(Rectangle::new(
|
||||||
|
Point::from((0., 0.)),
|
||||||
|
postprocess_state.output_config.size.to_logical(1).to_f64(),
|
||||||
|
)),
|
||||||
|
Some(
|
||||||
|
postprocess_state
|
||||||
|
.output_config
|
||||||
|
.size
|
||||||
|
.to_f64()
|
||||||
|
.to_logical(postprocess_state.output_config.fractional_scale)
|
||||||
|
.to_i32_round(),
|
||||||
|
),
|
||||||
|
Kind::Unspecified,
|
||||||
|
);
|
||||||
|
elements[1] = Some(TextureShaderElement::new(
|
||||||
texture_elem,
|
texture_elem,
|
||||||
postprocess_texture_shader.0.clone(),
|
postprocess_texture_shader.0.clone(),
|
||||||
vec![
|
vec![
|
||||||
|
|
@ -1113,23 +1276,24 @@ impl SurfaceThreadState {
|
||||||
.unwrap_or(0.),
|
.unwrap_or(0.),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
));
|
||||||
|
|
||||||
constrain_render_elements(
|
constrain_render_elements(
|
||||||
std::iter::once(texture_elem),
|
elements.into_iter().flatten(),
|
||||||
(0, 0),
|
(0, 0),
|
||||||
Rectangle::from_size(
|
Rectangle::from_size(
|
||||||
self.output
|
self.output
|
||||||
.geometry()
|
.geometry()
|
||||||
.size
|
.size
|
||||||
.as_logical()
|
.as_logical()
|
||||||
.to_f64()
|
.to_physical_precise_round(
|
||||||
.to_physical(self.output.current_scale().fractional_scale())
|
self.output.current_scale().fractional_scale(),
|
||||||
.to_i32_round(),
|
),
|
||||||
),
|
),
|
||||||
texture_geometry,
|
Rectangle::new(Point::from((0, 0)), postprocess_state.output_config.size),
|
||||||
ConstrainScaleBehavior::Fit,
|
ConstrainScaleBehavior::Fit,
|
||||||
ConstrainAlign::CENTER,
|
ConstrainAlign::CENTER,
|
||||||
1.0,
|
postprocess_state.output_config.fractional_scale,
|
||||||
)
|
)
|
||||||
.map(CosmicElement::Postprocess)
|
.map(CosmicElement::Postprocess)
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
|
|
@ -1141,7 +1305,7 @@ impl SurfaceThreadState {
|
||||||
compositor.render_frame(
|
compositor.render_frame(
|
||||||
&mut renderer,
|
&mut renderer,
|
||||||
&elements,
|
&elements,
|
||||||
[0.0, 0.0, 0.0, 1.0],
|
[0.0, 0.0, 0.0, 0.0],
|
||||||
self.frame_flags.union(additional_frame_flags),
|
self.frame_flags.union(additional_frame_flags),
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -1222,9 +1386,12 @@ impl SurfaceThreadState {
|
||||||
.map_err(|_| OutputNoMode)? // eh, we have to do some error
|
.map_err(|_| OutputNoMode)? // eh, we have to do some error
|
||||||
.expect("We should be able to convert all hardcoded shm screencopy formats");
|
.expect("We should be able to convert all hardcoded shm screencopy formats");
|
||||||
|
|
||||||
if pre_postprocess_texture
|
if pre_postprocess_data
|
||||||
|
.texture
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.is_some_and(|tex| tex.format() == Some(format))
|
.is_some_and(|tex| tex.format() == Some(format))
|
||||||
|
&& (session.draw_cursor() == false
|
||||||
|
|| pre_postprocess_data.cursor_texture.is_none())
|
||||||
{
|
{
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -1262,21 +1429,25 @@ impl SurfaceThreadState {
|
||||||
.flatten();
|
.flatten();
|
||||||
|
|
||||||
// If the screen is rotated, we must convert damage to match output.
|
// If the screen is rotated, we must convert damage to match output.
|
||||||
let adjusted = damage.iter().copied().map(|mut d| {
|
let adjusted = damage
|
||||||
d.size = d
|
.iter()
|
||||||
.size
|
.copied()
|
||||||
.to_logical(1)
|
.map(|mut d| {
|
||||||
.to_buffer(1, output_transform)
|
d.size = d
|
||||||
.to_logical(1, Transform::Normal)
|
.size
|
||||||
.to_physical(1);
|
.to_logical(1)
|
||||||
d
|
.to_buffer(1, output_transform)
|
||||||
});
|
.to_logical(1, Transform::Normal)
|
||||||
|
.to_physical(1);
|
||||||
|
d
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
if let Some(tex) = pre_postprocess_texture.as_mut() {
|
if let Some(tex) = pre_postprocess_data.texture.as_mut() {
|
||||||
let mut tex_fb = renderer.bind(tex).map_err(RenderError::<<GlMultiRenderer as RendererSuper>::Error>::Rendering)?;
|
let mut tex_fb = renderer.bind(tex).map_err(RenderError::<<GlMultiRenderer as RendererSuper>::Error>::Rendering)?;
|
||||||
|
|
||||||
if let Some(fb) = fb.as_mut() {
|
if let Some(fb) = fb.as_mut() {
|
||||||
for rect in adjusted {
|
for rect in adjusted.iter().copied() {
|
||||||
renderer
|
renderer
|
||||||
.blit(
|
.blit(
|
||||||
&mut tex_fb,
|
&mut tex_fb,
|
||||||
|
|
@ -1291,6 +1462,68 @@ impl SurfaceThreadState {
|
||||||
>::Rendering,
|
>::Rendering,
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
if let Some(cursor_geometry) = pre_postprocess_data
|
||||||
|
.cursor_geometry
|
||||||
|
.as_ref()
|
||||||
|
.filter(|_| session.draw_cursor())
|
||||||
|
{
|
||||||
|
let cursor_damage = adjusted
|
||||||
|
.iter()
|
||||||
|
.filter_map(|rect| {
|
||||||
|
cursor_geometry.intersection(*rect)
|
||||||
|
})
|
||||||
|
.map(|rect| {
|
||||||
|
Rectangle::new(
|
||||||
|
rect.loc - cursor_geometry.loc,
|
||||||
|
rect.size,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
let mut frame = renderer
|
||||||
|
.render(fb, output_size, output_transform)
|
||||||
|
.map_err(
|
||||||
|
RenderError::<
|
||||||
|
<GlMultiRenderer as RendererSuper>::Error,
|
||||||
|
>::Rendering,
|
||||||
|
)?;
|
||||||
|
frame
|
||||||
|
.as_mut()
|
||||||
|
.render_texture_from_to(
|
||||||
|
pre_postprocess_data
|
||||||
|
.cursor_texture
|
||||||
|
.as_ref()
|
||||||
|
.unwrap(),
|
||||||
|
Rectangle::new(
|
||||||
|
Point::from((0., 0.)),
|
||||||
|
cursor_geometry
|
||||||
|
.size
|
||||||
|
.to_logical(1)
|
||||||
|
.to_buffer(1, Transform::Normal)
|
||||||
|
.to_f64(),
|
||||||
|
),
|
||||||
|
*cursor_geometry,
|
||||||
|
&cursor_damage,
|
||||||
|
&[*cursor_geometry],
|
||||||
|
Transform::Normal,
|
||||||
|
1.0,
|
||||||
|
)
|
||||||
|
.map_err(GlMultiError::Render)
|
||||||
|
.map_err(
|
||||||
|
RenderError::<
|
||||||
|
<GlMultiRenderer as RendererSuper>::Error,
|
||||||
|
>::Rendering,
|
||||||
|
)?;
|
||||||
|
let sync = frame.finish().map_err(
|
||||||
|
RenderError::<
|
||||||
|
<GlMultiRenderer as RendererSuper>::Error,
|
||||||
|
>::Rendering,
|
||||||
|
)?;
|
||||||
|
renderer.wait(&sync).map_err(
|
||||||
|
RenderError::<
|
||||||
|
<GlMultiRenderer as RendererSuper>::Error,
|
||||||
|
>::Rendering,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
fb = Some(tex_fb);
|
fb = Some(tex_fb);
|
||||||
}
|
}
|
||||||
|
|
@ -1369,7 +1602,7 @@ impl SurfaceThreadState {
|
||||||
|
|
||||||
if self.mirroring.is_none() {
|
if self.mirroring.is_none() {
|
||||||
// If postprocessing, use states from first render
|
// If postprocessing, use states from first render
|
||||||
let states = pre_postprocess_states.unwrap_or(frame_result.states);
|
let states = pre_postprocess_data.states.unwrap_or(frame_result.states);
|
||||||
self.send_dmabuf_feedback(states);
|
self.send_dmabuf_feedback(states);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,7 @@ use smithay::{
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
input::Seat,
|
input::Seat,
|
||||||
output::{Output, OutputNoMode},
|
output::{Output, OutputModeSource, OutputNoMode},
|
||||||
utils::{
|
utils::{
|
||||||
IsAlive, Logical, Monotonic, Physical, Point, Rectangle, Scale, Size, Time, Transform,
|
IsAlive, Logical, Monotonic, Physical, Point, Rectangle, Scale, Size, Time, Transform,
|
||||||
},
|
},
|
||||||
|
|
@ -1003,6 +1003,8 @@ where
|
||||||
pub struct PostprocessState {
|
pub struct PostprocessState {
|
||||||
pub texture: TextureRenderBuffer<GlesTexture>,
|
pub texture: TextureRenderBuffer<GlesTexture>,
|
||||||
pub damage_tracker: OutputDamageTracker,
|
pub damage_tracker: OutputDamageTracker,
|
||||||
|
pub cursor_texture: Option<TextureRenderBuffer<GlesTexture>>,
|
||||||
|
pub cursor_damage_tracker: Option<OutputDamageTracker>,
|
||||||
pub output_config: PostprocessOutputConfig,
|
pub output_config: PostprocessOutputConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1032,9 +1034,54 @@ impl PostprocessState {
|
||||||
Ok(PostprocessState {
|
Ok(PostprocessState {
|
||||||
texture: texture_buffer,
|
texture: texture_buffer,
|
||||||
damage_tracker,
|
damage_tracker,
|
||||||
|
cursor_texture: None,
|
||||||
|
cursor_damage_tracker: None,
|
||||||
output_config,
|
output_config,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn track_cursor<R: Renderer + Offscreen<GlesTexture>>(
|
||||||
|
&mut self,
|
||||||
|
renderer: &mut R,
|
||||||
|
format: Fourcc,
|
||||||
|
size: Size<i32, Physical>,
|
||||||
|
scale: Scale<f64>,
|
||||||
|
) -> Result<(), R::Error> {
|
||||||
|
let buffer_size = size.to_logical(1).to_buffer(1, Transform::Normal);
|
||||||
|
|
||||||
|
if let (Some(tex), Some(tracker)) = (
|
||||||
|
self.cursor_texture.as_ref(),
|
||||||
|
self.cursor_damage_tracker.as_ref(),
|
||||||
|
) {
|
||||||
|
if tex.format().is_some_and(|f| f == format)
|
||||||
|
&& tracker.mode()
|
||||||
|
== &(OutputModeSource::Static {
|
||||||
|
size,
|
||||||
|
scale,
|
||||||
|
transform: Transform::Normal,
|
||||||
|
})
|
||||||
|
{
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let texture = Offscreen::<GlesTexture>::create_buffer(renderer, format, buffer_size)?;
|
||||||
|
|
||||||
|
let texture_buffer =
|
||||||
|
TextureRenderBuffer::from_texture(renderer, texture, 1, Transform::Normal, None);
|
||||||
|
|
||||||
|
let damage_tracker = OutputDamageTracker::new(size, scale, Transform::Normal);
|
||||||
|
|
||||||
|
self.cursor_texture = Some(texture_buffer);
|
||||||
|
self.cursor_damage_tracker = Some(damage_tracker);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn remove_cursor(&mut self) {
|
||||||
|
self.cursor_texture.take();
|
||||||
|
self.cursor_damage_tracker.take();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue