Rendering architecture: frame path and subsystems
Entities, resources, RenderingServer, drivers, buffers, extensions and source-based diagnosis.
This page maps the rendering data path in Reckfell 1.0.0 and helps locate a problem or extension point. The architecture was reviewed against current source. Execution evidence covers separate Windows/Vulkan Forward+ and Mobile scenarios, not every effect, driver or image-quality setting.
From Entity to frame
Entity / Resource
|
RenderingServer / RID
|
RendererSceneCull + RendererCanvasCull + RendererViewport
|
+-- Forward+ / Mobile --> RenderingDevice --> graphics driver --> GPU
|
+-- Compatibility ------> GLES3 renderer --> OpenGL driver --> GPUMeshInstance3D uses Mesh and material resources. VisualInstance3D creates a server instance, assigns its base resource and updates transforms through RenderingServer. Multiple Entities can share one Mesh; instance placement and resource geometry are separate data. Entity count is not draw-call count: surfaces, materials, passes and shadows affect rendering work.
RenderingServer provides resource and rendering operations through RID. RendererSceneCull prepares the visible 3D scene, RendererCanvasCull handles canvas, and RendererViewport organizes camera and target-texture output. Direct server-resource use is possible, but its setup and lifetime become the caller’s responsibility.
RenderingDevice is lower level: textures, buffers, shaders, pipelines, uniform sets and draw/compute command lists. It does not automatically supply Material, camera, collision or visibility policy. Its command graph handles GPU-work dependencies; gameplay hierarchy remains in EntityTree.
Rendering method and driver
| Method | Server implementation | Graphics path |
|---|---|---|
| forward_plus | RenderForwardClustered | RenderingDevice |
| mobile | RenderForwardMobile | RenderingDevice |
| gl_compatibility | GLES3 | OpenGL family |
| dummy | Diagnostic path without normal GPU output | Does not establish GPU rendering |
The method organizes rendering; the driver implements a graphics API. Startup code lists Vulkan, Direct3D 12 and Metal for Forward+/Mobile under corresponding build flags. Compatibility lists opengl3/opengl3_angle/opengl3_es. Driver source does not establish inclusion in a particular distribution or validation on your platform.
Record RenderingServer.GetCurrentRenderingMethod(), RenderingServer.GetCurrentRenderingDriverName(), GPU model and startup log together. The rendering/renderer/rendering_method setting alone is insufficient to diagnose every fallback. For example, RendererCompositorRD contains a clustered-to-Mobile fallback below 48 textures per shader stage; this is a source condition, not a test of such a GPU here.
Forward+ uses ClusterBuilderRD to prepare clustered data used for lighting. Mobile has separate pass and buffer organization; sharing RenderingDevice does not make feature sets identical. Compatibility has a separate GLES3 implementation. Choose using required features and target-scene measurements: the Mobile name alone guarantees no speed, nor Forward+ a finished high-quality image.
During drawing
RenderingServerDefault::_draw exposes these major steps:
- Begin frame and prepare XR when enabled.
- Update scene/canvas and particle data.
- Prepare reflection probes.
- Draw viewports.
- Finish frame and dispatch visibility notifications.
Inside the 3D path RendererSceneCull prepares camera, visible instances and related light, GI, decal, lightmap and fog data. The selected implementation then receives render_scene. Actual GPU-pass order depends on the method and enabled features; the list above is not a fixed render-pass sequence.
Viewport determines target size, camera and output configuration. RenderSceneBuffersRD holds intermediate RD textures and pass data. Size, view count, MSAA and formats affect memory and reading availability. Do not assume every effect always receives identical color/depth textures or that private internal buffer names are public SDK contracts.
Visible is only one participation condition: camera, layers, distance, culling and resource readiness also matter. For a missing object, check the route to the intended viewport before material/geometry, rather than starting with a driver change.
Project shaders and engine shaders
Shader sends prepared code through RenderingServer.shader_set_code. Material passes parameters and resource references; BaseMaterial3D generates code from its enabled features. A parameter change and a material-feature change can therefore have different preparation costs.
Internal RD/GLES3 shaders implement rendering stages. Their sources and generated headers are part of the engine build. Editing such a GLSL file in the repository does not change an already installed binary; applying the change requires the corresponding build. Project shaders use a different storage/compilation route. For an application effect start with the shading language, before changing a shared engine material shader.
First use of a new variant can include shader/pipeline preparation. This is a different source of delay from steady per-frame cost. Measure first use and the settled scene separately; this page establishes neither duration on your device.
Subsystem map
Paths below are relative to the local Source tree. They navigate source; they are not downloadable archives.
| Task | Start with |
|---|---|
| Mesh instance and server RID | scene/3d/mesh_instance_3d.cpp; scene/3d/visual_instance_3d.cpp |
| Frame update/dispatch | servers/rendering/rendering_server_default.cpp |
| Camera, visibility and scene data | servers/rendering/renderer_scene_cull.cpp |
| Viewport and canvas | servers/rendering/renderer_viewport.cpp; renderer_canvas_cull.cpp in the same directory |
| RD implementation selection | servers/rendering/renderer_rd/renderer_compositor_rd.cpp |
| Forward+ and clustering | servers/rendering/renderer_rd/forward_clustered/; cluster_builder_rd.cpp |
| Mobile | servers/rendering/renderer_rd/forward_mobile/ |
| Compatibility | drivers/gles3/ |
| Scene GPU buffers | servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp |
| GI, sky and volumetric fog | servers/rendering/renderer_rd/environment/gi.cpp, sky.cpp, fog.cpp |
| TAA, FSR2, DOF, screen-space effects | servers/rendering/renderer_rd/effects/ |
| Low-level GPU API | servers/rendering/rendering_device.cpp and rendering_device.h |
| CPU occlusion culling | modules/raycast/raycast_occlusion_cull.cpp |
| Import-time LOD generation | scene/resources/3d/importer_mesh.cpp |
An effect module does not establish support in every method. Use the feature guide for settings and limitations: volumetric fog, VRS. Import-time mesh LOD generation, camera LOD selection and occlusion rejection solve different tasks; distinguish them when investigating disappearing geometry.
Extending through Compositor
CompositorEffect receives RenderData at its selected rendering stage. This route exposes prepared scene buffers and requires the right stage, format, dimensions and lifetime.
| Method | Observed stages |
|---|---|
| Forward+ | PreOpaque, PostOpaque, PostSky, PreTransparent, PostTransparent |
| Mobile | PreOpaque, PreTransparent, PostTransparent |
In the retained Mobile run PostOpaque produced a warning and PostSky was not called. An enum value alone does not make an effect portable between methods. Camera.Compositor replaces the world compositor; even an empty camera compositor overrides the world list. This behavior was executed in the engine.
PostTransparent in the checked RD path precedes postprocessing and tonemap. Do not assume it is the final displayed image. Read buffers and RenderData inside the callback; do not keep borrowed frame data as long-lived resources. Contracts and example: CompositorEffect.
Threads, RID and GPU readback
RenderingServerDefault has a command queue and an optional separate render thread. A CPU call and completed GPU work are different events. Use the appropriate render-thread context for main RenderingDevice operations, such as a CompositorEffect callback; check scene-tree thread contracts before moving scene operations there.
GetRenderingDevice returns the engine’s shared device. CreateLocalRenderingDevice requires an available main RD and creates a separate device; it does not supply a missing RD in Compatibility. RIDs belong to the subsystem/device that created them. RenderingServer.FreeRid and RenderingDevice.FreeRid are not interchangeable. Do not free borrowed viewport-buffer RIDs as owned resources.
Rid.IsValid checks a nonzero identifier rather than resource existence in an owner. Freeing a resource does not automatically zero saved RID copies. Maintain explicit ownership, especially when releasing callback resources.
Synchronous RD texture_get_data can force pending GPU work to complete. Measure before adding continuous CPU image readback to the ordinary frame path; texture-content inspection and an efficient effect are different scenarios.
Symptom-based diagnosis
| Symptom | First check |
|---|---|
| Effect works in one method only | Actual method/driver, callback stage and required buffers |
| Black or incorrect custom-pass result | Format/usage/dimensions, MSAA/view count, dependencies and stage relative to tonemap |
| Brief first-material delay | New shader/pipeline preparation; compare repeated use |
| Continuously low FPS | Separate CPU/GPU frame time, surfaces/passes, shadows and resolution |
| Disappearing object | Camera/viewport, layers, visibility range, culling and mesh LOD |
| RID error or missing resource | Owner, device, lifetime and release; IsValid is insufficient |
| Headless check passes | Establish whether it used a real GPU renderer; dummy does not prove this |
Verification coverage
Forty earlier Windows/Vulkan Forward+/Mobile observations were reused: Compositor stages, camera override, color/depth/view-count access and VRS attachment allocation. Runtime, SDK and test assets were checked again; GPU scenes were not rerun. Identity verification includes launching console --version.
Original reports retain a Vulkan-loader warning and an unsupported Mobile-stage warning. Their negative status was not changed to positive. They establish bounded scenarios and structure, not acceptance of the whole renderer. D3D12, Metal, Compatibility, GI/TAA/DOF quality, FPS, MSAA, stereo, export and visual quality were not checked by this page. Engine code, SDK and installed Runtime were unchanged.