Skip to content

Commit 7373b3f

Browse files
committed
backend: Support screen filters in nested mode
1 parent 6391641 commit 7373b3f

File tree

4 files changed

+218
-47
lines changed

4 files changed

+218
-47
lines changed

src/backend/render/mod.rs

Lines changed: 192 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,16 @@ use smithay::{
4343
damage::{Error as RenderError, OutputDamageTracker, RenderOutputResult},
4444
element::{
4545
surface::{render_elements_from_surface_tree, WaylandSurfaceRenderElement},
46-
utils::{CropRenderElement, Relocate, RelocateRenderElement, RescaleRenderElement},
46+
texture::{TextureRenderBuffer, TextureRenderElement},
47+
utils::{
48+
constrain_render_elements, ConstrainAlign, ConstrainScaleBehavior,
49+
CropRenderElement, Relocate, RelocateRenderElement, RescaleRenderElement,
50+
},
4751
AsRenderElements, Element, Id, Kind, RenderElement,
4852
},
4953
gles::{
50-
element::PixelShaderElement, GlesError, GlesPixelProgram, GlesRenderer, Uniform,
54+
element::{PixelShaderElement, TextureShaderElement},
55+
GlesError, GlesPixelProgram, GlesRenderer, GlesTexProgram, GlesTexture, Uniform,
5156
UniformName, UniformType,
5257
},
5358
glow::GlowRenderer,
@@ -1071,7 +1076,7 @@ pub struct ScreenFilterStorage {
10711076
}
10721077

10731078
#[profiling::function]
1074-
pub fn render_output<'d, R, OffTarget>(
1079+
pub fn render_output<'d, R>(
10751080
gpu: Option<&DrmNode>,
10761081
renderer: &mut R,
10771082
target: &mut R::Framebuffer<'_>,
@@ -1081,14 +1086,15 @@ pub fn render_output<'d, R, OffTarget>(
10811086
now: Time<Monotonic>,
10821087
output: &Output,
10831088
cursor_mode: CursorMode,
1089+
screen_filter: &'d mut ScreenFilterStorage,
10841090
) -> Result<RenderOutputResult<'d>, RenderError<R::Error>>
10851091
where
10861092
R: Renderer
10871093
+ ImportAll
10881094
+ ImportMem
10891095
+ ExportMem
10901096
+ Bind<Dmabuf>
1091-
+ Offscreen<OffTarget>
1097+
+ Offscreen<GlesTexture>
10921098
+ Blit
10931099
+ AsGlowRenderer,
10941100
R::TextureId: Send + Clone + 'static,
@@ -1116,27 +1122,154 @@ where
11161122
ElementFilter::All
11171123
};
11181124

1119-
let result = render_workspace(
1120-
gpu,
1121-
renderer,
1122-
target,
1123-
damage_tracker,
1124-
age,
1125-
None,
1126-
shell,
1127-
zoom_state.as_ref(),
1128-
now,
1129-
output,
1130-
previous_workspace,
1131-
workspace,
1132-
cursor_mode,
1133-
element_filter,
1134-
);
1125+
let mut postprocess_texture = None;
1126+
let result = if !screen_filter.filter.is_noop() {
1127+
if screen_filter.state.as_ref().is_none_or(|state| {
1128+
state.output_config != PostprocessOutputConfig::for_output_untransformed(output)
1129+
}) {
1130+
screen_filter.state = Some(
1131+
PostprocessState::new_with_renderer(
1132+
renderer,
1133+
target.format().unwrap_or(Fourcc::Abgr8888),
1134+
PostprocessOutputConfig::for_output_untransformed(output),
1135+
)
1136+
.map_err(RenderError::Rendering)?,
1137+
);
1138+
}
1139+
1140+
let state = screen_filter.state.as_mut().unwrap();
1141+
let mut result = Err(RenderError::OutputNoMode(OutputNoMode));
1142+
state
1143+
.texture
1144+
.render()
1145+
.draw::<_, RenderError<R::Error>>(|tex| {
1146+
let mut target = renderer.bind(tex).map_err(RenderError::Rendering)?;
1147+
result = render_workspace(
1148+
gpu,
1149+
renderer,
1150+
&mut target,
1151+
&mut state.damage_tracker,
1152+
1,
1153+
None,
1154+
shell,
1155+
zoom_state.as_ref(),
1156+
now,
1157+
output,
1158+
previous_workspace,
1159+
workspace,
1160+
cursor_mode,
1161+
element_filter,
1162+
);
1163+
std::mem::drop(target);
1164+
postprocess_texture = Some(tex.clone());
1165+
1166+
Ok(if let Ok((res, _)) = result.as_ref() {
1167+
renderer.wait(&res.sync).map_err(RenderError::Rendering)?;
1168+
let transform = output.current_transform();
1169+
let area = tex.size().to_logical(1, transform);
1170+
1171+
res.damage
1172+
.cloned()
1173+
.map(|v| {
1174+
v.into_iter()
1175+
.map(|r| r.to_logical(1).to_buffer(1, transform, &area))
1176+
.collect::<Vec<_>>()
1177+
})
1178+
.unwrap_or_default()
1179+
} else {
1180+
Vec::new()
1181+
})
1182+
})?;
1183+
1184+
if result.is_ok() {
1185+
let texture_elem = TextureRenderElement::from_texture_render_buffer(
1186+
(0., 0.),
1187+
&state.texture,
1188+
Some(1.0),
1189+
None,
1190+
None,
1191+
Kind::Unspecified,
1192+
);
1193+
1194+
let postprocess_texture_shader = renderer
1195+
.glow_renderer_mut()
1196+
.egl_context()
1197+
.user_data()
1198+
.get::<PostprocessShader>()
1199+
.expect("OffscreenShader should be available through `init_shaders`");
1200+
let texture_geometry =
1201+
texture_elem.geometry(output.current_scale().fractional_scale().into());
1202+
let elements = {
1203+
let texture_elem = TextureShaderElement::new(
1204+
texture_elem,
1205+
postprocess_texture_shader.0.clone(),
1206+
vec![
1207+
Uniform::new(
1208+
"invert",
1209+
if screen_filter.filter.inverted {
1210+
1.
1211+
} else {
1212+
0.
1213+
},
1214+
),
1215+
Uniform::new(
1216+
"color_mode",
1217+
screen_filter
1218+
.filter
1219+
.color_filter
1220+
.map(|val| val as u8 as f32)
1221+
.unwrap_or(0.),
1222+
),
1223+
],
1224+
);
1225+
constrain_render_elements(
1226+
std::iter::once(texture_elem),
1227+
(0, 0),
1228+
Rectangle::from_size(
1229+
output
1230+
.geometry()
1231+
.size
1232+
.as_logical()
1233+
.to_f64()
1234+
.to_physical(output.current_scale().fractional_scale())
1235+
.to_i32_round(),
1236+
),
1237+
texture_geometry,
1238+
ConstrainScaleBehavior::Fit,
1239+
ConstrainAlign::CENTER,
1240+
1.0,
1241+
)
1242+
.map(CosmicElement::Postprocess)
1243+
.collect::<Vec<_>>()
1244+
};
1245+
1246+
damage_tracker.render_output(renderer, target, age, &elements, CLEAR_COLOR)?;
1247+
}
1248+
1249+
result
1250+
} else {
1251+
render_workspace(
1252+
gpu,
1253+
renderer,
1254+
target,
1255+
damage_tracker,
1256+
age,
1257+
None,
1258+
shell,
1259+
zoom_state.as_ref(),
1260+
now,
1261+
output,
1262+
previous_workspace,
1263+
workspace,
1264+
cursor_mode,
1265+
element_filter,
1266+
)
1267+
};
11351268

11361269
match result {
11371270
Ok((res, mut elements)) => {
11381271
for (session, frame) in output.take_pending_frames() {
1139-
if let Some((frame, damage)) = render_session::<_, _, OffTarget>(
1272+
if let Some((frame, damage)) = render_session::<_, _, GlesTexture>(
11401273
renderer,
11411274
&session.user_data().get::<SessionData>().unwrap(),
11421275
frame,
@@ -1184,24 +1317,46 @@ where
11841317
}
11851318

11861319
if let (Some(ref damage), _) = &res {
1187-
if let Ok(dmabuf) = get_dmabuf(buffer) {
1188-
let mut dmabuf_clone = dmabuf.clone();
1189-
let mut fb = renderer
1190-
.bind(&mut dmabuf_clone)
1320+
let blit_to_buffer =
1321+
|renderer: &mut R, blit_from: &mut R::Framebuffer<'_>| {
1322+
if let Ok(dmabuf) = get_dmabuf(buffer) {
1323+
let mut dmabuf_clone = dmabuf.clone();
1324+
let mut fb = renderer.bind(&mut dmabuf_clone)?;
1325+
for rect in damage.iter() {
1326+
renderer.blit(
1327+
blit_from,
1328+
&mut fb,
1329+
*rect,
1330+
*rect,
1331+
TextureFilter::Nearest,
1332+
)?;
1333+
}
1334+
} else {
1335+
let fb = offscreen
1336+
.expect("shm buffers should have offscreen target");
1337+
for rect in damage.iter() {
1338+
renderer.blit(
1339+
blit_from,
1340+
fb,
1341+
*rect,
1342+
*rect,
1343+
TextureFilter::Nearest,
1344+
)?;
1345+
}
1346+
}
1347+
1348+
Result::<_, R::Error>::Ok(())
1349+
};
1350+
1351+
// we would want to just assign a different framebuffer to a variable, depending on the code-path,
1352+
// but then rustc tries to equate the lifetime of target with the lifetime of our temporary fb...
1353+
// So instead of duplicating all the code, we use a closure..
1354+
if let Some(tex) = postprocess_texture.as_mut() {
1355+
let mut fb = renderer.bind(tex).map_err(RenderError::Rendering)?;
1356+
blit_to_buffer(renderer, &mut fb)
11911357
.map_err(RenderError::Rendering)?;
1192-
for rect in damage.iter() {
1193-
renderer
1194-
.blit(target, &mut fb, *rect, *rect, TextureFilter::Nearest)
1195-
.map_err(RenderError::Rendering)?;
1196-
}
11971358
} else {
1198-
let fb =
1199-
offscreen.expect("shm buffers should have offscreen target");
1200-
for rect in damage.iter() {
1201-
renderer
1202-
.blit(target, fb, *rect, *rect, TextureFilter::Nearest)
1203-
.map_err(RenderError::Rendering)?;
1204-
}
1359+
blit_to_buffer(renderer, target).map_err(RenderError::Rendering)?;
12051360
}
12061361
}
12071362

src/backend/winit.rs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
use crate::{
44
backend::render,
5-
config::OutputConfig,
5+
config::{OutputConfig, ScreenFilter},
66
shell::{Devices, SeatExt},
77
state::{BackendData, Common},
88
utils::prelude::*,
@@ -14,7 +14,6 @@ use smithay::{
1414
egl::EGLDevice,
1515
renderer::{
1616
damage::{OutputDamageTracker, RenderOutputResult},
17-
gles::GlesRenderbuffer,
1817
glow::GlowRenderer,
1918
ImportDma,
2019
},
@@ -34,14 +33,15 @@ use smithay::{
3433
use std::{borrow::BorrowMut, cell::RefCell, time::Duration};
3534
use tracing::{error, info, warn};
3635

37-
use super::render::{init_shaders, CursorMode};
36+
use super::render::{init_shaders, CursorMode, ScreenFilterStorage};
3837

3938
#[derive(Debug)]
4039
pub struct WinitState {
4140
// The winit backend currently has no notion of multiple windows
4241
pub backend: WinitGraphicsBackend<GlowRenderer>,
4342
output: Output,
4443
damage_tracker: OutputDamageTracker,
44+
screen_filter_state: ScreenFilterStorage,
4545
}
4646

4747
impl WinitState {
@@ -52,7 +52,7 @@ impl WinitState {
5252
.backend
5353
.bind()
5454
.with_context(|| "Failed to bind buffer")?;
55-
match render::render_output::<_, GlesRenderbuffer>(
55+
match render::render_output(
5656
None,
5757
renderer,
5858
&mut fb,
@@ -62,6 +62,7 @@ impl WinitState {
6262
state.clock.now(),
6363
&self.output,
6464
CursorMode::NotDefault,
65+
&mut self.screen_filter_state,
6566
) {
6667
Ok(RenderOutputResult { damage, states, .. }) => {
6768
std::mem::drop(fb);
@@ -122,6 +123,11 @@ impl WinitState {
122123
Ok(vec![self.output.clone()])
123124
}
124125
}
126+
127+
pub fn update_screen_filter(&mut self, screen_filter: &ScreenFilter) -> Result<()> {
128+
self.screen_filter_state.filter = screen_filter.clone();
129+
Ok(())
130+
}
125131
}
126132

127133
pub fn init_backend(
@@ -209,6 +215,7 @@ pub fn init_backend(
209215
backend,
210216
output: output.clone(),
211217
damage_tracker: OutputDamageTracker::from_output(&output),
218+
screen_filter_state: ScreenFilterStorage::default(),
212219
});
213220

214221
state

0 commit comments

Comments
 (0)