diff --git a/build.py b/build.py index 928784b49..c55209a82 100755 --- a/build.py +++ b/build.py @@ -488,7 +488,7 @@ def _assert_so_has_egl(so_path): with open(so_path, 'rb') as f: blob = f.read() except OSError as err: - raise Exception(f'cannot read the built libdrmtap at {so_path}: {err}') + raise Exception(f'cannot read the built libdrmtap at {so_path}: {err}') from err missing = [m for m in (b'libEGL.so.1', b'eglCreateImageKHR') if m not in blob] if missing: raise Exception( diff --git a/src/server/wayland.rs b/src/server/wayland.rs index 40869903d..f08a19717 100644 --- a/src/server/wayland.rs +++ b/src/server/wayland.rs @@ -457,25 +457,37 @@ pub(super) fn get_capturer_for_display( None => (None, false), }; if let Some(advertised) = advertised { - // The advertised DRM geometry is PHYSICAL while the PipeWire rect is the - // compositor's LOGICAL size (try_fix_logical_size), so on a scaled output the - // two sizes legitimately disagree (2880x1800 vs 1440x900) even when the stream - // IS this display. On a single-display host the whole-desktop stream is this - // display by construction, so only the position has to agree there; comparing - // the physical size too rejected the one valid fallback and restart-looped the - // display instead of degrading. On a multi-monitor host the size check stays: - // it is what tells one connector apart from the full-desktop rect. + // Compare LOGICAL against LOGICAL. The advertised DRM geometry carries the + // PHYSICAL mode plus the compositor scale (augment_with_wayland_geometry sets + // x/y/scale and deliberately leaves width/height physical), while the PipeWire + // rect is already logical (try_fix_logical_size). Comparing the two raw made a + // scaled output disagree with itself -- 2880x1800 against 1440x900 -- and the + // guard then rejected a portal stream that really was this display, leaving it + // advertised offline instead of degrading to PipeWire. + // + // The size check itself stays, because on a multi-monitor host it is what + // tells a single connector apart from the whole-desktop rect the portal + // usually exposes. On a single-display host that rect IS this display by + // construction, so only the position has to agree. + let scale = if advertised.scale > 0.0 { + advertised.scale + } else { + 1.0 + }; + let logical_w = (advertised.width as f64 / scale).round() as usize; + let logical_h = (advertised.height as f64 / scale).round() as usize; let consistent = advertised.x == rect.0 .0 && advertised.y == rect.0 .1 - && (single_display - || (advertised.width as usize == rect.1 - && advertised.height as usize == rect.2)); + && (single_display || (logical_w == rect.1 && logical_h == rect.2)); if !consistent { + // Report the LOGICAL numbers, the ones actually compared, so the message + // does not look like a mismatch of quantities that were never expected to + // match on a scaled output. bail!( - "drm display {} demoted with no geometry-consistent PipeWire stream (advertised {}x{}+{}+{} vs stream {}x{}+{}+{}); advertised offline", + "drm display {} demoted with no geometry-consistent PipeWire stream (advertised {}x{} logical +{}+{} vs stream {}x{}+{}+{}); advertised offline", display_idx, - advertised.width, - advertised.height, + logical_w, + logical_h, advertised.x, advertised.y, rect.1,