Render: render.backend says why it renders on the CPU; mcp --gpu documented (#262)

get_project / render.backend reported "gpuAcceleration": true with
"active": "cpu" and no reason, which read as a broken GPU. The
headless MCP server only attaches the GPU compositor when started with
--gpu, which docs/agents.md didn't mention, and a failed --gpu said
only "no usable GPU adapter" (the adapter's error went to a log no
one sees). The session now keeps the host's reason there is no GPU
compositor (accel_note): the CLI's "headless: renders on the CPU
unless started with --gpu", or the desktop app's compositor setup or
retirement error. The status reports it as `why` whenever it renders
on the CPU (or that the project's renderer is Software Only). --gpu
failures include the adapter's error (Gpu::try_headless).
docs/agents.md documents `mcp --gpu`.

Test: render_backend_says_why_it_renders_on_the_cpu (engine).
Checked with effectcraft-cli mcp and mcp --gpu.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
bflatastic
2026-10-08 18:09:01 +07:00
co-authored by Claude Opus 5.5
parent 0d3b5ed286
commit 4eb69e7577
7 changed files with 46 additions and 5 deletions
+9
View File
@@ -546,11 +546,20 @@ fn render_backend(s: &mut Session, p: &Value) -> Result<Value> {
pub fn backend_status(s: &Session) -> Value {
let adapter = s.accel.as_ref().map(|a| a.name());
let gpu = s.project.settings.gpu_acceleration;
// Why it renders on the CPU (#262).
let why = if !gpu {
Some("the project's renderer is Mercury Software Only".to_string())
} else if adapter.is_none() {
Some(s.accel_note.clone().unwrap_or_else(|| "no GPU compositor is attached".into()))
} else {
None
};
json!({
"renderer": if gpu { "Mercury GPU Acceleration" } else { "Mercury Software Only" },
"gpuAcceleration": gpu,
"adapter": adapter,
"active": if gpu && adapter.is_some() { "gpu" } else { "cpu" },
"why": why,
})
}
+4
View File
@@ -340,6 +340,9 @@ pub struct Session {
/// that ask for [`effectcraft_render::Backend::Gpu`]/`Auto`, and by Render Queue exports
/// when the project's renderer is the GPU.
pub accel: Option<Arc<dyn effectcraft_render::Accelerator>>,
/// 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>,
/// 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>>,
@@ -473,6 +476,7 @@ impl Default for Session {
footage: Arc::new(NoFootage),
expr: None,
accel: None,
accel_note: None,
expr_check: None,
importer: None,
exporter: None,
+12
View File
@@ -536,3 +536,15 @@ fn unicode_label_colors_fall_back_without_panicking() {
s.execute("prefs.set", json!({"key": "labels.0.color", "value": "#aBcD09"})).unwrap();
assert_eq!(s.prefs.label_rgb(Label::Red), [0xab, 0xcd, 9]);
}
/// `render.backend` says why it renders on the CPU (#262): the Software Only renderer, or the
/// host's reason there is no GPU compositor.
#[test]
fn render_backend_says_why_it_renders_on_the_cpu() {
let mut s = Session::default();
let why = |s: &mut Session| s.execute("render.backend", json!({})).unwrap()["why"].clone();
assert_eq!(why(&mut s), json!("no GPU compositor is attached"));
s.accel_note = Some("headless: renders on the CPU unless started with --gpu".into());
assert_eq!(why(&mut s), json!("headless: renders on the CPU unless started with --gpu"));
assert_eq!(s.execute("render.backend", json!({"backend": "cpu"})).unwrap()["why"], json!("the project's renderer is Mercury Software Only"));
}