Open-Source Wikis

/

Godot

/

Systems

/

Servers and the multi-threaded wrapper

godotengine/godot

Servers and the multi-threaded wrapper

Purpose

servers/ collects the engine's thread-safe façades for heavyweight subsystems: rendering, physics (2D and 3D), audio, navigation (2D and 3D), display, text, and XR. Each server presents a public C++ API plus a WrapMT shim that funnels calls onto a dedicated thread when the engine runs in multi-threaded mode. This page describes the server pattern itself; one page per server covers the specifics.

Directory layout

servers/
├── audio/                 AudioServer mixer + AudioStream playback infrastructure
├── camera/                CameraServer (webcam capture, used for AR)
├── debugger/              ServersDebugger client (for the editor remote debugger)
├── display/               (display server lives in display_server.cpp at this level)
├── movie_writer/          Headless movie capture (--write-movie)
├── navigation_2d/         NavigationServer2D
├── navigation_3d/         NavigationServer3D
├── physics_2d/            PhysicsServer2D (default backend in modules/godot_physics_2d)
├── physics_3d/            PhysicsServer3D (default in modules/godot_physics_3d, alt in modules/jolt_physics)
├── rendering/             RenderingServer + Forward+/Mobile/Compatibility methods + RD layer
├── text/                  TextServerManager (active + secondary servers)
├── xr/                    XRServer + XRPose, XRController, XRTracker
├── register_server_types.cpp / .h     Registers all server classes with ClassDB
├── server_wrap_mt_common.h            Macro toolkit for generating WrapMT wrappers
├── nav_heap.h                         Shared heap used by 2D/3D navigation
├── audio_server.h / .cpp              Public AudioServer API (in audio/ as well)
├── physics_server_3d.h / .cpp         Public PhysicsServer3D
├── physics_server_2d.h / .cpp         Public PhysicsServer2D
├── rendering_server.h / .cpp          Public RenderingServer
├── display_server.h / .cpp            Public DisplayServer (impls live under platform/)
├── navigation_server_2d.h / .cpp
├── navigation_server_3d.h / .cpp
└── text_server.h / .cpp               TextServer interface + TextServerExtension hook

The server pattern

The constraints that drive the pattern:

  • GPU access must be single-threaded in many graphics APIs; the rendering thread is the only thread allowed to issue draw calls.
  • Engine code is single-threaded by default for sanity; nodes call into rendering, physics, and audio from the main thread.
  • Some subsystems run on their own threads (rendering and physics, in particular) for performance.

Solution: every server has

  1. A pure-virtual interface (e.g., RenderingServer).
  2. A "default" implementation that owns the actual state and runs on the server's thread (e.g., RenderingServerDefault for rendering, GodotNavigationServer3D from the navigation backend for navigation).
  3. A WrapMT wrapper generated by macros in servers/server_wrap_mt_common.h (or a hand-written RenderingServerWrapMT) that exposes the same API to callers but enqueues commands onto the server thread when running threaded, and forwards directly when running synchronously.
graph LR
    Caller[Main thread<br/>scene/editor/script] -->|API call| WrapMT["RenderingServerWrapMT /<br/>NavigationServer*WrapMT"]
    WrapMT -->|synchronous| Server[RenderingServerDefault<br/>(actual state)]
    WrapMT -->|deferred command| Queue[Command queue]
    Queue -->|on server thread| Server
    Server --> Driver[Driver: Vulkan / D3D12 / Metal / GLES3]

server_wrap_mt_common.h provides macros (FUNC0RC, FUNC1, FUNC2, FUNC3R, … with the suffix encoding "R" for "returns" and the digit being the parameter count) that expand to a switch between synchronous and queued execution. The header is ~29 KB of macro forwarding because servers expose dozens of methods.

RIDs as the lingua franca

Servers do not return raw pointers. They return RIDs — opaque 64-bit handles that the server can reverse-map to its internal state via RID_Owner<T>. Examples:

API RID points to
RenderingServer::texture_2d_create(image) a Texture in the renderer's internal table
RenderingServer::mesh_create() a Mesh storage
RenderingServer::canvas_item_create() a 2D draw command list
RenderingServer::instance_create() a 3D scene instance
PhysicsServer3D::body_create() a rigid body simulated by Godot Physics or Jolt
PhysicsServer3D::shape_create_box() a collision shape
AudioServer::bus_* audio bus indices (these are int, not RID, but follow the same pattern)
NavigationServer3D::map_create() a navigation map
NavigationServer3D::region_create() a region within a map

Because the data is owned by the server, RIDs survive across threads safely — the server lock-protects mutations, while clients only hold the handle. Many node types own one or more RIDs and forward setter calls to the server.

Initialization order

Servers come up in Main::setup2() in roughly this order:

  1. DisplayServer — created by the platform layer. Owns the window and the GL/Vulkan/D3D12/Metal context.
  2. RenderingServer — created with a backend selected by the rendering driver setting. Wrapped in RenderingServerWrapMT if rendering/driver/threads/thread_model = Multi-Threaded.
  3. AudioServer — picks an audio driver (ALSA, PulseAudio, WASAPI, CoreAudio, XAudio2, Web).
  4. PhysicsServer3D / PhysicsServer2D — chosen via physics/3d/physics_engine and physics/2d/physics_engine project settings; default to the built-in Godot Physics. Jolt 3D backends ship with the engine and can be selected.
  5. NavigationServer3D / NavigationServer2D — single backend.
  6. TextServer — set of TextServers managed by TextServerManager. Default is text_server_adv (HarfBuzz + ICU + FreeType); fallback text_server_fb if advanced features are not needed.
  7. XRServer — created unconditionally; XR interfaces (OpenXR, Mobile VR, WebXR) plug in later.

register_server_types.cpp performs the ClassDB registration of every server class, plus auxiliary types like XRPose, AudioEffect* and the RenderingDevice API surface.

Thread model nuances

  • Rendering: in multi-threaded mode, every RenderingServer call returns immediately. The server thread drains the command queue once per frame and flushes commands to the underlying driver; the engine waits at RenderingServer::sync() if the renderer is behind.
  • Physics: the physics simulation runs on its own thread when physics/common/physics_thread_model = Single-Threaded is overridden. Most simulation work happens during _physics_process.
  • Audio: drivers run their own callback thread (AudioDriver::*) and pull mixed buffers from AudioServer. Mixing happens inside AudioServer::_driver_process on that thread.
  • Worker threads: WorkerThreadPool (core/object/worker_thread_pool.cpp) is independent of the servers; it is used by resource loaders, navigation baking, and lightmappers.

RenderingDevice

RenderingDevice (servers/rendering/rendering_device.cpp, the largest file in servers/ at ~452 KB) is a vendor-neutral GPU API that sits below the RenderingServer. It is what the modern renderer_rd/ backends target, and is also exposed to scripting so users can write compute pipelines in GDScript/C# without dropping into shader source. It abstracts:

  • Buffers, textures, samplers, render targets, framebuffers.
  • Pipelines (graphics + compute), descriptor sets ("uniform sets"), push constants.
  • Render passes with Vulkan-like semantics.
  • Synchronization via RenderingDeviceGraph (rendering_device_graph.cpp, ~160 KB), which builds a DAG of GPU commands and schedules barriers automatically.

The drivers under drivers/vulkan, drivers/d3d12, and drivers/metal implement the RenderingDeviceDriver C++ interface to back this API. See Drivers.

Key abstractions

Abstraction File Role
RenderingServer servers/rendering_server.h Public rendering API
RenderingServerWrapMT servers/rendering_server_wrap_mt.h Threaded shim for the above
RenderingDevice servers/rendering/rendering_device.h Vendor-neutral GPU device
PhysicsServer3D / PhysicsServer2D servers/physics_server_3d.h, physics_server_2d.h Physics interfaces
AudioServer servers/audio_server.h Audio mixer + bus graph
DisplayServer servers/display_server.h Window + input from OS
TextServer, TextServerManager, TextServerExtension servers/text_server.h Text shaping/breaking
NavigationServer2D, NavigationServer3D servers/navigation_server_*.h Navigation maps and agents
XRServer, XRInterface, XRPose, XRController servers/xr_server.h, xr/*.h XR origin, tracker, camera plumbing
RID_Owner<T> core/templates/rid_owner.h Per-server RID-to-state mapping

Entry points for modification

  • Adding a new server method → declare on the public interface, add a FUNC* line in the WrapMT header, and implement on the default backend.
  • Swapping a backend → set the relevant project setting (rendering/renderer/rendering_method, physics/3d/physics_engine, audio/driver/driver, …) or pass the matching CLI flag.
  • Writing a new physics engine → see Physics servers; registration happens through PhysicsServer3DManager/PhysicsServer2DManager.
  • Writing a new text server → subclass TextServerExtension (or implement TextServer directly for a built-in module) and register it in register_module_types.

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Servers and the multi-threaded wrapper – Godot wiki | Factory