CNA-BUG-244: README.md's Usage Example does not compile (nonexistent Graphics/GraphicsDeviceManager.hpp include, unqualified CornflowerBlue) and presents every frame twice

CNA snapshot 009d40f5  ·  Known Issues › Current bugs  ·  source links pinned to 009d40f5

✓

Evidence basis: source-verified at the pinned commit; executed for this entry (the Evidence section names exactly what was run); tests exist (not executed for this page). Claims on this page were checked by reading the CNA source at commit 009d40f5; unless a sentence says otherwise, nothing here was built or executed. Nothing on this page was executed unless the Evidence section says so.

The README's game skeleton includes a nonexistent header path, writes CornflowerBlue without Color::, and calls device.Present() in Draw although EndDraw() already presents, so the copied program fails to compile and, once repaired, presents twice per frame.

Identifier
CNA-BUG-244
Category
Bug
Subsystem
Documentation & release tooling
Status
Open
Verified against
CNA 009d40f5 (009d40f5dd085c4e674d3479675fac84b12b3e0a)
Severity
Medium (a triage suggestion, not a project priority)
Evidence basis
Reproduced: executed for this entry (the Evidence section names exactly what was run)
Tests touching this area
Yes: see Current tests
Affected contract
README.md section 10 (Usage Example): the minimal Game skeleton; Microsoft/Xna/Framework/GraphicsDeviceManager.hpp, Color::CornflowerBlue and the Game::Draw / EndDraw presentation contract

Expected behaviour

The README's “Minimal XNA-style game skeleton” is the first program most users copy. It should compile against the public headers and follow the frame contract CNA shares with XNA: Game::Tick calls BeginDraw(), Draw() and EndDraw(), and GraphicsDeviceManager::EndDraw presents, so a Draw override never calls Present() itself. CNA's own stub_smoke_test.cpp states exactly that rule (“No explicit Present() here”).

Actual behaviour at TARGET

At 009d40f5 the example in README.md:

  • includes Microsoft/Xna/Framework/Graphics/GraphicsDeviceManager.hpp; the only such header is Microsoft/Xna/Framework/GraphicsDeviceManager.hpp and no forwarding header exists anywhere in the tree;
  • calls device.Clear(CornflowerBlue) with only using namespace Microsoft::Xna::Framework and Microsoft::Xna::Framework::Graphics in effect, but CornflowerBlue is the static member Color::CornflowerBlue (Color.hpp) and no namespace-scope name exists;
  • ends Draw with device.Present(). Game::Tick then calls EndDraw(), GraphicsDeviceManager::EndDraw calls GraphicsDevice::Present() again, and GraphicsDevice::Present has no once-per-frame guard, so the renderer's Present() runs twice every frame.

The overrides also skip Game::Update and Game::Draw, which update and draw registered components and call FrameworkDispatcher::Update(); harmless in this component-free skeleton, but it drops the base-call pattern of the XNA template. The rest of the example (GraphicsDeviceManager(Game*), the CNAEXT Texture2D(path, device) constructor and SpriteBatch::Draw(texture, x, y)) matches the headers.

Source locations

Evidence

Read at 009d40f5: README section 10, the header tree, Color.hpp, GraphicsDeviceManager::EndDraw, Game::Tick, Game::Update, Game::Draw and GraphicsDevice::Present. Executed: the README code block was extracted verbatim and syntax-checked with g++ -std=c++23 -fsyntax-only -DCNA_RENDERER_SDL_RENDERER -DCNA_PLATFORM_SDL3 against every TARGET modules/*/include root and a sharp-runtime next checkout at 41b918c9 (a sibling revision not pinned by TARGET). The verbatim block stops with “Microsoft/Xna/Framework/Graphics/GraphicsDeviceManager.hpp: No such file or directory”; with the include corrected it stops with “‘CornflowerBlue’ was not declared in this scope”; with Color::CornflowerBlue as well it compiles. The double present is established by reading; nothing was linked or run, so what the second present shows on each renderer was not observed. README.md last changed in 9a42a7e82 and still carries the example at TARGET.

Focused reproduction

Executed (syntax check only), from a scratch directory, with the README block saved as readme.cpp:

T=/path/to/cna-target; SR=/path/to/sharp-runtime
INC=$(for d in $T/modules/*/include $SR/modules/*/include; do printf ' -I%s' "$d"; done)
g++ -std=c++23 -fsyntax-only -DCNA_RENDERER_SDL_RENDERER -DCNA_PLATFORM_SDL3 $INC readme.cpp
# fatal error: Microsoft/Xna/Framework/Graphics/GraphicsDeviceManager.hpp: No such file or directory
# after fixing the include:  error: 'CornflowerBlue' was not declared in this scope

Current tests

No CNA test compiles README snippets; the documentation-labelled CTests (for example CnaXnbPlanStatusConsistency) check plan tables, not examples. stub_smoke_test.cpp and the other renderer examples demonstrate the correct Draw without Present(), but nothing counts presents per Tick.

Regression test

A documentation gate that extracts the README's C++ block and syntax-checks it against the public headers with the flags above; optionally a HEADLESS or STUB example that counts renderer Present() calls per Tick and asserts one. The fix: include Microsoft/Xna/Framework/GraphicsDeviceManager.hpp, write Color::CornflowerBlue, drop device.Present(), and end the overrides with Game::Update(gameTime) / Game::Draw(gameTime).

Blast radius

Every user who starts from CNA's README: the example fails at its first include; a user who repairs the two compile errors gets a program that presents twice per frame. No library code is affected, and the other CNA examples do not repeat the pattern.

Workaround

Start from the corrected skeleton of the first-game walkthrough: #include "Microsoft/Xna/Framework/GraphicsDeviceManager.hpp", device.Clear(Color::CornflowerBlue), no Present() in Draw.

The same subject is explained at several altitudes. These are the neighbouring pages at each one.

Known issues
Bug index