From b655af305a8c554c318fbf46eac04171e419751d Mon Sep 17 00:00:00 2001 From: jyviko <2501648+jyviko@users.noreply.github.com> Date: Fri, 16 Oct 2026 07:42:59 -0400 Subject: [PATCH] gpu: Capturer::on_device and Renderer::report A capturer on a device already open (the app's), and the renderer's JSON shared by every reply. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo --- Cargo.lock | 1 + crates/gpu/Cargo.toml | 1 + crates/gpu/src/capture.rs | 6 ++++++ crates/gpu/src/lib.rs | 9 +++++++++ crates/mcp/src/backend.rs | 5 +---- 5 files changed, 18 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9f3f041..47a0bca 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1379,6 +1379,7 @@ dependencies = [ "fieldcraft-render", "log", "pollster 0.4.0", + "serde_json", "thiserror 2.0.21", "wgpu", ] diff --git a/crates/gpu/Cargo.toml b/crates/gpu/Cargo.toml index 4f0e24e..abca5f4 100644 --- a/crates/gpu/Cargo.toml +++ b/crates/gpu/Cargo.toml @@ -13,6 +13,7 @@ fieldcraft-render = { workspace = true } wgpu = { workspace = true } log = { workspace = true } thiserror = { workspace = true } +serde_json = { workspace = true } [target.'cfg(not(target_arch = "wasm32"))'.dependencies] pollster = { workspace = true } diff --git a/crates/gpu/src/capture.rs b/crates/gpu/src/capture.rs index f5330e7..a3986ae 100644 --- a/crates/gpu/src/capture.rs +++ b/crates/gpu/src/capture.rs @@ -61,6 +61,12 @@ impl Capturer { .map_err(|e| GpuError::Device(e.to_string()))?; // Errors outside a scope are logged, replacing wgpu's default handler, which panics. device.on_uncaptured_error(Arc::new(|e: wgpu::Error| log::error!("graphics device error: {e}"))); + Capturer::on_device(adapter, device, queue, tier) + } + + /// A capturer on a device already open on `adapter` (the desktop app's), which keeps its + /// error handler: pictures share the window's device instead of opening another. + pub fn on_device(adapter: &wgpu::Adapter, device: wgpu::Device, queue: wgpu::Queue, tier: Tier) -> Result { let samples = if adapter.get_texture_format_features(FORMAT).flags.sample_count_supported(SAMPLES) && adapter.get_texture_format_features(DEPTH).flags.sample_count_supported(SAMPLES) { diff --git a/crates/gpu/src/lib.rs b/crates/gpu/src/lib.rs index 9ae3c50..62f6370 100644 --- a/crates/gpu/src/lib.rs +++ b/crates/gpu/src/lib.rs @@ -69,4 +69,13 @@ impl Renderer { Renderer::Cpu { .. } => "cpu", } } + + /// What drew a picture, for a reply: `{kind, adapter, msaa}` on a GPU, `{kind, why}` on + /// the CPU (`why` null when the CPU was asked for). + pub fn report(&self) -> serde_json::Value { + match self { + Renderer::Gpu { adapter, samples, .. } => serde_json::json!({"kind": self.kind(), "adapter": adapter, "msaa": samples}), + Renderer::Cpu { why } => serde_json::json!({"kind": self.kind(), "why": why}), + } + } } diff --git a/crates/mcp/src/backend.rs b/crates/mcp/src/backend.rs index f35d297..7524467 100644 --- a/crates/mcp/src/backend.rs +++ b/crates/mcp/src/backend.rs @@ -35,10 +35,7 @@ fn draw(f: &fieldcraft_engine::view::Framed, w: u32, h: u32) -> Result<(Vec, /// the adapter, or why the CPU drew it), `results` (step, scale, contour), `undrawn_bodies` and /// `sampled_symbols`. The MCP `screenshot` reply and `fieldcraft-cli snapshot` print it. pub fn picture_report(r: &Renderer, shown: &Shown) -> Value { - let renderer = match r { - Renderer::Gpu { adapter, samples, .. } => json!({"kind": r.kind(), "adapter": adapter, "msaa": samples}), - Renderer::Cpu { why } => json!({"kind": r.kind(), "why": why}), - }; + let renderer = r.report(); let contour = shown .contour .as_ref()