render2d: Headless-Rendering — PNG ohne Fenster + Golden-Image-Test

HeadlessRenderer (Feature headless) baut Instance/Adapter/Device ohne
Surface (Vulkan, kein Display-Server); render_to_image rendert in eine
Rgba8Unorm-Texture (non-sRGB wie ColorMode::Web) und liest mit 256-Byte-
Row-Padding zurueck. Draw-Code unveraendert geteilt mit dem Fenster-Pfad.
CLI-Bin render_png (Demo-Szene, 990x630); Demo additiv um 45-Grad-
Schraffur, Tuerblatt und Schwenkbogen erweitert, damit das Golden alle
Pfade abdeckt. Golden-Test mit eingechecktem Referenzbild: 0/623700 Pixel
Abweichung, bit-exakt reproduzierbar; bei Abweichung Diff-Dump nach
target/. Doku in docs/design/engine-headless.md.
This commit is contained in:
2026-07-03 08:31:38 +02:00
parent 23410f9b9e
commit 918f60c498
8 changed files with 625 additions and 9 deletions
+27
View File
@@ -52,6 +52,13 @@ web = [
"dep:serde_json",
]
# Offscreen-Renderpfad (kein Fenster/Surface): Adapter/Device ohne Surface,
# Render-Target ist eine `wgpu::Texture` statt einer Surface-Textur, Ergebnis als
# PNG kodiert (`image`-Crate). Fuer Golden-Image-Tests und headlessen PNG-Export
# (Engine-Nordstern, siehe docs/design/engine-headless.md). Bewusst NICHT Teil von
# `render`/`web`: die `image`-Abhaengigkeit soll den wasm-Build nicht belasten.
headless = ["render", "dep:image"]
[dependencies]
serde = { version = "1", features = ["derive"] }
# JSON-Szene (dieselbe Ableitung wie der native Push): im Web-Pfad zur Laufzeit
@@ -69,6 +76,12 @@ pollster = { version = "0.3", optional = true }
# an wgpu gekoppelt: die 0.6er-Reihe ist die zu wgpu 22 passende.
glyphon = { version = "0.6", optional = true }
# --- Headless-PNG-Export (nur mit Feature "headless") ------------------------
# Nur der PNG-Codec noetig (kein volles Format-Universum) -> default-features aus.
image = { version = "0.25", optional = true, default-features = false, features = [
"png",
] }
# --- Fenster (nur mit Feature "window") --------------------------------------
winit = { version = "0.30", optional = true }
env_logger = { version = "0.11", optional = true }
@@ -99,3 +112,17 @@ naga = { version = "22", features = ["wgsl-in"] }
name = "spike"
path = "src/bin/spike.rs"
required-features = ["window"]
# Headless-CLI-Beweis: rendert die Demo-Szene ohne Fenster/Surface nach PNG.
# Nur mit Feature "headless" verfuegbar (siehe Cargo-Feature-Kommentar oben).
[[bin]]
name = "render_png"
path = "src/bin/render_png.rs"
required-features = ["headless"]
# Golden-Image-Test des Headless-Renderpfads. Nur mit Feature "headless" gebaut
# (der Vergleich laedt das Referenzbild ueber `headless::RgbaImage::decode_png`).
[[test]]
name = "golden"
path = "tests/golden.rs"
required-features = ["headless"]