XNA 4.0 Compatibility
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
| Question | Answer at this snapshot |
|---|---|
| Reference inventory | Microsoft'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). |
| Types | 331/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. |
| Members | 3,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 classified | 1,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” requires | A 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 claimed | Behaviour, 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 produced | A 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 it | Nothing 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. |
| History | The 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 namespace | Members | Notes |
|---|---|---|
Microsoft.Xna.Framework (core, math, Game) | 1,009 | Includes Game, GameTime, the math value types and bounding volumes. |
….Graphics | 823 (+20) | The extra 20 are the four model-collection enumerators. |
….Graphics.PackedVector | 196 | |
….Input | 318 | |
….Input.Touch | 60 (+5) | TouchCollection::Enumerator. |
….Media (incl. Video) | 211 | |
….Audio (incl. XACT) | 152 | |
….Content | 62 | Runtime side; the Pipeline is separate. |
….Design | 53 | The thirteen converters — Framework.Design. |
….GamerServices (incl. Avatar) | 501 (+5) | GamerCollection<T> enumerator. |
….Net | 177 | |
….Storage | 35 |
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
| Namespace | State | What 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 owncna-content..cnb— CNA's checksummed binary container, the default output ofcna-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,.gltfand.glb, and a descriptor must carry thecnjVersionandtypeenvelope, so rename an old descriptor to.cnjand 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
EffectReaderloads supported XNA/FNA Effect Framework bytecode only when the active renderer advertises compiled-effect capability; it rejects unsupported formats and renderer configurations..xnbfiles 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).
ResourceContentManageris implemented overSystem::Resources::ResourceManager(OpenStreamreturns a memory stream over the binary resource), but the publicLoad<T>ladder does not use it; only derived classes reach the resource path through the protectedReadAsset<T>. Its one-argument constructor is a CNAEXT convenience whoseOpenStreamthrowsContentLoadException.- The build-time pipeline produces
.xnbfrom.fbx,.x, images, audio,.spritefont(FreeType) and.fxb; it has no.mgcbroute, 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 throwGamerServicesNotAvailableException, 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 duringGamerServicesDispatcher::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:
Matrixcarries its full static factory set includingDecompose, the billboard pair, shadow and reflection, and the scalar-leftoperator*(float, Matrix);Curve::Evaluateimplements every loop type;Colordefines the full named-constant set, and a default-constructedColoris transparent black.Gameis a genuine platform loop with both fixed and variable timestep and a separate Emscripten path; its default presentation mode isLetterbox, so the viewport is the backbuffer size whatever the window's shape. Among the named holes isBoundingFrustum::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);BoundingSphereandBoundingBoxContains(BoundingFrustum)never answerDisjoint. - Graphics. Every XNA Graphics type exists, with
GraphicsDevice's full event andDraw*surface (including the generic array overloads ofDrawUserPrimitives, spelled withstd::vector) andSpriteBatch's fullBegin,DrawandDrawStringoverload 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 onlyHEADLESShonours every argument andSOFTWAREhonours a source rectangle; every other renderer throwsNotSupportedException. - 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
Inputis a real SDL3 bridge on the default platform. Rumble, trigger rumble, LED colour, hot-plug and per-device capability probing all work, andKeyscarries the full XNA key set (160 enumerators). The input namespace is the one with compile-time signature-freeze tests.Input::Touchgenuinely detects the XNA gesture types through a real state machine wired to SDL3 touch events.TouchCollection::getIsReadOnlyProperty()returnstruewhile the mutators and the indexer setter mutate, as FNA's do; XNA 4.0's throwNotSupportedException. CNA's tests pin this as deliberate FNA parity, not XNA's contract.Microsoft::DevicesandSensorstalk to real hardware.AccelerometerandGyroscopeask 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.VibrateControllerreally vibrates through SDL's haptic API, deliberately excluding gamepads.CompassandMotiongenuinely are Android-only, built on an NDK sensor fusion, and reportNotSupportedeverywhere 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::Apply3DafterPlay()on a pan-mode instance throwsInvalidOperationException, as in XNA, and multi-listenerApply3Daccepts any positive count. Named boundaries: XMA or WMA content in a wave bank logs to stderr and returnsnullptr, so the sound is silently absent rather than an exception — note that the XNBSoundEffectReaderpath does throw on the same content; and.m4a/.aaccannot be decoded at all.Net. Real UDP transport with LAN broadcast discovery and measured RTT for QoS forNetworkSessionType::SystemLink, plus the in-processLocaltype and, through the CNA server,PlayerMatchandRanked.SimulatedLatencyandSimulatedPacketLossare 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,RankedandJoinInvitedwork through the optional CNA Gamer Services server and its relay; without a configured server they are refused.Storage. Realstd::filesystemIO with correct player namespacing. TheBegin*/End*pairs are synchronous, running the callback inline beforeBegin*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 andDeleteContainer, 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.
| Area | What 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.
| Result | Detail |
|---|---|
| 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 returnstd::unique_ptr<IAsyncResult>, andContentManager::Load<T>returnsTby value. - No properties: C# properties become getter/setter methods named
getXProperty()andsetXProperty(value)(e.g.getGraphicsDeviceProperty()instead of the C#GraphicsDeviceproperty). 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::Frameworkwith::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
Gameis supported.Game::Run()blocks on the caller's stack through Asyncify, so the old “Gamemust be heap-allocated” rule is obsolete. Application executables built by CNA opt in automatically; an external consumer's final link must use theCNA::EmscriptenAsyncifytarget.
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
EffectReaderon 11 of the 14 identities: FNA3D always, and the rest behind default-OFFoptions. HLSL.fxsource, 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
ContentManagerloads; the build-time pipeline authors —cna-contentwrites.xnband.cnb, but the pipeline is never part of a running game, has no.mgcbroute, and its.fxroute 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-allocatedGameis 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. GamerServicesis 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 standardGuide::Show*page opens.- Online sessions need a CNA server —
SystemLinkis direct ENet on the LAN (discovery excluded on Emscripten) andLocaldelivers no packets;PlayerMatch,RankedandJoinInvitedgo 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
Tagcarrier and are omitted with a diagnostic. - CNAEXT, device-extension and design layers are opt-in —
CNA_CNAEXTandCNA_DEVICES(the CNA-specific device extensions; theMicrosoft::Devicessensors are always built) both default toOFF, andCNA::Designis 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.DepthBiasis 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), andSurfaceFormat::Alpha8render 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
.mgcbprojects. Runtime code loads.xnb,.cnb,.cnjand loose files. - The
Microsoft.Xna.Framework.Designdesigner host — the thirteen converters are implemented in the opt-inCNA::Designmodule; 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.
GamerServicespersists 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,RankedandJoinInvitedthrowGamerServicesNotAvailableException; 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
- Microsoft XNA 4.0 API Reference (Microsoft Learn)
- FNA Documentation
- MonoGame Documentation
- CNA's generated XNA 4.0 runtime member coverage report (the census behind 331/331 and 3,627/3,627, at snapshot c1c316b9)
- Framework.Design · Storage · Verification & Known Issues
Deep dives on this topic
Long-form pages that explain the exact semantics, invariants and evidence behind this subject.
- Auditing the XNA API surface: the census, xna4-spec and two worked audits — How CNA's 331/331 and 3,627/3,627 API census is produced and read, which reference settles which question, and worked surface audits of Ray and Viewport against XNA's own IL.
- Avatars: the standard XNA avatar API on CNA's own avatars — How CNA's XNA avatar classes draw original CNA avatars on XNA's 71-bone rig: descriptions, the renderer, the 31 presets, catalogs and the editor, plus the separate SkinnedModelEXT extension and the evidence behind both.
- CNA and XNA 4.0: what the compatibility promise covers — What CNA translates and cannot load, which reference settles a disputed XNA question, what CNA deliberately is not at snapshot c1c316b9, and its Ms-PL licence and FNA provenance.
- CNAEXT catalogue: extension surfaces by namespace — A catalogue of CNA's non-XNA surface at snapshot c1c316b9, namespace by namespace, with member names, reasons and boundaries, how much the CNAEXT marker covers, and what the strict check proves.
- Compatibility levels and the evidence vector — The distinct levels of XNA compatibility CNA keeps apart, the evidence vocabulary used across the site, what each renderer class can prove, and how to state a verification claim.
- Core framework and graphics API map — An orientation map of CNA's core framework and graphics API: owning headers, public shape, the boundary that trips ports, and where each behaviour is explained, for math, framework, content, resources, effects and device state.
- Framework services and ecosystem quick reference — A map of CNA's input, audio, media, device, network, gamer-services, storage and sharp-runtime types with their current boundaries and owner pages, plus the bindings and showcase applications around CNA.
- From C# to C++: CNA's translation conventions — How CNA represents C# XNA concepts in C++ so that code stays diffable against the reference: names, properties, aliases, events, interfaces, disposal, visibility, layout and the porting checklist.
- GamerServices behaviour contract — What CNA's GamerServices does with local offline profiles and with a configured CNA service: sign-in, configuration and credentials, the offline store, achievements, leaderboards, the Guide and the dispatcher.
- Glossary of XNA and CNA terms — Checked definitions of the XNA and CNA terms used across libcna.com, grouped by subject, each correcting common older readings and linking to the page with the detail.
- Network sessions and the SystemLink protocol — What each NetworkSessionType does in CNA, online sessions through the CNA service relay, the SystemLink wire and discovery protocols, the trust model, delivery guarantees, host migration and the evidence behind them.
Known issues in this area
Current defects, gaps and limitations at this snapshot that touch this subject.
- CNA-BUG-061: README.md, docs/coverage.md and docs/xna-4-api-coverage.md still report 3,467/3,627 runtime members and 160 gaps; the generated report says 3,627/3,627 — CNA's root README and two coverage documents print the pre-closure XNA runtime member figure (3,467 of 3,627, 95.59%, 160 gaps), while the generated member report they point to records 3,627 of 3,627 represented and none
- CNA-BUG-083: PhoneApplicationService::getCurrentProperty()'s static instance detaches from an already-destroyed Game during static destruction — The process-wide PhoneApplicationService is a function-local static holding a borrowed Game*; attached to a Game that is destroyed first, its destructor calls DetachEXT on the dead game's events.
- CNA-BUG-092: Public non-XNA members Texture::GetFormatSizeEXT, GetBlockSizeSquaredEXT, GetPixelStoreAlignment, ValidateGetDataFormat and GameWindow's IsBorderlessEXT accessors carry no CNAEXT marker — Four public static Texture helpers and the GameWindow borderless getter and setter are not XNA 4.0 API but are not tagged CNAEXT, so a CNA_STRICT_XNA_API build compiles calls to them silently.
- CNA-BUG-156: HttpNotificationChannel answers length-less, chunked and truncated pushes with 200 and reads request bodies of unbounded size — ReadRequestBody's comment says unreadable pushes are refused rather than delivered truncated, but a request without Content-Length gets 200 and is dropped, a short body gets 200 and is queued truncated, and the length is
- CNA-BUG-157: HttpNotificationChannel::Close and the channel destructor block indefinitely while a connected peer sends nothing — The single listener thread reads each accepted connection with a blocking recv and no timeout; Close shuts down only the listening socket and then joins that thread, so a silent peer stalls Close and the destructor.
- CNA-BUG-158: RawPushNotificationMessage::SendAsync and ToastPushNotificationMessage::SendAsync return true for a push the receiver rejected — Both SendAsync methods are documented to return true when the receiver accepted the notification, but they return true whenever the whole request was written; the reply is read and discarded, so an HTTP 400 still yields
- CNA-BUG-159: ToastPushNotificationMessage::SendAsync inserts Title and SubTitle into the toast XML without escaping — The toast body is built by string concatenation, so a Title or SubTitle containing an ampersand, a less-than sign or markup produces malformed or altered XML; the channel delivers the bytes unparsed.
- CNA-BUG-160: Two open HttpNotificationChannel objects with the same name leave Find unable to locate one that is still open — Open assigns the registry entry for the name without checking for an existing channel, and when the later channel closes first it erases the name while the earlier one is still listening, so Find returns null for a live
- CNA-BUG-161: A handler that throws during HttpNotificationChannel::DispatchPendingNotificationsEXT discards every remaining notification of that batch — DispatchPendingNotificationsEXT moves the whole queue into a local vector before raising; an exception from a HttpNotificationReceived handler propagates and destroys the notifications not yet raised.
- CNA-BUG-163: HttpNotificationChannel writes its reply with ::send flags 0, so a peer that aborts its connection mid-request can end the process with SIGPIPE — The listener's 200 or 400 reply is written with no MSG_NOSIGNAL or SO_NOSIGPIPE, unlike CNA's other socket code. After a peer's abortive close has been reported to the worker as a receive error, Linux delivers SIGPIPE on
- CNA-BUG-164: HttpNotificationChannel's listener reads listenSocket_ unsynchronised while Close resets it, and spins without backoff on a persistent accept error — listenSocket_ is a plain int that the worker reads for every accept while Close closes the descriptor and writes -1 from another thread, a data race; a persistent accept failure such as EMFILE makes the worker loop at fu
- CNA-BUG-259: Matrix::Decompose follows FNA's algorithm, not XNA 4.0's: a mirrored matrix decomposes to positive scales and a non-unit quaternion, and a sheared matrix reports success — Matrix::Decompose never checks the determinant: a mirrored matrix returns positive scales, a non-unit quaternion and true where XNA 4.0 negates the largest scale, and a sheared matrix returns true where XNA returns false
- CNA-BUG-264: Vulkan passes XNA's normalised RasterizerState.DepthBias to vkCmdSetDepthBias unscaled, so a realistic bias has no effect — VulkanRenderer hands DepthBias to vkCmdSetDepthBias raw, but that constant factor counts minimum depth steps; EasyGL, SDL_GPU, Metal and Direct3D 11 scale XNA's normalised value by the depth format, so -0.0001 offsets no
- CNA-VGAP-049: The XNA API census (331/331 types, 3,627/3,627 members) measures representation only and is a manually run script — Every member row of docs/xna-4-runtime-member-coverage.json records behavior_assessed false, and tools/audit_xna_runtime_surface.py is run by no workflow or CTest, so behavioural evidence exists only for the subsets name