mirror of
https://github.com/rustdesk/rustdesk.git
synced 2026-09-14 00:11:01 +03:00
drm: stop altering the stock (drm-off) Wayland path (review 3.2, 4.6)
3.2: get_capturer_for_display no longer falls back to cap_map[0] for a missing
index. CapturerPtr is a bare *mut Capturer cloned by raw-pointer copy, so aliasing
one entry to two display_idx values let two video-service threads call frame() on
the same Recorder unsynchronised (data race / UB), reachable in a plain build via
CaptureDisplays{set:[0,3]}. Restore the exact-index lookup + bail; a demoted DRM
index is dropped from the advertised list at the source instead.
4.6: revert check_init to upstream (flag set before the per-display loop, direct
insert). The staged-all-or-nothing variant turned a partial per-display failure
into a permanent 1Hz retry loop and was not drm-gated. Both restore the drm-off
build to byte-identical with upstream.
This commit is contained in:
@@ -228,6 +228,7 @@ pub(super) async fn check_init() -> ResultType<()> {
|
|||||||
}
|
}
|
||||||
log::debug!("Attempting to fix logical size with try_fix_logical_size()");
|
log::debug!("Attempting to fix logical size with try_fix_logical_size()");
|
||||||
try_fix_logical_size(&mut all);
|
try_fix_logical_size(&mut all);
|
||||||
|
*PIPEWIRE_INITIALIZED.write().unwrap() = true;
|
||||||
let num = all.len();
|
let num = all.len();
|
||||||
let primary = super::display_service::get_primary_2(&all);
|
let primary = super::display_service::get_primary_2(&all);
|
||||||
let mut displays = super::display_service::update_sync_displays(&all);
|
let mut displays = super::display_service::update_sync_displays(&all);
|
||||||
@@ -249,20 +250,14 @@ pub(super) async fn check_init() -> ResultType<()> {
|
|||||||
num_cpus::get()
|
num_cpus::get()
|
||||||
);
|
);
|
||||||
|
|
||||||
// Create every per-display capturer FIRST into owned temporary storage, so a failure
|
// Create individual CapDisplayInfo for each display with its own capturer
|
||||||
// partway does not publish a partial set. If `Capturer::new` errors, the `?` returns
|
|
||||||
// and the already-staged capturers drop cleanly (no leaked raw pointers, and
|
|
||||||
// CAP_DISPLAY_INFO stays empty so the next check_init retries instead of seeing a
|
|
||||||
// non-empty map and skipping re-init).
|
|
||||||
let mut staged = Vec::with_capacity(num);
|
|
||||||
for (idx, display) in all.into_iter().enumerate() {
|
for (idx, display) in all.into_iter().enumerate() {
|
||||||
let capturer = Capturer::new(display)
|
let capturer =
|
||||||
.with_context(|| format!("Failed to create capturer for display {}", idx))?;
|
Box::into_raw(Box::new(Capturer::new(display).with_context(|| {
|
||||||
staged.push((idx, capturer));
|
format!("Failed to create capturer for display {}", idx)
|
||||||
}
|
})?));
|
||||||
// All capturers created: publish them atomically.
|
let capturer = CapturerPtr(capturer);
|
||||||
for (idx, capturer) in staged {
|
|
||||||
let capturer = CapturerPtr(Box::into_raw(Box::new(capturer)));
|
|
||||||
let cap_display_info = Box::into_raw(Box::new(CapDisplayInfo {
|
let cap_display_info = Box::into_raw(Box::new(CapDisplayInfo {
|
||||||
rects: rects.clone(),
|
rects: rects.clone(),
|
||||||
displays: displays.clone(),
|
displays: displays.clone(),
|
||||||
@@ -271,12 +266,9 @@ pub(super) async fn check_init() -> ResultType<()> {
|
|||||||
current: idx,
|
current: idx,
|
||||||
capturer,
|
capturer,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
lock.insert(idx, cap_display_info as u64);
|
lock.insert(idx, cap_display_info as u64);
|
||||||
}
|
}
|
||||||
// Mark PipeWire initialized only AFTER the full set was published, so a partial
|
|
||||||
// failure above leaves the flag false and the next check_init retries. This matters
|
|
||||||
// more now that the per-display DRM->PipeWire fallback funnels through here.
|
|
||||||
*PIPEWIRE_INITIALIZED.write().unwrap() = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -377,20 +369,17 @@ pub(super) fn get_capturer_for_display(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
let cap_map = CAP_DISPLAY_INFO.read().unwrap();
|
let cap_map = CAP_DISPLAY_INFO.read().unwrap();
|
||||||
// DRM and PipeWire do NOT share a display-index space: DRM enumerates one entry per connector
|
// Serve ONLY the exact PipeWire entry for this index. Do NOT fall back to another index's
|
||||||
// (0..N), while the portal/PipeWire ScreenCast commonly enumerates a SINGLE whole-desktop stream
|
// `CapDisplayInfo`: `CapturerPtr` is a bare `*mut Capturer` cloned by raw-pointer copy, so aliasing
|
||||||
// (index 0). So when a per-display DRM capture is demoted to PipeWire for a non-primary DRM index
|
// one entry to two `display_idx` values would let two video-service threads call `frame()` on the
|
||||||
// that PipeWire cannot serve, `cap_map.get(&display_idx)` is None. Bailing here returned an Err
|
// same `Recorder` with no lock (data race / UB), and it would also mis-map input against the wrong
|
||||||
// that ServiceTmpl::run retries every MAX_ERROR_TIMEOUT (1s) forever — the multi-monitor restart
|
// rect. DRM and PipeWire do not share an index space (the portal often exposes one whole-desktop
|
||||||
// loop. Degrade to the whole-desktop stream (index 0) that PipeWire does provide instead: the
|
// stream at index 0), so a demoted non-primary DRM index has no PipeWire entry here; that case is
|
||||||
// user sees that monitor's content within the desktop stream rather than a 1s spin. Healthy DRM
|
// handled at the source by dropping the demoted display from the advertised list (see
|
||||||
// displays never reach here (they return above).
|
// drm_capturer demotion) so the client re-enumerates against a consistent list, rather than being
|
||||||
let addr = cap_map
|
// papered over with a shared/mismatched capturer.
|
||||||
.get(&display_idx)
|
if let Some(addr) = cap_map.get(&display_idx) {
|
||||||
.or_else(|| cap_map.get(&0))
|
let cap_display_info: *const CapDisplayInfo = *addr as _;
|
||||||
.copied();
|
|
||||||
if let Some(addr) = addr {
|
|
||||||
let cap_display_info: *const CapDisplayInfo = addr as _;
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let cap_display_info = &*cap_display_info;
|
let cap_display_info = &*cap_display_info;
|
||||||
let rect = cap_display_info.rects[cap_display_info.current];
|
let rect = cap_display_info.rects[cap_display_info.current];
|
||||||
|
|||||||
Reference in New Issue
Block a user