@@ -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 > >
10851091where
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
0 commit comments