Frequently Asked Questions

Common questions about CNA

CNA is the project name. It reflects the C++ nature of the reimplementation and draws on the XNA lineage. It is not an official acronym - think of it as "C++ native approach to XNA" or simply the project identifier for this open-source effort.

0.1.0-alpha.1 is the first tagged pre-release. It is suitable for C++ porting experiments, research and demos, but public APIs may still change before 1.0. Its experimental native C ABI source surface is not consumable at this tag because the final implementation fails a renderer-identity count assertion.

What is real: CNA covers the public XNA 4.0 namespace surface except Framework.Design, and Graphics, Input, Audio, Net, Media and Storage contain genuine implementations rather than only API-shaped shims. Achievements and leaderboards persist to disk, and MediaLibrary scans real user folders.

What to plan around: renderer capabilities vary widely; compiled XNA/FNA Effect Framework bytecode works only on qualified builds and is not HLSL .fx source support; multi-renderer selection is opt-in and latches before device creation; and the Web target has real persistence and media caveats. Start from Releases, XNA Compatibility and Verification & Known Issues.

FNA is an excellent managed C# reimplementation of XNA 4.0. It targets the .NET runtime, is binary-compatible with XNA 4.0, and is used commercially. CNA is a completely separate, C++-only project. It does not provide C# bindings. It targets engineers who need or want native C++ - no managed runtime, no garbage collector. CNA shares the Ms-PL licence with FNA and draws on it as a reference, but the two projects are independent and serve different ecosystems.

A couple of places where CNA deliberately goes further than FNA: FNA's GamerServices is a permanent no-op shim, while CNA persists achievements and leaderboards to local disk, and FNA's Guide message-box and keyboard-input paths are stubs where CNA draws a real overlay. CNA also uses a running FNA build as one of its verification oracles — a harness dumps FNA's reference values to JSON and a script diffs CNA's against them.

MonoGame is a cross-platform C# successor to XNA used commercially to ship games. It is mature, production-tested, and C#-based. CNA is a C++ project with a different target audience - engineers building in C++ who want an XNA-style framework without a managed runtime. Both MonoGame and FNA are better choices if you want to build games in C# today. CNA is for the C++ ecosystem specifically.

One practical relationship worth knowing: MonoGame's content pipeline is a perfectly good way to produce the .xnb files that CNA reads. CNA has no build-side content pipeline of its own and does not plan one.

Several reasons:

  • No managed runtime: C++ avoids garbage collection pauses, managed heap overhead, and JIT warmup. Useful for performance-critical or embedded scenarios.
  • Toolchain flexibility: C++ integrates naturally with any C or C++ codebase, LLVM toolchains, console SDKs, and embedded targets that may not support .NET.
  • API preservation: The XNA programming model is genuinely good design. Preserving it in C++ gives the XNA conceptual clarity to the C++ ecosystem.

CNA is built to the C++23 standard and needs CMake 3.20 or newer. If you want to build games in C# today, FNA and MonoGame are the right tools. CNA fills a different niche.

No. CNA is an independent open-source project with no affiliation with or endorsement by Microsoft Corporation. XNA is referenced as the compatibility target and API inspiration only. XNA is a trademark of Microsoft. CNA does not use any Microsoft or XNA branding assets.

CNA is licensed under the Microsoft Public License (Ms-PL). This is the same licence used by FNA, reflecting that portions of CNA draw on FNA as a reference. The Ms-PL is a permissive open-source licence. See the LICENSE file for the full terms.

Start with the default for your platform and change it only when you have a reason. The defaults are WEBGL2 under Emscripten, OPENGLES3 on Linux, and SDL_RENDERER everywhere else. You pick one at configure time with -DCNA_GRAPHICS_RENDERER=<NAME>, or the equivalent -DCNA_RENDERER_<NAME>=ON — do not mix the two forms.

Things that will narrow the choice for you before taste does:

  • Platform gates are hard errors. Fourteen renderers are Windows-only — the eleven DirectX renderers from DIRECTX1 to DIRECTX12, plus DIRECT2D, GLIDE and GDI, with GLIDE additionally needing a 32-bit toolchain. METAL is macOS-only. WEBGL1, WEBGL2, CANVAS, HTML_DOM, SVG_DOM and PIXIJS are Emscripten-only. Configuring the wrong one stops CMake with a FATAL_ERROR.
  • Several renderers are 2D-only by design and throw deterministically on 3D calls — SDL_RENDERER, DIRECT2D, CANVAS, HTML_DOM, SKIA, BLEND2D, FREEDIRECT, DIRECTX1, GDI, SVG_DOM and OPENVG.
  • Two produce no pixels at all by design: HEADLESS and STUB, which are for validating game logic and call correctness. SOFTWARE and PORTABLEGL rasterize for real but never present to a window — you read pixels back with GetBackBufferData().
  • Custom shaders do not run everywhere. See the shader question below.

What you will not find on this site is a single maturity ranking of all 50 identities. The renderer reference instead records checkable platform, dependency and capability boundaries.

The 50 public renderer identities live in 46 implementation families, and the breadth is a statement about the abstraction rather than a promise that all 50 are equally complete. If a single IGraphicsRenderer interface can be satisfied by DirectX 3, WebGPU, a CPU rasterizer, an SVG DOM and Metal, then the interface is genuinely doing its job.

Two details explain most of the count. First, the DirectX line is covered version by version — eleven separate renderers from DIRECTX1 to DIRECTX12 — which is a deliberate historical exercise as much as a practical one. Second, five identities — OPENGLES2, OPENGLES3, OPENGL33, WEBGL1 and WEBGL2 — share one internal implementation (EasyGL) distinguished by a CNA_GL_PROFILE_* define. Those five are not cosmetic variants: OPENGLES2 and WEBGL1 genuinely lose multiple render targets, occlusion queries, Texture3D, instancing and multi-stream vertex input.

The default keeps one renderer per build. CNA_GRAPHICS_RENDERERS can opt into several compatible implementations with pre-device runtime selection and fallback, at the cost of additional dependencies, build time and binary size. CNA's 21 workflows still do not cover every identity, driver and platform combination.

Yes, and Windows has the widest renderer selection of any platform: fourteen renderers are Windows-only, including the eleven DirectX renderers from DIRECTX1 to DIRECTX12, plus DIRECT2D, GDI and GLIDE. SDL_RENDERER is the default there.

Two caveats to hold on to. First, the repository offers manual Linux-to-Windows cross-build and Wine + DXVK/vkd3d-proton validation paths, but no automatic Wine workflow; native-MSVC workflows are manual-dispatch too. Second, video is absent from Windows builds entirely — the video translation units are excluded, so Video and VideoPlayer compile against their headers and then fail to link. Reproducible real-Windows-hardware results remain especially valuable.

Yes. macOS has the METAL renderer and, unusually for this project, real automatic CI — a macos-14 runner builds it on every push and pull request. FFmpeg is a hard build requirement on macOS as it is on Linux, so install the libavcodec/libavformat/libavutil/libswresample development packages before configuring.

Alpha.1 also has a narrow experimental iOS path, restricted to SDL_RENDERER. CI final-links a device application and launches a one-frame simulator smoke test; it does not establish physical-device, pixel, audio or broader renderer support. tvOS remains unsupported.

Both, with caveats you should read before you start.

For the browser, CNA builds through Emscripten and offers six identities: WEBGL2 (the default), WEBGL1, CANVAS, HTML_DOM, SVG_DOM and PIXIJS. The three caveats are real and none of them produce a helpful error message:

  • There is no save persistence at all. Under Emscripten SDL_GetPrefPath resolves into volatile MEMFS; CNA mounts no IDBFS and never calls FS.syncfs, so every save is silently discarded on page reload. If your game needs saves in the browser, you need your own browser-storage path.
  • There is no video. The video translation units are excluded from Emscripten builds, so Video/VideoPlayer code compiles and then fails to link.
  • Game must be heap-allocated. A stack-allocated Game is silently corrupted under Emscripten. There is no diagnostic; it simply misbehaves.

For Android, the code paths and the NDK sensor implementations exist, and Compass and Motion are implemented there specifically. But Android has no automatic CI at all, and video is excluded from Android builds too. See Platforms for the per-platform detail.

The alpha.1 tree has 568 C++ test sources and 8,263 statically discoverable GoogleTest-family definitions. Those are source-inventory counts, not a universal executable or pass count. CTest registration varies with renderer set, platform, audio implementation, host and feature options; report ctest -N for the configuration you actually built.

The most rigorous check is the 39-scene XNA oracle corpus: scenes rendered by real XNA 4.0 and diffed byte for byte. DIRECTX9 matches all 39 at tolerance 0. That is a statement about DIRECTX9 specifically — other renderers match far fewer, and CNA does not claim that all renderers are pixel-perfect.

The tag contains 21 workflow files covering important Linux, Apple, Emscripten, platform-abstraction, multi-renderer and declared C API gates; Windows D3D/GDI lanes are manual. The C API final target is compile-blocked, and this inventory still does not exhaust every renderer/driver combination or the full GPU pixel/oracle matrix. Verification & Known Issues has the scoped inventory.

CNA is open source under Ms-PL. The most valuable contributions at this stage are:

  • Reproducible native-Windows verification for the DirectX renderers; the tag's Wine/DXVK and vkd3d-proton paths and MSVC workflows are manual, not continuous gates
  • CI coverage for renderer, driver and platform combinations not exercised by the alpha.1 workflows
  • Tests for the thin spots, above all Storage, whose module carries five test macros and whose StorageContainer has none
  • glTF follow-through — remove the reported mixed skin/rigid Tag carrier boundary and close renderer-qualified extension gaps
  • Per-sample runtime verification in cna-samples, where "builds" is currently the claim rather than "runs correctly"
  • Porting games to CNA to expose API gaps

Open a GitHub issue or pull request at github.com/openeggbert/cna. Check the TODO list and existing issues first.

sharp-runtime is a C++ reimplementation of a narrow subset of the .NET API that CNA's internals depend on. It is roughly 158,000 lines across 41 selectable modules, with over 14,000 tests of its own (its README reports 14,070 passing as of 2026-07-29). It provides primitives CNA uses internally but does not expose through the game-facing API.

It must be cloned as a sibling directory next to CNA before building — it is a separate checkout, not a submodule, and every CNA build needs it.

Siblings next to cna/, all separate clones rather than submodules:

  • ../sharp-runtime — required by every build.
  • ../easy-gl (which itself needs ../meta-gl) — required by the five GL-profile renderers, which includes the Linux default OPENGLES3. So a plain default Linux build needs three siblings, not one.
  • ../free-direct (which uses ../free-api) — required only by FREEDIRECT.

On Linux and macOS you also need the FFmpeg development packages — libavcodec, libavformat, libavutil, libswresample — because FFmpeg is a hard requirement there and configure fails without them. Inside the repository, git submodule update --init is correct; the recursive form is unnecessary and much slower. See Building.

Not for every architectural layer. Alpha.1 separates host platform integration, graphics rendering and audio-device selection. CNA_PLATFORM selects SDL3, real SDL 2.30, Headless or POSIX Terminal; CNA_AUDIO_PLATFORM independently accepts SDL3, SDL2 or Null. However, only SDL3 audio defines SOUND_ENABLED and links the SDL3_mixer engine used by XNA playback, decoding, MediaPlayer and XACT. SDL2/Null are real low-level device/configuration selections, not equivalent high-level audio engines. Some combinations are rejected — for example, an SDL2 platform/audio build cannot use renderer families that directly require SDL3.

Yes, for reading. CNA has an XNB loader with 50 built-in type readers (49 in a build without FFmpeg, which drops VideoReader), covering the primitives, the math types, textures, SpriteFont, SoundEffect, Song, the five stock effects and the model family, behind a real LZX decompressor.

Two things to know before your first load:

  • The readers are not auto-registered. Call CNA::Internal::Xnb::RegisterAllBuiltInXnbReaders() once at startup or every .xnb load fails. C++ has no reflection to discover them the way XNA does.
  • CNA never writes an .xnb. It is read-side only: it consumes files produced by XNA, MonoGame or FNA. There is no ContentImporter, ContentProcessor or ContentCompiler, and building one is explicitly out of scope. "XNB loader" is the accurate phrase; "content pipeline" is not.

Alongside .xnb, ContentManager reads CNA's .cnj descriptors and older loose-file .model.json; models can also load from .gltf/.glb. EffectReader is real in alpha.1 for XNA/FNA D3D9 Effect Framework bytecode when the active renderer supports compiled effects. Custom XNB readers can be registered explicitly, though CNA has no reflection-based discovery. See XNB Content Pipeline and ContentManager.

Yes, with no tooling step. Drop a .gltf or .glb into the content root and call Content.Load<Model>("name"). The importer uses vendored cgltf 1.15 and is unconditional. It handles skeletal and rigid animation, morph targets, LINEAR/STEP/CUBICSPLINE interpolation, build-dependent Draco decoding and the material/scene extensions classified by its source-owned registry.

The runtime path imports every mesh group into one Model, exposes every skin through getSkinsEXTProperty(), retains unskinned scene-node clips through ModelAnimationsEXT, and preserves factor-only and vertex-coloured PBR materials. It also converts strip/fan/loop topologies and rejects unsupported required extensions up front.

Use cna_tool_gltf_to_cnj when you need a unit scale other than 1.0 or prefer one output asset per mesh group. Read getGltfImportReportEXTProperty() for named diagnostics. One alpha boundary remains important: when skins and extra rigid tracks share a file, Tag is occupied by the compatibility SkinningData, so the additional rigid tracks are omitted with a diagnostic. See Model Loading.

Yes, with the default CNA_AUDIO_PLATFORM=SDL3. XACT is implemented rather than stubbed: the .xgs/.xsb/.xwb binary formats are parsed and played back through SDL3_mixer, with real category and cue lifecycle management and 3D positioning. Basic playback through SoundEffect, SoundEffectInstance, DynamicSoundEffectInstance and MediaPlayer/Song uses the same path. SDL2/Null audio selections omit that mixer-dependent engine at alpha.1.

The boundaries worth knowing: 3D audio supports exactly one AudioListener and a second one throws; a wave bank containing XMA or WMA data does not throw but logs to stderr and returns nullptr, so the sound is simply missing (the XNB SoundEffectReader path does throw on the same content); and .m4a/.aac cannot be decoded at all, because SDL3_mixer ships no AAC decoder. See Audio System.

Yes, through two distinct paths. CNAEXT ShaderEffect accepts renderer-native source or binaries and works with SpriteBatch, post-processing and direct 3D draws. The XNA-compatible Effect(GraphicsDevice&, bytecode) and XNB EffectReader accept XNA/FNA D3D9 Effect Framework binaries on FNA3D or opted-in EasyGL-family, SDL_GPU and Vulkan builds. CNA does not compile HLSL .fx source or parse DXBC/MGFX as that format.

Where they actually execute: the five GL-profile renderers, OPENGL2, OPENGL4, VULKAN, SDL_GPU, SOKOL, LLGL, MAGNUM, DIRECTX9, DIRECTX11 and DIRECTX12. HEADLESS records them without drawing. BGFX and SOFTWARE accept and silently ignore them, which is the failure mode most likely to waste your afternoon. GDI, METAL, HTML_DOM and SVG_DOM throw, and FNA3D cannot compile custom shaders at all. See Shader Effects.

On desktop, yes. This page and others used to say the opposite, and that was wrong. Achievements and leaderboard entries are written as JSON under <SDL_GetPrefPath>/GamerServices/ with an atomic temp-file-and-rename, and they reload in a later process. LeaderboardWriter and LeaderboardReader are real, with sorting, ranks and paging. Storage is real std::filesystem IO with correct per-player namespacing.

Three qualifications. Persistence is local — there is no Xbox LIVE sign-in, no matchmaking and no cloud sync. The Begin*/End* pairs on both Storage and GamerServices are synchronous: the callback runs inline before Begin* returns, faithful to XNA's own fake-async but no way to move work off the frame. And on the Web nothing persists at all — Emscripten's pref path is volatile memory and every save is discarded on reload.

easy-gl is a toolkit-independent C++20 wrapper over OpenGL and OpenGL ES. It is a sibling repository to CNA (../easy-gl, itself needing ../meta-gl) and is required by the five GL-profile renderers: OPENGLES2, OPENGLES3, OPENGL33, WEBGL1 and WEBGL2. Since OPENGLES3 is the Linux default and WEBGL2 the Emscripten default, most people need it.

"EasyGL" is also the name used for that shared internal implementation inside CNA — it is not itself a selectable renderer value. Passing -DCNA_GRAPHICS_RENDERER=EASYGL is a configure error today; name the profile you want instead.

CNAEXT marks every declaration in CNA's headers that is not part of the XNA 4.0 public API. Some are small ergonomics — C++ iterator support, convenience constructors — and some are substantial capabilities XNA never had: ShaderEffect, PbrEffect and SkinnedPbrEffect, skeletal animation, the post-process effects (AsciiPostProcessEffect, CRTEffect, DepthEffect, ColorMatrixEffect) and the whole CNA:: desktop-application surface.

The marker is enforceable, not decorative: build with -DCNA_STRICT_XNA_API=ON and any use of a CNA extension becomes a compile error, which answers "would this code also compile against real XNA?" mechanically. Note that the CNAEXT engine layer is opt-in — CNA_CNAEXT defaults to OFF, as does CNA_DEVICES for the device layer. (The older name for this marker was NOXNA; it is CNAEXT now.)

Both. The XNA gesture types are genuinely detected by a real state machine wired end-to-end to SDL3's touch events, and the TouchPanel API is fully connected to it.

Sensors are not Android-only, contrary to what this site used to say: Accelerometer and Gyroscope reach a real SDL3 hardware probe on desktop Linux, Windows and macOS as well as on Android. Compass and Motion genuinely are Android-only, built on an NDK sensor fusion, and report NotSupported elsewhere rather than faking values. The whole device layer is built only when CNA_DEVICES=ON, which is not the default. See Sensors.

The mechanical changes are: (1) namespace syntax, Microsoft.Xna.FrameworkMicrosoft::Xna::Framework; (2) properties become getter/setter methods, game.GraphicsDevicegame.getGraphicsDeviceProperty(); (3) memory management, replacing new/IDisposable patterns with std::unique_ptr; (4) events, where C# delegates become virtual method overrides; (5) no LINQ, extension methods or reflection.

Content is easier than it used to be: your existing .xnb files load directly, once you call RegisterAllBuiltInXnbReaders() at startup. You can also author .cnj descriptors or drop glTF files straight into the content root. XNA/FNA D3D9 Effect Framework binaries can come across on FNA3D or an explicitly enabled SDL_GPU, EasyGL-family or Vulkan build. HLSL .fx source, DXBC, MGFX and renderer-native shaders are different inputs; use the active renderer's ShaderEffect path when an effect does not fit the compatible binary path. The porting checklist in the CNA repository (CHECKLIST.md) documents the systematic deviations from FNA/XNA conventions, and Migration from MonoGame walks through the process.