Frame execution
A frame updates retained renderer state, produces commands for selected viewports, and submits the resulting GPU work. Server synchronization, command recording, GPU execution, and presentation occur at different points.
Main loop decision
The main loop calls RenderingServer::sync() before scheduling rendering. It considers
whether the display can draw, whether there are additional outputs, whether the render
loop is enabled, and whether RD has pending resource processing. Low-processor-usage
mode also consults has_changed(). An engine iteration does not imply an unconditional
presented frame.
RenderingServerDefault::draw() requires the main thread. It emits frame_pre_draw,
resets its change counter, and either queues _draw() or calls it directly. A queued
draw can outlive the return from draw().
Server frame order
RenderingServerDefault::_draw() performs these operations in order:
- Call the compositor's
begin_frame()and start timestamps. - Call XR
pre_render()when XR exists. - Update the scene culler, then the canvas culler.
- Update particles after scene instances and collision inputs.
- Render probes.
- Call
RendererViewport::draw_viewports(). - Update the canvas renderer, then call compositor
end_frame(). - Call XR
end_frame()and update visibility notifiers. - Arrange frame callbacks and collect profiling/memory information.
RendererSceneCull::update() also updates dirty instances/resources and renders
particle colliders. Moving particle simulation earlier can consume stale collider or
transform data.
Viewport execution
RendererViewport evaluates update modes, sizes, output attachments, and XR requirements. It sorts active outputs and records texture-use relationships. Each selected viewport combines 3D and canvas work according to its environment/background settings. The viewport's scene renderer chooses its own pass structure.
For RD outputs, screen blits are collected by window and issued through the compositor
when presentation is requested. For OpenGL, context switching and gl_end_frame()
happen at the viewport/window integration points. Do not move all GL buffer swaps to the
RD frame boundary.
Submit and retire
The RD compositor's end_frame() calls RenderingDevice::swap_buffers(). RD closes
command recording, flushes the command graph, submits queues, optionally presents,
advances the frame slot, and begins recording again. Reusing a frame slot waits for the
relevant GPU completion and retires its deferred resource deletions.
Frame callbacks are CPU-side notifications. On the separate-render-thread path,
_run_post_draw_steps() is deferred. A callback or frame_post_draw signal is not a
general promise that arbitrary GPU readback has completed. Use the resource/device
operation's synchronization contract for that work.
Sources: server frame and main loop, viewports, and device submission.