XNA 4.0 Compatibility

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

How this page measures compatibility

At this snapshot every documented public type and member of the ten Microsoft XNA 4.0 runtime assemblies has a matching C++ declaration in CNA: 331 of 331 types and 3,627 of 3,627 members — including the Microsoft.Xna.Framework.Design converters, which alpha.1 listed as the one namespace it did not cover. That is a measurement of representation: a symbol with the documented shape exists. It is not a claim that every member behaves like Microsoft's runtime. Behaviour is judged namespace by namespace below, and it is verified against the real runtime only for the subsets named on the Verification & Known Issues page.

ⓘ

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 were withdrawn rather than carried forward. What replaced them was a per-namespace judgement, stated in words, with the specific boundaries named, and that judgement is still how behaviour is reported here. What is new in this snapshot is a reproducible, machine-generated representation census, described below with exactly what it does and does not count. A number you cannot recompute is worse than a sentence you can check, so the census is quoted together with its method.

What 331/331 and 3,627/3,627 mean

QuestionAnswer at this snapshot
Reference inventoryMicrosoft's own XNA 4.0 runtime XML documentation (ten files: Framework, Avatar, Game, GamerServices, Graphics, Input.Touch, Net, Storage, Video, Xact) plus the matching Microsoft DLL metadata, with a SHA-256 recorded for every file. It is not FNA. The build-time Content Pipeline XML is excluded (it has its own, separate census).
Types331/331 represented: 329 exactly, and 2 as host-language substitutions (the generic ContentTypeReader<T> family and generic IPackedVector<T>). Six nested public enumerator types are counted separately, 6/6.
Members3,627/3,627 = 253 constructors + 1,518 methods + 1,040 properties + 753 fields + 63 events. Operators (145), indexers (29) and enum values (661) are subsets inside those rows, not extra ones.
How each match is classified1,746 exact, 1,823 semantic, 58 host-language substitution; 0 missing, 0 needing review, 0 exempted. The 1,039 semantic properties are semantic because C++ spells them getXProperty()/setXProperty().
What “represented” requiresA public or protected C++ declaration whose signature shape matches: overloads, generic arity, ref/out, static ownership, return type, accessor pairs, enum numeric values. An ambiguous match is never credited.
What is not claimedBehaviour, exception detail and messages, event delivery, renderer output, CLR serialization semantics, and the availability of online services. The generated JSON records behavior_assessed: false for all 3,627 entries. Not counted at all: public members Microsoft's XML does not document, private members, the Windows Phone assemblies (Microsoft.Devices/Microsoft.Phone are separate), and the Content Pipeline (128/128 types and 705/705 members, its own generated report, a build-time tool).
How it is producedA manual Python script, tools/audit_xna_runtime_surface.py --write-reports, which runs Clang over CNA's public headers and compares them with the reference corpus. The corpus lives outside the CNA repository, so the census cannot be re-run from a plain clone. The script has its own unit tests; it is not a CTest and not a CI job.
What guards itNothing gates the 3,627 in CTest or CI. Compile-time signature-freeze tests exist for one namespace, Microsoft.Xna.Framework.Input. CNA_STRICT_XNA_API is a compile definition (not a CMake option): its only automated check, cna_strict_xna_api_check, covers Microsoft::Devices/Sensors and runs in the Devices workflow.
HistoryThe first census found 3,463/3,627 (95.48%); the gaps were closed by 2026-09-21. CNA's own README.md, docs/coverage.md and docs/xna-4-api-coverage.md still print the older 3,467 / 95.59% figure; the generated docs/xna-4-runtime-member-coverage.md is the current one.

Where the 3,627 live

Declaring namespaceMembersNotes
Microsoft.Xna.Framework (core, math, Game)1,009Includes Game, GameTime, the math value types and bounding volumes.
….Graphics823 (+20)The extra 20 are the four model-collection enumerators.
….Graphics.PackedVector196
….Input318
….Input.Touch60 (+5)TouchCollection::Enumerator.
….Media (incl. Video)211
….Audio (incl. XACT)152
….Content62Runtime side; the Pipeline is separate.
….Design53The thirteen converters — Framework.Design.
….GamerServices (incl. Avatar)501 (+5)GamerCollection<T> enumerator.
….Net177
….Storage35

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. One project rule shapes the third category: since September 2026, where a measured Microsoft XNA 4.0 behaviour and FNA disagree, XNA wins, and each divergence is recorded; FNA remains the day-to-day readable reference, and API shape comes from Microsoft's XML and DLL metadata.

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 platform loop with fixed and variable timestep and a separate Emscripten path. Since this snapshot the game clock is XNA's: with a fixed time step the first Update runs with an elapsed time of zero and TotalGameTime advances after Update returns (the Emscripten frame body keeps its own fixed-step clock). Vector3::Transform, matrix products and inversion, and BoundingSphere::CreateFromPoints reproduce XNA's 32-bit x87 accumulation (Vector3 length and distance still sum in float). Among the named gaps is BoundingFrustum::Intersects(Ray), which is partial where XNA 4.0 computes a real entry distance: it returns “no hit” for an origin outside (even when the ray crosses the frustum), 0 for an origin inside, and throws NotImplementedException only for an origin on the boundary; BoundingSphere and BoundingBox Contains(BoundingFrustum) also never answer Disjoint (see Known Issues).
….Design Real opt-in Thirteen TypeConverters for the math value types (Point through Ray), culture-aware, with property descriptors, CreateInstance and InstanceDescriptor. It is the separate target CNA::Design, not part of the CNA umbrella, and it has no property-grid UI. See Framework.Design.
….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 14 renderer identities — see the renderer reference. The default GraphicsProfile is Reach and is now enforced on every renderer (multiple render targets, occlusion queries, 32-bit indices, float targets and large cubes throw unless HiDef is requested). State objects follow XNA's binding rule: mutating one after it was bound to a device throws InvalidOperationException. 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. Float construction of the 14 integer-packed types saturates, rounds ties-to-even and packs NaN as zero, as measured on the genuine XNA 4.0 runtime (68 recorded measurements); the three half-float types use the IEEE half codec.
….Audio Real named boundaries XACT is implemented rather than stubbed: wave banks are parsed and played through the selected audio mixer (SDL3_mixer with the SDL3 audio choice, CNA's own mixer with ALSA), and 3D audio follows XNA's Doppler and attenuation rules. Any positive AudioListener count is accepted and the nearest listener decides; zero or a null array throws. Boundaries: a wave bank holding XMA or WMA data logs and returns nullptr instead of playing; the reverb send is a no-op; .m4a and .aac cannot be decoded at all. With the Null audio choice the XACT engine compiles but produces no audible output.
….Content Real A real XNB loader with 61 built-in type readers (60 in a build without native 128-bit integer support), CNA's own .cnb binary and .cnj JSON formats, and runtime glTF loading — plus, new in this snapshot, a build-time content pipeline (cna-content) that writes .cnb and .xnb. Game registers the built-in readers for you. See below.
….Input Real A real gamepad bridge on the default SDL3 platform: rumble, trigger rumble, LED colour, hot-plug and per-device capability probing. CNA adds a large extension surface on top — clipboard (now MIME-typed), 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. Mouse-to-touch emulation is an opt-in CNA extension and is off by default, as in XNA/FNA.
….Media (incl. Video) Real build-gated video Both halves are real: playback and the catalogue layer. MediaLibrary resolves the real Music and Pictures folders through the selected platform and scans them; MediaPlayer exposes real visualization data. The boundary is a build option, not a link error: video decoding needs the optional FFmpeg backend (CNA_ENABLE_VIDEO, found automatically on Linux and macOS); without it the Video/VideoPlayer types still link and file-backed playback throws NotSupportedException. See below.
….Net Real online via the CNA server SystemLink is genuine UDP (ENet) with LAN broadcast discovery and works offline; the in-process Local type works for gamers, events and state transitions. PlayerMatch and Ranked work through the optional CNA Gamer Services server: its session directory and an authenticated relay (no peer-to-peer or NAT traversal), with invitations, host migration, extra local gamers and Opus voice. SimulatedLatency and SimulatedPacketLoss are really implemented. Discovery and the relay are absent in browser builds; online sessions refuse guests and online QoS is unavailable. See Gamer Services & Avatars.
….Storage Real lightly tested Real std::filesystem IO with correct player namespacing and, new in this snapshot, path containment (absolute, .. and symlink escapes are refused). The Begin*/End* pairs are synchronous — the callback runs inline, before Begin* returns. The module carries 14 test macros in one file (path containment, DeleteContainer, exception serialization) but none that writes and re-reads a file, so treat read/write behaviour as read-not-run. The root comes from an environment-variable chain, not SDL; see Storage.
….GamerServices Real Offline local profiles by default, with achievements and leaderboards persisted locally; an optional self-hosted CNA server adds accounts, friends, presence, pictures, server leaderboards and online sessions. See below.
Microsoft.Devices (incl. Sensors) Real hardware opt-in Accelerometer and Gyroscope use a real sensor when the selected CNA platform reports one (a hardware probe on desktop Linux, Windows and macOS as well as on Android — they are not Android-only, though most desktops have none). Compass and Motion are Android-backed and honestly report NotSupported elsewhere. Environment::getDeviceTypeProperty() reports Device on mobile targets and Emulator elsewhere. The sensor layer is built in every configuration; CNA_DEVICES=ON (not the default) gates only the separate CNA-specific device extensions in CNA::Devices. The separate opt-in CNA::Phone module adds the Windows Phone 7 lifecycle and push-notification API (Microsoft::Phone), which is not part of XNA 4.0.

Compiled effects: format and renderer boundary

At this snapshot, Effect(GraphicsDevice&, bytecode) and the XNB EffectReader are real for XNA/FNA D3D9 Effect Framework binary bytecode — not a throwing stub. 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, and none of those is compiled at run time.

Renderer support is deliberately narrow and off by default. Compiled effects are supported by 11 of the 14 renderer identities, in 9 families: FNA3D enables them as part of the renderer, and eight default-OFF build options switch on the rest — CNA_EASYGL_COMPILED_EFFECTS (which covers all three GL identities), CNA_VULKAN_, CNA_WEBGPU_, CNA_SOFTWARE_, CNA_DIRECTX9_, CNA_DIRECTX11_, CNA_METAL_ and CNA_SDL_GPU_COMPILED_EFFECTS. A default configure reports the CompiledEffects capability true on FNA3D only; the other 13 identities report false. 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. The build-time cna-content tool can compile a .fx source into an XNB Effect through an external, legacy fxc that you supply; CNA's own notes say that route has not been checked against a genuine Microsoft fxc, so treat it as unverified. See Effects & Shaders for the accepted formats and exact build switches.

Content: the XNB loader, CNB and the build-time pipeline

ⓘ

Correction to alpha.1: CNA now has a content pipeline as well as a loader. Earlier versions of this page said CNA only ever reads .xnb and would never build a ContentImporter, ContentProcessor or ContentCompiler. That is no longer true. This snapshot has a build-time Microsoft::Xna::Framework::Content::Pipeline façade (128 of 128 types and 705 of 705 members represented in its own census; 10 importers, 12 processors), a cna-content command-line tool, and writers for both .xnb (with LZX compression available) and CNA's own .cnb. The pipeline lives in a separate module that is never linked into a running game. The runtime ContentManager still only loads. See XNB Loading.

The loader is real. There are 61 built-in type readers — 60 in a build without native 128-bit integer support, which drops DecimalReader; the video reader is registered in every build — 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. Not by ContentManager itself: a stand-alone ContentManager used without a Game (a tool, a test) starts with an empty registry and must call CNA::Internal::Xnb::RegisterAllBuiltInXnbReaders() itself. A Game, however, calls it in its constructor, so a game gets the built-in readers with no setup (alpha.1 required the explicit call in every program). C++ has no reflection to discover readers the way XNA does; custom types register with ContentTypeReaderManager::AddTypeCreator, or declare a field list once with ReflectiveTypeReaderBuilder<T>.

Content formats, and which one wins

Load<T> returns T by value and resolves a name in this order:

  • .xnb — tried first. Produced by XNA, MonoGame, FNA or CNA's own cna-content.
  • .cnb — CNA's checksummed binary container, the default output of cna-content.
  • .cnj — CNA's JSON descriptor format, for assets you author for CNA rather than import; then the per-type loose files (PNG, WAV, glTF and so on).
  • .model.json — the former name of the loose model descriptor. It is no longer a resolution step: the Model reader tries .cnj, .gltf and .glb, and a descriptor must carry the cnjVersion and type envelope, so rename an old descriptor to .cnj and add them.

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 getContentProperty().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().

This snapshot 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 (matching FNA).
  • DDS cube maps are documented as limited to DXT1, DXT3 and DXT5 (unchanged from alpha.1; not re-verified for this snapshot).
  • ResourceContentManager is implemented over System::Resources::ResourceManager (OpenStream returns a memory stream over the binary resource), but the public Load<T> ladder does not use it; only derived classes reach the resource path through the protected ReadAsset<T>. Its one-argument constructor is a CNAEXT convenience whose OpenStream throws ContentLoadException.
  • The build-time pipeline produces .xnb from .fbx, .x, images, audio, .spritefont (FreeType) and .fxb; it has no .mgcb route, and skeleton, animation and morph data are dropped, with warnings, when a glTF model is written as .xnb.

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 the selected platform's file-system service (SDL_GetUserFolder on the SDL3 platform) and scans them. It parses ID3v2, Vorbis, Opus and FLAC tags, probes durations through FFmpeg when the video backend is present, 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 the audio 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: SDL3 capture devices, and ALSA capture on SDL-free Linux builds; Microphone.All lists only the machine's real devices, and BufferDuration uses TotalMilliseconds as XNA does. Song::FromUri(name, System::Uri) accepts local file: or relative URIs and rejects other schemes.

⚠

Video is a platform question, not an implementation one. Video decoding is optional and its absence is a run-time error, not a link error. FFmpeg is controlled by CNA_ENABLE_VIDEO=AUTO|ON|OFF (default AUTO). On Linux and macOS, AUTO uses it when libavcodec, libavformat, libavutil and libswresample are found and otherwise falls back; ON requires them. FFmpeg is never used on Windows, Emscripten, Android or iOS (ON there is a configure error). Everywhere else Video and VideoPlayer compile and link; playing a file-backed Video without the backend throws System::NotSupportedException, while metadata-only Video and the XNB VideoReader work in every build. Guard with CNA_VIDEO_AVAILABLE or catch the exception. The optional split has not been run on macOS by its author. See Video Playback.

GamerServices — offline by default, server-backed when configured

With no service configured, players are local offline profiles: nobody is signed in until Guide::ShowSignIn (or the auto-sign-in setting), achievements and leaderboard entries are stored locally and reload in a later process, and LeaderboardWriter/LeaderboardReader are real implementations with sorting, ranks and paging. Configured outside the game’s code (an endpoint and a game id from the environment, a cna-title.json manifest or user settings), the same XNA calls use the self-hosted CNA Gamer Services server over HTTPS: server accounts signed in through the Guide, friends, presence, messages, gamer pictures, server leaderboards and online sessions. It is a CNA service, not Xbox LIVE, and no public instance is operated.

The Guide is a console-style system UI drawn by CNA: every standard Guide::Show* page opens, message boxes and keyboard input render with password masking and pointer hit-testing, and the Guide owns input while it is visible. Avatars use XNA’s AvatarDescription, AvatarAnimation (31 presets) and AvatarRenderer::Draw with a 71-bone skeleton and CNA’s own avatar art; bone transforms follow XNA’s coordinate space.

What to keep in mind:

  • Social features need the server. Friends, presence, messages and pictures need a server account: for a local profile the friend list throws XNA’s GamerPrivilegeException, the social Guide pages throw GamerServicesNotAvailableException, a gamer picture comes back null, and presence is never published.
  • Achievements and scores are client claims. The server authenticates and validates them, but a modified client can submit plausible fake results; there is no anti-cheat.
  • Qualification is Linux-first (CNA’s recorded Linux runs: 649 GamerServices and 524 Net tests passed; its Apple campaign records the test trees and the server suite passing on one Apple M4, where online play needs a WebSocket-capable libcurl rather than Apple’s system one); Windows, a real wide-area network and avatar pixels on Direct3D and Metal are not qualified, and browser builds have no service, relay or voice.
  • The Begin*/End* pairs of local operations complete synchronously, as XNA’s own did; server-backed operations complete on the game thread during GamerServicesDispatcher::Update.

See Gamer Services & Avatars for the full picture and the tutorials.

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, and the scalar-left operator*(float, Matrix); Curve::Evaluate implements every loop type; Color defines the full named-constant set, and a default-constructed Color is transparent black. Game is a genuine platform loop with both fixed and variable timestep and a separate Emscripten path; its default presentation mode is Letterbox, so the viewport is the backbuffer size whatever the window's shape. Among the named holes is BoundingFrustum::Intersects(Ray), which throws for a ray origin exactly on the frustum boundary and never computes an entry distance (an origin outside always reports no hit); BoundingSphere and BoundingBox Contains(BoundingFrustum) never answer Disjoint.
  • Graphics. Every XNA Graphics type exists, with GraphicsDevice's full event and Draw* surface (including the generic array overloads of DrawUserPrimitives, spelled with std::vector) and SpriteBatch's full Begin, Draw and DrawString overload sets. What differs is the renderer underneath: 14 renderer identities across 12 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. One of them, SDL_RENDERER, is 2D-only by design. Consult the renderer reference and explicit capability reports (RendererCapabilityProfile: 32 features, 22 limits) rather than assuming the identities are interchangeable. GraphicsDevice::Present(src, dst, hwnd) is represented but only HEADLESS honours every argument and SOFTWARE honours a source rectangle; every other renderer throws NotSupportedException.
  • PackedVector. The packed formats are real, on a correct IEEE 754 half-float codec that handles subnormals, infinities and NaN in both directions. See PackedVector Types.

Input, Touch and Sensors

  • Input is a real SDL3 bridge on the default platform. Rumble, trigger rumble, LED colour, hot-plug and per-device capability probing all work, and Keys carries the full XNA key set (160 enumerators). The input namespace is the one with compile-time signature-freeze tests.
  • Input::Touch genuinely detects the XNA gesture types through a real state machine wired to SDL3 touch events. TouchCollection::getIsReadOnlyProperty() returns true while the mutators and the indexer setter mutate, as FNA's do; XNA 4.0's throw NotSupportedException. CNA's tests pin this as deliberate FNA parity, not XNA's contract.
  • Microsoft::Devices and Sensors talk to real hardware. Accelerometer and Gyroscope ask the selected CNA platform for a real sensor 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. See Sensors.
💡

The Microsoft::Devices sensor layer is built in every configuration, a stock build included. CNA_DEVICES=ON, which is not the default, gates only the separate CNA-specific device extensions (CNA::Devices: clipboard, dialogs, camera and so on).

Audio, Net and Storage

  • Audio. XACT is implemented rather than faked: wave banks are parsed and played through the selected mixer, and 3D audio follows XNA's rules. SoundEffectInstance::Apply3D after Play() on a pan-mode instance throws InvalidOperationException, as in XNA, and multi-listener Apply3D accepts any positive count. Named boundaries: 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 for NetworkSessionType::SystemLink, plus the in-process Local type and, through the CNA server, PlayerMatch and Ranked. 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 it is excluded on Emscripten. PlayerMatch, Ranked and JoinInvited work through the optional CNA Gamer Services server and its relay; without a configured server they are refused.
  • 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 14 test macros in one file, ten of them about path containment and DeleteContainer, and none that writes a file and reads it back.
⚠

On the Web, saves persist in the browser. CNA’s storage module mounts the browser’s IndexedDB (IDBFS) for StorageDevice and isolated storage and restores it before main(), so saves survive a page reload. Threaded WebAssembly builds need CNA_EMSCRIPTEN_USE_WASMFS=OFF for this; if the mount fails, StorageDevice reports it as not connected. See Storage.

CNAEXT: what CNA adds beyond XNA

CNA ships a substantial non-XNA surface. Declarations in the XNA-shaped namespaces that are not part of XNA 4.0 carry the CNAEXT marker (a code-token count with comments stripped finds 1,843 markers across 330 public headers at this snapshot); the CNA::Graphics extensions and the other CNA:: namespaces are instead gated by CNA_CNAEXT or named with an EXT suffix. The tagging is a convention, not something the compiler checks over the whole surface. CNA_STRICT_XNA_API is a compile definition, not a CMake option: define it on a target (for example target_compile_definitions(my_game PRIVATE CNA_STRICT_XNA_API)) and every use of a CNAEXT declaration becomes a [[deprecated]] warning, so “would this also compile against real XNA?” can be answered by the compiler for the code you compile that way. CNA's own automated check of this mode covers only Microsoft::Devices/Sensors; passing -DCNA_STRICT_XNA_API=ON to CMake configure sets an unused cache variable.

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. Eight implementation families implement the model: seven (nine identities: Direct3D 9 and 11, the three EasyGL identities, SDL_GPU, Vulkan, WebGPU and Metal) sample the material texture maps, including the specular ones, and the Software renderer is a separate reduced CPU cross-check. FNA3D refuses PBR draws by name.
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 (MIME-typed data, and the primary selection of X11 and Wayland desktops through SDL3), haptics, joysticks, battery state, IME candidates, gamepad light bar, gyro and touchpad access, opt-in mouse-to-touch emulation and touch suppression while a Guide dialog is open — none of which XNA had a way to express.
Content authoring The cna-content build-time tool, the .cnb container and its C ABI surface, and the XNA-shaped Content Pipeline façade.
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 (98 public headers at this snapshot, up from 12), plus the opt-in CNA::Diagnostics profiler and Inspector.
💡

The CNAEXT extensions are opt-in: CNA_CNAEXT defaults to OFF, and it is what gates AsciiPostProcessEffect, CRTEffect, DepthEffect, DebugDraw and the rest of the CNA::Graphics surface. CNA_DEVICES, which gates the CNA-specific device extensions (not the Microsoft::Devices sensors, which are always built), is OFF by default too, and CNA::Design is linked only by the targets that ask for it.

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. Its counts are its own and are pinned here to cna-samples @ 5db32e6 (2026-10-03); they describe CNA next on that date, not alpha.1 and not necessarily this snapshot.

ResultDetail
91 C++ sample and game ports marked complete The repository’s plan audits 153 entries (SAMPLE-001 to SAMPLE-153), which is the size of the audit list, not a count of 153 XNA 4.0 games: 91 are complete under a stricter bar than “builds” (a native run, and a browser run where the sample has a web build, per the repository’s own definition; this site has not replicated those gates), 8 relevant XNA 4.0 C# programs remain, and 54 entries are not port targets (XNA 3.x or older, Silverlight, WinForms tools, VB.NET, C++, asset packs). 90 C++ builds are playable at samples.libcna.com; the Racing Game Kit is ported in its own plan and is not hosted. The same Microsoft samples also run from their unchanged C# source through CNA.NET.
What blocked the rest not the shader format The alpha.1-era explanation that samples were blocked by HLSL .fx effects no longer holds: shader-driven samples such as Bloom, Normal Mapping and Shadow Mapping are marked complete, loading the official effect XNBs through the compiled-effect path. The remaining rows wait on owner decisions (Windows Phone and WinForms apps, Avatar content, networking without a web transport, tools).

Beyond the samples, cna-craft (a subtree of the cna-lab repository) 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; like the samples, they are evidence for the CNA revision they were built against.

💡

Honest positioning: CNA is a research-grade porting framework, not yet a ship-a-commercial-game framework. The strongest true claims are a closed API-representation census (331/331 types, 3,627/3,627 members — representation, not behaviour), a genuinely real Graphics, Input, Audio, Net, Media and Storage core, and recorded byte-exact agreement of the DIRECTX9 renderer with the real XNA 4.0 runtime on the 39-scene oracle corpus (reference images captured under Wine with DXVK on Linux, at tolerance zero; not run in CI). 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. Begin/End pairs return std::unique_ptr<IAsyncResult>, and ContentManager::Load<T> returns T by value.
  • No properties: C# properties become getter/setter methods named getXProperty() and setXProperty(value) (e.g. getGraphicsDeviceProperty() instead of the C# GraphicsDevice property). This is also why 1,039 of the 1,040 documented properties are classified “semantic” rather than “exact” in the census.
  • 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 custom XNB readers are registered by hand or declared with ReflectiveTypeReaderBuilder<T> rather than discovered.
  • No extension methods, LINQ, or C#-style generics. Generic families are stored as host-language substitutions (for example ContentTypeReaderBase, IPackedVectorT).
  • On the Web, a stack-allocated Game is supported. Game::Run() blocks on the caller's stack through Asyncify, so the old “Game must be heap-allocated” rule is obsolete. Application executables built by CNA opt in automatically; an external consumer's final link must use the CNA::EmscriptenAsyncify target.

Known gaps and limitations

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

  • Representation is not behaviour — 3,627/3,627 members exist with the documented shape; how each behaves is verified only for subsets (framework packing oracle, math oracles, the 39-scene graphics corpus on DIRECTX9, an FNA differential harness, the Input signature-freeze tests). The census is a manual script, not a CI gate.
  • Compiled effects are renderer-qualified — XNA/FNA D3D9 Effect Framework bytecode loads through the bytecode constructor and XNB EffectReader on 11 of the 14 identities: FNA3D always, and the rest behind default-OFF options. HLSL .fx source, DXBC and MGFX are not accepted at run time.
  • Renderer capability is not uniform — 14 public identities share 12 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.
  • The runtime ContentManager loads; the build-time pipeline authors — cna-content writes .xnb and .cnb, but the pipeline is never part of a running game, has no .mgcb route, and its .fx route needs an external compiler CNA does not ship.
  • Web caveats — saves persist in the browser’s IndexedDB only when the build uses the legacy file system (threaded builds need -DCNA_EMSCRIPTEN_USE_WASMFS=OFF); no LAN discovery, no online service, relay or voice; and video that throws at run time. (A stack-allocated Game is fine.)
  • Video decoding is optional — the types link everywhere; without the FFmpeg backend (never available on Windows, Web, Android or iOS) file-backed playback throws NotSupportedException.
  • GamerServices is offline unless a CNA server is configured — local profiles and local achievements and leaderboards by default; accounts, social features and online sessions need a self-hosted CNA Gamer Services server (not Xbox LIVE compatible, no public instance, no cloud sync of local saves). Every standard Guide::Show* page opens.
  • Online sessions need a CNA server — SystemLink is direct ENet on the LAN (discovery excluded on Emscripten) and Local delivers no packets; PlayerMatch, Ranked and JoinInvited go through a configured CNA Gamer Services server and its relay (no peer-to-peer path, no NAT traversal) and throw without one.
  • Audio boundaries — XMA/WMA wave-bank content goes silently missing; no AAC decoder; reverb send is a no-op.
  • 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, device-extension and design layers are opt-in — CNA_CNAEXT and CNA_DEVICES (the CNA-specific device extensions; the Microsoft::Devices sensors are always built) both default to OFF, and CNA::Design is linked only on request.
  • iOS support is narrow and experimental — CI final-links an SDL_RENDERER device application and launches a one-frame simulator smoke test. It is not evidence for physical devices, pixels, input, audio or storage, or the wider renderer inventory. tvOS remains unsupported.
  • Known renderer bug — RasterizerState.DepthBias is not scaled to renderer depth units on every renderer: EasyGL, SDL_GPU and Direct3D 11 convert XNA's normalised value, Vulkan passes it unscaled so a realistic bias has no effect (CNA-BUG-264), and SurfaceFormat::Alpha8 render targets are refused.

Intentionally excluded from CNA

  • The content pipeline inside your game — the build-time importers, processors and compilers are implemented, but in a module that is never linked into a running game, and CNA does not read .mgcb projects. Runtime code loads .xnb, .cnb, .cnj and loose files.
  • The Microsoft.Xna.Framework.Design designer host — the thirteen converters are implemented in the opt-in CNA::Design module; the Windows Forms / Visual Studio property grid, CodeDOM serialization and arbitrary runtime reflection have no C++ equivalent and are out of scope.
  • Xbox LIVE server-side services — authentication against Microsoft's servers, Xbox LIVE matchmaking and cloud-synced saves. GamerServices persists locally, or uses CNA’s own self-hosted server, which is not Xbox LIVE compatible.
  • An offline stand-in for online sessions — without a configured CNA server, PlayerMatch, Ranked and JoinInvited throw GamerServicesNotAvailableException; 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 on the first successful renderer creation. It does not switch an existing device while the game is running.

Reference resources