Westeros is a lightweight Wayland compositor library that enables applications to create one or more Wayland displays. It is designed to be compatible with applications built for standard Wayland compositors and is structured as a library rather than a standalone application, allowing it to be embedded inside a host process. It supports three compositor modes: a normal compositor that renders its composited output directly to the screen, a nested compositor that connects to another compositor as a client and renders onto a surface of that parent compositor, and an embedded compositor whose composited output is driven by the hosting application through explicit calls. This flexibility allows Westeros to act as the top-level display server on a device, as an intermediary layer in a compositor chain, or as an off-screen compositor integrated into an application's rendering pipeline.

At the device level, Westeros provides a Wayland display endpoint that UI frameworks, media players, and other application runtimes connect to as Wayland clients. At the module level, it exposes a C API for creating, configuring, and starting compositor instances, a pluggable renderer interface that allows vendor-specific rendering backends to be loaded at runtime, and a set of Wayland protocol extensions — Simple Shell, VPC, linux-dmabuf, and explicit sync — that provide surface management and video path control beyond the base Wayland protocol.

```mermaid
flowchart LR

classDef Apps stroke:#00B9F1,fill:#E6F7FD,stroke-width:2px
classDef RDKMW stroke:#75D701,fill:#F1FFE6,stroke-width:2px
classDef VL stroke:#808080,fill:#F2F2F2,stroke-width:2px

    subgraph Apps["Apps and Runtimes"]
        RDKUI["UI"]
        FBApps["Firebolt Apps"]
        WPE_RT["WPE Runtime"]
    end

    subgraph RDKMW_SUB["RDK Core Middleware"]
        AM["App Manager"]
        Rialto["Rialto"]
        Westeros["Westeros Wayland Compositor"]
        Thunder["WPEFramework Thunder"]
    end

    subgraph VL_SUB["Vendor Layer"]
        SOCHAL["westeros-soc SOC Render HAL"]
        BSP["BSP"]
        DRM["DRM EGL Libraries"]
    end

    RDKUI -->|Wayland Protocol| Westeros
    FBApps -->|Wayland Protocol| Westeros
    WPE_RT -->|Wayland Protocol| Westeros
    Westeros -->|Renderer Module API| SOCHAL
```

Key Features & Responsibilities:


Design

Westeros is designed around a library model where the compositor runs inside the host process. The compositor context (WstContext) holds all shared state and runs a dedicated compositor thread that owns the Wayland display event loop, client connections, and frame generation. The public WstCompositor handle is the per-instance API object and decouples the calling thread from the compositor thread, with a 64-entry event queue (WstEvent) bridging input events from the application thread to the compositor thread. A recursive pthread mutex (ctx->mutex) serializes access to shared context state between the caller and the compositor thread.

The three compositor modes — normal, nested, and embedded — are controlled by flags set before WstCompositorStart is called. In nested mode, a WstNestedConnection is established on a separate thread to maintain the connection to the parent Wayland display, receiving output geometry, keyboard map, and VPC events from the parent and forwarding them into the local compositor event flow. In embedded mode, composition is triggered only when the hosting application calls WstCompositorComposeEmbedded, and both that call and WstCompositorStart must be issued from the same thread. Normal mode drives composition from a timer event source on the compositor thread at the configured frame rate.

Rendering is fully decoupled through the WstRenderer interface: the compositor calls renderer_init in the loaded module to populate a function table, then calls surfaceCreate, surfaceCommit, updateScene, and related methods for each frame. This separation means the compositor core has no dependency on any specific GPU API; EGL and GLES2 are engaged only when a GL-based renderer module is loaded. Buffer sharing between clients and the renderer is handled through wl_shm, wl_sb, zwp_linux_dmabuf_v1, or EGL Wayland buffer extensions, depending on which protocols are enabled at build time.

Northbound interaction with hosted clients is via the Wayland socket protocol: clients connect, bind globals, create surfaces, attach buffers, and commit. The hosting application also controls embedded instances through the C API, while southbound interaction is through the renderer module's function table.

For non-nested starts, the keyboard map is initialized from libxkbcommon using the evdev rule set and the us layout by default; nested instances receive the parent compositor's keymap.

```mermaid
graph TD
    subgraph WesterosProcess["Westeros Process"]
        subgraph PublicAPI["Public API Layer"]
            WstComp["WstCompositor API Handle"]
        end

        subgraph CoreContext["Compositor Context WstContext"]
            CompThread["Compositor Thread wstCompositorThread"]
            EventQ["Event Queue 64 entries"]
            SurfaceMap["Surface Map surfaceId to WstSurface"]
            Seat["WstSeat keyboard pointer touch"]
            Output["WstOutput geometry and mode"]
            ShellGlobals["Shell Globals wl_shell xdg_shell wl_simple_shell"]
        end

        subgraph RendMod["Renderer Module dlopen"]
            RendGL["libwesteros_render_gl or libwesteros_render_embedded"]
        end

        subgraph NConn["Nested Connection"]
            NCThread["Nested Connection Thread"]
        end
    end

    subgraph VendorLayer["Vendor Layer"]
        SOC["westeros-soc DRM EGL"]
    end

    WstComp -->|enqueue input events| EventQ
    EventQ -->|drain and dispatch| CompThread
    CompThread -->|surface commit and compose| RendGL
    NCThread -->|output keyboard VPC callbacks| CompThread
    RendGL -->|EGL GLES2 DMA-buf| SOC
    NCThread -->|nested wl events| CompThread
```

Threading Model

Prerequisites and Dependencies

Platform and Integration Requirements


Component State Flow

Initialization to Active State

The compositor transitions through the following states during its lifecycle: Uninitialized (before WstCompositorCreate) → Configured (WstCompositorSet* calls establish display name, renderer module, frame rate, and mode flags) → Starting (WstCompositorStart spawns the compositor thread) → Ready (the compositor thread has created the Wayland display, seat, output, and shell globals; embedded mode initializes its renderer immediately after this signal in WstCompositorStart) → Active (the compositor thread runs the event loop, accepting client connections and generating frames) → Shutdown (WstCompositorStop signals the compositor thread to exit, renderer and seat resources are released).

```mermaid
sequenceDiagram
    participant App as Host Application
    participant Comp as WstCompositor API
    participant CThread as Compositor Thread
    participant Renderer as Renderer Module
    participant XKB as libxkbcommon

    App->>Comp: WstCompositorCreate()
    App->>Comp: WstCompositorSetRendererModule()
    App->>Comp: WstCompositorSetDisplayName()
    App->>Comp: WstCompositorSetFrameRate()
    App->>Comp: WstCompositorStart()
    Comp->>CThread: pthread_create wstCompositorThread
    CThread->>XKB: xkb_context_new and xkb_keymap_new_from_names
    XKB-->>CThread: keymap ready
    CThread->>Renderer: dlopen and renderer_init
    Renderer-->>CThread: WstRenderer function table populated
    CThread->>CThread: wl_display_create and register globals
    CThread->>CThread: wstSeatInit wstOutputInit wstShmInit
    CThread-->>Comp: compositorReady = true
    Comp-->>App: WstCompositorStart returns true

    loop Frame Loop
        CThread->>CThread: wl_display_flush_clients
        CThread->>Renderer: updateScene
    end

    App->>Comp: WstCompositorStop()
    CThread->>Renderer: renderTerm
    CThread->>CThread: wstSeatTerm wstOutputTerm
    CThread-->>Comp: thread exits
```

Runtime State Changes

State Change Triggers:

Context Switching Scenarios:


Call Flows

Initialization Call Flow

```mermaid
sequenceDiagram
    participant App as Host Application
    participant API as WstCompositor API
    participant CThread as Compositor Thread
    participant Renderer as Renderer Module
    participant WlDisplay as wl_display

    App->>API: WstCompositorCreate()
    App->>API: WstCompositorSet display renderer framerate mode
    App->>API: WstCompositorStart()
    API->>CThread: pthread_create
    CThread->>WlDisplay: wl_display_create()
    CThread->>WlDisplay: register globals wl_compositor wl_shm wl_seat wl_output xdg_shell wl_simple_shell vpc
    CThread->>Renderer: dlopen rendererModule and renderer_init
    Renderer-->>CThread: WstRenderer function table
    CThread->>CThread: wstSeatInit wstOutputInit wstShmInit
    CThread-->>API: compositorReady = true
    API-->>App: WstCompositorStart returns true
```

Request Processing Call Flow

Surface buffer rendering is the primary runtime operation. A Wayland client attaches a buffer to its surface and issues a commit. The compositor thread receives the commit, passes the buffer to the renderer module for upload or import, schedules a repaint, and on the next frame tick calls the renderer's updateScene to produce the composited output.

```mermaid
sequenceDiagram
    participant WlClient as Wayland Client
    participant CThread as Compositor Thread
    participant Renderer as Renderer Module
    participant SOC as Vendor SOC Layer

    WlClient->>CThread: wl_surface.attach buffer
    WlClient->>CThread: wl_surface.commit
    CThread->>CThread: wstISurfaceCommit update WstSurface state
    CThread->>Renderer: surfaceCommit surface bufferResource
    Renderer->>SOC: import or upload buffer via EGL or DMA-buf
    SOC-->>Renderer: texture or buffer handle
    CThread->>CThread: wstCompositorScheduleRepaint
    Note over CThread: next frame tick
    CThread->>Renderer: updateScene
    Renderer->>SOC: draw surfaces via GLES2 or HW overlay
    CThread->>WlClient: frame callback done
```

Internal Modules

Module / ClassDescriptionKey Files
WstCompositorPublic API handle. Holds per-instance output dimensions, keyboard/pointer/touch objects, client status callbacks, and the 64-entry event queue. Each virtual embedded instance has its own WstCompositor sharing a single WstContext.westeros-compositor.cpp, westeros-compositor.h
WstContextInternal compositor context. Owns the wl_display, compositor thread, renderer module, seat, output, surface maps, nested connection, and all Wayland global objects. One WstContext per non-virtual compositor instance.westeros-compositor.cpp
WstRendererPluggable rendering interface. Loaded at runtime via dlopen; the module exports renderer_init to populate a function table of surface and scene operations. Two built-in modules are provided: a GLES2 GL renderer and an embedded renderer.westeros-render.h, westeros-render-gl.cpp, westeros-render-embedded.cpp
WstNestedConnectionManages the Wayland client connection to a parent compositor in nested or repeater mode. Runs on a dedicated thread. Receives output, keyboard, and VPC events from the parent and delivers them via callbacks into the compositor context.westeros-nested.h, westeros-nested.cpp
WstSurfacePer-surface state: position, size, opacity, z-order, attached buffer resource, frame callback list, and explicit-sync fences. Maintains a reference to its WstRenderSurface within the renderer and to any associated WstVpcSurface.westeros-compositor.cpp
WstSeat / WstKeyboard / WstPointer / WstTouchInput seat abstraction. Tracks focused surfaces, current keyboard modifiers via libxkbcommon xkb_state, and pointer position. Dispatches Wayland seat events to client resources.westeros-compositor.cpp
WstSimpleShellServer implementation of the wl_simple_shell protocol. Allows privileged clients to set surface name, visibility, geometry, opacity, z-order, scale, and focus by surface ID, and to receive creation/destruction broadcast notifications.simpleshell/westeros-simpleshell.cpp, simpleshell/westeros-simpleshell.h
WstVpcSurfaceTracks the video path control state for a surface (hardware path vs. graphics path) and the position/scale transform communicated to the compositor chain via the vpc protocol.westeros-compositor.cpp
WstLinuxDmabufProtocol module implementing zwp_linux_dmabuf_v1. Handles multi-plane DMA-buf buffer import with format and modifier negotiation between client and renderer.linux-dmabuf/westeros-linux-dmabuf.cpp, linux-dmabuf/westeros-linux-dmabuf.h
WstLinuxExpSyncProtocol module implementing linux_explicit_synchronization_unstable_v1. Manages per-surface acquire fence descriptors and buffer release fence signalling between client and renderer.linux-expsync/westeros-linux-expsync.cpp, linux-expsync/westeros-linux-expsync.h

Component Interactions

Westeros operates as a self-contained Wayland display server. Northbound communication is entirely via the Wayland socket protocol; southbound communication is via the renderer module's function table.

Interaction Matrix

Target Component / LayerInteraction PurposeKey APIs / Topics
Wayland Clients

UI / App RuntimesSurface creation, buffer submission, input receptionwl_compositor, wl_surface, wl_seat, xdg_shell, wl_simple_shell, vpc
Media / Video ClientsVideo path and position negotiationvpc_surface.set_geometry, vpc_surface.video_path_change
Renderer Module / HAL

virtual/westeros-soc rendererCompositing surfaces to display outputrenderer_init(), surfaceCommit(), updateScene(), surfaceSetGeometry(), surfaceSetZOrder(), holePunch()
EGL / GLES2 / DMA-bufGPU buffer import and renderingeglBindWaylandDisplayWL, eglQueryWaylandBufferWL, WstLDBBufferGet*
System

libxkbcommonKeyboard layout and modifier state managementxkb_context_new, xkb_keymap_new_from_names, xkb_state_new, xkb_state_update_mask
Wayland display socketInter-process communication with compositor clientswl_display_create, wl_display_add_socket, wl_display_run

Events Published

Event NameWayland TopicTrigger ConditionSubscriber
output.modewl_outputOutput size changes via WstCompositorResolutionChangeEndAll connected Wayland clients
keyboard.keymapwl_keyboardCompositor start or nested keymap update from parentClients with keyboard focus
keyboard.key / keyboard.modifierswl_keyboardKey event injected via WstCompositorKeyEventClient with keyboard focus
pointer.motion / pointer.buttonwl_pointerPointer event injected via WstCompositorPointerMoveEvent / WstCompositorPointerButtonEventClient under pointer
touch.down / touch.up / touch.motionwl_touchTouch event injected via WstCompositorTouchEventClient with touch focus
shell_surface.created / shell_surface.destroyedwl_simple_shellSurface created or destroyed on the displayAll wl_simple_shell bound clients
vpc_surface.video_path_changevpcVideo surface changes path via wstDefaultNestedVpcVideoPathChangeVPC-bound client surfaces
frame callbackwl_callbackFrame composition completedWayland clients that requested frame callback

IPC Flow Patterns

Primary Surface Commit Flow:

Clients communicate with Westeros over the Wayland socket. Westeros validates the buffer resource type (shm, EGL Wayland buffer, DMA-buf, or simple-buffer) at commit time and dispatches to the renderer for import. Buffer sharing is mediated through the Wayland shm pool mechanism and the enabled buffer protocol extensions.

```mermaid
sequenceDiagram
    participant Client as Wayland Client
    participant WlServer as wl_display Westeros
    participant Comp as Compositor Thread
    participant Renderer as Renderer Module

    Client->>WlServer: wl_surface.attach buffer
    Client->>WlServer: wl_surface.commit
    WlServer->>Comp: wstISurfaceCommit dispatch
    Comp->>Renderer: surfaceCommit surface bufferResource
    Renderer-->>Comp: buffer imported
    Comp-->>WlServer: schedule repaint
    WlServer-->>Client: frame callback on next vsync
```

VPC Video Path Control Flow:

```mermaid
sequenceDiagram
    participant VideoClient as Video Client
    participant Comp as Compositor Thread
    participant ParentComp as Parent Compositor nested

    VideoClient->>Comp: vpc_surface.set_geometry x y w h
    Comp->>Comp: update WstVpcSurface transform
    Comp->>ParentComp: forward vpc xform via nested connection
    ParentComp-->>Comp: vpc video_path_change event
    Comp->>VideoClient: vpc_surface.video_path_change notification
```

Implementation Details

Major HAL APIs Integration

The HAL boundary for Westeros is the renderer module interface. All functions below are called through the WstRenderer function pointer table populated by the renderer module's renderer_init entry point.

Renderer Module APIPurposeImplementation File
renderer_init()Entry point called after dlopen; populates the WstRenderer function tablewesteros-render-gl.cpp, westeros-render-embedded.cpp
surfaceCreate()Allocates a per-surface render object (WstRenderSurface) within the rendererwesteros-render-gl.cpp
surfaceCommit()Imports or uploads the Wayland client buffer into the renderer (EGL Wayland buffer, DMA-buf, or shm)westeros-render-gl.cpp, westeros-render-embedded.cpp
surfaceImportSync()Imports the explicit sync fence for a surface buffer commitwesteros-render-gl.cpp
surfaceSetGeometry()Sets the position and dimensions of a surface for the next scene updatewesteros-render-gl.cpp, westeros-render-embedded.cpp
surfaceSetZOrder()Sets the rendering order of a surfacewesteros-render-gl.cpp, westeros-render-embedded.cpp
surfaceSetOpacity()Sets the alpha multiplier for a surfacewesteros-render-gl.cpp, westeros-render-embedded.cpp
surfaceSetVisible()Controls whether a surface participates in scene renderingwesteros-render-gl.cpp, westeros-render-embedded.cpp
surfaceSetCrop()Sets the source crop rectangle for a surfacewesteros-render-embedded.cpp
updateScene()Renders all visible surfaces to the output target for the current framewesteros-render-gl.cpp, westeros-render-embedded.cpp
holePunch()Clears a screen region to allow hardware video overlay to show throughwesteros-render-embedded.cpp
queryDmabufFormats() / queryDmabufModifiers()Queries supported DMA-buf pixel formats and modifiers from the rendererwesteros-render-gl.cpp
resolutionChangeBegin() / resolutionChangeEnd()Signals the renderer before and after an output resolution changewesteros-render-gl.cpp
renderTerm()Releases all renderer resources at shutdownwesteros-render-gl.cpp, westeros-render-embedded.cpp

Key Implementation Logic


Configuration

Key Configuration Parameters

ParameterTypeDefaultDescription
WESTEROS_DEBUGint3Log verbosity level (0 = fatal/error only, 3 = info and debug, 6 = full trace). Read once at WstCompositorCreate.
WAYLAND_DISPLAYstringwayland-0Name of the Wayland socket created by the compositor, set in westeros-init before launch.
XDG_RUNTIME_DIRstring/runDirectory used for the Wayland socket file. westeros-init waits up to 60 seconds for this path to become available.
WESTEROS_GL_MODEstringOutput mode string (e.g., 3840x2160x60) passed to the GL renderer module for display mode selection.
WESTEROS_GL_GRAPHICS_MAX_SIZEstringMaximum graphics plane size (e.g., 1920x1080) passed to the GL renderer module.
WESTEROS_GL_USE_REFRESH_LOCKintWhen set to 1, instructs the GL renderer to synchronise frame generation to display refresh.
WESTEROS_VPC_BRIDGEstringDisplay name of a compositor to establish a VPC bridge with, used by embedded compositors.
WESTEROS_RENDER_GL_FPSEnables frame-rate reporting in the GL renderer module.
WESTEROS_FAST_RENDERstringFor embedded composition, names a fast-render shared library implementing delegateUpdateScene.

Runtime Configuration

The westeros-init script selects the renderer module before launching the compositor. Its RENDERER assignment overrides any value from /etc/default/westeros-env, so change the init script or invoke westeros directly when selecting a renderer.

To apply supported environment-file changes:

systemctl restart westeros

The frame rate and display name can also be passed on the command line when invoking the westeros binary directly:

westeros --renderer /usr/lib/libwesteros_render_gl.so.0 --framerate 60 --display wayland-0