Blog
Software Engineering
A Minimal 2D Rust Renderer for Safety-Critical Situation Displays

A Minimal 2D Rust Renderer for Safety-Critical Situation Displays.

Introduction

This post introduces Wilhelm Renderer, a 2D graphics engine designed specifically for building high-performance situation displays.

A situation display—commonly referred to as a radar display—is the primary screen located at the centre of an air traffic controller’s working position (see Figure 1, below). As its name suggests, the situation display is a critical tool for maintaining situational awareness, providing controllers with essential operational information such as aircraft identity, position, altitude, speed, and trajectory.

Wilhelm Renderer

Figure 1: An Air Traffic Control Monitoring a Situation Display (image source: HungaroControl)

Besides displaying aircraft positions, modern situation displays also present a wide range of supplementary information, including overlay maps showing waypoints, airways, obstacles, and weather activity (see Figure 2, below). In addition to these core visualization capabilities, advanced tools such as conflict detection and trajectory prediction are often integrated into the display system.

Wilhelm Renderer

Figure 2: A Situation Display Prototype built with Wilhelm Renderer (click to enlarge)

Graphics Rendering for Situation Displays

Given the operational requirements of modern situation displays, the underlying graphics engine must be capable of rendering a large number of graphical elements while maintaining a high level of responsiveness and visual smoothness. Some of the key requirements include:

  • Stable frame rate: Rendering performance should consistently remain at 60 FPS or higher.
  • Low display latency: Aircraft track updates and visual changes must appear without noticeable lag.
  • Low input latency: User interactions such as panning and zooming should feel immediate and responsive.
  • High rendering capacity: The engine should be capable of rendering thousands of graphical objects simultaneously without performance degradation.

Wilhelm Renderer

Wilhelm Renderer is a high-performance 2D graphics engine designed specifically for building modern situation displays. The engine focuses on delivering low-latency rendering, high responsiveness, and the ability to efficiently render large volumes of graphical data in real time.

Built with performance and scalability in mind, Wilhelm Renderer is intended for applications that require smooth visualization of continuously updating data, such as radar tracks, overlay maps, trajectories, and other operational graphics commonly found in air traffic management systems.

At its core, Wilhelm Renderer provides a set of fundamental 2D graphics primitives used to construct the various elements displayed within a situation display. The API exposes standard primitives including points, lines, polylines, arcs, and polygons, while relying on OpenGL as the underlying rendering technology. The table shown next illustrates how the 2D rendering primitives exposed by Wilhelm Renderer map to common graphical elements found in situation displays:

Wilhelm Renderer PrimitiveSituation Display Element
PointHistory dots (past aircraft positions)
LineSpeed vectors, Leader lines, measurement tools
PolylineAirways, country borders
PolygonAirspace sectors, Restricted Areas, Danger Areas, AoR
ArcHolding racetracks
TextAircraft labels, Flight levels, sector names, etc.
Image

Figure 2 in the previous section also illustrates several of the graphics primitives described above within a situation display.

OpenGL-Based Graphics

Using OpenGL makes it possible to leverage hardware-accelerated graphics rendering while maintaining portability across all major operating systems. Although the OpenGL API itself is relatively low-level and primarily centered around concepts such as vertex buffers and shaders, Wilhelm Renderer exposes a significantly higher-level API designed to be used directly by client applications.

By combining the primitives mentioned above, a client application such as a situation display can efficiently render radar tracks, labels, trajectories, overlay maps, weather layers, and other operational graphics commonly found in air traffic management systems.

Written in Rust

Wilhelm Renderer is written in Rust in order to achieve the stability and reliability required by safety-critical systems such as situation displays. The Rust programming language provides several advantages for implementing this type of software:

  • Memory safety: Rust enforces memory safety and prevents common programming errors such as buffer overflows, memory leaks, and dangling pointer dereferences through a compile-time mechanism known as the borrow checker.

  • Concurrency and thread safety: Situation displays are highly concurrent systems in which events must be processed asynchronously from the actual rendering of the display. Rust provides powerful abstractions for writing safe concurrent code while preventing common concurrency issues such as race conditions and data corruption.

  • Deterministic resource management: Rust provides fine-grained control over the lifetime of memory and graphics resources. In practice, this enables precise management of the allocation and cleanup of GPU resources such as buffers, shaders, textures, and other OpenGL handles. Furthermore, unlike garbage-collected languages, Rust does not introduce unpredictable GC pauses that could negatively impact rendering smoothness or input responsiveness.

  • Qualified toolchain: An important aspect of developing safety-critical software is ensuring that the compiler used to generate the final executable produces the expected and verifiable artefact. This assurance is typically achieved by relying on a qualified compiler toolchain. As Rust continues to gain traction within the safety-critical software industry, qualified toolchains for Rust are also becoming increasingly available.

Layered Architecture

Wilhelm Renderer is designed around a layered architecture depicted next.

Wilhelm Renderer

At the base level, the renderer relies on the native OpenGL system libraries for hardware-accelerated rendering. Built on top of the OpenGL libraries, the wilhelm_renderer_sys crate encapsulates the GLFW library for window management and the FreeType library for text rendering. Both libraries are statically linked and packaged as part of wilhelm_renderer_sys.

The advantage of statically linking these libraries is that it provides a self-contained crate without relying on platform-specific dependencies. The low-level wilhelm_renderer_sys system crate also provides the bulk of the FFI bindings. This includes bindings to the OpenGL rendering APIs, GLFW window management APIs, and additional operating system abstractions used to isolate the renderer from platform-specific APIs.

Built on top of wilhelm_renderer_sys, the wilhelm_renderer crate exposes the high-level, memory-safe APIs used to render the various 2D graphics primitives provided by the engine. Additional integration layers, such as wilhelm_renderer_imgui, provide bindings for immediate-mode UI elements such as menus and buttons while remaining isolated from the core rendering APIs.

Separating the renderer into distinct crates improves the testability of the low-level FFI bindings while helping to ensure the stability of the high-level APIs. This design follows a common Rust idiom in which low-level native bindings are isolated within a dedicated *_sys crate, while higher-level crates expose safe and ergonomic abstractions built on top of those bindings.

Wilhelm Renderer in Action

Finally, the short video below illustrates a situation display prototype built with Wilhelm Renderer using many of the primitives and rendering techniques described throughout this article.


SkyGuard prototype (use video controls for fullscreen)

Source Repository

Wilhelm Renderer is open source and available on GitHub:

algonents/wilhelm_renderer