From b2b988cdc8051dcfd49d32c90143961dce25ee5f Mon Sep 17 00:00:00 2001 From: pakiat <49967840+pakiat@users.noreply.github.com> Date: Tue, 3 Nov 2026 21:01:59 +0700 Subject: [PATCH] Tests: harnesses that render through wgpu take turns (#5354) Two wgpu devices drawing at once crash Windows' software rasterizer (WARP, d3d10warp.dll: 0xc0000005, sometimes heap corruption 0xc0000374), which is the adapter a machine without a GPU or a remote session gets. The ui-egui tests that render (a dragged shape, a rotation drag, and the ignored spelling review preview) now hold one lock while their harness lives. On Windows 11 over SSH the two rendering tests crashed 8 of 20 runs together (0 of 20 alone), and the whole ui-egui lib run 2 of 6; with the lock 0 of 20 and 0 of 10. Co-authored-by: Claude Opus 5.5 --- crates/ui-egui/src/objects/tests.rs | 6 ++++-- crates/ui-egui/src/proofing_pane.rs | 1 + crates/ui-egui/src/table_resize/tests.rs | 8 ++++++++ 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/crates/ui-egui/src/objects/tests.rs b/crates/ui-egui/src/objects/tests.rs index 50e7c3b7b5..72b1b1a5ff 100644 --- a/crates/ui-egui/src/objects/tests.rs +++ b/crates/ui-egui/src/objects/tests.rs @@ -563,7 +563,8 @@ fn an_inline_picture_drags_to_the_insertion_cursor_and_stays_inline() { /// page: its preview has its red outline and nothing dark inside. #[test] fn a_dragged_shape_leaves_the_text_behind_it() { - use crate::table_resize::tests::{H, button, steps}; + use crate::table_resize::tests::{H, button, gpu_turn, steps}; + let _gpu = gpu_turn(); let text = "MMMMMMMMMMMM ".repeat(12); let mut a = WordApp::new(wordcraft_engine::Session::new(Document::from_text(&text)), Default::default()); let shape = InlineObject::Shape { @@ -758,7 +759,8 @@ fn rotation_window(app: WordApp) -> crate::table_resize::tests::H { /// pictures whose cached preview already contains a rotation and either reflection. #[test] fn rotation_drag_turns_picture_pixels_live_and_commits_once_or_cancels() { - use crate::table_resize::tests::{H, button, steps}; + use crate::table_resize::tests::{H, button, gpu_turn, steps}; + let _gpu = gpu_turn(); for (initial, flip_h, flip_v) in [(0.0, false, false), (30.0, true, false), (90.0, false, true), (315.0, true, true)] { // Four original colour quadrants make both accidental extra rotation and reflected // UVs observable. Sample near the long ends after a quarter turn, outside the old diff --git a/crates/ui-egui/src/proofing_pane.rs b/crates/ui-egui/src/proofing_pane.rs index 91cf5dac0a..806b25038f 100644 --- a/crates/ui-egui/src/proofing_pane.rs +++ b/crates/ui-egui/src/proofing_pane.rs @@ -373,6 +373,7 @@ mod tests { #[test] #[ignore = "offscreen visual review; requires a software or hardware graphics adapter"] fn spelling_review_dialog_preview() { + let _gpu = crate::table_resize::tests::gpu_turn(); let mut a = app("The quick brwn fox."); a.run("review.spelling", json!({})).unwrap(); let mut h = egui_kittest::Harness::builder().with_size(egui::vec2(1000.0, 700.0)).wgpu().build_ui_state(frame, a); diff --git a/crates/ui-egui/src/table_resize/tests.rs b/crates/ui-egui/src/table_resize/tests.rs index c4300ee99a..0bb4895cad 100644 --- a/crates/ui-egui/src/table_resize/tests.rs +++ b/crates/ui-egui/src/table_resize/tests.rs @@ -65,6 +65,14 @@ pub(crate) fn steps(h: &mut H, n: usize) { } } +/// Held by a test while its harness renders through wgpu: two devices drawing at once crash +/// Windows' software rasterizer (WARP, `d3d10warp.dll`), which is what a machine without a GPU +/// or a remote session gets, so those tests take turns. +pub(crate) fn gpu_turn() -> std::sync::MutexGuard<'static, ()> { + static GPU: std::sync::Mutex<()> = std::sync::Mutex::new(()); + GPU.lock().unwrap_or_else(std::sync::PoisonError::into_inner) +} + /// A real mouse drag of a column border: the resize arrow on hover, a preview and no change /// while dragging, then one undo step on release, the selection untouched. #[test]