Rendering and presentation
What actually gets drawn, how many times, and who composites the result.
A headset frame is not a browser frame. Your scene is drawn once per view — two views for a stereo headset, sometimes more — into a framebuffer the runtime owns, at a cadence the runtime sets, and then a compositor you do not control decides what the user actually sees and when. Most performance surprises in WebXR come from not knowing where that boundary sits.
These three pages approach that boundary from different sides. Stereo rendering is what happens on your side of it: why each eye needs its own projection and view matrix, why the two are not simply offset copies, and what the cost of drawing everything twice does to a frame budget that was already tight. Layers is about giving work back across the boundary — handing the runtime a quad or a cylinder of content and letting the compositor place it, instead of texturing it onto geometry yourself. Foveated rendering is about paying less for the pixels you were never going to see clearly, and about the fact that the number you set is a request the runtime is free to reinterpret.
The through-line is that the compositor is not an implementation detail you can ignore. It reprojects late, it can be handed content at a different resolution than your main scene, and it is the reason text drawn into your 3D scene looks soft while the same text handed over as a layer stays sharp. Knowing which side of the line a problem lives on is most of solving it.
In this section
- Stereo renderingAn XR frame is not two renders of two scenes. It is one scene, culled once, drawn into several viewports of a single framebuffer — and the number of views is not always two.
- WebXR layersEverything you render goes through one downsampled framebuffer — unless you hand it to the compositor directly as a layer, in which case it is sampled once, at full resolution, after your frame is done.
- Foveated renderingA headset spends most of its pixels where you cannot see detail. Foveation is the runtime shading those pixels less, and letting you say how aggressively.
Read these in order
Stereo rendering first. It explains the per-view loop that layers is an optimisation of — the cost you are trying to avoid paying twice.
Layers second, because its value is only visible once you know what drawing into the main scene costs. Read the other way round and layers looks like an exotic API rather than the obvious answer to a problem you just measured.
Foveated rendering last, because it is the one that needs a measurement to be worth anything. It saves fragment shading, so on a frame that is limited by draw calls or by the CPU, turning it to maximum changes nothing at all.