Godot Server System Architecture: How DisplayServer, RenderingServer, and PhysicsServer Work
Godot’s engine core isolates platform-specific logic, GPU rendering, and physics simulation into three singleton server subsystems—DisplayServer, RenderingServer, and PhysicsServer—that communicate through an abstract RID-based API.
The godotengine/godot repository implements a modular server architecture that separates the engine’s high-level game logic from low-level platform dependencies. This design allows Godot to run on Windows, Linux, macOS, Web, and mobile platforms while maintaining a consistent API for window management, GPU resource allocation, and physics simulation.
Core Design Principles of Godot's Server Architecture
Godot’s server system relies on three architectural patterns that ensure cross-platform compatibility and backend flexibility.
Singleton Pattern and Global Access
Each server maintains a single global instance accessible via get_singleton(). In servers/display/display_server.h, the DisplayServer declares:
static DisplayServer *get_singleton() { return singleton; }
This pattern allows any engine module—from the main loop to editor plugins—to query window dimensions, submit input events, or create GPU resources without passing server pointers through every function call.
The RID Resource System
All server-managed objects—textures, meshes, physics bodies, and spaces—are referenced through opaque Resource IDs (RIDs) rather than raw pointers. This abstraction, defined in core/templates/rid.h, enables:
- Backend swapping: The core engine holds an
RIDwithout knowing whether the underlying texture is a Vulkan image or an OpenGL handle. - Memory safety: Servers track object lifetimes internally; calling
free_rid()on any server invalidates the resource across all references.
Abstract Interfaces with Backend Registration
Each server defines a pure virtual base class that concrete backends implement. Backends register themselves via static factory functions:
- DisplayServer:
DisplayServer::register_create_function(name, create_fn, get_rendering_drivers)inservers/display/display_server.h - RenderingServer:
RenderingServer::register_create_functioninservers/rendering/rendering_server.h - PhysicsServer3D:
PhysicsServer3DManager::register_serverinservers/physics_3d/physics_server_3d.h
At engine initialization, the appropriate backend is selected based on platform detection or project settings.
DisplayServer: Managing Windows and Input
The DisplayServer handles all platform-specific windowing, input devices, and display management. Defined in servers/display/display_server.h, it abstracts operations like window creation, mouse capture, clipboard access, and virtual keyboard handling.
Platform Implementations
Each supported platform provides a concrete implementation:
- Windows:
platform/windows/display_server_windows.cppimplements Win32 window management and OpenGL/Vulkan context creation. - Linux (X11):
platform/linuxbsd/x11/display_server_x11.cpphandles X11 windows and input events. - Linux (Wayland):
platform/linuxbsd/wayland/display_server_wayland.cppmanages Wayland surfaces. - Web:
platform/web/display_server_web.cppintegrates with HTML5 Canvas and forwards JavaScript events. - Headless:
servers/display/display_server_headless.cppprovides a no-window mode for server-side rendering and CI testing.
Creating a Window via DisplayServer
// Obtain the global DisplayServer singleton
DisplayServer *ds = DisplayServer::get_singleton();
// Create a sub-window with specific dimensions
DisplayServer::WindowID win_id = ds->create_sub_window(
DisplayServer::WINDOW_MODE_WINDOWED,
DisplayServer::VSYNC_ENABLED,
0, // no special flags
Rect2i(Point2i(100, 100), Size2i(800, 600)),
false, // not exclusive
DisplayServer::MAIN_WINDOW_ID // parent = main window
);
// Show the window and set its title
ds->show_window(win_id);
ds->window_set_title("My Godot Window", win_id);
Source: [servers/display/display_server.h](https://github.com/godotengine/godot/blob/master/servers/display/display_server.h)
RenderingServer: GPU Resource Management
The RenderingServer manages all GPU-related resources including textures, meshes, materials, lights, viewports, and post-processing effects. Defined in servers/rendering/rendering_server.h, it provides a high-level API that abstracts the underlying graphics API (Vulkan, OpenGL, or software rasterizers).
Default Implementation Architecture
The concrete implementation RenderingServerDefault in servers/rendering/rendering_server_default.cpp translates high-level rendering commands into low-level GPU operations through the RenderingDevice abstraction (servers/rendering/rendering_device.h). This separation allows Godot to support multiple graphics APIs without changing the scene system.
Resource Creation Flow
- Engine startup registers the default backend via
RenderingServer::register_create_function("default", RenderingServerDefault::create, ...). - When the engine initializes rendering,
RenderingServer::create(...)instantiates the concrete server. - Scene nodes call
RenderingServer::get_singleton()to allocate resources, receiving anRIDfor each texture, mesh, or material.
Uploading a Texture via RenderingServer
RenderingServer *rs = RenderingServer::get_singleton();
// Create a 2D texture from an Image resource
RID texture = rs->texture_2d_create(image);
// Create a material and assign the texture
RID material = rs->material_create();
rs->material_set_shader(material, my_shader_rid);
rs->material_set_texture(material, "albedo_texture", texture);
// The material RID can now be assigned to mesh surfaces
Source: [servers/rendering/rendering_server.h](https://github.com/godotengine/godot/blob/master/servers/rendering/rendering_server.h)
PhysicsServer: Collision and Simulation
The PhysicsServer handles collision detection, rigid body simulation, and spatial queries. Godot provides separate servers for 2D and 3D physics, with PhysicsServer3D defined in servers/physics_3d/physics_server_3d.h and PhysicsServer2D following a similar pattern.
Backend Management
The PhysicsServer3DManager class maintains a registry of available physics backends. The default implementation is selected via PhysicsServer3DManager::new_default_server(), which instantiates the concrete physics engine (Godot’s internal solver, Bullet, or Jolt).
Query Flow for Raycasting
- Create a physics space using
PhysicsServer3D::space_create(). - Add bodies and shapes to the space.
- Construct a
PhysicsRayQueryParameters3Dobject defining the ray origin, direction, collision mask, and exclusions. - Obtain the direct state via
PhysicsServer3D::space_get_direct_state(space). - Call
PhysicsDirectSpaceState3D::intersect_ray(...)to retrieve collision results including the collider RID, position, and normal.
Performing a Raycast via PhysicsServer
# Create a new physics space
var space = PhysicsServer3D.space_create()
var direct_state = PhysicsServer3D.space_get_direct_state(space)
# Configure ray query parameters
var query = PhysicsRayQueryParameters3D.create(
Vector3(0, 5, 0), # from
Vector3(0, -5, 0), # to
0xFFFFFFFF, # collision mask
[] # exclude array
)
# Execute the raycast
var result = PhysicsDirectSpaceState3D.new()
if direct_state.intersect_ray(query.get_parameters(), result):
print("Hit collider RID:", result.collider)
print("Collision point:", result.position)
print("Surface normal:", result.normal)
Source: [servers/physics_3d/physics_server_3d.h](https://github.com/godotengine/godot/blob/master/servers/physics_3d/physics_server_3d.h)
How the Servers Interact
While each server operates independently, they coordinate through the engine’s main loop and scene system:
- DisplayServer provides the window surface and input events that drive the rendering and gameplay loops.
- RenderingServer receives viewport dimensions from the DisplayServer and outputs frames to the window surface.
- PhysicsServer runs on its own thread (or the main thread depending on configuration) and synchronizes transform data with the scene nodes each frame.
All communication uses the RID system, ensuring that the high-level scene system remains agnostic to whether the underlying physics engine is Bullet or Jolt, or whether the renderer uses Vulkan or OpenGL.
Summary
Godot’s server system architecture separates platform-specific, rendering, and physics concerns into three singleton subsystems:
- DisplayServer abstracts window management and input across platforms via concrete implementations like
DisplayServerX11andDisplayServerWindows. - RenderingServer manages GPU resources through an RID-based API, with
RenderingServerDefaulttranslating high-level commands to theRenderingDeviceabstraction. - PhysicsServer provides collision and simulation APIs for both 2D and 3D, allowing backend swapping via
PhysicsServer3DManagerwithout changing game logic.
This architecture enables Godot to maintain cross-platform compatibility, support multiple rendering APIs, and swap physics engines while keeping the core engine code clean and platform-agnostic.
Frequently Asked Questions
What is the purpose of the RID system in Godot's servers?
The RID (Resource ID) system provides an opaque handle to server-managed resources like textures, meshes, and physics bodies. By using RID instead of raw pointers, Godot keeps the high-level engine code decoupled from specific backend implementations, allowing resources to be created, shared, and freed safely across different rendering APIs and physics engines without exposing internal memory structures.
How does Godot choose which DisplayServer backend to use?
Godot selects the DisplayServer backend during engine initialization based on the target platform. Each platform implementation—such as DisplayServerWindows for Windows or DisplayServerX11 for Linux—registers itself via DisplayServer::register_create_function(). The engine then detects the current platform and invokes the appropriate creation function, instantiating the concrete backend that handles window creation, input polling, and display management for that specific operating system.
Can I use PhysicsServer directly in GDScript for custom collision queries?
Yes, the PhysicsServer API is fully exposed to GDScript, allowing you to perform low-level physics operations without using high-level nodes. You can create physics spaces, add bodies and shapes, and execute queries like raycasts using PhysicsServer3D.space_create(), PhysicsServer3D.body_create(), and PhysicsDirectSpaceState3D.intersect_ray(). This approach is useful for server-authoritative multiplayer games or procedural collision detection that bypasses the scene tree overhead.
What is the difference between RenderingServer and RenderingDevice?
The RenderingServer is the high-level API that the engine uses to create and manage visual resources like textures, materials, and meshes. It operates with abstract concepts such as "texture" and "mesh" using the RID system. The RenderingDevice is the low-level abstraction that the RenderingServer uses to execute actual GPU commands. It handles specific graphics API implementations like Vulkan or OpenGL, managing command buffers, pipelines, and memory allocation. In essence, RenderingServer provides the "what" (create a texture) while RenderingDevice handles the "how" (allocate Vulkan image memory).
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →