Expand description
§zenfg
zenfg is a renderer-agnostic FrameGraph compiler and transient-resource
executor for wgpu. It records logical resources and accesses, validates content
flow, builds dependencies, culls dead work, derives usage, plans transient
aliasing, and optionally materializes retained work on a caller-owned device and
queue.
ZenFG does not own scenes, pipelines, bind groups, samplers, surfaces, presentation, or device-loss policy. This is a public beta crate; pin the exact prerelease version while integrating.
§Installation
cargo add zenfg@=0.1.0-beta.4§Features
| Feature | Default | Adds |
|---|---|---|
default | Yes | Empty feature set; the core compiler and device-backed executor are always available |
serde | No | Serde support for internal compilation report types |
snapshot | No | zenfg-snapshot, wire-type re-exports, and portable report export |
FrameGraph::new() is CPU-only. FrameGraph::with_device() stores a cloned
wgpu::Device, owns a transient pool, and enables execution. The queue and all
imported resources remain caller-owned.
§Quick start
Use a Cargo application with the toolchain in Compatibility.
Place this code inside fn main() -> Result<(), zenfg::FrameGraphError> and finish
with Ok(()). Run cargo run; the assertion succeeds without requiring a GPU.
Lines prefixed with # in this Markdown are rustdoc test scaffolding, not lines to paste.
This complete CPU-only example records one transient output, retains it, and compiles a diagnostic plan:
use zenfg::{
BufferDesc, BufferRange, CompileOptions, FrameGraph, RootReason,
UsagePolicy, WriteContents,
};
let mut graph = FrameGraph::new();
let mut frame = graph.begin_frame();
let output = frame.create_buffer(BufferDesc {
label: "output".into(),
size: 1024,
usage: UsagePolicy::Infer,
})?;
let mut pass = frame.compute_pass("produce");
let _output = pass.storage_buffer_write(
output,
BufferRange::whole(),
WriteContents::Overwrite,
)?;
pass.finish()?;
frame.mark_buffer_root(output, BufferRange::whole(), RootReason::Output)?;
let compiled = frame.compile(CompileOptions::full_report())?;
assert_eq!(compiled.report().unwrap().summary.retained_node_count, 1);§Lifecycle
FrameGraph -> Frame<'frame> -> CompiledFrame<'frame> -> execute(queue)
runtime recording retained CPU plan optional, one-shotbegin_frame()exclusively borrows the runtime and creates one recording.Frame::compile()consumes the recording. Handles and access tokens carry runtime and recording identities enforced by the API and validation.CompiledFrame::execute()is one-shot. Native bindings and callbacks needed only by culled work are released after compilation.- Surface acquisition and presentation remain caller-owned; import and bind a fresh current surface texture for each presentation frame.
- Dropping
FrameGraphreleases retained pool and profiler resources, but not caller-owned imported resources.
§Common tasks
| Task | Public API |
|---|---|
| Create a CPU-only compiler | FrameGraph::new() |
| Create a device-backed runtime | FrameGraph::with_device() |
| Start a recording | begin_frame() |
| Create transient storage | create_texture(), create_buffer() |
| Register imported storage | import_texture(), import_surface_texture(), import_buffer() |
| Bind imported native objects | bind_imported_texture(), bind_imported_buffer() |
| Select texture subresources | create_texture_view() |
| Record render or compute work | render_pass() / finish_render(), compute_pass() / finish_compute() |
| Record copies or clears | copy_pass() with typed copy methods, clear_buffer(), clear_buffers() |
| Encode custom graph-owned commands | command_pass() / finish_command() |
| Call a renderer that submits itself | external_submission() / finish_external() |
| Retain observable values | mark_present(), mark_buffer_root(), mark_texture_root(), mark_readback() |
| Compile compact or full diagnostics | compile(CompileOptions::default()), compile(CompileOptions::full_report()) |
| Execute retained work | execute(), execute_with_options() |
| Request CPU/GPU timing | execute_with_timing() |
| Inspect or clear retained allocations | resource_pool_stats(), clear_resource_pool() |
| Export Snapshot 1.2 | snapshot::create_frame_graph_snapshot() with feature snapshot |
Exact signatures, fields, defaults, and structured FGxxxx errors are
documented on docs.rs.
§Key pattern: bind and resolve typed access
Imported storage is declared logically, then bound to a caller-owned native object. Transient and imported storage resolve through the same typed pass tokens:
use zenfg::{
BufferDesc, BufferRange, CompileOptions, FrameGraph, ImportBufferOptions,
InitialContents,
};
let mut graph = FrameGraph::with_device(device);
let mut frame = graph.begin_frame();
let buffer = frame.import_buffer(
BufferDesc::new("input", native.size()),
ImportBufferOptions::new(InitialContents::Defined),
)?;
frame.bind_imported_buffer(buffer, native)?;
let mut pass = frame.compute_pass("consume");
let input = pass.storage_buffer_read(buffer, BufferRange::whole())?;
pass.finish_compute(move |ctx| {
let _native = ctx.resources.buffer(input)?;
// Set a compute pipeline and dispatch through ctx.pass.
Ok(())
})?;
frame.compile(CompileOptions::default())?.execute(queue)?;Resolved transient objects are valid only inside their execution callback. Imported objects remain caller-owned, but every graph-visible access still needs a matching declaration.
§Resource and integration choices
Declaration granularity is optional: complex workloads can keep private weights, parameters, and scratch internally bound, while teaching or diagnostic use can expose more resources. Graph-visible dependencies and access correctness still apply. See Choosing resource declaration granularity.
For resources exposed to the graph:
- Use transient resources for storage needed only by one compiled execution; import storage that the caller owns or that must survive execution.
- Imported resources explicitly choose
InitialContents::DefinedorInitialContents::Undefined. The first write to a transient range must fully overwrite it. - Prefer structured render, compute, copy, and clear nodes. Use command passes for custom work on a graph-owned encoder.
- Use external submissions for renderers that own and submit their encoders. The boundary orders queue submissions but is not a GPU-completion fence.
- ZenFG performs no cross-frame dependency analysis and never acquires or presents a surface for the application.
See Core concepts for the shared ownership, content, dependency, lifetime, and integration model.
§Common mistakes
| Symptom | Fix |
|---|---|
| A pass is absent from the compiled plan | Retain its final value with the appropriate root, or declare only genuine side effects. |
| A read or preserving write reports undefined contents | Overwrite the complete range first or choose the correct imported initial contents. |
| An imported resource cannot execute | Bind the matching native object and ensure descriptor and usage metadata agree. |
| A typed token fails to resolve | Resolve it only through the pass that declared it and only inside that pass’s callback. |
| A transient object is used later | Never clone or retain resolved transient wgpu handles across callbacks or frames. |
| External work is incorrectly ordered | Submit all declared work on the shared queue before the external callback returns. |
| Timing is unavailable | Treat unsupported, busy, readback failure, and overflow as non-fatal timing results. |
§Complete examples
The following Cargo examples are published with the crate and compile-checked outside the workspace:
| Workflow | Example |
|---|---|
| Minimal presentation lifecycle | minimal_frame.rs |
| Transient render target to presentation | transient_to_present.rs |
| Caller-owned imported resource | imported_resource.rs |
| Cross-frame persistent state | persistent_state.rs |
| Opaque third-party submission | external_submission.rs |
| Portable Snapshot export | snapshot_export.rs |
| Asynchronous GPU timing | gpu_timing.rs |
| Compute storage output | compute_output.rs |
The repository also contains CPU-only compile and pool benchmarks. Snapshot
export requires the snapshot feature.
§Further reading
§Documentation and versions
This README describes zenfg 0.1.0-beta.4. Registry badges show the current published channel, not your installed version.
- Exact installed APIs: read the included
src/, or runcargo doc --openin your consuming project. - Online guide (development branch). The site may describe changes newer than this package.
- Rust API for this version.
- Source and documentation for this release.
- Shared concepts for this release and compatibility.
- Plain Markdown documentation index (development branch).
- Complete Cargo recipes are included in
examples/.
§Execution timing
Use execute_with_timing(&queue, options, TimingMode::Cpu),
TimingMode::Gpu, or TimingMode::Both. The result owns an optional synchronous
CPU report and optional GPU readback. Poll the latter with try_take(); CPU-only
execution never waits for a GPU result. Ordinary execution collects no timing.
CPU is synchronous elapsed time for all executed node kinds, not thread CPU
usage. Execution total includes preparation, submission and transient release.
Modules§
- snapshot
- Snapshot 1.2 export plus the portable
zenfg_snapshotwire API.
Structs§
- Access
Id - Recording-local identity of a declared resource access.
- Access
Report - One declared resource access in recording order.
- Access
Token - A typed identity for one declared access in one pass.
- Allocation
Id - Compilation-local identity of a physical allocation.
- Allocation
Report - One physical transient allocation and all aliased logical resources assigned to it.
- Buffer
- Typed handle to one logical buffer in a single frame recording.
- Buffer
Copy Dst - Type marker for the
BufferCopyDstaccess role. - Buffer
Copy Src - Type marker for the
BufferCopySrcaccess role. - Buffer
Desc - Logical buffer descriptor used for validation and transient allocation.
- Buffer
Range - A byte range within a logical buffer.
- Buffer
Texture Copy Location - One logical buffer and texel layout used by a buffer-texture copy operation.
- Clear
Buffer Op - One ordered zero-fill operation in a structured clear-buffer node.
- Color
Attachment - Type marker for the
ColorAttachmentaccess role. - Color
Attachment Ops - Load/store operations for one color attachment.
- Command
Context - Synchronous callback context for direct command encoding.
- Compilation
Report - Optional compilation diagnostics selected by
ReportLevel. - Compilation
Summary - Counts, memory estimates, and timings available at summary report level.
- Compilation
Timings - CPU time spent in each compilation phase, in nanoseconds.
- Compile
Options - Options controlling CPU compilation and report generation.
- Compiled
Frame - An owned, single-use compilation result.
- Compute
Pass Context - Synchronous callback context for one retained structured compute node.
- CpuTiming
Node Report - CPU-side elapsed time for one executed node, including local setup and cleanup.
- CpuTiming
Report - Detached CPU report from one successful execution.
- Culled
Node Report - One removed node in original recording order.
- Debug
Group Id - Recording-local identity of a diagnostic debug group.
- Debug
Group Report - One recording-only diagnostic scope in group-open order.
- Dependency
Report - One value-carrying or ordering dependency between graph nodes.
- Depth
Attachment - Type marker for the
DepthAttachmentaccess role. - Depth
Attachment Ops - Load/store operations for one writable, pure-depth attachment.
- Diagnostic
- Structured non-fatal diagnostic attached to a compilation report.
- Execution
Options - Options controlling one GPU execution without changing the compiled plan.
- Execution
Resources - Pass-scoped resolver for logical resources declared by typed access tokens.
- Execution
Segment Report - Ordered retained nodes belonging to one execution segment.
- Execution
Timing - Immediate CPU results and an independently asynchronous GPU readback.
- External
Submission Context - Synchronous callback context for caller-controlled queue submission.
- Frame
- A single-use FrameGraph recording.
- Frame
Graph - Long-lived owner of frame identities, transient allocations, and GPU timing state.
- Full
Compilation Report - Complete recording, retention, dependency, and allocation tables.
- GpuTiming
Node Report - GPU duration for one retained render or compute pass.
- GpuTiming
Readback - A one-shot, non-blocking handle for one GPU timing result.
- Import
Buffer Options - Initial-content and native-usage contract for an imported buffer.
- Import
Texture Options - Initial-content and native-usage contract for an imported texture.
- Index
Buffer - Type marker for the
IndexBufferaccess role. - Indirect
Buffer - Type marker for the
IndirectBufferaccess role. - Node
Report - One retained node in original recording order.
- Normalized
Texture View Desc - Fully resolved recording-time metadata for a logical texture view.
- Pass
Builder - Builder for one graph node and its declared resource accesses.
- PassId
- Recording-local identity of a graph node/pass.
- Render
Pass Context - Synchronous callback context for one retained structured render node.
- Resource
Id - Recording-local identity of a logical resource.
- Resource
Lifetime - Inclusive retained execution-order interval of one logical resource.
- Resource
Pool Stats - Aggregate counters for the FrameGraph-owned transient resource pool.
- Resource
Report - Descriptor, usage, lifetime, and allocation facts for one logical resource.
- Root
Report - One observable resource range and the producers that keep it defined.
- Root
Resolution - Sources of the final contents in a root’s selected range.
- Sampled
Texture - Type marker for the
SampledTextureaccess role. - Storage
Buffer Read - Type marker for the
StorageBufferReadaccess role. - Storage
Buffer Write - Type marker for the
StorageBufferWriteaccess role. - Storage
Texture Read - Type marker for the
StorageTextureReadaccess role. - Storage
Texture Write - Type marker for the
StorageTextureWriteaccess role. - Texture
- Typed handle to one logical texture in a single frame recording.
- Texture
Copy Dst - Type marker for the
TextureCopyDstaccess role. - Texture
Copy Location - One logical texture subresource location used by a declarative copy operation.
- Texture
Copy Src - Type marker for the
TextureCopySrcaccess role. - Texture
Desc - Logical texture descriptor used for validation and transient allocation.
- Texture
Subresource Range - One normalized texture subresource range.
- Texture
View - Typed handle to one normalized logical texture view in a single recording.
- Texture
View Desc - Descriptor for a logical texture view.
- Uniform
Buffer - Type marker for the
UniformBufferaccess role. - ValueId
- Recording-local identity of a logical content value.
- Value
Report - One initial or pass-produced logical content value.
- Vertex
Buffer - Type marker for the
VertexBufferaccess role. - ViewId
- Recording-local identity of a logical texture view.
- View
Report - One normalized logical texture view.
Enums§
- Access
Mode - Whether an access reads or writes a logical resource.
- Access
Role - Pipeline role declared for one resource access.
- Attachment
Store Op - Whether attachment contents remain defined after the pass.
- Color
Attachment Load Op - Load/store operations for one color attachment.
- Culled
Node Reason - Why a recorded node was removed from the retained plan.
- Dependency
Kind - Whether a dependency carries data or only constrains execution order.
- Depth
Attachment Load Op - Load/store operations for one writable, pure-depth attachment.
- Diagnostic
Severity - Severity of a compilation diagnostic.
- Execution
Segment Kind - Kind of encoder/submission segment in the retained execution plan.
- Frame
Graph Error - All recording, compilation, and execution errors emitted by the FrameGraph.
- GpuTiming
Node Kind - The executable node kinds that can be measured with pass timestamp writes.
- GpuTiming
Report - The result of one requested GPU timing sample.
- GpuTiming
Unavailable Reason - Why a timed execution completed without timestamp values.
- Hazard
Kind - Hazard that caused a graph dependency.
- Initial
Contents - Whether an imported resource contains readable data at frame start.
- Node
Kind - Kind of work represented by a graph node.
- Report
Level - Amount of compilation diagnostics to retain.
- Resource
Descriptor - Snapshotted logical descriptor of a reported resource.
- Resource
Kind - Kind of logical resource recorded in a frame.
- Resource
Origin - Ownership and allocation source of a logical resource.
- Resource
Range - Normalized region of a logical resource used in reports.
- Resource
Usage - Effective native usage inferred for a retained logical resource.
- Root
Reason - Why the contents of a resource must remain live after graph compilation.
- Texture
Target - A whole logical texture or an explicitly created logical view.
- Timing
Mode - Timing families requested for one synchronous execution.
- Undefined
Cause - Origin of undefined contents reported by the compiler.
- Usage
Policy - Policy used to choose native wgpu usage flags for a transient resource.
- Value
Kind - Origin of one logical content value.
- Write
Contents - Content behavior of a write access.
Traits§
- Access
Marker - Sealed type-level role carried by an
AccessToken. - Buffer
Access Marker - Access role that resolves to a
wgpu::Bufferduring execution. - Texture
Access Marker - Access role that resolves to a
wgpu::Textureorwgpu::TextureView.