Repository navigation
PRD-539: try Unreal TSR history levers and benchmark against Unreal - #606
Conversation
…al TSR levers 1-2) historyScale stores resolve and history at 2x the display raster (r.TSR.History.ScreenPercentage=200); velocityWeightClamp ports TSR's sample-count clamp under motion. Both are opt-in arms of the unchanged gate.
…reader, static-camera gate control (PRD-539)
…t-refine arm A full-resolution input under a 2x history keeps its owned point sample, so history scale is the only variable. The tsr arm adds Unreal TSR's refine rule: the current frame enters each history pixel through the history-pixel kernel and weighs by its nearest jittered sample's alignment.
A pixel's footprint does not move with the TRAA subpixel offset. The jittered frustum let a receiver on the view's edge enter and leave, so a lamp whose footprint sat on a mip boundary flipped its map size every frame and reallocated it. On the Wasm engine the released maps waited for JS GC: the PRD-539 cornell motion run at screenPercentage=50 grew VRAM about 65 MB per step and lost the device (VK_ERROR_OUT_OF_DEVICE_MEMORY) before frame 0. Red-green: lamp_size_ignores_temporal_jitter read 2 sizes over 16 still TRAA frames before, 1 after. lamp_atlas and 24 lamp/shadow/light/TRAA render-database cases pass.
Same scene, Unreal 5.8.3 against ThreeNative: TSR/TRAA at 50% screen percentageScene: Columns: UNREAL 5.8.3 100% | UNREAL TSR 50% | THREENATIVE 100% | THREENATIVE 50%. Rows: frames 10, 25, 40, 55. Bottom row: 3× crop at frame 40 (box edge against the green wall). Quality, moving frames 0–60, each 50% arm against its own 100%
Distance from ThreeNative to Unreal is the same at both scales: mean abs error .0277 at 100%, .0274 at 50%. GPU cost (2 runs per arm, p50)
Engine fix needed for the 50% capture (
Gate run 3: Unreal's alignment refine ( Raw: sheet · metrics · cross-engine |
…ted refine and spatial-AA arms Gate run 4: Unreal TSR's spatial anti-aliasing of rejected input leaves edge error unchanged and raises reveal stale (full .0003 -> .0024, low input .0177 -> .0204). Gate run 3 already rejected the alignment refine. Both arms leave the provider and the gate; their numbers stay in the PRD. history200-clamp stays opt-in: as a default it presents a 2x raster.
Port of Unreal TSR's history resolve (UE 5.8.3 TSRResolveHistory.usf:312-357): a 4x4 Mitchell (B=C=1/3) downsample with the 1/(R+2G+B+4) HDR weight, clamped to the samples' range. At historyScale 2 the chain now reads a display-sized raster instead of the 2x history, so later post stages stop paying 4x pixels. Red: presented 3840x2160 for a 1920x1080 display. Green: 1920x1080.
WGSL has no infinity literal; gate run 5 failed the history200 arm with 'expected , for function call' at vec4<f32>(Infinity.0, ...).
With no weighting named, the provider keeps history at 200% of the display
(UE 5.8.3 BaseScalability.ini:89) with the velocity-clamped weight, and the
chain reads the display-sized Mitchell resolve. The raw4 path keeps 100%.
{ historyScale: 1, velocityWeightClamp: false } is the named override and the
new history100 gate arm. Gate run 6 measured the two-lever arm at edge .04387
against the .04616 bar (the 100% default read .0486 reference).
The resolve moves to temporalHistoryResolve.ts and the 100% reset seed into
frames.draw, so every starter render file stays under 200 lines.
Red: default history 1920 wide at a 1920 display. Green: 3840.
…y full-resolution check
Temporal AA now defaults to Unreal's Epic-tier TSR historyColumns: BEFORE (100% history, 2 runs) · AFTER (200% history + velocity clamp, shown through the display-sized Mitchell resolve, 2 runs) · REFERENCE (supersampled). Commit Judge (Opus, read-only): full resolution IMPROVEMENT: the fence bars and the rod are cleaner, with no ghosting, halo or colour shift. Low input NEUTRAL.
|
…uction, not history
Port of Unreal TSR's moire measurement (UE 5.8.3 TSRShadingAnalysis.ush: 225-229,263-271,381-455,477-490,586-593): a ping-pong state of luma gradient, total variation and flicker count, decayed by 0.95 on still pixels, widens the clip box by 3x the moire error. Opt in with flickerRejection: true; gate arms flicker, flicker-open and quality-flicker. No 5x5 flicker dilation yet. Red-green: the kernel holds the moire ramp only with the lever on, and the update pass compiles to WGSL with no unparseable literal.
Unreal accumulates max3x3(max3x3()) of the flicker and its variation (UE 5.8.3 TSRShadingAnalysis.ush:441-455). Without it a sub-texel bar that moves between neighbours across jitter phases flickered too rarely at any one pixel: gate run 8 moved low-input edge .07055 -> .07048 only. The update is now a detect pass and a dilate-and-accumulate pass.
…(opt-in) Static-camera gates showed the per-pixel clip to the low-input 3x3 box erases sub-texel detail that unclipped history keeps. Unreal compares input and history after a 3x3 blur and lerps the clamped history back to the unclamped one by Min3x3(Median3x3(rejection)), 0 on disocclusion (UE 5.8.3 TSRShadingAnalysis.ush:25,509-525,563-566,589-636, TSRRejectShading.usf:863, TSRUpdateHistory.usf:1256-1257). Six input-raster passes before the resolve. Gate arms release, release-open, quality-release. Red-green: the kernel reads the release only with the lever on; all six passes compile to WGSL.
…e clamp-release rejection UE 5.8.3: TSRShadingAnalysis.ush:569-613. The gate's solo flicker and release arms become one flicker-release arm; their gate-10 numbers stay in the PRD.
…n scene for Unreal TN_TEMPORAL_PROBE=arm,arm captures only those arms and prints their edge error (diagnostic).
… scenes take no motion run), bars share one region
…ter than full res; it stays opt-in
PRD-539: Unreal same-scene benchmark at a locked GPU clock, leanpi review fix, judge 3Same scene against Unreal 5.8.3 (gi:cornell, 1280x720, GPU clock locked at 1500 MHz for both engines, 2 runs per arm, GPU ms):
One method difference: Unreal times the pan motion, ThreeNative the still poses. leanpi review ( Judge 3 (fresh read-only Opus, criteria first, shooter
Sheets: still run 1 · still run 2 · strafe run 1 · strafe run 2 · floor still · wall still · floor strafe · wall strafe · criteria |
…nst shipped MSAA Moves the PRD out of done/. What regressed: the box-97 visual verdict. Judge 2 rated TRAA 0.667 NEUTRAL (slight softness); judge 3 (commit 9b7ddb4, sheets ee4d4ed on prd-539-screenshots) rates it a REGRESSION with moderate softness, and a perf win counts only when the judge passes. Box 97 and acceptance 3 are unticked with their numbers kept; a textured same-scene comparison against Unreal TSR at 67% is the new open box.
…tured same scene; PRD-539 done gi:neon-corridor brick wall, both engines at 100% and 67%, sameness PASS (16 objects, 1 px). Judge 4 (anisotropy 1): FAIL, far-wall loss larger. Judge 5 (anisotropy 8, Unreal Epic r.MaxAnisotropy): PASS, EQUAL. Adds the calibration harness knob anisotropy=<n>. Files PRD-789 for the engine default anisotropy (deferred).
Textured same scene: TRAA 67% loses detail equal to Unreal TSR 67% (judge 5 PASS)Commit
Judge 5 sheets: far wall run 1 · run 2 · mid wall · full frames · criteria |
…istory # Conflicts: # README.md # docs/PRDs/Unreal/performance/PRD-539-low-resolution-temporal-reconstruction-quality-and-cost.md # docs/PRDs/Unreal/research/port-history.json # docs/PRDs/Unreal/research/unreal-port-progress.svg # docs/PRDs/Unreal/research/unreal-port-status.svg # docs/PRDs/Unreal/research/unreal-visuals-and-performance-feature-map.html # packages/runtime-native/tests/native-engine/render_database_test.cpp
… max (VERDICT OK), rounding fixed, shooter-in-Unreal decision
…coverage record for PRD-539 sources overlay_over_frame read the presented frame within 4000 polls; on a loaded host (load 12-19) the readback landed after that, so presented stayed empty (1 of 3 and 1 of 6 runs red). A 10 s bound plus CHECK(read): 12 of 12 green under the same load. The coverage record digest was stale after this branch's native changes (CI budgets red on run 41704323408).
…e-scene benchmark
|
The merge queue stopped on
Fix, push, re-enqueue. |
No box is ticked: every open criterion still needs a run this branch cannot produce. Each box now carries its measured numbers and the one run that would close it. PRD-628 - line 31 (payload reuse): run 41688813459 built `v8-android-6d7f399f…` in 1 h 45 min (18:18:44Z -> 20:03:42Z, artifact 13268070999, 27,451,905 bytes) after `No published …tgz`, `v8.artifact skipped` and `Cache not found`. Run 41718807432 restored it in 1.4 s and skipped the build. Both are `workflow_dispatch` on the same ref, so the pull-request scope stays unproven; the artifact read is verified read-only (v8-artifact-pick.mjs -> 41688813459). - line 32 (cancel keeps progress): run 41670763005 cancelled at `[1781/3519]`, saved `android-v8-source-…-41670763005-1`; run 41688813459 restored it and planned 1724 edges, not 3519. A dispatch run, so the `pull_request` arm stays unproven. - line 36 (ccache >= 80%): `test-native` 229/1076 = 21.28% (nothing restored), against 256/256, 280/280 and 312/312 = 100% in native-engine and starter-linux on the same board. - line 37 (cache table): second full warm table from 41688813459 attempt 1, 70 job logs and 181 cache lines; pnpm store, Playwright, Cargo, emsdk and third-party hit, Gradle misses. - line 55 (budget): 70 entries / 8.63 GiB at 21:19:40Z -> 86 entries / 9.28 GiB at 22:07:51Z, zero evictions; no full board completed in the window. PRD-480 AC-2 and its phase box: per-job wait p90 26.3 min (41718838521, merge group #606), 7.8 min (41718807432, dispatch #605) and 11.4 min (41569108715); median 11.4 min against 10, not met. 11 jobs per board on `tn-` runners.
|
The merge queue stopped on
Fix, push, re-enqueue. |
develop's copy of each of the seven conflicted files is byte-identical to the #606 queue commit 6103e42 that 605-sync round 1 resolved in 04f56b60c, #605 has not touched them since, and neither side changed packages/runtime-native or the templates since then, so those seven files are taken from 04f56b60c as is. Round 1 built render_database_test (123/123) and regenerated the coverage report (82.15%, every floor met) on that same content. Checks on this merge: unreal:status up to date, check:docs 3670 links, scaffold.spec 78/78, check-native-coverage + pre-commit-hook specs 8/8, pnpm typecheck exit 0.




What is this PR about?
PRD-539: a lower internal raster must reconstruct into a stable full-resolution frame. This PR tries Unreal TSR's untried levers as arms of the unchanged quality gate, and benchmarks the same scene in Unreal 5.8.3 and ThreeNative side by side.
Why does it matter?
Five earlier reconstructors failed the gate. Unreal's TSR attacks the same camera-drift loss with a 200% history and a velocity clamp on the history weight. If one of these arms clears the gate, low-resolution rendering can buy frame time with no visible loss.
Done
historyScale(1 or 2) andvelocityWeightClampoptions on the generated temporal provider, ported from UE 5.8.3TemporalSuperResolution.cpp:3219-3224andTSRUpdateHistory.usf:1262-1276Gate arms
history200,velocity-clamp,history200-clamp(and-open/quality-variants), reported underleverArms; thresholds unchangedRed-green unit test: history target at 2× display
Display-sized history resolve (4×4 Mitchell, HDR weight, sample clamp), ported from UE 5.8.3
TSRResolveHistory.usf:312-357; red-green: presented raster 3840×2160 → 1920×1080Provider default = Unreal Epic tier (200% history + velocity clamp,
BaseScalability.ini:89);{ historyScale: 1, velocityWeightClamp: false }is the named override and thehistory100gate arm. Gate run 7 passes every full-resolution check (edge .04387 < .04616); judge IMPROVEMENTEngine fix: lamp shadow-map size reads the unjittered camera (red-green
lamp_size_ignores_temporal_jitter)Low-input bar = Unreal TSR at the same input on the same fence scene (owner option 1); Unreal reveal measured with an occluder run. Gate run 12 exits 0, 15/15 checks
Unreal's view texture mip bias under temporal upscaling (lever 7,
SceneVisibility.cpp:5337-5351): judge IMPROVEMENT against no bias, NEUTRAL against full resolution; MSAA path pixel-identicalScripted three-scale scaler route conformance row
temporal-aa-scaler-routeShooter kit, GPU clock locked at 1500 MHz: TRAA 0.667 against shipped 4x MSAA, GPU p50 -40 to -46% web, -47% desktop native; p95 lower on both (look: judge 3 REGRESSION, moderate softness)
Same scene against Unreal 5.8.3 (gi:cornell, locked clock): at 67% ThreeNative 4.78-6.06 ms GPU p50 against Unreal 5.94-6.09
leanpi DeepSeek v4.1 flash max review of lever 7: node
texture()bias fix 8223caa (judge NEUTRAL, kept as Unreal parity)Not done (deferred, recorded in the PRD)
hightier default: not in this PRD's scopePRD-539 checklist
Phase 1
Phase 2
Acceptance
docs/PRDs/done/(33c5246)