@@ -5490,20 +5490,6 @@ fn render_surface(
54905490 );
54915491 current_window_elements.extend(popup_elements);
54925492 }
5493- if use_full_window_snapshot {
5494- current_window_elements.extend(non_root_surface_elements_for_window(
5495- window,
5496- &mut backend.renderer,
5497- physical_location,
5498- client_physical_geometry,
5499- output_geo.loc,
5500- scale,
5501- scale,
5502- visual_state,
5503- visual_state.opacity,
5504- content_clip,
5505- ));
5506- }
55075493 window_timing.popup_phase_ms =
55085494 popup_phase_started_at.elapsed().as_secs_f64() * 1000.0;
55095495 if output_render_debug_enabled() {
@@ -5533,8 +5519,8 @@ fn render_surface(
55335519 "output_render_debug: window rendered"
55345520 );
55355521 }
5536- // Window-source effects sample only the top-level window. `Full` means
5537- // root surface plus SSD decoration, but not popup/subsurface content .
5522+ // Full window sources include subsurfaces and SSD decorations.
5523+ // Popups remain independently composed above the window effect .
55385524 let source_clip_scale = if use_full_window_snapshot {
55395525 scale
55405526 } else {
@@ -5573,7 +5559,7 @@ fn render_surface(
55735559 })
55745560 .unwrap_or_default();
55755561 let root_surface_source_elements = if needs_root_surface_source {
5576- root_surface_source_elements_for_window (
5562+ window_surface_source_elements_for_window (
55775563 window,
55785564 &mut backend.renderer,
55795565 physical_location,
@@ -5584,12 +5570,13 @@ fn render_surface(
55845570 visual_state,
55855571 visual_state.opacity,
55865572 content_clip,
5573+ false,
55875574 )
55885575 } else {
55895576 Vec::new()
55905577 };
55915578 let mut full_window_source_elements = if needs_full_window_source {
5592- root_surface_source_elements_for_window (
5579+ window_surface_source_elements_for_window (
55935580 window,
55945581 &mut backend.renderer,
55955582 physical_location,
@@ -5600,6 +5587,7 @@ fn render_surface(
56005587 visual_state,
56015588 visual_state.opacity,
56025589 content_clip,
5590+ true,
56035591 )
56045592 } else {
56055593 Vec::new()
@@ -5826,7 +5814,12 @@ fn render_surface(
58265814 .ok()
58275815 });
58285816 if let Some(replace_effects) = replace_effects {
5829- if !use_full_window_snapshot {
5817+ // Full replacement owns subsurfaces too (e.g. OBS's video preview).
5818+ // Drawing them again here bypasses the shader's visibility mask.
5819+ if !matches!(
5820+ replace_effect_slot.as_ref().map(|effect| &effect.effect.input),
5821+ Some(EffectInput::WindowSource(WindowSourceInclude::Full))
5822+ ) {
58305823 current_window_elements.extend(non_root_surface_elements_for_window(
58315824 window,
58325825 &mut backend.renderer,
@@ -5842,6 +5835,20 @@ fn render_surface(
58425835 }
58435836 current_window_elements.extend(replace_effects);
58445837 } else {
5838+ if use_full_window_snapshot {
5839+ current_window_elements.extend(non_root_surface_elements_for_window(
5840+ window,
5841+ &mut backend.renderer,
5842+ physical_location,
5843+ client_physical_geometry,
5844+ output_geo.loc,
5845+ scale,
5846+ scale,
5847+ visual_state,
5848+ visual_state.opacity,
5849+ content_clip,
5850+ ));
5851+ }
58455852 current_window_elements.extend(original_window_body_elements);
58465853 }
58475854 if window_effect_debug_enabled() {
@@ -7527,7 +7534,7 @@ fn transform_clipped_elements(
75277534 .collect()
75287535}
75297536
7530- fn root_surface_source_elements_for_window (
7537+ fn window_surface_source_elements_for_window (
75317538 window: &smithay::desktop::Window,
75327539 renderer: &mut GlesRenderer,
75337540 physical_location: Point<i32, smithay::utils::Physical>,
@@ -7538,6 +7545,7 @@ fn root_surface_source_elements_for_window(
75387545 visual: WindowVisualState,
75397546 alpha: f32,
75407547 content_clip: Option<crate::ssd::ContentClip>,
7548+ include_subsurfaces: bool,
75417549) -> Vec<TtyRenderElements> {
75427550 if let Some(content_clip) = content_clip.filter(|clip| clip.clips_surface) {
75437551 let clipped = window_render::clipped_surface_elements(
@@ -7555,11 +7563,28 @@ fn root_surface_source_elements_for_window(
75557563 .inspect_err(|error| {
75567564 warn!(
75577565 ?error,
7558- "failed to build clipped root surface source elements"
7566+ "failed to build clipped window surface source elements"
75597567 );
75607568 })
75617569 .unwrap_or_default();
75627570
7571+ if include_subsurfaces {
7572+ return clipped
7573+ .into_iter()
7574+ .flat_map(|element| match element {
7575+ window_render::WindowClipElement::Clipped(element) => {
7576+ transform_clipped_elements(vec![element], visual)
7577+ }
7578+ window_render::WindowClipElement::Raw(element) => transform_window_elements(
7579+ vec![element],
7580+ visual,
7581+ TtyRenderElements::Window,
7582+ TtyRenderElements::TransformedWindow,
7583+ ),
7584+ })
7585+ .collect();
7586+ }
7587+
75637588 let mut root_raw_element = None;
75647589 for element in clipped {
75657590 match element {
@@ -7583,13 +7608,13 @@ fn root_surface_source_elements_for_window(
75837608 }
75847609
75857610 transform_window_elements(
7586- window_render::root_surface_elements(
7587- window,
7588- renderer,
7589- physical_location,
7590- output_scale,
7591- alpha,
7592- ) ,
7611+ if include_subsurfaces {
7612+ window_render::surface_elements( window, renderer, physical_location, output_scale, alpha)
7613+ } else {
7614+ window_render::root_surface_elements(
7615+ window, renderer, physical_location, output_scale, alpha ,
7616+ )
7617+ } ,
75937618 visual,
75947619 TtyRenderElements::Window,
75957620 TtyRenderElements::TransformedWindow,
0 commit comments