# 69 — BPC_PerformanceScaler ## Blueprint Spec — UE 5.5–5.7 --- ### Parent Class `ActorComponent` ### Dependencies - [`BPC_RenderPipelineManager`](../12-settings/149_BPC_RenderPipelineManager.md) — **Delegates all CVar application** (GI, shadows, upscaling, Nanite, quality tiers) - [`DA_RenderPipelineProfile`](../14-data-assets/DA_RenderPipelineProfile.md) — Reads render config per platform + quality tier - [`BPC_LightingManager`](65_BPC_LightingManager.md) — Controls light quality - [`BPC_AudioManager`](66_BPC_AudioManager.md) — Controls audio quality - [`BPC_VFXManager`](67_BPC_VFXManager.md) — Controls particle LOD - [`BPC_AtmosphereController`](64_BPC_AtmosphereController.md) — Preset complexity reduction - [`SS_SaveManager`](../05-saveload/28_SS_SaveManager.md) — Save performance settings - [`GI_GameFramework`](../01-core/04_GI_GameFramework.md) — Frame time measurement ### Purpose Automatically adjusts rendering, audio, and gameplay quality settings based on real-time performance metrics (frame time, draw calls, memory usage). **Delegates all render pipeline CVar changes to `BPC_RenderPipelineManager`** — this component focuses on monitoring performance and deciding WHEN to change quality tiers. The RenderPipelineManager handles the HOW (which CVars to execute, whether a reload is needed). Supports manual user override via Settings menu and adaptive automatic mode. Maintains a performance budget that is dynamically allocated across subsystems. ### Enums **EPerformanceQualityLevel** | Value | Description | |-------|-------------| | Low | Minimum quality, max performance | | Medium | Balanced quality/performance | | High | High quality | | Ultra | Maximum quality, no compromises | | Cinematic | Maximum visual fidelity, 30fps target | **EScalingTarget** | Value | Description | |-------|-------------| | ResolutionScale | Screen percentage | | ShadowQuality | Shadow resolution and distance | | TextureQuality | Texture streaming pool | | PostProcessQuality | Post-process complexity | | ParticleLOD | VFX particle count | | AudioQuality | Audio layer count | | ViewDistance | Draw distance | | FoliageDensity | Foliage and grass density | | AntiAliasing | Anti-aliasing method | | GlobalIllumination | GI quality | ### Variables | Name | Type | Description | |------|------|-------------| | `CurrentQualityLevel` | EPerformanceQualityLevel | Active quality level | | `TargetQualityLevel` | EPerformanceQualityLevel | Quality being transitioned to | | `bAdaptiveMode` | Bool | Auto-adjust based on performance | | `bUserOverride` | Bool | Player manually set quality | | `FrameTimeHistory` | TArray\ | Rolling frame time samples | | `AverageFrameTime` | Float | Smoothed average frame time | | `FrameTimeVariance` | Float | Frame time stability metric | | `TargetFrameTime` | Float | Desired frame time (e.g., 16.67ms for 60fps) | | `PerformanceBudget` | Float | Allowed ms per frame | | `ScalerSettings` | TMap\ | Current scaling multipliers | | `bIsScalingInProgress` | Bool | Currently adjusting settings | | `MeasurementInterval` | Float | Seconds between performance checks | | `AdjustmentCooldown` | Float | Min time between quality changes | | `LastAdjustmentTime` | Float | Last quality change timestamp | | `QualityOverrideLevel` | EPerformanceQualityLevel | Manual override level | | `PlatformProfile` | FName | Detected platform profile | ### Functions | Name | Inputs | Outputs | Description | |------|--------|---------|-------------| | `Initialize` | — | — | Read saved settings, detect platform | | `SetQualityLevel` | Level: EPerformanceQualityLevel | — | Apply quality level | | `SetAdaptiveMode` | bEnabled: Bool | — | Toggle adaptive scaling | | `GetCurrentQualityLevel` | — | EPerformanceQualityLevel | Current level | | `GetRecommendedQuality` | — | EPerformanceQualityLevel | System-recommended level | | `MeasurePerformance` | — | — | Sample frame time from GI_GameFramework | | `EvaluateScaling` | — | — | Decide if scaling is needed | | `ApplyScalerSettings` | Level: EPerformanceQualityLevel | — | Apply settings to subsystems | | `SetResolutionScale` | Scale: Float | — | Screen percentage | | `SetShadowQuality` | Level: Int32 | — | Shadow resolution preset | | `SetTexturePoolSize` | SizeMB: Int32 | — | Texture streaming pool | | `SetViewDistance` | Distance: Float | — | Draw distance | | `SetFoliageDensity` | Density: Float | — | Foliage cull distance | | `SetParticleLOD` | LODLevel: Int32 | — | Particle LOD for VFXManager | | `SetAudioQuality` | Quality: Int32 | — | Audio layer count | | `SetGlobalIllumination` | Quality: Int32 | — | GI method | | `NotifySubsystemScaled` | Target: EScalingTarget | — | Broadcast scaled subsystems | | `SavePerformanceSettings` | — | — | Persist to SS_SaveManager | | `OnFrameTimeSpike` | SpikeValue: Float | — | Handle sudden frame drop | ### Blueprint Flow ``` [BeginPlay] └─► Initialize(): Detect platform (Console, PC Low/Med/High, Steam Deck, etc.) Load saved settings from SS_SaveManager If no saved settings: GetRecommendedQuality() based on platform Apply quality level Start measurement timer with MeasurementInterval [Timer - MeasurePerformance] └─► MeasurePerformance(): Get frame time from GI_GameFramework.FrameTimeHistory Add to local FrameTimeHistory, keep rolling window (last 60 frames) Calculate AverageFrameTime (exponential moving average) Calculate FrameTimeVariance (standard deviation of history) If bAdaptiveMode and not bUserOverride: EvaluateScaling() [EvaluateScaling] └─► If AverageFrameTime > TargetFrameTime * 1.2: (Running slow, too many frames over target) If TimeSince LastAdjustment > AdjustmentCooldown: SetQualityLevel(CurrentQualityLevel - 1) └─► If AverageFrameTime < TargetFrameTime * 0.7 and FrameTimeVariance < 2.0: (Running fast, stable, can upgrade) If TimeSince LastAdjustment > AdjustmentCooldown * 2: SetQualityLevel(CurrentQualityLevel + 1) └─► If FrameTimeVariance > 5.0: (Unstable frame times, reduce quality for stability) SetQualityLevel(CurrentQualityLevel - 1) [SetQualityLevel] └─► If CurrentQualityLevel == Level: return └─► TargetQualityLevel = Level └─► bIsScalingInProgress = true └─► Delegate to BPC_RenderPipelineManager.ApplyQualityPreset(PresetName) → RenderPipelineManager handles ALL CVar application → Reads DA_RenderPipelineProfile for current platform → Returns whether reload is required └─► For each non-render subsystem: BPC_LightingManager: Reduce dynamic light count BPC_AudioManager: Reduce active layers and spatial audio BPC_VFXManager: SetParticleLOD mapped to QualityLevel BPC_AtmosphereController: Reduce preset complexity └─► bIsScalingInProgress = false └─► CurrentQualityLevel = TargetQualityLevel └─► OnQualityLevelChanged.Broadcast(CurrentQualityLevel) └─► SavePerformanceSettings() [ApplyScalerSettings - Quality Levels] └─► Low: ResolutionScale = 0.7 ShadowQuality = 0 (off/low) TexturePoolSize = 512 MB PostProcessQuality = Low ParticleLOD = 2 (minimum) AudioQuality = 0 (mono, 2 layers max) ViewDistance = Low FoliageDensity = 0.3 AntiAliasing = TSR Low GlobalIllumination = None └─► Medium: ResolutionScale = 0.85 ShadowQuality = 1 (medium) TexturePoolSize = 1024 MB PostProcessQuality = Medium ParticleLOD = 1 (reduced) AudioQuality = 1 (stereo, 4 layers) ViewDistance = Medium FoliageDensity = 0.6 AntiAliasing = TSR Medium GlobalIllumination = Lumen Low └─► High: ResolutionScale = 1.0 ShadowQuality = 2 (high) TexturePoolSize = 2048 MB PostProcessQuality = High ParticleLOD = 0 (full) AudioQuality = 2 (surround, all layers) ViewDistance = High FoliageDensity = 1.0 AntiAliasing = TSR High GlobalIllumination = Lumen High └─► Ultra: ResolutionScale = 1.0 ShadowQuality = 3 (ultra) TexturePoolSize = 4096 MB PostProcessQuality = Cinematic ParticleLOD = 0 (full with extras) AudioQuality = 3 (full spatial, max layers) ViewDistance = Epic FoliageDensity = 1.5 AntiAliasing = TSR Epic GlobalIllumination = Lumen Ultra └─► Cinematic: ResolutionScale = 1.0 (or 1.25 for supersampling) ShadowQuality = 3 (ultra with contact shadows) TexturePoolSize = 8192 MB PostProcessQuality = Cinematic with extra effects ParticleLOD = 0 with extra presets AudioQuality = 3 ViewDistance = Epic with forced high-resolution impostors FoliageDensity = 2.0 AntiAliasing = TSR Epic with extra samples GlobalIllumination = Lumen Ultra + Path Tracing toggle [OnFrameTimeSpike] └─► If spike > 50ms (sudden freeze): SetQualityLevel(Low) temporarily After 5 seconds of stable performance: Gradually restore to previous level ``` ### Event Dispatchers | Name | Payload | Description | |------|---------|-------------| | `OnQualityLevelChanged` | NewLevel: EPerformanceQualityLevel | Broadcast quality change | | `OnScalingTargetAdjusted` | Target: EScalingTarget, NewValue: Float | Per-target adjustment | ### Communications With | Target | Method | Why | |--------|--------|-----| | [`BPC_RenderPipelineManager`](../12-settings/149_BPC_RenderPipelineManager.md) | Direct call | **All render CVar application** — delegates quality tier to pipeline manager | | [`GI_GameFramework`](../01-core/04_GI_GameFramework.md) | Direct call | Frame time data source | | [`SS_SaveManager`](../05-saveload/28_SS_SaveManager.md) | Direct call | Save/load settings | | [`BPC_LightingManager`](65_BPC_LightingManager.md) | Get from player | Light quality reduction | | [`BPC_AudioManager`](66_BPC_AudioManager.md) | Get from player | Audio quality reduction | | [`BPC_VFXManager`](67_BPC_VFXManager.md) | Get from player | Particle LOD control | | [`BPC_AtmosphereController`](64_BPC_AtmosphereController.md) | Get from player | Preset complexity reduction | | [`WBP_SettingsUI`](../06-ui/44_WBP_SettingsUI.md) | Event | User quality override | | [`BPC_PlayerController`] | Cast | Console command execution | ### Reuse Notes - Works with any subsystem that exposes quality API: Lighting, Audio, VFX, etc. - Frame time history rolling window: last 60 frames for smooth average - Adaptive mode is off by default; user must enable in settings - User override locks quality level until adaptive mode is re-enabled - PlatformProfile stores detected hardware for initial recommendation - Adjustment cooldown prevents oscillation between quality levels - Per-scaling-target notifications enable UI to show specific quality changes