XNA 4.0 Compatibility

Namespace by namespace: what is real, what is a declared boundary, and where porting actually hurts

How this page measures compatibility

CNA covers the public Microsoft.Xna.Framework namespace surface except Framework.Design. That omitted namespace is tied to the C# Windows Forms designer and has no C++ equivalent. Rather than presenting a mutable type total as a compatibility score, CNA pins public signatures with compile-time freeze tests and offers a CNA_STRICT_XNA_API purity mode, so a signature cannot drift and non-XNA surface cannot leak into XNA-shaped code without the compiler saying so.

Earlier versions of this page quoted two percentages — a type-presence figure and a functional-coverage figure. Neither was reproducible from the source tree, so both have been withdrawn rather than carried forward. What replaces them is a per-namespace judgement, stated in words, with the specific boundaries named. A number you cannot recompute is worse than a sentence you can check.

The distinction that still matters is between a type existing and a member doing the work. This page marks each namespace as one of three things: real (implemented and doing the job), real with declared boundaries (implemented, with named things it will not do), or a deliberate deviation (behaves differently from XNA on purpose). Where a boundary exists it is named here, not summarised into a score.

Namespace by namespace

NamespaceStateWhat that means in practice
Microsoft.Xna.Framework (core) Real The full math suite: Matrix's complete static factory set including Decompose, the billboard pair, shadow and reflection; every Curve loop type; the full set of named Color constants. Game is a genuine SDL loop with both fixed and variable timestep and a separate Emscripten path. The one named gap is BoundingFrustum::Intersects(Ray), which is partial.
….Graphics Real renderer-dependent Every XNA Graphics type exists, and GraphicsDevice and SpriteBatch carry their full overload sets. Behaviour below the API depends on the active one of 50 renderer identities — see the renderer reference. Compiled XNA/FNA Effect Framework bytecode works only on qualified renderer builds, as detailed below.
….Graphics.PackedVector Real The packed formats are real, built on a correct IEEE 754 half-float codec that handles subnormals, infinities and NaN in both directions.
….Audio Real named boundaries XACT is implemented rather than stubbed: wave banks are parsed and played through SDL3_mixer, and 3D audio uses FAudio's Doppler and attenuation maths. Boundaries: exactly one AudioListener is supported (a second throws); a wave bank holding XMA or WMA data logs and returns nullptr instead of playing; .m4a and .aac cannot be decoded at all, because SDL3_mixer ships no AAC decoder.
….Content Real, read-side A real XNB loader with 50 built-in type readers (49 in a build without FFmpeg), plus CNA's own .cnj JSON format and runtime glTF loading. Two things to know: the readers are not auto-registered, and CNA never writes an .xnb. See below.
….Input Real A real SDL3 gamepad bridge: rumble, trigger rumble, LED colour, hot-plug and per-device capability probing. CNA adds a large extension surface on top — clipboard, haptics, joysticks, battery, IME candidates, gamepad light bar, gyro and touchpad.
….Input.Touch Real The XNA gesture types are genuinely detected by a real state machine, wired end-to-end to SDL3's touch events.
….Media (incl. Video) Real platform-gated video Both halves are real: playback and the catalogue layer. MediaLibrary resolves the real Music and Pictures folders and scans them; MediaPlayer exposes real visualization data. The boundary is platform, not implementation: video is absent from Windows, Web and Android builds. See below.
….Net Real for SystemLink Genuine UDP with LAN broadcast discovery and measured RTT for QoS. SimulatedLatency and SimulatedPacketLoss are really implemented, with a deferred delivery queue and a seeded drop RNG. Discovery is SystemLink only, and there is nothing at all on Emscripten. NetworkMachine::RemoveFromSession() throws.
….Storage Real barely tested Real std::filesystem IO with correct player namespacing. The Begin*/End* pairs are synchronous — the callback runs inline, before Begin* returns. The whole module carries five test macros and StorageContainer has none, so treat its behaviour as read-not-run.
….GamerServices Real, local Achievements and leaderboards genuinely persist to disk and reload in a later process. What does not exist is the online half. See below.
Microsoft.Devices (incl. Sensors) Real hardware opt-in Accelerometer and Gyroscope reach a real SDL3 hardware probe on desktop Linux, Windows and macOS as well as on Android — they are not Android-only. Compass and Motion are Android-only and honestly report NotSupported elsewhere. The whole layer is built only when CNA_DEVICES=ON, which is not the default.

Compiled effects: format and renderer boundary

At 0.1.0-alpha.1, Effect(GraphicsDevice&, bytecode) and the XNB EffectReader are real for XNA/FNA D3D9 Effect Framework binary bytecode. The loader handles techniques, passes, parameters, annotations, arrays, structures, pass state, cloning, SpriteBatch use and 3D use. This is compiled Effect Framework data, commonly stored as .fxb or wrapped inside an XNB; it is not HLSL .fx source, DXBC, MGFX/.mgfxo, or an arbitrary shader binary.

Renderer support is deliberately narrow. FNA3D enables compiled effects as part of the renderer. SDL_GPU, EasyGL-family and Vulkan builds can opt in with their renderer-specific CNA_*_COMPILED_EFFECTS option, which defaults to OFF. Other renderers report no compiled-effect capability. A load on an incapable active renderer fails rather than silently substituting another shader.

CNAEXT ShaderEffect remains the portable path for renderer-native shader sources or binaries. Stock effects such as BasicEffect use a separate working path. See Effects & Shaders for the accepted formats and exact build switches.

Content: the XNB loader and its siblings

"Content pipeline" is the wrong phrase for what CNA has. A content pipeline builds .xnb files at design time. CNA only ever reads them: it consumes .xnb produced by XNA, MonoGame or FNA, and it has no ContentImporter, ContentProcessor or ContentCompiler — that side is explicitly out of scope and will not be built. The accurate phrase is XNB loader, or read-side XNB support.

Within that scope the loader is real. There are 50 built-in type readers — 49 in a build without FFmpeg, which drops VideoReader — covering the primitives, the math types, Texture2D/Texture3D/TextureCube, SpriteFont, SoundEffect, Song, the five stock effects and the model family, behind a real LZX decompressor and two-pass shared-resource resolution.

💡

The readers are not auto-registered. Call CNA::Internal::Xnb::RegisterAllBuiltInXnbReaders() once at startup or every .xnb load will fail. C++ has no reflection to discover them the way XNA does. The call currently lives in an Internal header, which is a known ergonomics gap rather than a design intent.

Three content formats, and which one wins

  • .xnb — read-only, as above. Load<T> tries this first.
  • .cnj — CNA's own JSON descriptor format, for assets you author for CNA rather than import.
  • .model.json — the older loose-file model format, still supported.

Runtime glTF loading

CNA also loads glTF 2.0 at runtime with no tooling step at all: 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; use cna_tool_gltf_to_cnj when you need unit scaling or separate per-group output assets. Multiple skins are exposed through getSkinsEXTProperty().

Alpha.1 retains unskinned rigid clips through ModelAnimationsEXT, preserves factor-only and vertex-coloured PBR, converts non-triangle primitive topologies, validates extensionsRequired, and attaches stable diagnostics through getGltfImportReportEXTProperty(). A mixed skin-plus-rigid file still loses the additional rigid tracks because Tag already carries SkinningData, but the loss is explicitly reported.

Named content gaps

  • EffectReader loads supported XNA/FNA Effect Framework bytecode only when the active renderer advertises compiled-effect capability; it rejects unsupported formats and renderer configurations.
  • .xnb files that use Intel E8 preprocessing are not decoded.
  • DDS cube maps are limited to DXT1, DXT3 and DXT5.
  • ResourceContentManager::OpenStream throws.

Media — playback and catalogue

Correction to earlier versions of this page. The Media catalogue types were once described here as API-shaped no-ops that throw on every member. That is no longer true, and it was the largest stale negative claim on the site.

MediaLibrary resolves the real Music and Pictures folders through SDL_GetUserFolder and scans them. It parses ID3v2, Vorbis, Opus and FLAC tags, probes durations through FFmpeg, finds album art, parses playlists and saves pictures. Album, Artist, Genre, Playlist, Picture and their collections are populated from that scan rather than throwing.

On the playback side, MediaPlayer plays songs through SDL3_mixer and MediaPlayer::GetVisualizationData returns a genuine FFT spectrum and waveform. VideoPlayer decodes through FFmpeg, plays the audio track and can select among multiple tracks. Microphone capture is real too.

Video is a platform question, not an implementation one. The video translation units are excluded from Windows, Emscripten and Android builds, so Video and VideoPlayer are missing symbols there. The headers still exist, which means calling code compiles happily and then fails at link time. On Linux and macOS, FFmpeg is a hard requirement: configure fails without libavcodec, libavformat, libavutil and libswresample development packages, and no option disables it.

GamerServices — local, and real

Correction to earlier versions of this page. This section previously said that nothing behind GamerServices persists and that it was a faithful port of FNA's no-op shim. That is wrong. FNA's shim is permanent; CNA's is not.

Achievements and leaderboard entries are written as JSON under <SDL_GetPrefPath>/GamerServices/, using an atomic temp-file-and-rename, and they reload in a later process. LeaderboardWriter and LeaderboardReader are real implementations with sorting, ranks and paging.

Guide::BeginShowMessageBox/EndShowMessageBox and Guide::BeginShowKeyboardInput/EndShowKeyboardInput are real too, with actual SpriteBatch overlay rendering, password masking and mouse hit-testing. Where FNA leaves permanent stubs, CNA draws the overlay.

Avatars render genuine 3D geometry through the CNAEXT AvatarRenderer::DrawRealEXT path, with real GPU skinning on a 19-bone rig, verified by pixel-readback tests. The XNA-spec Draw() deliberately stays inert, which is the faithful behaviour.

What is not there:

  • No online service. There is no sign-in against Microsoft's servers, no matchmaking and no cloud sync. Persistence is local to the machine.
  • 15 Guide::Show* overlay entry points are documented no-ops — the Begin/End pairs above are not among them.
  • Achievement::GetPicture() and PropertyDictionary::CopyTo() throw.
  • The Begin*/End* pairs are synchronous: the callback runs inline before Begin* returns. That is faithful to XNA's own fake-async, but do not lean on it to keep a frame moving.

Framework core, Graphics and PackedVector

These three are the load-bearing part of the API and the part that holds up best.

  • Framework core. The math library is complete and heavily tested: Matrix carries its full static factory set including Decompose, the billboard pair, shadow and reflection; Curve::Evaluate implements every loop type; Color defines the full named-constant set. Game is a genuine SDL loop with both fixed and variable timestep and a separate Emscripten path. The one named hole is BoundingFrustum::Intersects(Ray).
  • Graphics. Every XNA Graphics type exists, with GraphicsDevice's full event and Draw* surface and SpriteBatch's full Begin, Draw and DrawString overload sets. What differs is the renderer underneath: 50 renderer identities across 46 implementation families, with genuinely different capabilities. The default build contains one; an opt-in multi-renderer build can contain several and select one before the first device is created. Some renderers are 2D-only by design, and cube faces inside a multiple-render-target set are unimplemented on eight otherwise-capable 3D renderers. Consult the renderer reference and explicit capability reports rather than assuming the identities are interchangeable.
  • PackedVector. The packed formats are real, on a correct IEEE 754 half-float codec that handles subnormals, infinities and NaN in both directions.

Input, Touch and Sensors

  • Input is a real SDL3 bridge. Rumble, trigger rumble, LED colour, hot-plug and per-device capability probing all work, and Keys carries the full XNA key set.
  • Input::Touch genuinely detects the XNA gesture types through a real state machine wired to SDL3 touch events.
  • Microsoft::Devices and Sensors talk to real hardware. Accelerometer and Gyroscope reach a real SDL3 hardware probe on desktop Linux, Windows and macOS as well as on Android — the old claim that sensors were Android-only was wrong. VibrateController really vibrates through SDL's haptic API, deliberately excluding gamepads. Compass and Motion genuinely are Android-only, built on an NDK sensor fusion, and report NotSupported everywhere else rather than faking values.
💡

The Microsoft::Devices layer is built only when CNA_DEVICES=ON, which is not the default. A stock build does not contain it.

Audio, Net and Storage

  • Audio. XACT is implemented rather than faked: wave banks are parsed and played through SDL3_mixer, and 3D audio uses FAudio's Doppler and attenuation maths. Named boundaries: exactly one AudioListener (a second throws); XMA or WMA content in a wave bank logs to stderr and returns nullptr, so the sound is silently absent rather than an exception — note that the XNB SoundEffectReader path does throw on the same content; and .m4a/.aac cannot be decoded at all.
  • Net. Real UDP transport with LAN broadcast discovery and measured RTT for QoS, gated to NetworkSessionType::SystemLink. SimulatedLatency and SimulatedPacketLoss are genuinely implemented, with a real deferred delivery queue and a seeded RNG for drops — useful for testing a port under bad-network conditions. Discovery works for SystemLink only, and there is nothing on Emscripten. NetworkMachine::RemoveFromSession() throws.
  • Storage. Real std::filesystem IO with correct player namespacing. The Begin*/End* pairs are synchronous, running the callback inline before Begin* returns — faithful to XNA, but not a way to move work off the frame. The caveat is coverage rather than correctness: the module carries five test macros in total and StorageContainer has none.

On the Web there is no save persistence at all. Under Emscripten, SDL_GetPrefPath resolves into volatile MEMFS; CNA mounts no IDBFS and never calls FS.syncfs. Every save your game writes is silently discarded on page reload. Plan an explicit browser-storage path if you need saves on the Web.

CNAEXT: what CNA adds beyond XNA

CNA ships a substantial non-XNA surface. Every declaration that is not part of XNA 4.0 is tagged with the CNAEXT marker, and the CNA_STRICT_XNA_API option turns any use of one into a compile error — so "would this also compile against real XNA?" is a question the build system answers for you.

AreaWhat CNA adds
Shading ShaderEffect takes renderer-native custom source/binary and is separate from the XNA-compatible compiled Effect Framework path. Its actual shader dialect and execution support are renderer-dependent; query capabilities and use the renderer reference rather than treating one format as portable across all identities.
PBR PbrEffect and SkinnedPbrEffect are real glTF 2.0 metallic-roughness implementations. Sixteen implementation families consume the universal PBR draw parameters; verification ranges from pixel tests to source and native-compile contracts. The Software renderer is a separate reduced CPU cross-check.
Post-processing effects AsciiPostProcessEffect (the successor to the old ASCII renderer), CRTEffect, DepthEffect and ColorMatrixEffect.
Animation and geometry Skeletal animation, morph-target blend shapes, tangent and skinned vertex types, and the runtime glTF importer described above.
Input Clipboard, haptics, joysticks, battery state, IME candidates, and gamepad light bar, gyro and touchpad access — none of which XNA had a way to express.
The CNA:: namespace A desktop-application surface with no XNA counterpart at all: file dialogs, message boxes, system tray, URL launching, locale, display and system information, logging, and the CNA::Graphics render-pipeline settings including PbrMaterial.
💡

The CNAEXT engine layer is opt-in: CNA_CNAEXT defaults to OFF, and it is what gates AsciiPostProcessEffect, CRTEffect, DepthEffect, PbrMaterial and the CNA::Graphics surface. CNA_DEVICES, the device layer, is OFF by default too.

Is it actually usable?

The most direct evidence that CNA's XNA surface holds up under real code is the sibling cna-samples repository, which ports Microsoft's official XNA Game Studio 4.0 sample collection to C++ on CNA.

ResultDetail
63 of 86 in-scope samples ported and building Of 153 samples upstream, 67 are out of scope for CNA. Of the 86 that remain, 63 are ported and build today.
Per-sample runtime verification open campaign "Builds" is what is claimed. Whether each sample behaves correctly when run is being worked through sample by sample — so read the 63 as a compile-and-link result, not as 63 verified-working games.

Beyond the samples, cna-craft ports fogleman/Craft onto CNA with SQLite persistence, multiplayer and a WebAssembly build — its own README calls it an early prototype rather than a finished game — and cna-extended is a C++23 port of MonoGame.Extended on top of CNA. Both exercise the API from outside the project's own test suite.

💡

Honest positioning: CNA is a research-grade porting framework, not yet a ship-a-commercial-game framework. The strongest true claims are an XNA namespace surface complete but for Framework.Design and pinned by compile-time checks, a genuinely real Graphics, Input, Audio, Net, Media and Storage core, and byte-exact verification of the DIRECTX9 renderer against the real XNA runtime. The boundaries on this page are the other half of that picture.

C++ API differences from C# XNA

While CNA mirrors XNA's API surface, some differences follow unavoidably from the language:

  • No garbage collection: resources are managed with RAII and std::unique_ptr / std::shared_ptr.
  • No properties: C# properties become getter/setter methods (e.g. getGraphicsDeviceProperty() instead of the C# GraphicsDevice property).
  • No C# delegates: event semantics are preserved where XNA has them, but through C++ callback objects and virtual overrides rather than event/delegate.
  • Namespace syntax: Microsoft::Xna::Framework with :: instead of ..
  • No reflection: which is why XNB readers are registered by hand rather than discovered.
  • No extension methods, LINQ, or C#-style generics.
  • On the Web, Game must be heap-allocated. A stack-allocated Game is silently corrupted under Emscripten, with no diagnostic.

Known gaps and limitations

The headline gaps are below; the Verification & Known Issues page carries the current list in full.

  • Compiled effects are renderer-qualified — XNA/FNA D3D9 Effect Framework bytecode loads through the bytecode constructor and XNB EffectReader on FNA3D, or on opted-in SDL_GPU, EasyGL-family and Vulkan builds. HLSL .fx source, DXBC and MGFX are not accepted.
  • Renderer capability is not uniform — 50 public identities share 46 implementation families. A build defaults to one renderer; multi-renderer selection and fallback are explicit opt-ins and cannot combine every platform or graphics stack.
  • XNB is read-side only — CNA consumes .xnb and will never produce it, and the built-in readers need one explicit RegisterAllBuiltInXnbReaders() call.
  • Web caveats — no save persistence at all, no video, and Game must be heap-allocated.
  • Video is absent on Windows, Web and Android — the headers compile and the link then fails. On Linux and macOS, FFmpeg is a hard build requirement.
  • GamerServices has no online half — local persistence is real; sign-in, matchmaking and cloud sync do not exist. 15 Guide::Show* overlay entry points are documented no-ops.
  • Networking is SystemLink only, with nothing on Emscripten.
  • Audio boundaries — one AudioListener; XMA/WMA wave-bank content goes silently missing; no AAC decoder.
  • glTF mixed-animation boundary — rigid clips work on unskinned models, but extra rigid tracks in a skinned model cannot share the compatibility Tag carrier and are omitted with a diagnostic.
  • CNAEXT and device layers are opt-inCNA_CNAEXT and CNA_DEVICES both default to OFF.
  • iOS support is narrow and experimental — the tag's CI final-links an SDL_RENDERER device application and launches a one-frame simulator smoke test. It is not evidence for physical devices, pixels, or the wider renderer inventory. tvOS remains unsupported.

Intentionally excluded from CNA

  • The write side of the content pipeline — no ContentImporter, ContentProcessor or ContentCompiler. CNA reads .xnb; producing it stays with XNA, MonoGame and FNA.
  • Microsoft.Xna.Framework.Design — a Windows Forms designer namespace with no C++ equivalent, and the only XNA 4.0 namespace CNA does not cover.
  • Xbox LIVE server-side services — authentication against Microsoft's servers, matchmaking and cloud-synced saves. GamerServices persists locally instead.
  • Non-SystemLink NetworkSessionType values (PlayerMatch, Ranked) — they no-op rather than pretending, and no synthetic offline approximation is attempted.
  • Hot renderer switching — a multi-renderer build chooses before the first graphics device is created and then latches that choice. It does not switch an existing device while the game is running.

Reference resources