Layer overview

  ┌─────────────────────────────────────────────────────────────────┐
  │                    Game / Application Code                      │
  │        Uses: Microsoft::Xna::Framework API                      │
  │        Example: MyGame extends Game, calls SpriteBatch::Draw()  │
  └────────────────────────────┬────────────────────────────────────┘
                               │
                               ▼
  ┌─────────────────────────────────────────────────────────────────┐
  │               XNA-Compatible Public API Layer                   │
  │   include/Microsoft/Xna/Framework/...                           │
  │   Game · GraphicsDevice · SpriteBatch · Texture2D · Color       │
  │   Vector2/3/4 · Matrix · Rectangle · GameTime · Input           │
  └────────────────────────────┬────────────────────────────────────┘
                               │
                               ▼
  ┌─────────────────────────────────────────────────────────────────┐
  │        CNA Internal Abstraction Layer (sharp-runtime support)   │
  │   include/CNA/Internal/Renderers/...                            │
  │   IGraphicsRenderer · ISpriteBatchRenderer · ITextureRenderer   │
  │   Registry · descriptors · GraphicsRendererSelection           │
  └──────────┬───────────────┬──────────────┬───────────────────────┘
             │               │              │
             ▼               ▼              ▼
  ┌──────────────┐  ┌──────────────┐  ┌────────────────────────────┐
  │ OPENGLES3    │  │  VULKAN      │  │  DIRECTX11 · METAL · BGFX  │
  │ WEBGL2 · …   │  │  SDL_GPU     │  │  CANVAS · SOFTWARE · …     │
  │              │  │              │  │  (50 identities total)     │
  └──────┬───────┘  └──────┬───────┘  └──────────────┬─────────────┘
         │                 │                         │
         └─────────────────┴──────────────────────────┘
                               │
                               ▼
  ┌─────────────────────────────────────────────────────────────────┐
  │   Independent host and audio services                           │
  │   CNA_PLATFORM: SDL3 · SDL2 · HEADLESS · TERMINAL               │
  │   CNA_AUDIO_PLATFORM: SDL3 · SDL2 · NULL                        │
  └─────────────────────────────────────────────────────────────────┘

Every renderer family publishes a descriptor and namespaced factory into a generated runtime registry. A normal build emits one entry; CNA_GRAPHICS_RENDERERS can emit a compatible set. The 50 public identities include five EasyGL profiles and the newer TINYGL, IGL, PIXIJS and NANOVG identities. See the renderer reference.

Detailed architecture diagram

CNA detailed architecture diagram

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.

Layer 2 - Public API

XNA-Compatible API Layer

Lives under include/Microsoft/Xna/Framework/. 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.

Layer 3 - Internal Abstractions

CNA Internal Layer & sharp-runtime Support

Lives under modules/graphics/include/CNA/Internal/Renderers/, in the CNA::Internal::Renderers namespace. It defines renderer interfaces plus the descriptor/registry contract used before a device exists. GraphicsRendererSelection 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>/: 46 implementation families carrying 50 identities. Platform implementations separately implement CNA::Platform::IPlatform; audio implementations separately implement the audio device surface. The target OS is a fourth concern, reported by CNA::TargetPlatform.

SDL3 and SDL2

SDL3 remains the default platform and audio selection, but it is no longer inseparable from CNA. CNA_PLATFORM=SDL2 uses the real SDL 2.30 API, while Headless and POSIX Terminal avoid a graphical host. Audio-device code may independently be SDL3, SDL2 or Null; only SDL3 defines SOUND_ENABLED and supplies alpha.1's high-level SDL3_mixer playback/decoding engine.

  • SDL3_mixer uses the MIX_Mixer model with track-based, per-mixer channels — unlike SDL2_mixer's global audio system.
  • SDL3_image is used for texture/image loading.
  • All three libraries (SDL, SDL_image, SDL_mixer) are vendored as Git submodules under third_party/. No system SDL install is required by default; pass -DCNA_USE_SYSTEM_SDL=ON to use system packages instead.

The platform service contract covers:

  • WindowingSDL_Window creation and management
  • Event loop — cross-platform event pumping
  • InputSDL_Keyboard, SDL_Mouse, SDL_Gamepad, SDL_Touch
  • Audio initialisation — SDL3_mixer setup
  • OpenGL context creation — used by the EasyGL renderer
  • Vulkan surface creation — used by the VULKAN renderer
  • Native surface creation — used by the WEBGPU renderer (Win32/Metal/X11/Wayland surfaces built directly from SDL3 window properties, no separate compatibility library needed)
  • 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 the full SDL3 audio engine; graphical applications can select Null to remove it, with the resulting no-playback boundary documented explicitly. See Platform Support for valid combinations.

Required sibling repositories

CNA depends on two sibling C++ libraries that must be cloned adjacent to the CNA repository. They are not vendored inside CNA — they live at predictable relative paths and are discovered by CMake automatically.

Sibling — clone at ../sharp-runtime/

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.

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
  • Stringstd::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
Sibling — clone at ../easy-gl/ (OPENGLES3 renderer only)

easy-gl

easy-gl wraps OpenGL ES 3.0/3.2 for CNA's OPENGLES3 renderer. Clone it at ../easy-gl/ relative to the CNA repo root. It is required only for the OPENGLES3 renderer — not needed for SDL_RENDERER, VULKAN, BGFX, WEBGPU, HEADLESS, SOFTWARE, DIRECTX11, or DIRECTX12.

  • Abstracts GLSL shader compilation, linking, and uniform binding
  • Manages VAOs, VBOs, FBOs, textures, and renderbuffers
  • Provides the OpenGL context for both Linux desktop (OpenGL 3.0+ with ES emulation) and WebGL 2 (via Emscripten)

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.

RendererBest forScopePlatform
OPENGLES3Most Linux and Android games2D + 3DDesktop/mobile GL (default on Linux)
WEBGL2Browser games with 3D2D + 3DEmscripten only (the web default)
SDL_RENDERERPure 2D, maximum portability2D onlyAnywhere SDL3 runs (default elsewhere)
VULKANLow-level GPU control2D + 3DAny Vulkan-capable target
DIRECTX11Native Windows 3D2D + 3DWindows only
DIRECTX9XNA pixel authenticity2D + 3DWindows only
FNA3DRunning XNA's real compiled stock effects2D + 3DAny; cannot compile custom shaders
METALNative macOS2D + 3DmacOS only
CANVASBrowser 2D with no GPU context2D onlyEmscripten only
SKIA2D vector rasterisation2D onlyAny; needs a pre-built Skia
SOFTWAREDeterministic pixels with no GPU2D + 3DAny; never presents to a window
HEADLESSFast CI of game logicno outputAny; renders nothing by design

This is a starting point, not the full list: the tag exposes 50 identities across 46 families. Judge a renderer by the scope, dependencies and platform it actually claims; see the renderer reference.

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.

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. No system SDL packages needed. bgfx is fetched via CMake FetchContent. 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.

📝

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.

Key C++23 features used in CNA

CNA targets C++23 and uses several modern standard library features to mirror XNA's C# semantics cleanly without a managed runtime.

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.

Directory structure

cna/
├── modules/                          ← every source file lives in a module
│   ├── core/
│   ├── 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/            ← renderer interfaces
│   │   │       ├── Common/IGraphicsRenderer.hpp
│   │   │       ├── ISpriteBatchRenderer.hpp
│   │   │       └── ITextureRenderer.hpp
│   │   ├── src/
│   │   ├── tests/
│   │   └── examples/
│   ├── graphics-ext/                 ← CNAEXT engine layer (-DCNA_CNAEXT=ON)
│   ├── content/  audio/  input/  media/  net/  storage/
│   ├── devices/  devices-ext/  gamer-services/  runtime/
│   └── renderers/                    ← 46 families, 50 public identities
│       ├── easygl/                   ← OPENGLES2/3, OPENGL33, WEBGL1/2
│       ├── vulkan/   sdl-gpu/   bgfx/   webgpu/   metal/
│       ├── directx1/ … directx12/    ← the Windows Direct3D ladder
│       ├── canvas/   html-dom/  svg-dom/         ← Emscripten-only
│       ├── skia/     blend2d/   openvg/          ← 2D vector rasterizers
│       └── software/ portablegl/ headless/ stub/ ← no GPU required
│
├── third_party/                      ← SDL, SDL_image, SDL_mixer, cgltf, enet, stb
├── tools/                            ← gltf_to_cnj, xna-oracle, reference dumpers
├── cmake/                            ← CMake helpers and renderer selection
├── examples/  tests/  docs/  scripts/
└── CMakeLists.txt