No matching questions found
Try searching for terms like "5.5", "CPU", "ladder", "lock", or "tests".
Engine & Multi-Version Support
How a single source tree serves Unreal Engine 5.5, 5.6, 5.7, and 5.8 without preprocessor spaghetti.
Engine Matrix How does TargetFrame support UE 5.5, 5.6, 5.7, and 5.8 from one codebase? ↓
TargetFrameEngineCompat.h and use BuildSettingsVersion.Latest so target files compile across all four engines without edits.
TargetFrame establishes Unreal Engine 5.5 as the absolute floor. It avoids version-specific C++ APIs by encapsulating necessary version shims into TargetFrameEngineCompat.h (such as GetTotalDeviceWorkingMemory which was introduced in 5.6).
In addition, target files use BuildSettingsVersion.Latest (which resolves cleanly to V5 on 5.5/5.6, V6 on 5.7, and V7 on 5.8) because no single build settings literal compiles across all four versions.
Descriptors Why do neither TargetFrame nor TargetFrameSample declare EngineVersion in .uplugin? ↓
EngineVersion as an exact-match gate. Declaring "5.7.0" would make the plugin refuse to load in 5.5, 5.6, or 5.8. Packaging tools stamp the exact version dynamically.
In Unreal Engine, FPluginManager::IsPluginCompatible treats EngineVersion as an exact-match gate, not a minimum floor. If a descriptor declares "EngineVersion": "5.7.0", it is instantly rejected when opened in 5.5, 5.6, or 5.8.
By omitting EngineVersion in source, the plugin opens cleanly in any compatible engine. When built for Fab distribution via RunUAT BuildPlugin, Unreal's automation tool automatically stamps the exact per-engine version into the output descriptor.
Content Rules What is the Package Version 1013 rule and why does it matter? ↓
Unreal Engine reads packages older than the running engine, but never packages newer than itself. Shipped plugin assets (such as WBP_TargetFrameExperience.uasset) are strictly authored and serialized on UE 5.5 (package version 1013).
If an asset were saved in UE 5.7 or 5.8, its version would increase to 1018, causing a hard crash/failure when loaded in UE 5.5 or 5.6. This requirement is enforced by Scripts/CheckContentEngineFloor.py.
Two-Plugin Clean Architecture
Why showcase code was extracted and how it preserves clean commercial shipping.
Architecture Why is TargetFrame split into TargetFrame and TargetFrameSample? ↓
In earlier builds, demo classes like AScalabilityGameMode, AScalabilityDebugHUD, and ATargetFrameShowcaseActor lived inside the runtime plugin. This polluted the consumer's UObject namespace and forced games to compile demo assets and hardcoded shape lookups.
Plugins/TargetFrame: The pure runtime policy module, settings CDO, math library, and drop-in onboarding widget. Zero sample maps or demo classes.Plugins/TargetFrameSample: The optional showcase arena, camera tour, and developer debug HUD, equipped withCoreRedirectsso existing assets seamlessly resolve.
State Machine What are the 5 Gates of the TargetFrame State Machine? ↓
- Creation Gate: Under
UE_SERVER,IsRunningDedicatedServer(), or!FApp::CanEverRender(), the subsystem refuses creation entirely. Zero memory allocated. - Session Gate:
IsDisabledInCurrentSessionchecks world type, map filters, and per-instance PIE overrides. - Activation Gate:
bPolicyControlActivemust be explicitly activated by the game. Until then, TargetFrame only observes and benchmarks; it writes zero settings. - Governor Gate: Enforces warmup (default 10s), evaluation cadence (default 4s), and suppression when window is unfocused, paused, or during cinematics.
- Lock Gate: The fire-and-forget stabilization lock, which silences all adjustments once frame rate is stable and only wakes on severe deficits.
Governor & Asymmetric Cost Ladder
How the governor distinguishes hitches from sustained drift and navigates quality steps.
Cost Ladder What is the exact order of the Asymmetric Cost Ladder? ↓
When defending a deficit (StepQualityDown):
- CPU Groups: (View Distance & Foliage) — only if the frame is classified as CPU-bound.
- Upscaler Quality: Steps vendor upscaler mode (e.g. Quality → Balanced).
- Triangle Culling Scale: Tightens cull distances on heavy static meshes.
- Overall Scalability Level: Steps down base presets (Epic → High → Medium).
- Nanite Pixels-per-Edge: Softens rasterization density.
- Resolution Scale: Reduces 3D scene render percentage.
When recovering during a surplus (StepQualityUp), the order is reversed, with CPU groups restored last. This asymmetry prevents foliage and view distances from oscillating ahead of resolution and Nanite.
Filtering How does the wall-clock exponential filter reject hitches? ↓
Isolated long frames (e.g., streaming hitches or garbage collection pauses exceeding HitchThresholdSeconds = 0.1s) are excluded from the smoothed frame rate.
However, if a slow frame run persists longer than SustainedSlowFrameWindowSeconds = 1.0s, TargetFrame recognizes that the machine is genuinely struggling and integrates the true frame rate, triggering controlled step-downs.
Dual Quality Accounting
The architectural solution that allows CPU-bound adjustments to coexist with overall quality.
Dual Accounting What was the defect with overall quality in earlier builds? ↓
GetOverallScalabilityLevel() returns -1 if a single setting diverges. In old builds, stepping foliage down caused the policy to read back -1 and permanently freeze overall scalability.
Unreal's UGameUserSettings::GetOverallScalabilityLevel() returns -1 whenever any single per-group value (like Foliage or Shadows) diverges from a standard preset. In earlier builds, as soon as the CPU governor stepped down foliage, the policy engine read back -1, assumed overall quality was permanently invalid, and froze the overall scalability lever for the rest of the session.
Dual Accounting How does Dual Quality Accounting fix this? ↓
Status.OverallQualityLevel (engine mirror) and Status.ManagedOverallQualityLevel (our internal target). Applying presets preserves the independent CPU and resolution levers.
TargetFrame separates quality into two distinct properties:
Status.OverallQualityLevel: Faithfully mirrors the engine's report (reporting-1for custom mixes).Status.ManagedOverallQualityLevel: Tracks the actual tier TargetFrame is actively driving, seeded at activation.
When ApplyOverallQualityLevel writes a preset, it explicitly preserves ResolutionQuality (owned by the resolution lever) and, when bCPUQualityManaged is set, the foliage and view-distance groups. The two levers compose harmoniously without clobbering each other.
Engine-Calibrated Hardware Tiers
Fixing benchmark index thresholds by reading GScalabilityIni dynamically.
Tiers What was the hardware tier calibration defect and how was it resolved? ↓
GScalabilityIni dynamically where 115 is Epic tier, restoring 90 FPS performance.
Unreal's synthetic benchmark returns a normalized performance index on a scale where 115 represents the boundary for Epic-quality settings (as defined by [ScalabilitySettings] PerfIndexThresholds_* across UE 5.5–5.8: GPU 18 42 115).
An earlier build of TargetFrame mistakenly demanded an index of 220 for its top tier. As a result, powerful cards (such as an RTX 5060 Ti) were erroneously demoted to Entry tier and capped at 45 FPS.
The Fix: TargetFrame now dynamically reads PerfIndexThresholds directly from GScalabilityIni at runtime:
- Entry: Index < 42 (Target: 45 FPS)
- Mainstream: Index 42 – 114 (Target: 60 FPS)
- Performance: Index ≥ 115 (Target: 90 FPS)
Mobile What happens if a mobile or integrated GPU returns a negative benchmark score? ↓
On devices like the Mali-G57 (tested on Android 14), Unreal's synthetic GPU benchmark can fail or return an invalid negative score (e.g. -25.1). TargetFrame's pure math core detects the non-monotonic or negative score, rejects it, falls back to the CPU benchmark score, and applies the low-memory constraint to select Entry tier safely.
CPU Governor & Thread Decoupling
Attacking GameThread bottlenecks without needlessly degrading image resolution.
CPU vs GPU Why does dropping resolution fail to fix CPU bottlenecks? ↓
Render resolution scale affects GPU pixel shading and rasterization cost. If the game is bottlenecked by the GameThread (e.g., hundreds of ticking actors, AI, or complex animation graphs), dropping the screen percentage from 100% to 50% yields 0 ms of CPU savings while making the game blurry. TargetFrame instead targets CPU-bound scalability levers (View Distance and Foliage) to reduce culling and transform overhead.
Validation How was the CPU Governor validated in automated tests? ↓
TargetFrame.Soak.CPUBoundRealWorkload, executing 30ms/frame of genuine math on the GameThread. UE measured 31.5ms GameThread vs 6.1ms GPU, properly triggering CPU step-downs.
TargetFrame includes two complementary soak tests:
TargetFrame.Soak.CPUBoundLadder: Injects deterministic thread timings (40ms GameThread vs 6ms GPU) to test the decision logic.TargetFrame.Soak.CPUBoundRealWorkload: Executes 30ms/frame of genuine mathematical work on the Unreal GameThread. Across all four engines (5.5–5.8), the engine measured 31.3–31.6ms ofGGameThreadTimevs 6.0–6.3ms GPU time, proving that real workloads properly trigger the CPU ladder.
Console Variable Ownership Semantics
How TargetFrame interacts with Unreal's internal CVar priority hierarchy.
Priority What CVar priority does TargetFrame use? ↓
ECVF_SetByGameSetting. This ranks above engine scalability presets (SetByScalability), preventing engine sweeps from wiping our VSM or texture pool caps.
TargetFrame writes console variables at ECVF_SetByGameSetting. In Unreal Engine's priority hierarchy:
ECVF_SetByCode > ECVF_SetByGameSetting > ECVF_SetByScalability > ECVF_SetByProjectSetting
This means TargetFrame overrides standard engine scalability sweeps (sg.*), preventing Unreal from clobbering its VSM page limits or texture pool budgets.
Instrumentation What is Status.RejectedConsoleVariables? ↓
SetByCode, lower-priority writes are ignored. TargetFrame detects this and logs the rejected variable so developers always know what took precedence.
If a variable is locked by C++ code using ECVF_SetByCode or by an active Device Profile, Unreal silently ignores writes with lower priority. TargetFrame instruments this, detects when a write is rejected, records the variable in Status.RejectedConsoleVariables, and notes it in the diagnostic summary.
27 Automation Tests
Comprehensive test coverage across pure math, runtime state, and soak endurance.
Test Matrix What are the three automation test suites? ↓
| Suite | Tests | Execution Context | Coverage |
|---|---|---|---|
TargetFrame.PolicyMath | 12 | Any context (Instant) | Pure math, budgets, hitch rejection, smoothing consistency at 33Hz and 333Hz, tier decisions. |
TargetFrame.Runtime | 11 | Client context (Live World) | Snapshots, custom mix protection, fractional t.MaxFPS, UI separation, delegates. |
TargetFrame.Soak | 4 | Client context (Live World) | Governor ladder sweep, level travel recovery, injected CPU ladder, and 30ms real CPU workload. |
Integrity Why were tests updated to remove EditorContext? ↓
true — producing 12 false "green" passes. Removing EditorContext and requiring a live world guarantees 100% real execution.
In a bare editor session with no active world or GameInstance, client-dependent tests hit their "no live subsystem" guard. Previously, this guard logged a warning but returned true — resulting in 12 tests reporting a false "green" pass without ever executing.
Removing EditorContext ensures they only run when a live world exists (via -game or PIE), and the guard now explicitly calls AddError so silent skips are impossible.
Troubleshooting & Integration Pitfalls
Fast diagnosis for common integration and packaging hurdles.
Packaging BuildPlugin fails on TargetFrameSample with "missing plugin dependency". Why? ↓
RunUAT BuildPlugin runs in an isolated sandbox containing only that single plugin. Because the sample depends on TargetFrame, package the parent project or package TargetFrame first.
Unreal's RunUAT BuildPlugin compiles a plugin inside an isolated throwaway host project containing only that plugin. Because TargetFrameSample explicitly depends on TargetFrame, BuildPlugin cannot resolve the dependency in an isolated container. To package the sample, package the parent host project or include both plugins in your game repository.
TargetFrame