Part 5 of the Metal PathTracer Architecture series, based on the renderer documentation snapshot created on May 14, 2026.
Real-time rendering features often sound like algorithms first and memory-management problems second. A reservoir, a denoiser history, a path-guiding field, or a reprojection mask is usually introduced by describing what it estimates. In an interactive renderer, though, the difficult question arrives one frame later: what survives, who owns it, and what makes it invalid?
I have been making those questions explicit in my Metal path tracer through a render pass graph and a transport-memory registry. This is less glamorous than adding another sampling mode, but it has changed how I think about the renderer. History is not an invisible side effect of a feature. It is a resource with a lifetime, a storage class, a confidence state, and a cost.
Making the frame visible
The pass graph gives optional work a concrete shape. A pass has a name and a type—host, compute, render, or external—along with resource reads and writes, feature masks, settings dependencies, history dependencies, pipeline keys, dispatch kind, debug labels, and timing labels.
The graph includes ordinary work such as acceleration-structure updates, accumulation clearing, megakernel integration, wavefront work-graph execution, and presentation. It also represents optional paths: ReSTIR DI initialization, initial candidates, temporal reuse, spatial reuse, visibility, lighting application, and debug AOV output. Denoising passes such as SVGF and OIDN have a place there too, as does an ML-backend no-op entry for a path that is represented architecturally but not active as a neural solution.
Naming these operations matters. If a frame uses temporal reuse, I want to be able to see the pass that reads the previous frame and the pass that writes the next state. If a feature gate is off, the graph should make that absence clear. A single monolithic integration path can still produce an image, but it makes basic questions unnecessarily difficult: did the feature run, did it read history, and which pass was responsible for the memory that changed?
The graph is not an attempt to hide the complexity of rendering behind a new abstraction. It is a way to count and inspect that complexity. When an experiment changes the frame, the renderer should be able to say where the change entered the frame and which resources carried information into it.
A registry for transport state
The companion registry tracks persistent and transient state used by sampling and reconstruction features. Its categories include ReSTIR DI, ReSTIR GI, and ReSTIR PT reservoirs; path-guiding fields; the radiance, visibility, and denoiser caches; variance and confidence state; reprojection-validity masks; debug readback; wavefront queues; caustic path-space state; and ML-backend tensors.
Each record describes an owner and, where relevant, a target owner. It identifies a resource group and storage class, its lifetime, history policy, invalidation behavior, confidence state, debug-readback policy, migration risk, and whether it is hot-path memory. That information is useful both for correctness and for performance. A resource that persists across frames has a different failure surface from a temporary queue, and a CPU-visible debug buffer has a different cost from a GPU-only allocation.
I think of ownership as a form of documentation that the renderer can enforce. If a temporal reservoir is updated by one pass and invalidated by an unrelated setting change, the relationship should be visible rather than living in an informal convention. If path guiding is enabled only for diffuse events, the guide's lifetime and invalidation rules should not be confused with those of a denoiser history. Similar-looking “history” is not necessarily interchangeable history.
Invalidation is part of the algorithm
Temporal techniques are powerful because adjacent frames are often similar. They are also fragile for exactly the same reason: a small change can make old information misleading. Camera movement, resolution changes, scene edits, material changes, feature toggles, or a change in sampling configuration may all require some state to be cleared, reprojection-tested, or rebuilt.
Without explicit invalidation, a renderer can look stable while accumulating an error that is difficult to attribute. A reservoir may reuse a sample from a different lighting configuration. A denoiser may treat a disoccluded pixel as continuous. A guiding cell may retain evidence from a scene arrangement that no longer exists. A radiance cache may appear to converge while its metadata no longer matches the surface being shaded.
The registry does not make those problems disappear. It gives them a place to be recorded and inspected. The important boundary is that history is not assumed valid merely because a buffer still contains numbers. Validity needs a policy, and confidence needs to be represented alongside the value it qualifies.
This is also why the renderer keeps feature gates visible. ReSTIR GI is a bounded diffuse-first prototype, and ReSTIR PT is a research scaffold with a conservative experimental path-reuse mode—not a production implementation of either name. Path guiding and radiance caching remain gated prototypes. A feature being present in the pass graph or registry means that its resources and execution shape are accounted for; it does not mean the feature is enabled by default or ready for every scene.
The cost of remembering
History consumes more than allocation size. It adds synchronization, bandwidth, invalidation work, debug complexity, and sometimes migration risk when a resource moves between CPU and GPU visibility. The registry's “hot-path memory” flag is a small reminder that a convenient persistent buffer can become part of every frame's critical path.
That cost is worth paying when history gives a feature a meaningful advantage, but it needs to be measured in context. A temporal pass can reduce noise and still hurt an interactive frame if its bookkeeping or readback path consumes too much budget. Conversely, a compact piece of state can be valuable precisely because it replaces more expensive repeated work. The graph and registry make those tradeoffs easier to discuss in concrete terms.
For me, the central lesson is simple: history is a rendering resource, not a magical extension of the current frame. It has an owner, a lifetime, a confidence level, and reasons to be invalidated. Once those properties are explicit, experimental transport features become easier to compare with the baseline, easier to debug, and safer to describe publicly.
The renderer is still an active experiment. The pass graph is not proof that every listed path is mature, and the registry is not a guarantee that every invalidation policy is complete. It is a commitment to keep the boundaries visible while the work evolves. In a real-time path tracer, knowing what the frame remembers is often as important as knowing how the frame samples.
Continue the series
Previous: Guiding and Caching Diffuse Indirect Light.