mirror of
https://github.com/rustdesk/rustdesk.git
synced 2026-10-02 10:08:05 +00:00
feat(drm): say once where the cursor hotspot came from
The provenance decision was unverifiable anywhere but a unit test: nothing on a running box distinguishes the three states, so a deploy proved nothing. One info line does, and with it all three are measured -- Some(false) on i915, None with a 0.5.4 library swapped in behind the soname, and Some(true) via a C probe on virtio-gpu, where no rustdesk build runs. Once per state, not once per sample. A cursor is read on every capture iteration and its provenance changes approximately never; a per-frame log line here is the same defect libdrmtap already shipped once. Measured on Sigma-26: one line across a whole session. The should-we-log decision is its own function so it cannot quietly become per-sample again.
This commit is contained in:
@@ -75,6 +75,51 @@ fn cursor_id(hash: u64, width: u32, height: u32, hotx: i32, hoty: i32, hot_measu
|
||||
id
|
||||
}
|
||||
|
||||
/// Encodes a provenance answer for the one-shot log below. -1 is "nothing reported yet".
|
||||
fn provenance_code(answered: Option<bool>) -> i8 {
|
||||
match answered {
|
||||
None => 0,
|
||||
Some(false) => 1,
|
||||
Some(true) => 2,
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether this sample's provenance is worth a log line, given what was last reported.
|
||||
///
|
||||
/// Its own function because the obvious version of this is a line per cursor read, and a cursor is
|
||||
/// read far more often than it changes. A per-sample log here was a real defect in libdrmtap for
|
||||
/// the same reason. So: the first sample of a run, and thereafter only a genuine change of state.
|
||||
fn provenance_is_news(last: i8, now: i8) -> bool {
|
||||
last != now
|
||||
}
|
||||
|
||||
static LAST_PROVENANCE: std::sync::atomic::AtomicI8 = std::sync::atomic::AtomicI8::new(-1);
|
||||
|
||||
/// Say once, and again only if it changes, where the hotspot is coming from. Without this the
|
||||
/// three states are indistinguishable on a running box, which makes the decision unverifiable
|
||||
/// anywhere but a unit test.
|
||||
fn note_hotspot_provenance(answered: Option<bool>, hot_measured: bool) {
|
||||
let now = provenance_code(answered);
|
||||
let last = LAST_PROVENANCE.swap(now, std::sync::atomic::Ordering::Relaxed);
|
||||
if !provenance_is_news(last, now) {
|
||||
return;
|
||||
}
|
||||
match answered {
|
||||
Some(true) => log::info!(
|
||||
"drm: cursor hotspot provenance: the driver published HOTSPOT_X/Y, using its value"
|
||||
),
|
||||
Some(false) => log::info!(
|
||||
"drm: cursor hotspot provenance: the plane exposes no HOTSPOT_X/Y, inferring the \
|
||||
hotspot from the bitmap"
|
||||
),
|
||||
None => log::info!(
|
||||
"drm: cursor hotspot provenance: unavailable (libdrmtap older than 0.5.6, or a \
|
||||
pre-0.5.6 privileged helper); falling back to the coordinate heuristic, which says \
|
||||
hot_measured={hot_measured}"
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether `hot_x`/`hot_y` are the driver's answer rather than a guess.
|
||||
///
|
||||
/// `answered` is what `drmtap_cursor_hotspot_valid` said: `Some(v)` when it answered, `None` when
|
||||
@@ -483,6 +528,7 @@ impl DrmReader {
|
||||
(f(&c, &mut valid) == 0).then(|| valid != 0)
|
||||
});
|
||||
let hot_measured = hot_measured_from(answered, c.hot_x, c.hot_y);
|
||||
note_hotspot_provenance(answered, hot_measured);
|
||||
let (hotx, hoty) = if hot_measured {
|
||||
(c.hot_x, c.hot_y)
|
||||
} else {
|
||||
@@ -554,7 +600,30 @@ impl Drop for DrmReader {
|
||||
|
||||
#[cfg(test)]
|
||||
mod hotspot_provenance_tests {
|
||||
use super::{cursor_id, hot_measured_from};
|
||||
use super::{cursor_id, hot_measured_from, provenance_code, provenance_is_news};
|
||||
|
||||
/// The log this makes observable is one line per CHANGE, not one per cursor read. A cursor is
|
||||
/// read far more often than its provenance changes, and a per-sample line here would be the
|
||||
/// same defect libdrmtap already had once.
|
||||
#[test]
|
||||
fn provenance_is_logged_once_and_then_only_on_a_change() {
|
||||
let (none, guessed, measured) = (
|
||||
provenance_code(None),
|
||||
provenance_code(Some(false)),
|
||||
provenance_code(Some(true)),
|
||||
);
|
||||
assert_ne!(none, guessed);
|
||||
assert_ne!(guessed, measured);
|
||||
assert_ne!(none, measured);
|
||||
// First sample of a run: -1 is the unset sentinel, so anything is news.
|
||||
assert!(provenance_is_news(-1, measured));
|
||||
// The same state again is not.
|
||||
assert!(!provenance_is_news(measured, measured));
|
||||
assert!(!provenance_is_news(guessed, guessed));
|
||||
// A real transition is.
|
||||
assert!(provenance_is_news(guessed, measured));
|
||||
assert!(provenance_is_news(measured, none));
|
||||
}
|
||||
|
||||
/// The dedup key has to move when the provenance does, or the consumer is never told that the
|
||||
/// same picture now means something different. This is the transition that produces it: the
|
||||
|
||||
Reference in New Issue
Block a user