Native Platforms (X11, Wayland, Win32)

CNA snapshot 009d40f5

The SDL-free platform backends  ·  CNA snapshot 009d40f5  ·  CNA_PLATFORM=X11, WAYLAND, WIN32

ℹ

What is new in this snapshot. v0.1.0-alpha.1 had one real windowing platform, SDL3 (plus a narrow SDL2 edge, a headless platform and a POSIX terminal). The next branch adds three native platform backends written directly against the host window system — X11 (Xlib), WAYLAND (the Wayland protocols) and WIN32 (user32/gdi32) — and a CNA_ENABLE_SDL switch that lets a build contain no SDL at all. SDL3 is still the default, and the only platform CI configures, on macOS, iOS, Android and the web; nothing here removes or degrades it. The other axes (target OS, renderer, audio) stay independent.

What “native” means

A platform implementation owns windows, events, input, timing and host services (clipboard, dialogs, displays, controllers). CNA selects exactly one at configure time with CNA_PLATFORM; all of them implement the same CNA::Platform::IPlatform contract and report what they can do through a set of 32 capability flags. A native backend is one that talks to the operating system's own window-system API and contains no SDL code: source scans and link checks in CNA's test suite keep it that way. Three exist, and each is only offered where it can actually be built.

BackendRuns onTalks toOffered by CMake whenAutomatic CI workflow (as configured)
X11Linux and other Unix-like hosts with an X server (native Xorg, or Xwayland on a Wayland desktop)Xlib, XKB, XInput2, XRandR, Xcursor, MIT-SHM, GLX; the freedesktop D-Bus portal; kernel evdev for controllerslibX11, libXext and X11/XKBlib.h are found; the target is not Windows, Emscripten, Android or iOSYes two jobs in platform-ci.yml, on a virtual X server
WAYLANDLinux (a Wayland session, natively — no Xwayland)libwayland-client, xdg-shell, xkbcommon, wl_shm, EGL and Vulkan surfaces, text-input-v3, fractional scale and about a dozen more protocols; portal; evdevwayland-client ≥ 1.18, xkbcommon ≥ 0.5, wayland-scanner and wayland-protocols with stable/xdg-shell are found; not Windows, Emscripten, Android or AppleNo no workflow selects it; suites run locally
WIN32Windows, including a mingw-w64 cross-build from Linuxuser32, gdi32, opengl32 (WGL), ole32, shell32, uuid; Vulkan loaded at run timethe target system is WindowsPartly the platform module only: mingw cross-build under Wine on every push; native MSVC is manual

Each backend is a source directory of its own under modules/platform/src/: X11 has 43 source files, Wayland 34 and Win32 31, against 28 for the SDL3 backend. X11 and Wayland share a few helpers that are not specific to either — XKB key tables, the freedesktop portal client (libdbus, loaded at run time), POSIX timing and Linux evdev controller support (kernel <linux/input.h>, no libudev).

⚠

Requested means required. If you set CNA_PLATFORM=X11 or WAYLAND on a machine that cannot build it, configuration fails with the missing package named; it never falls back to SDL3 (or to X11 through Xwayland). Likewise WIN32 off Windows and TERMINAL on Windows are refused as “reserved identifier that is NOT implemented”, and SDL12 and EMSCRIPTEN are reserved everywhere. Values are case-sensitive.

Choosing between SDL3 and a native backend

If you want…UseWhy
The most complete backend, one code path for Linux, Windows, macOS, iOS, Android and the webSDL3 (default)It is the default (and the only one CI configures) on macOS, iOS, Android and Emscripten, and has the full capability set (gamepads and sensors everywhere, IME, drag-and-drop, tray, camera).
A Linux binary with no SDL in it, on X11 or XwaylandX11 with CNA_ENABLE_SDL=OFFA CI workflow is configured to build, link and run two real games this way (see What CI is configured to check).
A Linux binary that talks to a Wayland compositor directlyWAYLANDNative Wayland client with fractional scaling and text-input-v3. Treat it as implemented and locally tested, not CI-verified.
A Windows binary that calls only OS librariesWIN32 (with NULL audio for a fully SDL-free build)Links only user32, gdi32, opengl32, ole32, shell32, uuid. It has no gamepads, no IME and no drag-and-drop yet.
Gamepads on WindowsSDL3The Win32 backend does not wire up XInput.
No window at all (servers, tests, batch rendering)HEADLESS or TERMINALSee Platform Support.

Native X11

CNA_PLATFORM=X11 is written directly against Xlib and answers the question “can CNA run on a Linux desktop without SDL?” with a build configuration that a CI job builds and runs on every push. Only libX11, libXext and the XKBlib.h header are mandatory; every other extension is optional and switches off exactly one capability when absent, so the backend stays available on stripped-down systems.

Dependencies and what each one gates

PieceRequired?Without it
libX11, libXext, X11/XKBlib.hMandatoryThe backend is not offered; configure names the package (libx11-dev, libxext-dev).
libXi (XInput2)OptionalNo relativeMouse, no input-device enumeration; touch and pen contacts need a server that speaks XInput 2.2.
libXrandr (≥ 1.2)OptionalNo multipleDisplays; exclusive fullscreen has no mode to switch to and becomes borderless.
libXcursorOptionalNo custom ARGB cursors; the standard shapes still work.
libXfixes, libXau, libXssOptionalPointer hiding without an owned pixmap, the exclusive-fullscreen mode guardian's authorisation cookie, and a screen saver suspended for this client alone.
MIT-SHM (XShm.h)OptionalThe software presenter falls back to plain XPutImage.
GLX headers (libglvnd or Mesa)Optional; the entry points are resolved at run timeNo openGlContext, so no GL-family renderer can run.
Vulkan headersOptional; headers only, the loader is the renderer'svulkanSurface is unaffected: CMake defines CNA_X11_HAVE_VULKAN_HEADERS, but no X11 source reads it, and the loader and vkCreateXlibSurfaceKHR are resolved at run time. A machine without a Vulkan driver still builds and runs everything else.
D-Bus headers (libdbus-1-dev)Optional; libdbus-1.so.3 is loaded at run timeNo file dialogs, OpenUrl or desktop screen-saver inhibition through the portal.
Kernel headers (linux/input.h)OptionalNo gamepads, joysticks, rumble, haptics or power information (evdev and sysfs).

The configure log ends its X11 line with a summary such as “X11 + Xext; optional present: Xi, Xrandr, …; absent: …”, which is the quickest way to see which capabilities your build will have.

Behaviour worth knowing

  • No HiDPI, by design. X11 has one coordinate space, so highDpi is false and a window's display scale is 1. The session's scale is exposed per display as its content scale.
  • Keyboard. Layout-independent scancodes are derived from XKB key names; key releases are real events (nothing is synthesised). Text goes through XIM (Xutf8LookupString), and IME composition is available when the application asks to draw it.
  • Clipboard and drag-and-drop. ICCCM selection ownership including INCR, any MIME type, the middle-click PRIMARY selection, and XDND 5 as a drop target.
  • Fullscreen. Borderless fullscreen uses the EWMH hint when the window manager advertises it; exclusive fullscreen changes the display mode through XRandR and restores it on exit, and after SIGKILL through a guardian process.
  • Message boxes are drawn with Xlib in a window of their own; file dialogs come from the desktop portal when the session bus offers one. Nothing shells out to zenity or kdialog.
  • Under Xwayland (X11 on a Wayland desktop) the backend works, but the compositor owns the screen: the global pointer is exact only over your own windows, minimised windows can stay mapped, focus is the compositor's decision, and scaling happens in the compositor. CNA's notes record validation on GNOME 48 with real hardware; that is the project's own record, not a CI result.
  • Controllers need no display. Gamepads, joysticks, rumble, motion sensors and force-feedback devices come from the kernel's evdev nodes (Linux only), so they work even for a process that could not reach an X server.

Native Wayland

CNA_PLATFORM=WAYLAND is a genuine Wayland client: libwayland-client, xdg-shell, xkbcommon and the compositor's own protocols, with no SDL, no Xlib and no Xwayland. Window state follows an explicit configure state machine (CreateWindow returns only after the compositor's first configure has been acknowledged), and a compositor that goes away ends the connection cleanly instead of crashing the game.

Dependencies

PieceRequired?Without it
wayland-client ≥ 1.18, xkbcommon ≥ 0.5Mandatory, linkedThe backend is not offered.
wayland-scanner and wayland-protocols with stable/xdg-shellMandatory, build timeThe backend is not offered. Protocol bindings are generated into the build tree; nothing generated is committed.
Optional protocol XML files: xdg-output, viewporter, fractional-scale-v1, relative-pointer, pointer-constraints, text-input-v3, primary-selection, xdg-decoration, xdg-activation, idle-inhibit, xdg-foreign-v2, tablet-v2, cursor-shape-v1Optional, build timeExactly that protocol's capability (for example no IME without text-input-v3, no fractional scale without fractional-scale-v1 plus viewporter).
EGL and wayland-egl headersOptional; libEGL.so.1 and libwayland-egl.so.1 load at run timeNo openGlContext.
wayland-cursor headersOptional; loaded at run timeNo cursor-theme fallback (cursor-shape still works).
Vulkan headers, D-Bus headers, linux/input.hOptionalNo vulkanSurface without the Vulkan headers (unlike X11, where the surface does not depend on them), no desktop portal without the D-Bus headers, no evdev controllers without linux/input.h.
wayland-serverTest builds onlyThe in-process test compositor is unavailable; it is never linked into the platform library.

Behaviour worth knowing

  • Scaling. Fractional scale through wp_fractional_scale_v1 and wp_viewporter where offered, integer scale otherwise, so highDpi is true (unlike X11).
  • No global pointer, by design. Wayland gives a client neither the pointer position outside its surfaces nor the power to move it, so globalPointer is false and pointer capture, global position and warping refuse with PlatformNotSupportedException.
  • Window position belongs to the compositor. WindowDescription x/y/centre are ignored and no “moved” event exists. Exclusive fullscreen is requested but reported as borderless fullscreen: an ordinary Wayland client cannot own a display mode.
  • No message box and no tray. Wayland has no dialog protocol, and CNA declined both to embed a font and to launch zenity; draw the dialog with your own SpriteFont. File dialogs are unaffected (the desktop portal draws them).
  • Only unprivileged protocols. Nothing from wlr-*, no layer shell, no virtual input, no screen capture — a client that needed those would be a desktop component, not a game.
  • The capability set is fixed at start-up. If a compositor later withdraws a global, the corresponding call throws PlatformNotSupportedException naming it rather than silently pretending.
  • Software presentation. The wl_shm presenter service exists, but a CPU renderer (SOFTWARE) opens no window on any windowing platform; see Renderers on native platforms.
⚠

No CI for Wayland. No GitHub workflow selects CNA_PLATFORM=WAYLAND. The backend has its own registered suites (an in-process test compositor, headless Weston, GNOME's mutter with a real input method), but they are launched locally through tools/platform/wayland_test_server.sh; the claim that they pass on Weston and mutter comes from CNA's own documentation, and we did not run them. Treat native Wayland as implemented and locally tested, not continuously verified.

Native Win32

CNA_PLATFORM=WIN32 implements the platform contract directly on the Windows API: one HWND per window, WGL for OpenGL, StretchDIBits for CPU frames, Raw Input for relative mouse, IFileOpenDialog/IFileSaveDialog for file dialogs, EnumDisplayMonitors for displays. It links only operating-system import libraries — user32, gdi32, opengl32, ole32, shell32, uuid — and resolves vulkan-1.dll at run time, so a machine without a Vulkan driver simply reports vulkanSurface as false. It declares Windows 8.1 (0x0603) as the level its headers target; a source comment says every entry point above a Windows 7 floor is resolved at run time, so the binary itself is not meant to require more (read from source, not executed on Windows 7). It builds with MSVC and with mingw-w64.

What it does not have yet

Missing capabilityWhy / what is used instead
gamepad, joystick, rumble, sensors, hapticsXInput is not wired up. Use the SDL3 platform where Windows gamepads matter.
imeComposition and candidate lists are not delivered. Delivering composition without candidates would be a half-working IME a game cannot detect, so the flag stays false.
dragAndDrop, clipboardData, primarySelectionNo WM_DROPFILES/OLE drop target, no registered clipboard formats (the clipboard is text only), and Windows has no primary selection.
tray, camera, sensors, managedEntrypointNot wired up or out of scope.

Each missing capability is reported false, its service accessor returns nullptr, and a gated call raises PlatformNotSupportedException naming the capability — none is a stub that silently succeeds.

Host-process etiquette

  • The backend never sets DPI awareness, never raises the timer resolution, never changes the current directory and never takes over the thread's COM apartment. Declare DPI awareness in your manifest; the backend reports values that are coherent with whatever you chose.
  • Closing a window is a request. WM_CLOSE becomes CloseRequested and does not destroy the window; closing one of several windows does not quit the process at the platform level. A Game, however, calls Exit() on any CloseRequested without checking which window sent it.
  • Window sizes are client sizes (converted through AdjustWindowRectExForDpi).
  • If you include <windows.h> together with CNA platform headers, four macros collide with CNA identifiers (CreateWindow, CreateDirectory, MessageBox, GetClassName): #undef them or include the CNA headers first.

Audio on an SDL-free Windows build

Audio is a separate axis, and Windows has no SDL-free audio implementation: ALSA is Linux-only and WASAPI is reserved and refused. A fully SDL-free Win32 build therefore selects CNA_AUDIO_PLATFORM=NULL (silent). If you need sound on Windows, keep SDL3 audio (which needs SDL, so CNA_ENABLE_SDL cannot be OFF). See Audio System.

Capability differences

The platform contract exposes 32 boolean capabilities. Each backend reports what it can really do, and a false capability means the call refuses deterministically with PlatformNotSupportedException. The full seven-platform matrix is on Platform Support; here are the columns that matter for choosing a native backend, with SDL3 for comparison. “If…” means the answer depends on the running system and is decided once, when the platform object is created.

Capability flagSDL3X11WaylandWin32
multipleWindowsYesYesYesYes
highDpiYesNo (by design)Yes (fractional or integer)Yes
multipleDisplaysYesIf RandRYes, whenever the compositor connection succeeded (outputs are enumerated from wl_output)Yes
borderlessFullscreenYesIf the window manager advertises EWMH fullscreenYesYes
nativeWindowHandleYesYes (Display* + XID)Yes (wl_display* + wl_surface*)Yes (HWND)
surfacePresentationYesYes (XPutImage, MIT-SHM optional)If wl_shm offers XRGB8888Yes
openGlContextYesIf GLX 1.3 (loaded at run time)If EGL loads and initialisesYes (WGL)
vulkanSurfaceIf Vulkan is availableYes, with an X connection (the loader and the xlib-surface entry point are resolved at run time, not at build time)If Vulkan headers were present at buildIf vulkan-1.dll loads
clipboardYesYes (ICCCM, INCR)If a seat and data device existYes (text)
clipboardDataYesYes (any MIME type)If a data device existsNo
dragAndDropYesYes (XDND 5, target side)If a data device existsNo
primarySelectionYes (Unix desktops)YesIf the primary-selection protocol existsNo
textInputYesYesYesYes
imeYesIf the app draws composition and the input method agreesIf text-input-v3 existsNo
exactKeyboardStateYesYesYesYes
pixelAccurateMouseYesYesYesYes
relativeMouseYesIf XInput2 raw motionIf relative-pointer and pointer-constraintsYes
cursorShapesYesYesIf cursor-shape or a cursor theme / wl_shmYes
globalPointerYesYesNo (by design)Yes
inputDeviceEnumerationYesIf XInput2 (and evdev controllers)YesYes
gamepadYesYes on Linux (kernel evdev)Yes on Linux (kernel evdev)No (no XInput)
joystickYesYes on Linux (kernel evdev)Yes on Linux (kernel evdev)No
gamepadRumbleYesYes on Linux (evdev)Yes on Linux (evdev)No
gamepadSensorsYesYes on Linux (evdev)Yes on Linux (evdev)No
hapticsYesYes on Linux (force feedback)Yes on Linux (force feedback)No
sensorsYesNoNoNo
powerInfoYesYes on Linux (sysfs)Yes on Linux (sysfs)Yes
messageBoxYesYes (drawn with Xlib)No (by design)Yes
nativeFileDialogYesIf the desktop portal is on the session busIf the desktop portal is on the session busYes
trayIf supportedIf a system tray is runningNoNo
cameraIf supportedNoNoNo
managedEntrypointYes (Android and iOS main)NoNoNo

Sources: modules/platform/src/{Sdl3,X11,Wayland,Win32}/*Platform.cpp at snapshot 009d40f5, read directly.

Building without SDL

CNA_ENABLE_SDL decides whether the vendored SDL3 sub-build is configured at all.

ValueEffect
AUTO (default)SDL3 is configured exactly as before — identical to a build that never heard of the option.
ONThe same, stated explicitly.
OFFNo SDL source is fetched, built, found or linked (find_package for SDL and its satellites is blocked for every project in the tree). Any selection that genuinely requires SDL is refused at configure time, naming the reason; nothing is substituted.

With OFF, these selections are refused with a message that begins “CNA_ENABLE_SDL=OFF, but this configuration genuinely requires SDL”: platform SDL3 or SDL2; audio SDL3 or SDL2; and the renderers SDL_RENDERER, SDL_GPU, FNA3D and FREEDIRECT (also when they appear only in CNA_GRAPHICS_RENDERERS). Note that the default audio is SDL3, so an SDL-free configure must always choose NULL or ALSA explicitly.

Recipes

The first is the CI-proven, sound-free X11 cell; the second adds real renderers and ALSA audio. Both were run by CI at this snapshot; the exact flags are copied from the workflow.

# SDL-free X11, headless renderer, silent audio (workflow job "x11-sdl-free")
cmake -S . -B build -G Ninja \
  -DCMAKE_BUILD_TYPE=Debug \
  -DCNA_ENABLE_SDL=OFF \
  -DCNA_PLATFORM=X11 \
  -DCNA_GRAPHICS_RENDERER=HEADLESS \
  -DCNA_AUDIO_PLATFORM=NULL \
  -DCNA_ENABLE_NET=OFF

# SDL-free X11 with OpenGL 3.3, Vulkan, software and headless renderers
# selectable at run time, and ALSA audio (job "x11-sdl-free-gpu")
cmake -S . -B build -G Ninja \
  -DCMAKE_BUILD_TYPE=Release \
  -DCNA_ENABLE_SDL=OFF \
  -DCNA_PLATFORM=X11 \
  -DCNA_GRAPHICS_RENDERER=OPENGL33 \
  -DCNA_GRAPHICS_RENDERERS="OPENGL33;VULKAN;SOFTWARE;HEADLESS" \
  -DCNA_AUDIO_PLATFORM=ALSA \
  -DCNA_ENABLE_NET=OFF

A native-Wayland recipe and a mingw-w64 Windows recipe are in Build recipes. Step-by-step versions with run commands are tutorials 135, 136 and 138.

Proving that no SDL is in the binary

ldd build/cna_demo_2d | grep -i sdl                 # prints nothing
readelf -d build/cna_demo_2d | grep -i 'NEEDED.*sdl'  # prints nothing
nm -D --undefined-only build/cna_demo_2d | grep ' SDL_'   # prints nothing
find build -iname '*SDL2*' -o -iname '*SDL3*'         # no SDL artifact in the build tree

CI runs equivalent checks, plus one that asserts libasound is not a NEEDED entry: ALSA is dlopened at run time so that a machine without it still starts.

Renderers on native platforms

The platform and renderer axes are independent, but a renderer needs services the platform must offer (a native window handle, a GL context, a Vulkan surface). What that means for the native backends:

Renderer familyX11WaylandWin32
GL family: OPENGLES2, OPENGLES3, OPENGL33 (needs ../easy-gl and ../meta-gl)GLX contextEGL contextWGL context
OPENGL4 (desktop GL 4.1+ core)GLXEGLWGL
VULKANneeds Vulkan headers at buildneeds Vulkan headers at buildneeds vulkan-1.dll at run time
SOFTWARE, PORTABLEGL, HEADLESS, STUBOff-screen on every windowing platform: they create no window (readback only). Only SOFTWARE on TERMINAL presents.
DIRECTX9, DIRECTX11, DIRECTX12, DIRECT2D, GDInot buildable (Windows-only)not buildable (Windows-only)use the HWND
SDL_RENDERER, SDL_GPU, FNA3D, FREEDIRECTLink SDL3 by identity: refused when CNA_ENABLE_SDL=OFF. They can still be selected with a native platform if SDL is enabled.
WEBGPUNot exercised by any native-platform CI job; treat combinations with native platforms as unverified.
METAL, WEBGL1, WEBGL2, CANVAS, HTML_DOM, SVG_DOMPlatform-gated to macOS or Emscripten; not offered on these targets.
💡

No window? Check the renderer first. If a native-platform build starts, runs and shows nothing, you probably selected SOFTWARE, PORTABLEGL, HEADLESS or STUB. Those are deliberately window-less on X11, Wayland, Win32 and SDL3. Pick OPENGL33, OPENGLES3, OPENGL4 or VULKAN for a visible window, or set CNA_GRAPHICS_RENDERER in the environment at run time when the build contains several (see Runtime Renderer Selection).

Build recipes

These assume the workspace layout from Building: cna on the next branch, sharp-runtime on its next branch, and — for the GL-family renderers — easy-gl and meta-gl next to them. Package names are Debian/Ubuntu (CI uses Ubuntu 24.04 and GCC 14).

X11

sudo apt-get install -y g++-14 cmake ninja-build pkg-config \
  libx11-dev libxext-dev libxrandr-dev libxi-dev libxcursor-dev libxfixes-dev libxss-dev \
  libgl-dev libglx-dev libvulkan-dev libdbus-1-dev libasound2-dev

cd cna
git submodule update --init third_party/draco     # or add -DCNA_ENABLE_DRACO=OFF
cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release \
  -DCNA_ENABLE_SDL=OFF -DCNA_PLATFORM=X11 \
  -DCNA_GRAPHICS_RENDERER=OPENGL33 -DCNA_AUDIO_PLATFORM=NULL \
  -DCNA_BUILD_TESTS=OFF -DCNA_ENABLE_NET=OFF
cmake --build build --target cna_demo_2d
(cd build && ./cna_demo_2d)

Only libx11-dev and libxext-dev are mandatory. Add libasound2-dev only for CNA_AUDIO_PLATFORM=ALSA. Tutorial 135 walks through this end to end.

Wayland

sudo apt-get install -y g++-14 cmake ninja-build pkg-config \
  libwayland-dev libwayland-bin wayland-protocols libxkbcommon-dev \
  libegl-dev libvulkan-dev libdbus-1-dev

cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release \
  -DCNA_ENABLE_SDL=OFF -DCNA_PLATFORM=WAYLAND \
  -DCNA_GRAPHICS_RENDERER=OPENGL33 -DCNA_AUDIO_PLATFORM=NULL \
  -DCNA_BUILD_TESTS=OFF -DCNA_ENABLE_NET=OFF
cmake --build build --target cna_demo_2d

This is the documented recipe; it is not exercised by CI. Tutorial 136 covers it honestly, including what to check first.

Win32 (from Linux with mingw-w64, or natively)

# From Linux, targeting Windows
sudo apt-get install -y g++-mingw-w64-x86-64 cmake ninja-build
cmake -S . -B build-windows -G Ninja \
  -DCMAKE_TOOLCHAIN_FILE=cmake/toolchains/mingw-w64.cmake \
  -DCNA_ENABLE_SDL=OFF -DCNA_PLATFORM=WIN32 \
  -DCNA_AUDIO_PLATFORM=NULL -DCNA_GRAPHICS_RENDERER=DIRECTX11 \
  -DCNA_BUILD_TESTS=OFF -DCNA_BUILD_EXAMPLES=OFF

# Natively on Windows (MSVC)
cmake -S . -B build -DCNA_PLATFORM=WIN32 -DCNA_GRAPHICS_RENDERER=DIRECTX11

The full CNA + DirectX build for Windows is manual CI only; the automatic Windows evidence is the platform harness described in the next section.

Validation harnesses

CNA ships its own harnesses for the native backends. They are ordinary CTest entries or standalone programs in the repository, so you can re-run them.

HarnessBackendWhat it doesNeeds
ctest -R CnaX11 (seven entries: mapping, input method, evdev, integration, window manager, touchscreen, exclusive fullscreen)X11Key tables and event mapping, GLX contexts, clipboard interop, XDND, message boxes, portal dialogs, EWMH fullscreen, controllers through a virtual uinput device, touch and pen, exclusive fullscreen including SIGKILL recoveryXvfb (started privately by tools/platform/x11_test_server.sh); some suites need openbox, dbus-daemon, ibus, /dev/uinput and skip otherwise
cna_x11_desktop_validation <scenario>X11Drives the backend through the public contract and checks the result over a second X connection. Scenarios include info, lifecycle, wm, displays, glx, vulkan, presenter, lifetime, stress, clipboard, keyboard, mouse, relative, soak. Prints one PASS/FAIL/SKIP line per check; reports which server it ran on (Xorg, Xwayland or Xvfb).Built when CNA_PLATFORM=X11 and tests are on. Some scenarios inject input or overwrite the clipboard — read the table before running on your desktop.
ctest -R CnaWayland (mapping, protocol, portal, Weston, Weston GPU, Weston scaled, mutter, mutter Czech layout, ibus, link closure)Wayland78 protocol cases against an in-process compositor that raises the errors a strict compositor would; live suites on headless Weston and on GNOME's mutter with real input; a real Korean input method; a binary link-closure check (no SDL, X11, xcb or GLX)wayland-server for tests; Weston, gnome-shell, ibus as available — missing ones skip (exit 77). Launched through tools/platform/wayland_test_server.sh
cna_wayland_desktop_validation <scenario>Waylandinfo, lifecycle, scale, presenter, gl, vulkan, lifetime, stress, soak, clipboard, interactive. Never injects input.A running Wayland compositor (normally your real desktop)
tools/platform/standalone_tests (cna_platform_tests, cna_win32_directx_probe)Win32 (and any other)Builds the platform module and its whole suite on their own — no sharp-runtime, no SDL, no renderer — for any CNA_PLATFORM. Includes a probe that creates real Direct3D 11 and 12 devices and swap chains on a Win32 window.mingw-w64 + Wine on Linux, or MSVC on Windows
tools/platform/validate_win32_native.ps1 and friendsWin32Scripts for a real Windows machine (PowerShell, plus a shell script for the DPI matrix): interactive runs, clipboard interop, Unicode paths, soak, sanitizer buildsA Windows desktop

A minimal way to see which platforms your own binary contains and what the active one can do (this compiles against the snapshot's headers):

#include <iostream>

#include "CNA/Platform/IPlatform.hpp"
#include "CNA/Platform/PlatformCapabilities.hpp"
#include "CNA/Platform/PlatformFactory.hpp"

int main() {
    using CNA::Platform::PlatformFactory;

    // Every platform implementation compiled into this binary, and the default one.
    for (const std::string& name : PlatformFactory::GetAvailable()) {
        std::cout << "available: " << name << '\n';
    }
    std::cout << "default:   " << PlatformFactory::GetDefaultName() << '\n';

    auto platform = PlatformFactory::Create();
    const auto caps = platform->GetCapabilities();
    std::cout << std::boolalpha
              << "openGlContext=" << caps.openGlContext
              << " vulkanSurface=" << caps.vulkanSurface
              << " highDpi=" << caps.highDpi
              << " gamepad=" << caps.gamepad
              << " ime=" << caps.ime
              << " globalPointer=" << caps.globalPointer << '\n';
    return 0;
}

Exactly one implementation is compiled as the default (CNA_PLATFORM_<NAME>); HEADLESS is always compiled in, and TERMINAL is compiled on every non-Windows build, so GetAvailable() can list more than one name. There is no CNA_PLATFORM environment variable: the platform is a build-time choice.

What CI is configured to check

All of it lives in .github/workflows/platform-ci.yml and runs on push and pull request to next, develop and main unless noted. This section describes what those jobs are configured to build, run and assert, read from the workflow file; we did not inspect run results. These jobs fetch sharp-runtime through scripts/ci/clone_siblings.sh, which picks its next branch on a push to next — unlike several other workflows that pin an older revision (see Platform Support). Every Linux job runs under a virtual X server (Xvfb) and Mesa's software GL and Vulkan drivers; none is a real desktop or a physical GPU.

JobConfigurationWhat it checks
x11-sdl-freeCNA_ENABLE_SDL=OFF, X11, HEADLESS, NULL audio; Ubuntu 24.04, GCC 14, Xvfb + openboxBuilds the platform, audio, content and content-pipeline suites plus cna_content; no SDL artifact exists in the build tree and no test binary links SDL; the X11 suites pass; when the runner offers /dev/uinput, the uinput, D-Bus and private-server suites must run, not skip; the SDL-containment gates pass.
x11-sdl-free-gpuCNA_ENABLE_SDL=OFF, X11, OPENGL33;VULKAN;SOFTWARE;HEADLESS selectable at run time, ALSA audio, ReleaseBuilds cna_demo_2d, cna_house3d_demo and CnaAudioTests; neither SDL nor libasound is a NEEDED entry; both games run under every renderer (house demo smoke tests, exclusive fullscreen, cna_demo_2d --smoke 6 per renderer); the ALSA device, mixer, microphone and XACT suites pass on ALSA's silent null device.
win32-crossmingw-w64 cross-build of the standalone platform harness for WIN32, executed under WineThe backend still compiles for Windows, the full platform contract suite passes against it alongside Headless, its sources contain no SDL reference, and a Direct3D probe runs where Wine has a device. Wine is not Windows.
win32-nativeThe same harness on windows-latest with MSVCManual dispatch only adds a second compiler, a real per-monitor-DPI desktop, real Direct3D 11/12 and real shell dialogs.
sdl-enable-matrixCNA_ENABLE_SDL = AUTO, ON, OFF against platform choices (configure only)AUTO and ON configure; OFF + X11 configures; OFF + SDL3 must fail with “genuinely requires SDL”.
(no job)CNA_PLATFORM=WAYLANDNot covered Wayland development packages are installed in some jobs but every test there runs under Xvfb.

The Win32 jobs build tools/platform/standalone_tests, not the full CNA engine: the automatic Windows evidence is about the platform module, not about a DirectX game. The native-MSVC, Direct3D and GDI lanes of the full engine are manual workflows.

Honest limits

  • Wayland has no CI and its local validation is recorded only in CNA's own documents.
  • X11 evidence comes from Xvfb. A physical GPU's GLX driver, a real compositor's fullscreen behaviour, multi-monitor layouts and hot-plug, real input devices and language-specific input-method engines are outside what CI can show; CNA's notes record manual validation on real desktops, but that is not a gate.
  • Win32 has no gamepads, no IME, no drag-and-drop and text-only clipboard; the full-engine Windows lanes are manual.
  • No SDL-free audio on Windows or macOS. ALSA is Linux-only; OPENAL and WASAPI are reserved and refused.
  • SDL-free means no SDL-based renderers (SDL_RENDERER, SDL_GPU, FNA3D, FREEDIRECT).
  • X11 on other Unixes (FreeBSD, OpenBSD, NetBSD) is expected to build but is untested; native Wayland is not offered on macOS, iOS, Android or the web, and native X11 is not offered on iOS, Android or the web (on macOS it is offered whenever libX11, libXext and XKBlib.h are found; not exercised).
  • The native backends are new in this development snapshot on next; they are not part of the v0.1.0-alpha.1 tag.

Further reading