Layer overview

  ┌─────────────────────────────────────────────────────────────────┐
  │                     Game / Application Code                     │
  │        Uses: Microsoft::Xna::Framework API                      │
  │        Example: MyGame extends Game, calls SpriteBatch::Draw()  │
  └────────────────────────────┬────────────────────────────────────┘
                               │
                               ▼
  ┌─────────────────────────────────────────────────────────────────┐
  │                 XNA-Compatible Public API Layer                 │
  │   modules/*/include/Microsoft/Xna/Framework/...                 │
  │   Game · GraphicsDevice · SpriteBatch · Texture2D · Color       │
  │   Vector2/3/4 · Matrix · Input · Audio · Media · Content · Net  │
  │   Opt-in: CNAEXT extensions · Design · Phone · C ABI            │
  └────────────────────────────┬────────────────────────────────────┘
                               │
                               ▼
  ┌─────────────────────────────────────────────────────────────────┐
  │      CNA Internal Abstraction Layer (sharp-runtime support)     │
  │   modules/graphics/include/CNA/Internal/Renderers/Common/       │
  │   IGraphicsRenderer · ISpriteBatchRenderer · ITextureRenderer   │
  │   Descriptors · Registry · GraphicsRendererSelection (core)     │
  └─────────┬──────────────────────┬──────────────────────┬─────────┘
            │                      │                      │
            ▼                      ▼                      ▼
  ┌───────────────────┐ ┌─────────────────────┐ ┌───────────────────┐
  │ EasyGL family (3) │ │ Native GPU APIs (7) │ │  2D/CPU/none (4)  │
  │ OPENGLES3         │ │ VULKAN · SDL_GPU    │ │ SDL_RENDERER      │
  │ OPENGL33          │ │ DIRECTX9 · 11       │ │ SOFTWARE          │
  │ WEBGL2            │ │ METAL · WEBGPU      │ │ HEADLESS · STUB   │
  │                   │ │ FNA3D               │ │                   │
  └─────────┬─────────┘ └──────────┬──────────┘ └─────────┬─────────┘
            │                      │                      │
            └──────────────────────┴──────────────────────┘
                                   │
                                   ▼
  ┌─────────────────────────────────────────────────────────────────┐
  │         Independent host and audio services (build axes)        │
  │   CNA_PLATFORM: SDL3 · HEADLESS · TERMINAL                      │
  │     (SDL3 reaches Windows, X11, Wayland, macOS, iOS,            │
  │      Android and the web through its video drivers)             │
  │   CNA_AUDIO_PLATFORM: SDL3 · NULL · ALSA                        │
  │   CNA_ENABLE_SDL: AUTO | ON | OFF   (OFF = windowless, no SDL)  │
  └─────────────────────────────────────────────────────────────────┘

  ┌─────────────────────────────────────────────────────────────────┐
  │                  Build-time and optional pieces                 │
  │   cna-content · content-pipeline · CNB / XNB writers            │
  │   Opt-in: Inspector · C ABI (libcna_c_api) · Design             │
  │   Diagnostics is compiled out when CNA_DIAGNOSTICS=OFF          │
  └─────────────────────────────────────────────────────────────────┘

Every renderer family publishes a descriptor and namespaced factory into a generated runtime registry. A normal build emits one entry; CNA_GRAPHICS_RENDERER picks the default and CNA_GRAPHICS_RENDERERS can emit a compatible set. This snapshot exposes 14 public identities over 12 implementation families: three GL profiles (OPENGLES3, OPENGL33, WEBGL2) share the single EasyGL family. The host and audio services below the renderers are independent build axes, not part of any renderer. See the renderer reference, and the release notes for what changed since alpha.1.

Detailed architecture diagram

CNA architecture at snapshot c1c316b9: the runtime flow, the XNA-shaped Framework API, renderer selection and the IGraphicsRenderer interface, the 14 renderer identities in three groups, the platform and audio implementations chosen independently, and the target operating systems. A text alternative follows.
📌

Regenerated for this snapshot. The diagram earlier on this page was drawn for an early development stage and no longer matched the code, so it has been redrawn: it now shows the 14 renderer identities in three groups, the independent platform (CNA_PLATFORM) and audio (CNA_AUDIO_PLATFORM) selections, the sprite draw flow and the build-time selection options. It is generated by scripts/make_architecture_diagram.py; an SVG version scales without loss.

Text alternative to the diagram

  • Runtime flow: main → Game::Run → Initialize → LoadContent → the Update/Draw loop → Present (in Game::EndDraw).
  • Sprite draw flow: SpriteBatch::Begin → Draw → End → GraphicsDevice → the selected IGraphicsRenderer → a GPU API, the CPU or the browser.
  • Build-time choice: CNA_GRAPHICS_RENDERER decides which family (or, with CNA_GRAPHICS_RENDERERS, which set of families) is compiled; GraphicsRendererSelection decides among the compiled families at run time.
  • Services: the renderer obtains its window, GL context, Vulkan surface or native handle from the selected CNA_PLATFORM implementation; audio comes from CNA_AUDIO_PLATFORM; siblings (sharp-runtime, plus easy-gl/meta-gl for the GL renderers) sit beside the CNA tree.

The four build axes

CNA keeps four concerns apart, plus one switch. They are selected independently, with a small set of hard exclusions that fail at configure time with a named reason and never fall back silently.

AxisQuestion it answersSelected byValues at this snapshot
1. Target operating systemWhich ABI and toolchain is the binary for?The CMake toolchain and host; reported at run time by CNA::TargetPlatform (Desktop, Android, iOS, Web)Linux, Windows (MSVC or MinGW-w64), macOS, iOS, Android, Emscripten
2. Platform implementationWho owns windows, events, input, timing and host services?CNA_PLATFORM (default SDL3)SDL3, HEADLESS, TERMINAL; SDL12 and EMSCRIPTEN are reserved and refused
3. Graphics rendererWho turns draw calls into pixels?CNA_GRAPHICS_RENDERER (per-host default) and optionally CNA_GRAPHICS_RENDERERS14 public identities in 12 families
4. Audio implementationWho opens playback and capture, and for two values mixes?CNA_AUDIO_PLATFORM (default SDL3)SDL3, NULL, ALSA; OPENAL and WASAPI are reserved and refused
Switch: SDL availabilityIs SDL configured at all?CNA_ENABLE_SDL = AUTO (default), ON, OFFOFF refuses every selection that needs SDL: the SDL3 platform, SDL3 audio and the SDL_RENDERER, SDL_GPU and FNA3D renderers

Hard exclusions: TERMINAL accepts only the CPU renderers SOFTWARE, HEADLESS and STUB; TERMINAL is non-Windows-only (reserved and refused on Windows); ALSA is Linux-only. The platform and audio defaults are SDL3 on every OS; only the renderer default varies (Emscripten WEBGL2, Linux OPENGLES3, everything else SDL_RENDERER). See Platform Support and Native platforms.

Layer descriptions

Layer 1 - Highest

Game / Application Code

Your game logic. Subclasses Game, overrides LoadContent(), Update(), Draw(). Calls XNA-style APIs exclusively. Has zero knowledge of which renderer is in use - this is the contract CNA enforces. Games written against this layer are portable across renderers; the renderer-dependent parts (capabilities, the default Reach graphics profile) are queried through the public API rather than by renderer name.

Layer 2 - Public API

XNA-Compatible API Layer

Lives under each module's include/Microsoft/Xna/Framework/ tree. This is the surface that game code touches. Class names, namespaces, and method signatures mirror the original XNA 4.0 API as faithfully as practical in C++. No renderer-specific code leaks into this layer. Includes: Game, GraphicsDevice, GraphicsDeviceManager, SpriteBatch, Texture2D, Color, all math types, input surfaces, GameTime, GameComponent, etc. Beside it sit the opt-in extensions: the CNA::Graphics extensions (CNA_CNAEXT), CNA::Design converters, Microsoft::Phone and the C ABI adapter.

Layer 3 - Internal Abstractions

CNA Internal Layer & sharp-runtime Support

Lives under modules/graphics/include/CNA/Internal/Renderers/Common/, in the CNA::Internal::Renderers namespace. It defines the renderer interfaces (IGraphicsRenderer with ISpriteBatchRenderer, ITextureRenderer and the other resource interfaces) plus the descriptor/registry contract used before a device exists (GraphicsRendererDescriptor, GraphicsRendererRegistry). The public GraphicsRendererSelection API lives in the core module: it resolves the compiled default or an explicit runtime choice and then dispatches through the selected family's namespaced factory.

Layer 4 - Lowest

Renderer, platform and audio implementations

Concrete renderers live under modules/renderers/<family>/: 12 implementation families carrying 14 identities (plus shared common/d3d and common/mojoshader helper targets, which are not families). Platform implementations separately implement CNA::Platform::IPlatform under modules/platform/src/<Backend>; audio implementations separately implement the audio device surface under modules/audio/src/Platform and Backend. The target OS is a fourth concern, reported by CNA::TargetPlatform.

SDL3, Headless and Terminal

SDL3 is the default platform and audio selection, and CNA’s one windowing implementation: Windows, X11, Wayland, macOS, iOS, Android and the browser are reached through SDL’s own video drivers. Headless and POSIX Terminal avoid a graphical host, and CNA_ENABLE_SDL=OFF configures such a windowless build without SDL at all. Audio-device code may independently be SDL3, Null or ALSA; SDL3 (SDL3_mixer) and ALSA (CNA's own CnaMixer) define SOUND_ENABLED and supply the high-level playback and decoding engine.

  • SDL3_mixer uses the MIX_Mixer model with track-based, per-mixer channels.
  • SDL3_image is used for texture/image loading.
  • All three libraries (SDL, SDL_image, SDL_mixer) are vendored as Git submodules under third_party/, and SDL3 is built at configure time into a persistent .sdl-prebuilt-* cache. No system SDL install is required by default; pass -DCNA_USE_SYSTEM_SDL=ON to use system packages instead.

The platform service contract (a 32-flag PlatformCapabilities set, where a missing capability refuses deterministically) covers:

  • Windowing — window creation and management (SDL_Window, on whichever video driver SDL uses)
  • Event loop — cross-platform event pumping
  • Input — keyboard, mouse, gamepad and touch/pen state (SDL input; the Terminal platform reads the TTY)
  • Audio — not part of IPlatform: audio is a separate axis (CNA_AUDIO_PLATFORM) implemented in cna_audio
  • OpenGL context creation — used by the EasyGL renderers (created by SDL3 for its window)
  • Vulkan surface creation — used by the VULKAN renderer (created by SDL3 for its window)
  • Native window handles — used by the WEBGPU renderer and the Direct3D and Metal families: the SDL3 window’s HWND, X11 Display* and window, Wayland wl_display* and wl_surface*, or Cocoa/UIKit window, delivered as a NativeWindowHandle
  • CPU surface presentation — hands a finished software frame to the window or terminal (used by the Terminal platform with SOFTWARE)
  • Clipboard, drag-and-drop, message boxes, file dialogs, tray — host services, each capability-gated per backend
  • Android JNI Activity layer — Android platform integration
  • Emscripten main loop — WebAssembly/browser event scheduling

A renderer asks for narrow services such as a native surface, GL context or Vulkan surface. Headless and Terminal applications can still choose a full audio engine (SDL3 or ALSA); graphical applications can select Null to remove it, with the resulting no-playback boundary documented explicitly. See Platform Support for valid combinations.

Module layout

Every subsystem physically owns modules/<name>/{CMakeLists.txt, include/, src/, tests/, examples/}; consumer include spelling is unchanged because each module's include/ root reproduces the public Microsoft/... and CNA/... paths. The root CMakeLists.txt composes the modules with add_subdirectory(modules), and a configure-time validator fails the build if a production source file sits outside a declared module.

ModuleRoleCMake targetIn the CNA umbrella?
audioXNA audio and XACT; the audio device implementations (SDL3, Null, ALSA) and mixersCNA::AudioYes
c-apiExperimental C ABI 0.46.0 adapter over the C++ aggregate (the base of the C# binding CNA.NET) (libcna_c_api)CNA::CApiNo; separate shared library, CNA_BUILD_C_API (default OFF)
contentContentManager, XNB readers and writers, CNB codecs, the canonical pipeline engineCNA::ContentYes
content-pipelineBuild-time XNA Content Pipeline API, FreeType font route, FFmpeg media importers, effect-compiler serviceCNA::ContentPipelineBuildNo; linked only by the content compiler
coreBase types, TargetPlatform, the renderer identities and GraphicsRendererSelection, capability enumsCNA::CoreYes
designMicrosoft::Xna::Framework::Design type convertersCNA::DesignNo; opt-in
devicesMicrosoft::Devices sensors and vibrationCNA::DevicesYes
devices-extCNA::Devices: camera, clipboard, dialogs, tray, power, locale, URL launcherCNA::DevicesExtYes; its code compiles only with CNA_DEVICES
diagnosticsCounters, gauges, zones, frame history, trace exportCNA::DiagnosticsYes; does nothing when CNA_DIAGNOSTICS=OFF
gamer-servicesGamerServices, Guide, Avatar, local persistenceCNA::GamerServicesNo; linked explicitly, built with CNA_ENABLE_NET (default ON)
graphicsThe XNA graphics API plus renderer interfaces, descriptors and the registryCNA::GraphicsCoreYes
graphics-extThe opt-in CNAEXT extensions (CNA::Graphics, 11 public headers: retro effects, debug drawing, shader packages; see CNAEXT extensions)CNA::GraphicsExtYes; its code compiles only with CNA_CNAEXT
inputKeyboard, mouse, gamepad, touch panel and gesturesCNA::InputYes
inspectorIn-process agent, the cna-inspector bridge and its browser UICNA::InspectorNo; CNA_BUILD_INSPECTOR, link explicitly
mathVectors, matrices, quaternions, colours, bounding volumes, curves (a compiled module)CNA::MathYes
mediaMediaPlayer, MediaLibrary and the Video/VideoPlayer surface, link-complete without FFmpegCNA::MediaYes
netMicrosoft::Xna::Framework::Net over ENetCNA::NetNo; linked explicitly, built with CNA_ENABLE_NET
phoneMicrosoft::Phone shell and push notificationsCNA::PhoneNo; linked when a game names it
platformIPlatform and its six implementationsCNA::PlatformYes
renderers12 implementation families (plus shared common/d3d and common/mojoshader helpers)One cna_renderer_<family> per familyThe selected family, or the selected set
runtimeGame, GameWindow, GraphicsDeviceManager, components, the project graphics profileCNA::RuntimeYes
storageStorageDevice and StorageContainer with path containmentCNA::StorageYes
video-ffmpegOptional FFmpeg decoding backend, selected by CNA_ENABLE_VIDEOCNA::VideoFfmpegNo; linked into media only when enabled

A few dependency cycles are intentional and inherited from XNA's own semantics: graphics ↔ input (the device updates touch and mouse binding), audio ↔ media (the dispatcher pumps MediaPlayer, which plays through the mixer) and graphics ↔ the selected renderer (the factory edge). The CNA umbrella is an interface target that composes the runtime modules and the selected renderer; on native ELF GNU/Clang builds with CMake 3.27 or newer CNA_SHARED_LIBRARY defaults to ON, so executables link one libcna.so instead of each carrying a static copy of the engine.

Renderer registry, descriptors and selection

📋

Descriptors before devices

Each family publishes one GraphicsRendererDescriptor: everything GraphicsDevice must know before a renderer object exists — the window kind it needs (none, plain, OpenGL, Vulkan or Metal), whether a window or video subsystem is required, pre-window GL framebuffer attributes, adapter-level queries, declared maturity and category, and the factory. This replaces #ifdef chains inside GraphicsDevice. Every availability probe is unconditional, so “available” means “compiled in”; real failures arrive as initialization errors.

🔨

Generated registry and the descriptor gate

The build generates a registry listing the linked families with the default first; tests receive CNA_RENDERER_PRESENT_<IDENTITY> for each compiled-in family, and CNA_MULTI_RENDERER is defined when more than one is linked. The descriptor gate (CNA_BUILD_RENDERER_DESCRIPTOR_GATE, default ON) compiles every registered family's descriptor in every configuration, so a family nobody configured cannot silently rot (the Windows-SDK-bound Direct3D families are compiled by their own targets).

🔢

One list of 25, kept in sync mechanically

The identity list lives in five places — the CMake identity list, the C++ enum, the registry map, the C ABI header and the C ABI table — and scripts/check_renderer_identities.py (a CTest) holds them together. Names are exact; there are no aliases. A name outside the 14 is a configure-time error that names the offending route, never a silent fallback. C ABI values are sparse and stable, whereas the C++ enum ordinals are dense and explicitly not a contract.

🔒

Selection and latching

At run time GraphicsRendererSelection resolves, in order, an explicit SetPreferred(), the CNA_GRAPHICS_RENDERER environment variable (or the Emscripten Module.cnaPreferredRenderer property), then the build default. The selection latches when the first GraphicsDevice has successfully created a renderer; a failed attempt does not latch, so a game can catch the error and retry. Fallback is off by default; an opt-in chain or automatic fallback records every skipped renderer and why in GetFallbackHistory(), and a candidate that needs a different window kind makes CNA recreate a window it owns.

⚖

One combination rule

A multi-renderer build is checked at configure time: identities from different platform partitions — Windows-only, Emscripten-only, macOS-only — cannot mix, because one toolchain cannot target both. See Runtime renderer selection.

📡

Capabilities, not names

Because renderers differ, code asks the device: GraphicsDevice::SupportsCapability() answers 19 capabilities, and GetRendererCapabilityProfileEXT() adds 32 features, 22 limits and per-format usage. The renderer descriptors also carry CNA's own maturity (Production, Supported, Experimental) and category (Native, TranslationLayer, Software, Web, Diagnostic) per identity.

Build-time pieces outside the runtime closure

Some of the largest pieces of CNA are deliberately kept out of a shipped game's link closure.

Content pipeline

The build-time content pipeline

modules/content holds what a game needs to load content and also the canonical pipeline engine (importers, processors, writers), the XNB writer and the CNB codecs (CNB format). modules/content-pipeline holds the parts that must never ship: FreeType for .spritefont, FFmpeg-based media importers, FBX and .x readers, the external fxc service and the XNA Content.Pipeline facade (107 headers). Only cna_content_compiler (alias CNA::ContentCompiler) links it, and the cna-content executable is a tiny main over that library. The tool itself is built by default; only its optional inputs are switchable. See Content Pipeline and Command-line tools.

Optional development pieces

Diagnostics, Inspector, Design and the C ABI

CNA::Diagnostics is in the umbrella but compiles its instrumentation to nothing when CNA_DIAGNOSTICS=OFF (the default). CNA::Inspector and the cna-inspector bridge are built only with CNA_BUILD_INSPECTOR=ON, are refused on Emscripten, Android and iOS, and are linked explicitly by the games that start an agent. CNA::Design is a design-time facility that a game links only if it wants converter registration. The C ABI is a separate shared library over the C++ aggregate and needs CNA_BUILD_C_API=ON and CNA_ENABLE_NET=ON. See Diagnostics, Inspector, Framework.Design and C API.

Required sibling repositories

CNA depends on sibling C++ libraries that must be cloned adjacent to the CNA repository: sharp-runtime for every build, and easy-gl (with meta-gl) only for the GL renderers. They are not vendored inside CNA — they live at predictable relative paths and are discovered by CMake automatically. For this snapshot clone CNA and sharp-runtime on their apple/m4-stabilization branches; easy-gl and meta-gl use their default branch.

Sibling — clone at ../sharp-runtime/ (branch apple/m4-stabilization)

sharp-runtime

sharp-runtime is a C++ library that provides .NET-style type primitives for C++23. It allows CNA code to closely mirror XNA C# code structure without a managed runtime. Clone it at ../sharp-runtime/ relative to the CNA repo root, on branch apple/m4-stabilization: this snapshot requests the Resources and Xml.Serialization components, which the default branch does not contain.

Integer aliases:

  • bytecs — alias for uint8_t
  • shortcs — alias for int16_t
  • intcs — alias for int32_t
  • longcs — alias for int64_t
  • ushortcs, uintcs, ulongcs — unsigned variants

Other primitives:

  • Single — alias for float
  • String — std::string wrapper
  • IDisposable — virtual Dispose() interface
  • IEquatable<T> — Equals method interface
  • IComparable<T> — comparison interface
  • EventHandler<TArgs> — multicast delegate-style callbacks
  • List<T>, Dictionary<K,V> — collection wrappers
  • I/O primitives
  • Components CNA now requests beyond these: Collections, Threading, Text, Globalization, ComponentModel (for CNA::Design), Storage, Security.Cryptography, Xml, Resources and, off Windows, Xml.Serialization
Sibling — clone at ../easy-gl/ (the three GL identities only)

easy-gl

easy-gl wraps OpenGL, OpenGL ES and WebGL for CNA's EasyGL family, which serves OPENGLES3, OPENGL33 and WEBGL2. Clone it at ../easy-gl/ relative to the CNA repo root; it needs its own sibling ../meta-gl/. It is required only for those three identities — not needed for SDL_RENDERER, VULKAN, WEBGPU, SDL_GPU, METAL, FNA3D, HEADLESS, SOFTWARE, STUB, DIRECTX9 or DIRECTX11.

  • Abstracts GLSL shader compilation, linking, and uniform binding
  • Manages VAOs, VBOs, FBOs, textures, and renderbuffers
  • Supplies the GL/GLES/WebGL function layer for desktop and for WebGL 2 (via Emscripten); the GL context itself comes from the SDL3 platform

Everything else CNA needs is fetched at configure time when the matching renderer or option is selected (FNA3D with MojoShader, wgpu-native, SDL_shadercross) or vendored in the tree (ENet, stb, dr_libs, cgltf).

Which renderer should I choose?

Select your renderer at configure time with -DCNA_GRAPHICS_RENDERER=<NAME>. Use the table below to pick the best fit for your target platform and requirements; it lists all 14 identities.

RendererBest forScopePlatform
OPENGLES3Most Linux games2D + 3DNative GL hosts (default on Linux)
OPENGL33Desktop GL 3.3 core through EasyGL2D + 3DNative GL hosts
WEBGL2Browser games with 3D2D + 3DEmscripten only (the web default)
SDL_RENDERERPure 2D, maximum portability2D onlyAnywhere SDL3 runs (default off Linux and the web, iOS included)
VULKANLow-level GPU control and the broadest modern feature set2D + 3DAny Vulkan-capable target
SDL_GPUSDL3's GPU API, with SDL’s Direct3D 12 and Metal drivers via SDL_shadercross where enabled2D + 3DAny host SDL3's GPU API supports; needs SDL3
WEBGPUExperimenting with WebGPU, natively or in the browser2D + 3DLinux, macOS, Windows (wgpu-native) and Emscripten
DIRECTX11Native Windows 3D2D + 3DWindows only
DIRECTX9XNA pixel authenticity2D + 3DWindows only
FNA3DRunning any compiled XNA effect binary (.fxb)2D + 3DAny FNA3D + SDL3 host; cannot run ShaderEffect source
METALNative Apple GPU access on macOS and iOS2D + 3DmacOS and iOS
SOFTWAREDeterministic pixels with no GPU2D + 3DAny; off-screen (displayed by the Terminal platform)
HEADLESSFast CI of game logicno outputAny; renders nothing by design
STUBBuilds and tests that need no rendering at allno outputAny; all capabilities false

The table is a starting point, not a verdict: this snapshot exposes 14 identities across 12 families, and CNA itself says a renderer earns a place only with meaningful platform coverage, compatibility value, architectural value, or a capability the set does not otherwise cover. Judge a renderer by the scope, dependencies and platform it actually claims; see the renderer reference and the feature overview for per-renderer capabilities.

Key architectural decisions

🔒

Interface/Implementation separation

Public API headers (Microsoft/Xna/Framework/...) never include renderer headers. Renderer code never bleeds into game-facing APIs. This boundary is enforced by directory and include structure, and checked by per-module minimal-link probes in CTest.

⚙

Compact default, opt-in runtime selection

CNA_GRAPHICS_RENDERER keeps single-renderer builds small. CNA_GRAPHICS_RENDERERS opts into a compatible registry and selects before the first device, with hard failure by default and explicit fallback when requested.

📦

Vendored dependencies

SDL3, SDL3_image, and SDL3_mixer are vendored as Git submodules and built once into a persistent prebuilt cache. No system SDL packages needed. Renderer dependencies are pinned and fetched only when their renderer is selected (FNA3D with MojoShader, wgpu-native with a checked SHA-256, SDL_shadercross), and the sibling repositories are checked at configure time. This ensures reproducible builds across environments.

🧬

XNA namespace mirroring

C++ namespaces mirror XNA's hierarchy: Microsoft::Xna::Framework, Microsoft::Xna::Framework::Graphics, Microsoft::Xna::Framework::Input, etc. Reduces conceptual migration cost from XNA/MonoGame experience. Non-XNA members are marked CNAEXT, and the opt-in CNAEXT extensions live in their own CNA::Graphics namespace.

📝

sharp-runtime support layer

The sharp-runtime library provides utility and runtime support primitives that CNA's internals depend on. It builds cleanly on all supported platforms with no external dependencies of its own, and CNA links only the components it requests rather than the whole library.

🔁

Independent axes, hard exclusions

Target OS, platform, renderer and audio are chosen separately, and CNA_ENABLE_SDL can remove SDL altogether. Impossible combinations fail at configure time with a named reason instead of half-working, and reserved values are refused rather than silently substituted.

🧰

Build-time pipeline outside the runtime closure

Content compilation, FreeType, FFmpeg importers and the external effect compiler live in content-pipeline, which only the cna-content compiler links. A shipped game links the loaders, never the pipeline.

✂

A curated renderer set

Renderer count is not a goal. CNA maintains 14 public identities over 12 families, held together by an identity registry with stable, never-reused C ABI values, and a name outside that list is a configure error rather than an alias.

Key C++ features used in CNA (built as C++23)

CNA targets C++23 as a compiler floor, not a feature list: the modern standard library and language features it uses to mirror XNA's C# semantics cleanly without a managed runtime are C++17 and C++20 ones, and a text search of the module sources finds no C++23-only facility (see The C++ dialect).

Standard Library & Language Features
  • std::optional<T> — replaces XNA nullable types (Nullable<T>) for missing or unset values.
  • std::span<T> — provides buffer views in GetData()/SetData() without copying data.
  • std::string_view — zero-copy string parameters wherever a string is read but not owned.
  • std::unique_ptr<T> / std::shared_ptr<T> — RAII resource management, replacing C# using blocks and IDisposable patterns.
  • Ranges and concepts (where available) — type-safe template constraints replacing unconstrained templates.
  • [[nodiscard]] attributes — applied to Load<T>(), Begin(), and similar factory/guard calls to catch accidentally discarded return values.
  • Structured bindings — used for returning multiple values from internal helpers without heavyweight output-parameter patterns.
  • if constexpr — compile-time template branching in PackedVector implementations and format-dispatch helpers.
  • Inline variables — for static constants defined directly in header-only types without requiring a separate .cpp definition.
  • <format> — used unconditionally in the always-built content code, which is why the build effectively needs libstdc++ 13, a current libc++ or MSVC 2022.
🔬

Go deeper. This page is the user-facing map of the layers. For the maintainer view — how the layers relate in the source, who owns what, and how each subsystem behaves from construction to teardown — see the Architecture maps, the physical module dependency map, the Internals source tours (runtime, renderer selection, platform backends, audio, content) and the generated selection axes index.

Directory structure

cna/
├── modules/                          ← every source file lives in a module (23 modules)
│   ├── core/                         ← base types, renderer identities, GraphicsRendererSelection
│   ├── math/
│   ├── graphics/                     ← the XNA graphics API + renderer interfaces
│   │   ├── include/
│   │   │   ├── Microsoft/Xna/Framework/Graphics/   ← public XNA API
│   │   │   │   ├── GraphicsDevice.hpp
│   │   │   │   ├── SpriteBatch.hpp
│   │   │   │   └── Texture2D.hpp
│   │   │   └── CNA/Internal/Renderers/Common/      ← renderer interfaces and registry
│   │   │       ├── IGraphicsRenderer.hpp           ← also ISpriteBatchRenderer, ITextureRenderer
│   │   │       ├── GraphicsRendererDescriptor.hpp
│   │   │       └── GraphicsRendererRegistry.hpp
│   │   ├── src/
│   │   ├── tests/
│   │   └── examples/
│   ├── platform/                     ← IPlatform; src/ Sdl3 Headless Terminal (Windows, X11, Wayland via SDL3)
│   ├── audio/                        ← XNA audio; src/Platform: Sdl3 Alsa Null; src/Backend: Sdl3Mixer CnaMixer
│   ├── input/  media/  storage/  runtime/
│   ├── content/                      ← ContentManager, XNB reader and writer, CNB codecs
│   ├── content-pipeline/             ← build-time only: XNA Content.Pipeline API, FreeType, FFmpeg importers
│   ├── video-ffmpeg/                 ← optional FFmpeg backend (CNA_ENABLE_VIDEO)
│   ├── devices/  devices-ext/  phone/  gamer-services/  net/
│   ├── graphics-ext/                 ← CNAEXT extensions (-DCNA_CNAEXT=ON)
│   ├── design/                       ← Framework.Design converters (opt-in)
│   ├── diagnostics/  inspector/      ← optional observation layer and viewer
│   ├── c-api/                        ← experimental C ABI 0.46.0 (-DCNA_BUILD_C_API=ON)
│   └── renderers/                    ← 12 families, 14 public identities
│       ├── easygl/                   ← OPENGLES3, OPENGL33, WEBGL2
│       ├── vulkan/   sdl-gpu/   webgpu/   metal/   fna3d/
│       ├── directx9/  directx11/                               ← Windows-only
│       ├── sdl-renderer/                                       ← 2D over SDL3
│       ├── software/ headless/ stub/                           ← no GPU required
│       └── common/                   ← shared d3d and mojoshader helpers (not families)
│
├── third_party/                      ← SDL, SDL_image, SDL_mixer, draco, enet, stb, dr_libs, cgltf
├── vendor/                           ← googletest
├── tools/                            ← content (cna-content), gltf_to_cnj, gltf_to_cnb, cnj_to_cnb,
│                                        source_to_cnb, cnb_info, xna-oracle, reference dumpers
├── cmake/                            ← renderer/platform/audio selection, registry, third-party helpers
├── examples/  tests/  docs/  scripts/
└── CMakeLists.txt