mirror of
https://github.com/storytold/effectcraft.git
synced 2026-10-14 19:27:05 -04:00
Help: the System Compatibility Report says why there is no GPU and names the window's adapter (#596)
With no GPU compositor the report only said "GPU: none", though the host had recorded the reason (`Session::accel_note`: the compositor's setup error, a retired GPU preview, a headless start) and the window's wgpu adapter was known. Users with a capable GPU (#596, an RTX 4070) couldn't tell why it wasn't used. The report now carries `gpuNote` (the reason, when there is no compositor) and `windowGraphics` (the adapter, backend, device type and driver the window draws with, which the desktop app records when it sets up the GPU), and the text shows "GPU: none (CPU compositing): <reason>" and "Window graphics: …"; the issue line names the reason too. Test: the compatibility report test sets a reason and an adapter and checks the JSON and text. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01QiAJeFttZp83Fh7YuzAR5f
This commit is contained in:
4 files changed
+36
-2
No files matched your search
@@ -328,7 +328,10 @@ pub fn system_report(s: &Session) -> Value {
|
||||
let budgets = s.prefs.cache_budgets(mem.or(s.sys_memory));
|
||||
let mut issues = vec![];
|
||||
if gpu.is_none() {
|
||||
issues.push("No GPU compositor: rendering uses the CPU (all features still work).".to_string());
|
||||
issues.push(match &s.accel_note {
|
||||
Some(why) => format!("No GPU compositor ({why}): rendering uses the CPU (all features still work)."),
|
||||
None => "No GPU compositor: rendering uses the CPU (all features still work).".to_string(),
|
||||
});
|
||||
}
|
||||
if mem.is_some_and(|m| m.total < 8 << 30) {
|
||||
issues.push("Less than 8 GB of memory: use lower preview resolutions for long or large comps.".to_string());
|
||||
@@ -344,6 +347,8 @@ pub fn system_report(s: &Session) -> Value {
|
||||
"cores": crate::sysinfo::cpu_cores(),
|
||||
"memory": mem.map(|m| json!({"total": gb(m.total), "available": gb(m.available)})),
|
||||
"gpu": gpu,
|
||||
"gpuNote": if gpu.is_none() { s.accel_note.clone() } else { None },
|
||||
"windowGraphics": s.window_adapter,
|
||||
"caches": {"layer": gb(budgets.layer as u64), "footage": gb(budgets.media as u64), "preview": gb(budgets.preview as u64)},
|
||||
"import": IMPORT_FORMATS,
|
||||
"export": export,
|
||||
@@ -369,7 +374,14 @@ pub fn report_text(r: &Value) -> String {
|
||||
Some(m) => t.push_str(&format!("Memory: {} ({} available)\n", m["total"].as_str().unwrap_or("?"), m["available"].as_str().unwrap_or("?"))),
|
||||
None => t.push_str("Memory: unknown\n"),
|
||||
}
|
||||
t.push_str(&format!("GPU: {}\n", r.get("gpu").and_then(Value::as_str).unwrap_or("none (CPU compositing)")));
|
||||
match (r.get("gpu").and_then(Value::as_str), r.get("gpuNote").and_then(Value::as_str)) {
|
||||
(Some(gpu), _) => t.push_str(&format!("GPU: {gpu}\n")),
|
||||
(None, Some(why)) => t.push_str(&format!("GPU: none (CPU compositing): {why}\n")),
|
||||
(None, None) => t.push_str("GPU: none (CPU compositing)\n"),
|
||||
}
|
||||
if let Some(w) = r.get("windowGraphics").and_then(Value::as_str) {
|
||||
t.push_str(&format!("Window graphics: {w}\n"));
|
||||
}
|
||||
let c = &r["caches"];
|
||||
t.push_str(&format!(
|
||||
"Cache budgets: layer {}, footage {}, preview {}\n",
|
||||
|
||||
@@ -368,6 +368,9 @@ pub struct Session {
|
||||
/// Why there is no [`Session::accel`] (`render.backend`'s `why`): the host's reason, e.g. a
|
||||
/// headless start without `--gpu` or the compositor's setup error.
|
||||
pub accel_note: Option<String>,
|
||||
/// The graphics adapter and backend the window draws with (`NVIDIA GeForce RTX 4070
|
||||
/// (Vulkan)`), as the host reports it: the System Compatibility Report shows it.
|
||||
pub window_adapter: Option<String>,
|
||||
/// Expression syntax checker (set by the host that links the expression engine).
|
||||
pub expr_check: Option<fn(&str) -> std::result::Result<(), String>>,
|
||||
pub importer: Option<Arc<dyn Importer>>,
|
||||
@@ -511,6 +514,7 @@ impl Default for Session {
|
||||
expr: None,
|
||||
accel: None,
|
||||
accel_note: None,
|
||||
window_adapter: None,
|
||||
expr_check: None,
|
||||
importer: None,
|
||||
exporter: None,
|
||||
|
||||
@@ -455,6 +455,15 @@ fn compatibility_report_and_logging() {
|
||||
}
|
||||
let text = crate::commands::report_text_for_tests(&r);
|
||||
assert!(text.contains("Operating system") && text.contains("Import:"));
|
||||
// #596: without a GPU compositor the report says why, and names the window's adapter.
|
||||
s.accel_note = Some("GPU compositor unavailable: no storage textures".into());
|
||||
s.window_adapter = Some("NVIDIA GeForce RTX 4070 (Gl, DiscreteGpu)".into());
|
||||
let r = s.execute("help.systemReport", json!({"quiet": true})).unwrap();
|
||||
assert_eq!(r["gpuNote"], "GPU compositor unavailable: no storage textures");
|
||||
let text = crate::commands::report_text_for_tests(&r);
|
||||
assert!(text.contains("GPU: none (CPU compositing): GPU compositor unavailable: no storage textures"), "{text}");
|
||||
assert!(text.contains("Window graphics: NVIDIA GeForce RTX 4070 (Gl, DiscreteGpu)"), "{text}");
|
||||
assert!(r["issues"][0].as_str().is_some_and(|i| i.contains("no storage textures")), "{r}");
|
||||
s.drain_events();
|
||||
s.execute("help.systemReport", json!({})).unwrap();
|
||||
assert!(s.drain_events().iter().any(|e| matches!(e, crate::Event::Frontend { command, .. } if command == "app.showReport")));
|
||||
|
||||
@@ -612,6 +612,15 @@ impl EffectcraftApp {
|
||||
return;
|
||||
}
|
||||
let Some(rs) = frame.wgpu_render_state() else { return };
|
||||
// Help ▸ System Compatibility Report names the adapter and backend the window got.
|
||||
let info = rs.adapter.get_info();
|
||||
self.session.window_adapter = Some(format!(
|
||||
"{} ({:?}, {:?}{})",
|
||||
info.name,
|
||||
info.backend,
|
||||
info.device_type,
|
||||
if info.driver.is_empty() { String::new() } else { format!(", {} {}", info.driver, info.driver_info) }
|
||||
));
|
||||
// Backend validation can panic on shader compilation even when device creation
|
||||
// succeeded. Keep the document and the egui renderer, and use CPU compositing.
|
||||
let gpu = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| effectcraft_gpu::Gpu::new(&rs.adapter, rs.device.clone(), rs.queue.clone())));
|
||||
|
||||
Reference in new issue
Block a user