Build Log

What exactly is Deferred+? Poking at URP's newest rendering path

  • Unity
  • URP
  • Deferred+
  • Rendering
  • Graphics
  • Game Development

For three months, my rendering sandbox contained a set of pipeline assets named Deffered. The typo sat in a public repo through the winter until an April commit finally renamed them — which tells you both how often I look at my own asset names and how new this rendering path still feels to me. The misspelled assets belong to a small comparison rig for URP’s four rendering paths, and the newest of the four is what this post is about.

https://github.com/tang3cko/Sandbox_001

The four paths, quickly

Unity 6.1 added Deferred+ as a supported rendering path in URP, joining Forward, Forward+, and Deferred. The names are similar enough that I had to write the differences down to keep them straight.

Forward shades each object in one pass with the lights that affect it, and caps how many lights an object can receive. Cross that per-object limit and lights silently stop contributing — the classic “my fifth point light does nothing” surprise.

Forward+ replaces the per-object light list with clustered culling: the view is sliced into 3D cells, each cell gets its own light list, and a pixel only evaluates the lights in its cell. The per-object limit disappears; what remains is a per-camera cap on visible lights.

Deferred changes when shading happens rather than how lights are culled. Geometry is rendered once into a G-buffer (albedo, normals, material data), and lighting runs afterwards as a screen-space pass — so the cost scales with screen pixels and lights, not with object count times lights. The catch list is real, though: transparent objects can’t be deferred, and in classic Deferred they fall back to plain Forward, per-object light limits included.

Deferred+ is the combination of the previous two ideas. The official manual puts it in one sentence:

The Deferred+ rendering path, like the Deferred rendering path, has no limit on the number of lights that can affect an opaque GameObject, but uses Forward+ instead of Forward for the transparent and forward only opaque pass.

So opaques get deferred shading off the G-buffer, and everything that can’t go through the G-buffer — transparents, forward-only materials — gets Forward+‘s clustered culling instead of vanilla Forward. The weakest link in classic Deferred gets upgraded, and light culling becomes cluster-based across the board. The light budget follows Forward+‘s per-camera model.

On paper that makes Deferred+ the “many dynamic lights, and I also have transparents” path. Whether the paper holds is what the sandbox rig is for.

The rig — four URP assets and a switcher

The comparison corner of my sandbox is built around runtime switching, because alt-tabbing through Project Settings between runs is exactly the kind of friction that makes me not do the comparison at all.

The setup is four URP asset pairs — one pipeline asset plus one renderer asset per mode, with the renderer asset’s rendering mode set to Forward, Forward+, Deferred, or Deferred+ — and a RenderPipelineSwitcher component that swaps them at runtime:

currentIndex = index;
GraphicsSettings.defaultRenderPipeline = config.asset;
QualitySettings.renderPipeline = config.asset;

The two-line assignment is deliberate. QualitySettings.renderPipeline overrides GraphicsSettings.defaultRenderPipeline when set, so swapping only the graphics-settings one does nothing if the active quality level carries its own pipeline asset. I set both and stopped wondering. The component also remembers the original asset and restores it in OnDestroy, so leaving Play Mode doesn’t leave the project stuck on whatever mode I tested last.

On top of that sits a LightSpawner that scatters point lights into the scene — 10 on start, up to 200, optionally animated to keep the culling honest — and a UI Toolkit HUD showing FPS, draw calls, batches, and SetPass calls. One key cycles the rendering mode, number keys jump straight to a path, arrow keys add and remove lights. The whole point is that a comparison takes seconds: spawn 150 animated lights, hit the number keys, watch the stats panel.

What I can and can’t tell you yet

What the rig already makes obvious is the qualitative part. Walking the light count up under Forward shows lights dropping out per object as limits hit; the same scene under the clustered paths just keeps accepting lights. Switching between Deferred and Deferred+ looks like the upgrade the docs describe — same G-buffer story for opaques, different story for everything that falls back — though with only a couple of transparent test materials in view, “looks like” is as far as I’ll go.

What I can’t give you yet is numbers. The stats HUD shows live values but I haven’t recorded structured comparisons, and a sandbox scene with primitive geometry is not a representative workload anyway — the README’s own future-work list starts with profiler integration, a transparent-object stress test, and per-path shadow cost. Until that happens, my performance opinion of Deferred+ is “the design makes sense”, which is an opinion about the design, not a measurement.

One more honest note: Deferred+ also advertises compatibility with the GPU Resident Drawer in the Unity 6.1 release notes, and this rig doesn’t exercise that at all. Primitive walls and capsules don’t have enough instances for it to matter.

Things still bugging me

  • No recorded numbers, as above. The rig can show them; I haven’t captured them.
  • The scene is all opaque primitives plus a few test materials — the transparent stress test that would actually showcase the Deferred vs Deferred+ difference isn’t built yet.
  • Runtime URP-asset swapping causes a visible hitch on switch. Fine for a test rig, but I haven’t dug into what exactly gets rebuilt.

Wrap-up

The reason this corner of the sandbox exists is that rendering path names had quietly become a four-option multiple-choice question I couldn’t answer from memory — and apparently couldn’t spell, either. Now the answer lives in a scene I can open: each path is one keypress, and the differences are something I can see rather than recite.

Next visit to this subproject is the measurement pass. Until then, Deferred+ has earned a spot as the default candidate for any future project of mine with serious dynamic light counts — pending numbers.

https://github.com/tang3cko/Sandbox_001

References