fix(macos): gate real GL for the whole test build; add Windows diagnostics

- The macOS SIGSEGV moved from the gl_bridge unit tests (already gated)
  to other real-GL users in the same binary (suites::gl_render,
  render_driver): make the gate systemic in the test build on macOS.
  gl_available() reports unavailable and acquire() fails unless
  OAK_GPU_TESTS is set, so every unit test takes its documented CPU
  fallback; release builds are untouched.
- Dump Apple's crash reports on macOS failure: a SIGSEGV in a test binary
  prints nothing, and the .ips report carries the native stack.
- The Windows-only multicam graph test failure now prints both decoded
  media probes and both rendered source pixels: that separates a broken
  test-media encode from a broken graph switch in one run.
This commit is contained in:
2026-09-24 15:33:25 +08:00
parent b94158a941
commit 67cea4844c
3 changed files with 63 additions and 0 deletions
+32
View File
@@ -2500,6 +2500,32 @@ mod tests {
oak_codec::testmedia::write_test_clip_solid(&blue, 64, 64, 10, 10, [0.0, 0.0, 1.0, 1.0])
.expect("blue angle");
// Diagnostic (the Windows-only switch failure): decode each file
// directly, so a red-ish source 1 can be blamed on the generated
// media or on the graph.
let probe = |name: &str, path: &std::path::Path| -> (f32, f32) {
let texture = oak_render::eval::render_footage_frame(
&path.to_string_lossy(),
0,
oak_core::Rational::new(0, 1),
(64, 64),
oak_core::PixelFormat::F32,
)
.unwrap_or_else(|e| panic!("probe {name}: {e}"));
let frame = texture.to_frame().expect("probe readback");
let stride = frame.linesize_bytes() as usize;
let off = 8 * stride + 8 * 16;
(
f32::from_le_bytes(frame.data[off..off + 4].try_into().unwrap()),
f32::from_le_bytes(frame.data[off + 8..off + 12].try_into().unwrap()),
)
};
println!(
"multicam media probe: red={:?} blue={:?}",
probe("red", &red),
probe("blue", &blue)
);
let (project, seq, _rfoot) = project_with_clip(&red);
let bfoot = graphops::import_footage(&project, &blue).expect("import blue");
graphops::add_track(&project, seq, TrackType::Video).expect("track 1");
@@ -2623,6 +2649,12 @@ mod tests {
}
}
let (r1, b1) = render_rgb(0);
// Diagnostic on failure: identical pairs mean the second render was
// served the first frame; a red-ish source 1 means the selected
// element resolved wrong.
println!(
"multicam graph render: source 0 -> (r={r0:.4}, b={b0:.4}), source 1 -> (r={r1:.4}, b={b1:.4})"
);
assert!(
b1 > 0.4 && r1 < 0.4,
"source 1 switches the node-graph frame to blue (r={r1} b={b1})"
+20
View File
@@ -88,10 +88,24 @@ use crate::render::VideoParams;
// ---- 对外 API(平台无关签名;实现按平台 cfg 分派)----------------------
/// Whether the TEST build may touch the real CGL context on macOS. The
/// headless CI runner cannot exercise Apple's GL reliably (parallel unit
/// tests have segfaulted inside the driver), so the test build behaves as
/// if GL were unavailable unless `OAK_GPU_TESTS` asks for it — the same
/// gate the integration GL tests use. Release builds are untouched.
#[cfg(all(test, target_os = "macos"))]
fn real_gl_gated() -> bool {
std::env::var_os("OAK_GPU_TESTS").is_none()
}
/// GL 上下文是否可用(离屏上下文可创建)。use_opengl 决策用它当
/// "目标纹理有有效 GL 名" 的门:桥能为目标帧建出真实 GL 纹理 ⟺
/// 上下文可用。惰性创建,幂等。
pub fn gl_available() -> bool {
#[cfg(all(test, target_os = "macos"))]
if real_gl_gated() {
return false;
}
imp::gl_available()
}
@@ -99,6 +113,12 @@ pub fn gl_available() -> bool {
/// 返回的 guard 在 drop 时清 current 并放锁。失败(无 GL / 上下文
/// 创建失败)→ 调用方回退 CPU。
pub fn acquire() -> crate::error::Result<GlGuard> {
#[cfg(all(test, target_os = "macos"))]
if real_gl_gated() {
return Err(crate::error::Error::Failed(
"gl_bridge: real GL is gated behind OAK_GPU_TESTS in tests".to_string(),
));
}
imp::acquire()
}