Skip to content

RebindMenuScene.RendersRebindPanelAndProducesPng fails deterministically in full-suite runs on master (UI text does not render; passes in isolation) #520

Closed

Description

@drsnuggles8

Found while validating feature/shadow-pcss-performance (2026-07-03); reproduced on a freshly built master (36939c5) test exe, so it is pre-existing and unrelated to that branch.

Symptom: in a full-suite run, RebindMenuScene.RendersRebindPanelAndProducesPng fails its bright-pixel contract with the bit-identical value every time:

RebindMenuVisualEvidenceTest.cpp(146): error: Expected: (maxLum) > (0.3f), actual: 0.269014895 vs 0.3
no bright pixels — panel text/buttons may not have rendered

The evidence PNG shows the panel backdrop and button fills render fine but every text glyph is missing (title, row labels, button captions) — maxLum 0.269 is the button-fill grey; the >0.3 pixels the contract wants are the near-white text. So this is a text-rendering dropout, not a threshold-tuning issue.

Order dependence: passes in isolation (--gtest_filter=RebindMenuScene.*, maxLum ~0.93) and when run together with its immediate in-suite predecessors (SceneWithCamera, SceneRenders3D, LitCubeScene). Only the full 4000+-test run kills the text — some earlier test leaves font/text-path state (font atlas? MSDF asset cache? Renderer2D_Text resources) in a state where RuntimeInputRebindMenu's labels silently don't draw.

Repro (RTX 4090, Windows 11, Debug):

  1. build\OloEngine\tests\Debug\OloEngine-Tests.exe → FAILED, maxLum 0.269014895 (3/3 runs on the feature branch, 1/1 on fresh master)
  2. --gtest_filter=RebindMenuScene.* → OK

The deterministic 0.269014895 across branches and runs points at a reproducible state leak rather than flaky timing.

Score

capability: 1
craft: 2
stability: 8
decay: 3
effort: 2
confidence: 1.0
learning: 3
fun: 3
kano: table-stakes
blocked_by: []
blocks: []

Silently drops ALL UI text when a font is first parsed headless (before the renderer is up) then rendered — a real render-path correctness bug, not just test signal; sibling of #505 but worse (wrong pixels, not benign). Small, verified fix. Rated per issue-scoring.

Activity

  1. coderabbitai commented on Jul 3, 2026

    @coderabbitai
    Contributor
    🔗 Related PRs

    #250 - Fix viewport-resize rendering bugs (GTAO ghost halo + transient pool … [merged]
    #263 - fix(tests): untangle Renderer3D test coupling for full-pipeline render tests (#258) [merged]
    #404 - fix(renderer): repair reflection-probe bake (was all-black) + add vis… [merged]
    #465 - Fix/flaky fog visual evidence test [merged]
    #479 - feat(renderer): CAS contrast-adaptive sharpening pass (#432) [merged]


    🧪 Issue enrichment is currently in open beta.

    To disable automatic issue enrichment, add the following to your .coderabbit.yaml:

    issue_enrichment:
      auto_enrich:
        enabled: false

    💬 Have feedback or questions? Drop into our discord!

  2. added
    bugSomething isn't working
    robustnessProduction hardening / shipping robustness
    on Jul 3, 2026
  3. drsnuggles8 commented on Jul 3, 2026

    @drsnuggles8
    OwnerAuthor

    Fixed in #529 (commit e948d77).

    Root cause: Font::GetDefault() caches a process-global static Ref<Font>, and SlugFontProcessor::Process only creates the Slug curve/band GPU textures when a GL context is bound. In full-suite order, FontMeasureLineTest (a plain metrics-only TEST(), no GL context) calls Font::GetDefault() before any GPU test brings the renderer up, caching a font that is IsLoaded() but has null curve/band textures. RebindMenuScene then renders its labels through that poisoned cached font (UI text falls back to Font::GetDefault()), so every glyph silently drops — leaving only the button-fill grey (maxLum 0.269). In isolation the font is first loaded during a render (context live), so the textures exist and it passes.

    Fix: retain the packed texel data when the GPU upload is deferred and upload the textures lazily on first render (SlugFontProcessor::EnsureGpuTextures, called from Font::GetCurveTexture()/GetBandTexture()), freeing the CPU copy afterward. Makes any headless-first-touched font render-robust — not a test-ordering workaround.

    Verified: full suite 4041 passed / 0 failed with RebindMenuScene [ OK ] in the exact failing ordering; minimal poison-then-render repro passes; evidence PNG shows all glyphs rendering. Added deterministic guard SlugDeferredUploadTest.EnsureGpuTexturesUploadsRetainedData and documented the lazy-GPU-resource headless-cache-leak class in docs/agent-rules/testing-architecture.md §6.5.

  4. added 2 commits that reference this issue on Jul 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingrobustnessProduction hardening / shipping robustness

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions