Skip to content

renderer: idTech5-modernization ownership milestones + cinData_t init fix - #128

Merged
themuffinator merged 37 commits into
mainfrom
codex/idtech5-modernization-plan
Aug 26, 2026
Merged

renderer: idTech5-modernization ownership milestones + cinData_t init fix#128
themuffinator merged 37 commits into
mainfrom
codex/idtech5-modernization-plan

Conversation

@themuffinator

Copy link
Copy Markdown
Owner

What changed

This branch carries the idTech5-modernization renderer line (25 commits):

  • Ownership milestones C–F: progressively seals frame ownership for classic material deforms, capture-backed subviews, in-world GUIs (transactional), cinematic/authored post, render-demo special frames, direct/nested special subviews, and cubemap/depth subview captures, culminating in Milestone D ownership finalization.
  • Milestone E: temporal presentation.
  • Milestone F: advanced lighting, screen-space lighting completion, and airdefense optimization.
  • Validation: renderer savepaths isolated in the validation tooling.
  • Bug fix (ab67d4fe): idSoundSystemLocal::ImageForTime returned a cinData_t with cd.image uninitialized. Consumers (RB_BindVariableStageImage in the GL backend, and the Vulkan GUI executor) test cin.image and call UploadScratch from it, so stack garbage caused an upload from a wild pointer with 0x0 dimensions — reachable through any material using a "waveform" videomap. The struct is now zeroed before status = FMV_IDLE is set, matching the pattern the other ImageForTime implementations already use.

Why

The modernization milestones move renderer frame ownership onto explicit, sealed contracts so the modern GL/Vulkan paths and the classic ARB2 path can coexist without implicit shared state. The cinData_t fix closes a latent wild-pointer upload found while auditing that consumer chain.

Reviewer notes

  • The cinData_t fix needs no consumer-side changes: both the GL and Vulkan paths already take a safe fallback branch when cin.image is NULL.
  • Token-pinning tests referencing snd_system.cpp (tools/tests/level_load_cache.py, tools/tests/fatal_error_startup_safety.py) pass locally.

🤖 Generated with Claude Code

themuffinator and others added 26 commits August 19, 2026 20:42
Document the complete compatibility-safe roadmap and dated implementation state; land the P0 security, provenance, stock-evidence, PBR authoring/resource, packaging, renderer-readback, and multiplayer validation foundations. Companion game-code commit: 834ed9f28817e9d01355ea3aeecb0f144e1ce69b.
The struct was returned with cd.image uninitialized; consumers
(RB_BindVariableStageImage, the Vulkan GUI executor) test cin.image and
upload from it, so stack garbage triggered an UploadScratch from a wild
pointer with 0x0 dimensions via any "waveform" videomap material.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
# Conflicts:
#	docs/dev/release-completion.md
#	docs/dev/releases/v0.12.0.md

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ab67d4fe8a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread tools/tests/packaging_safety.py Outdated
themuffinator and others added 3 commits August 26, 2026 08:07
game_type_module_selection.py was updated to require GAME_API_VERSION 45
but both workflows still fetched openQ4-game at the GAME_API 44 companion
revision, failing Validation Script Smoke on every push. The 45-bearing
companion commits are now published on openQ4-game's matching branch;
pin its tip (80cbf476, "game: optimize presentation sampling and screen
effects"), which the full local smoke sweep passes against.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
stage_fast_install.py now stages by the host platform runtime policy, so
the guard/copy validation cannot pin Windows .exe/.dll artifact names:
on Linux the policy excludes them and the staged-file assertions fail.
Parametrize the fixture and assertions by sys.platform; exact
per-platform policy output stays pinned by
validate_fast_stage_cross_platform_policy.

Verified via the full smoke sweep on Windows and WSL Ubuntu (ext4).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
draw_arb2.cpp and draw_common.cpp call std::memcmp/memset/memcpy without
including <cstring>, which breaks the Linux ARM64 cross build (GCC
libstdc++ does not provide them transitively there). vk_GuiExecutor.cpp
has the same latent gap and is compiled by the Linux renderer-vk build,
which has been skipped on this branch while script-smoke was red.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
themuffinator and others added 8 commits August 26, 2026 14:20
uiFontParitySelfTest forces the retail bitmap path (the probe sets
r_useTrueTypeFonts 0) and then requires fonts/marine to register, but an
assetless validation startup has no retail .fontdat atlases, so
registration cannot succeed anywhere CI runs the probe. Windows dev
machines never showed this because fs_basepath auto-discovery silently
mounts the installed retail Quake 4 assets.

Skip the marine registration and atlas cases only when the TrueType path
is off, registration failed, and no marine fontdat exists to load - the
same say-so-instead-of-failing treatment the test already gives the
TrueType path. With retail assets installed, or TTF enabled, the cases
still run and still fail on a real regression.

Verified on a CI-parity Linux x64 build (assetless): the parity failure
is gone and the skip line is reported.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
RendererContractsTest deliberately stores out-of-range values (99) to
prove the validators reject corrupt passes, but loading such a value
from an unscoped enum without a fixed underlying type is undefined
behavior, and the Linux ASan+UBSan job fails on the validator load in
RendererContracts_ValidateMaterialPass. Give every contract enum ": int"
- layout-identical to what compilers already chose, so the shared ABI is
unchanged but now guaranteed, and any representable value round-trips
with defined behavior.

Verified with the contracts test under -fsanitize=address,undefined:
old header reproduces the CI error, fixed header runs clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…rning fixes

Shadow-map corrections across classic GL, direct Vulkan, and the shared
interaction paths: automatic culling stores the near shell for sealed
geometry and renders open/uncertain stock geometry two-sided; large
point-light bias is world-bounded; balanced filter footprints are tighter
and cheaper; PCSS blocker search is bias-consistent; map/alpha/dynamic
cache ownership fails closed; projected and point resources carry exact
world/pass/storage provenance through bind time; partial mapped ownerships
receive exact stencil supplements or return to full stencil; modern GL
refuses resources it cannot consume completely; atlas placement follows
physical limits; nested GL elapsed queries no longer raise validation
errors.

Stock startup warnings resolved without replacement content: the three
brown-fluid images and the large water splash gain fail-after-primary
shipped-media fallbacks; generated TrueType atlas materials bind their
already-uploaded intrinsic images on first parse and survive renderer
restart; wide loading backgrounds keep atomic publication under long
Windows save paths via a root-relative 128-bit CSPRNG staging identity;
generated image caches fall back from the legacy qpath to a versioned
SHA-256/128 compact identity without bypassing VFS or pure-server
policy; immediately clamped or rested rigid-body states become developer
diagnostics while unrecovered physics faults keep warning severity;
binary-image header, mip, and payload writes reject short output.
21 verified behavior-neutral optimization groups across the renderer and
asset pipeline, found by a fan-out/adversarial-verify sweep:

- modern GL: per-program shadow-uniform location memo; GPU-driven submit
  memset elision (~1.4 MB/frame); submit-plan permutation sort;
  shadow-planner fairness high-water mark; clustered UBO-fallback prefix
  uploads; GUI-domain index maps
- classic GL/ARB2: GLSL uniform dirty-tracking and program-bind record
  cache; ClassicInteractionDomain hash-index lookups; decal
  sealed-command O(records) lookup with CSR scratch/seal swap-publish
- frontend: AddActiveInteraction loop-invariant hoist and per-frame
  r_actualRenderApi memo; drawSurf area-resolve memo; scene-packet
  temporal history hashing; DM_CACHED bytewise-identical entity-update
  elide with a c_entityUpdatesElided counter under r_showUpdates;
  persistent-upload bind elision
- models: generated-cache hits no longer re-run R_BuildDeformInfo or
  R_IdentifySilEdges (new R_AllocDeformInfo); array-codec model cache
  serialization
- images: DDS-replacement probe memo; BinaryImage load copy elision
- cinematics: frameSerial dirty-tracking (cinData_t gains frameSerial;
  header mirrored to GameLibs)
- Vulkan: batched image upload replacing per-mip fence waits; triangle
  memo sized 4096; pipeline MRU and depth-fill rebind guards;
  interaction descriptor suffix-rebind
- materials: custom-GLSL chain-fact static flag

Validated: full MSVC build, 31 static pin tests, renderer validation
matrix, gameplay benchmark smoke on game/storage1.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The companion gains the lockstep cinData_t frameSerial / material
GLSL chain-fact header mirror and the recovered rigid-body diagnostic
severity change; GAME_API stays 45.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The release-docs generator rewrote every relative .md link to .html even
when the target is not part of the generated site, leaving dead links;
README's new .github/CONTRIBUTING.md reference broke the offline site's
link integrity. Resolve each .md link against the rendered source set
and point unrendered targets at the repository blob URL instead.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
An extensive find -> adversarial-verify -> implement sweep across the
renderer and asset pipeline. Every change was verified against the
current tree and the token-pinning tests; behavior is unchanged for
stock content except where a latent bug is corrected.

Robustness (untrusted file parsing and error paths):
- ROQ cinematic decoder: reject VQ frames before QUAD_INFO (was a wild
  heap write via uninitialized qStatus), bound the cel-stream walk to
  the chunk payload, and validate motion-compensation source blocks
  against the decode image; JPEG loader gains the TGA-style dimension
  overflow guard and a short-read check; MD5 mesh weight spans are now
  fatal-on-out-of-range instead of an OOB read/write.
- Render-world .proc parsing: bounds-check inter-area portal areas and
  point counts, validate the BSP node graph before it is recursed, and
  validate shadow-model counts/indices (FinishSurfaces is skipped there).
- Null/oob guards: ModelTrace deform+customShader surfaces, GetPortal
  area range, R_RemoteRender entity-less surfaces, zero-stage
  referenceShader, polytope degenerate windings, R_FindARBProgram table
  scan, R_FrameAlloc negative size, UpdateEntity/LightDef interaction
  table resize.
- Vulkan: recover the frame fence on submit failure and on a device-lost
  BeginFrame/screenshot-resume instead of wedging or deadlocking; fail
  closed when a swapchain reports more than 8 images; latch the frame
  ring overflow warning so one oversized scene cannot storm the console.

Correctness:
- Beam and sprite dynamic models freed their persistent vertex cache so
  parm-driven geometry/color changes reach the GPU again (the beam's
  reuse path was dead code); the modern light-image atlas re-uploads when
  a reload changes source dimensions under a recycled GL name.

Optimization (behavior-neutral):
- Frontend: per-entity draw-surf-area memo invalidation and a memo clear
  in FreeDefs; cached point-light emitter-caster verdict; Trace loop
  hoist and allocation-free name compares.
- Modern GL: viewLight->descriptor hash; mapped-light selection sorted
  once instead of rescanned; in-place shadow descriptor build; single
  memset for index/shadow staging; cluster bin bounds cached across the
  count/fill passes; light-atlas count refresh once per frame; debug-name
  formatting gated on the diagnostics that read it.
- Vulkan: one ring flush per frame instead of per allocation; depth
  capture via a single flipped blit when supported; interaction pipeline
  bind de-duplicated across a receiver chain.
- Classic GL: drop the redundant per-draw point-shadow-far upload; retain
  the scene-scale state across views; skip unit-1 combiner teardown when
  it was never set up; set the current-depth sampler parameters once per
  storage generation.

Validated: full MSVC build (client, dedicated, both renderer modules);
executed CI test suite; renderer validation matrix 36/36; gameplay
benchmark smoke on game/storage1 for both OpenGL and Vulkan.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@themuffinator
themuffinator merged commit fe99a3d into main Aug 26, 2026
11 of 16 checks passed
@themuffinator
themuffinator deleted the codex/idtech5-modernization-plan branch August 26, 2026 15:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant