fix(windows/vdisplay): QueryHardwareCursor3 + per-mode-commit cursor re-setup — M2c findings
Durable results of the M2c on-glass bring-up (.173, 2026-07-22): - The base IddCxMonitorQueryHardwareCursor DDI slot is stubbed to STATUS_NOT_SUPPORTED on WDK 26100 — add the ...QueryHardwareCursor3 wrapper (wdk-iddcx) and drain it instead; v3 X/Y are only meaningful when PositionValid, so a position-invalid tick keeps the prior position. - Hardware-cursor setup is per-mode-commit: the OS silently reverts to a software cursor on every mode commit, so re-issue the setup on each swap-chain assignment (monitor::resetup_cursor, called from assign_swap_chain) or the query fails NOT_SUPPORTED forever. - One caps definition for initial setup and re-setup, resting at XOR FULL: the query delivers ONLY alpha shapes in every configuration (all three ColorXorCursorSupport levels, event-driven and 30 Hz polled) — masked/monochrome cursors never arrive. FULL keeps the frame cursor-free for ALL cursor types; the full-fidelity shape comes from the session-side cursor source in the host (design/remote-desktop-sweep.md §8). - Poll the query at ~30 Hz instead of pure event-wait: masked cursors never fire the data event, and the seqlock's position/visibility should stay fresh regardless. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -495,6 +495,26 @@ pub fn take_preserved_stash(
|
||||
((low, high) == (luid_low, luid_high)).then_some(stash)
|
||||
}
|
||||
|
||||
/// Re-issue the hardware-cursor setup for the monitor identified by its IddCx `object`, if it
|
||||
/// has a live cursor worker (the M2c cursor channel). Called from `assign_swap_chain`: a mode
|
||||
/// commit reverts the OS to a software cursor, so the setup must be re-declared on the freshly
|
||||
/// committed path or `IddCxMonitorQueryHardwareCursor` returns STATUS_NOT_SUPPORTED forever.
|
||||
/// Reads the worker's data-event UNDER the lock (so the worker is provably alive), then calls
|
||||
/// the DDI OUTSIDE it (the DDI can re-enter the mode callbacks, which take this lock).
|
||||
pub fn resetup_cursor(object: iddcx::IDDCX_MONITOR) {
|
||||
let data_event = {
|
||||
let lock = lock_monitors();
|
||||
lock.iter()
|
||||
.find(|m| m.object == Some(object))
|
||||
.and_then(|m| m.cursor_worker.as_ref())
|
||||
.map(|w| w.data_event())
|
||||
};
|
||||
if let Some(ev) = data_event {
|
||||
let st = crate::cursor_worker::setup_hardware_cursor(object, ev);
|
||||
dbglog!("[pf-vd] cursor: re-setup on swap-chain assign -> {st:#x}");
|
||||
}
|
||||
}
|
||||
|
||||
/// Install a swap-chain processor on the monitor whose handle matches, returning any PREVIOUS processor
|
||||
/// for the caller to drop OUTSIDE the lock. Dropping a processor RAII-joins its worker thread, so it must
|
||||
/// never happen while holding `MONITOR_MODES` (the worker would block the whole control plane / risk a
|
||||
|
||||
Reference in New Issue
Block a user