PSO Autopilot Manual
Welcome to PSO Autopilot. This plugin is a reliable, production-ready solution to Unreal Engine 5's notorious shader compilation stutter and lag.
The "Shader Compilation" plugins on various marketplaces attempt to solve stutter by brute-forcing the Engine—loading all of your project's assets into memory simultaneously. If you are building a massive 50GB open-world game, this simplistic approach guarantees catastrophic RAM spikes, completely frozen loading screens, and eventually, Out-Of-Memory (OOM) crashes on consoles or lower-end PCs.
PSO Autopilot is different. It was created from the ground up to orchestrate Unreal's native hardware pipeline asynchronously, managing memory, threads, and driver caches with architectural precision.
🛡️ Robust Architecture
PSO Autopilot includes built-in safeguards like Blanket Scan Protection. If you accidentally clear your target directories, the plugin instantly aborts rather than attempting to scan your entire 100GB project folder, preventing massive Editor lockups.
Key Features at a Glance
- Memory-safe batching — flat RAM throughout the entire warmup cycle
- Time-sliced processing — 60fps loading screens with configurable frame budget
- Smart fingerprint caching — skip warmup entirely on subsequent launches
- Texture pre-heating — standard and Virtual Texture streaming before the loading screen drops
- Full vertex-factory coverage — Local, Nanite, ParticleSprite, BeamTrail, and MeshParticle PSOs
- Drop-in Boot Loader — zero-code loading screen with progress bar and level transition
- Blueprint-friendly delegates —
OnProgressUpdatedandOnWarmupComplete - Editor-aware — filesystem timestamps detected so you never test stale shaders
The 4 Pillars of PSO Autopilot
Our architecture is built upon the following pillars that make it unique in the Unreal ecosystem.
USP 1: Memory-Safe Chunking
Instead of loading thousands of assets simultaneously, PSO Autopilot utilizes Unreal's FStreamableManager to asynchronously stream your assets into memory in strictly controlled batches.
Once a batch is successfully compiled by the Engine's native FShaderPipelineCache, the plugin explicitly drops all asset references and requests a non-blocking Garbage Collection pass. Your RAM footprint remains completely flat throughout the entire process.
Async
Time-Sliced
Memory Cleared
USP 2: The Seamless Loading Screen
A frozen loading screen feels like a crash to a player. PSO Autopilot uses advanced C++ time-slicing within the Game Thread's Tick function. It processes Asset Registry queries and shader assignments for a strictly allocated timeframe per frame (e.g., 5.0 milliseconds).
If the time limit is reached, it yields execution back to the Engine. This guarantees that your loading screen videos, UI spinners, and progress bars remain buttery smooth at 60fps while intense compilation happens quietly in the background.
USP 3: Zero-Redundancy Boot (Smart Cache Hashing)
Players shouldn't have to wait for shaders they've already compiled. When a player boots your game for the second time, PSO Autopilot intelligently checks its generated MD5 fingerprint against the local config.
If the Pipeline State Objects (PSOs) for your project are already fully digested and stored on the user's hard drive, the plugin instantly skips the entire warmup sequence. A process that took two minutes on the first launch will take 0.05 seconds on all subsequent launches.
⏱️ Editor Timestamping
During development (WITH_EDITOR), the Smart Cache hashing algorithm actually interrogates the physical filesystem modification timestamps of your materials. If you tweak a Material Graph and save it, PSO Autopilot detects the change and bypasses the cache skip, ensuring you never test with stale shaders.
USP 4: Visual Continuity (Texture Pre-Heating) New in 1.2
Solving shader stutter is only half the battle. If your textures and virtual landscapes pop in blurry after the loading screen drops, the immersion is still broken.
Because PSO Autopilot already safely loads your materials into memory, it now automatically interrogates them for their texture dependencies. It seamlessly issues high-priority streaming requests for standard Textures (forcing high-res Mips) and pre-pages Virtual Textures (RVT/SVT) directly into VRAM before allowing the loading screen to finish.
Quick Start Guide
Follow these steps to get PSO Autopilot running in your project in under 5 minutes:
- Ensure the PSOAutopilot folder is located in your project's
Pluginsdirectory. - Launch your project in Unreal Engine 5.
- Go to Edit > Project Settings. Scroll down the left sidebar to the Plugins section and click on PSO Autopilot.
- Under Targeting, add the main directories containing your visual assets (e.g.,
/Game/Characters,/Game/VFX). - To test immediately, drop a BP_BootLoader actor into an empty starting map. It will automatically handle the loading screen UI and transition!
- Alternatively, open your primary GameInstance, use Get Game Instance Subsystem (
PSOAutopilotSubsystem), and call Start Warmup.
⚡ Minimum Viable Integration
The simplest possible integration is a single Blueprint node: GetGameInstanceSubsystem → StartWarmup. If you bind the OnWarmupComplete delegate to open your gameplay level, you have a fully working shader warmup pipeline in two nodes.
Configuration Settings
PSO Autopilot exposes powerful variables to Project Settings > Plugins > PSO Autopilot so you can tailor the memory/performance balance precisely to your hardware targets. All settings are stored in DefaultGame.ini under [/Script/PSOAutopilot.PSOAutopilotSettings].
Targeting
| Setting | Default | Description |
|---|---|---|
DirectoriesToScan |
(empty) | Array of content directories to recursively scan (e.g., /Game/Weapons, /Game/VFX). Do not set to /Game/ alone in large projects—isolate your heavy visual folders. Must contain at least one entry (Blanket Scan Protection). |
AdditionalClassesToScan |
(empty) | By default the plugin scans for UMaterialInterface. Add extra asset classes here (e.g., UNiagaraSystem, WidgetBlueprint). |
⚠️ Avoid Empty Path Entries
If your DefaultGame.ini contains +DirectoriesToScan=(Path=""), the empty string causes the Asset Registry filter to return zero results even when valid paths are also present. Remove any blank entries.
Memory Management
| Setting | Default | Description |
|---|---|---|
BatchSize |
100 | Number of assets loaded per batch. Lower to 50 for low-RAM targets (consoles, mobile). Higher values are faster but increase peak memory. |
bGarbageCollectBetweenBatches |
true | Request a GC pass after every batch is unloaded. Leave enabled for stable RAM. Disable only if warmup speed matters more than memory. |
Performance (Seamless UI)
| Setting | Default | Description |
|---|---|---|
MaxProcessingTimeMsPerFrame |
5.0 | Time budget (ms) for PSO processing per game-thread tick. A 60fps frame is 16.6ms—leaving 5ms gives the Engine 11.6ms for UI rendering. Increase up to ~10ms for faster warmup at the cost of choppier loading animations. |
Visual Continuity (VRAM) New in 1.2
| Setting | Default | Description |
|---|---|---|
bPreHeatTextureStreaming |
true | Forces standard textures referenced by scanned materials to load their high-resolution mip levels into VRAM during the warmup cycle. |
bPreHeatVirtualTextures |
true | Sends predictive page-in requests for Virtual Textures (RVT/SVT) to prevent grey blocks on world load. |
Validation & Minimum Duration
| Setting | Default | Description |
|---|---|---|
bEnforceMinimumValidationDuration |
false | When enabled, keeps the warmup in a hold state for a configurable time after all batches finish. Useful for stress-testing or demos where you want to observe the validation phase. |
MinimumValidationDurationSeconds |
0.0 | The minimum total warmup duration in seconds (only applies when enforcement is enabled). |
State Machine
Understanding the internal state machine helps you diagnose issues and integrate custom UI. PSO Autopilot transitions through these states sequentially:
The loop from Loading Batch through Waiting For GC repeats for each chunk of assets. Once every batch is processed, the machine enters Finished, fires the OnWarmupComplete delegate, writes the fingerprint to the config cache, and returns to Idle.
Batch Loop Details
Loading Batch — Uses FStreamableManager::RequestAsyncLoad to stream assets without blocking the game thread. A 60-second watchdog timer protects against stuck loads.
Processing Batch — Time-sliced PSO precaching via PrecachePSOs(). Covers Local, Nanite, ParticleSprite, BeamTrail, and MeshParticle vertex factories.
Streaming Textures — Calls SetForceMipLevelsToBeResident() on standard textures and UpdateResource() on Virtual Textures. A 30-second timeout prevents indefinite waits.
Unloading Batch — Releases all FStreamableHandle references and clears temporary component arrays.
Waiting For GC — If enabled, requests a full-purge Garbage Collection to reclaim memory before the next batch.
UI & Blueprint Integration
The PSOAutopilotSubsystem provides robust Blueprint delegates and a drop-in loading screen actor to drive your UI.
Boot Loader Actor Recommended
The APSOAutopilotBootLoader is the fastest way to add PSO warmup to your game. Drop it into your starting map (or a dedicated loading level) and configure it entirely from the Details panel—no C++ or Blueprints required.
| Property | Description |
|---|---|
LoadingScreenClass | Widget class to display during warmup. Falls back to UPSOAutopilotLoadingScreenWidget (a built-in dark-mode progress bar) if left empty. |
LevelToOpenOnComplete | Level name to open after warmup finishes. The Boot Loader validates the level exists before attempting the transition. Leave as None to stay in the current level. |
bApplySettingsOverride | When enabled, the Boot Loader temporarily overrides Project Settings with the values below, then restores them when done. |
DirectoriesToScanOverride | Override the target directories for this Boot Loader only. |
BatchSizeOverride | Override batch size (default 50). Clamped to 1–1000. |
MaxProcessingTimeMsPerFrameOverride | Override frame budget (default 5.0ms). Clamped to 0.1–33ms. |
bEnableMinimumDurationOverride | Enable/disable minimum validation duration for this instance. |
MinimumDurationSecondsOverride | Minimum hold time in seconds. |
bResetFingerprintOnBeginPlay | Force the warmup to run even if the fingerprint cache says it's complete. Useful for testing. |
bStartWarmupOnBeginPlay | Auto-start warmup in BeginPlay (default true). |
bRemoveLoadingWidgetOnComplete | Remove the loading widget from the viewport when warmup finishes (default true). |
🔄 Settings Snapshot & Restore
When bApplySettingsOverride is enabled, the Boot Loader captures a snapshot of your Project Settings before applying overrides. The original values are automatically restored when warmup completes or when the actor is destroyed, so your runtime settings are never permanently altered.
Delegates
On Progress Updated
Fires continuously during the warmup phase.
Overall Progress (Float): A normalized 0.0 to 1.0 value representing the total completion percentage. Bind this directly to a UMG ProgressBar.
Current Status Message (String): Live telemetry of the internal state. Messages cycle through: Scanning for Assets..., Loading Batch of 100..., Compiling PSOs... (42 remaining), Pre-heating VRAM..., Clearing Memory....
On Warmup Complete
Fires exactly once when the entire process is finished (or if it is instantly skipped via USP 3). Bind this event to close your loading screen and transition to gameplay.
Custom UMG Widgets
Don't want to build a UI from scratch? The plugin includes a highly customizable C++ base class: UPSOAutopilotLoadingScreenWidget. If dropped into a project without a custom UMG design, its fallback system will procedurally generate a sleek, dark-mode progress bar and status text UI automatically.
To customize: create a Widget Blueprint that inherits from UPSOAutopilotLoadingScreenWidget, design your own layout, and assign it to the Boot Loader's LoadingScreenClass property.
Blueprint-Driven Loading Screen
You can also use the subsystem directly from any Blueprint. Get the subsystem reference, bind to OnProgressUpdated and OnWarmupComplete, then call StartWarmup(). This gives you complete control over when and how the warmup runs.
// Blueprint pseudo-code
GameInstance -> GetSubsystem(PSOAutopilotSubsystem) -> subsystem
subsystem -> BindEvent(OnProgressUpdated) -> UpdateMyProgressBar
subsystem -> BindEvent(OnWarmupComplete) -> OpenLevel("MainMenu")
subsystem -> StartWarmup()
Fingerprint & Caching
PSO Autopilot uses an MD5 fingerprint to determine whether warmup needs to run. Understanding this system helps avoid unnecessary re-warmups and diagnose cache-related issues.
How the Fingerprint Works
- Scanning: After discovering assets, the plugin generates a fingerprint string from the sorted list of asset paths and their properties.
- Editor timestamps: In
WITH_EDITORbuilds, filesystem modification timestamps of source materials are mixed into the hash. This means saving a material automatically invalidates the cache. - MD5 hashing: The fingerprint string is hashed to produce a compact, deterministic identifier.
- Cache check: On startup, the plugin compares this fingerprint against previously completed fingerprints stored in
GameUserSettings.ini. - Skip or run: If the fingerprint matches a cached entry, the warmup is skipped entirely and
OnWarmupCompletefires immediately.
Multi-Configuration Cache New in 1.2
PSO Autopilot stores up to 8 completed fingerprints simultaneously using an LRU (Least Recently Used) eviction policy. This means:
- Different Boot Loaders scanning different directories won't invalidate each other's caches.
- Switching between build configurations preserves prior warmup results.
- When the 9th unique fingerprint completes, the oldest entry is evicted.
Cache Storage Location
Fingerprints are stored in GameUserSettings.ini under the [PSOAutopilot] section as a comma-separated list in the CompletedFingerprints key. You can clear this key to force a full re-warmup on the next launch.
⚠️ ResetCachedWarmupFingerprint
Calling ResetCachedWarmupFingerprint() on the subsystem clears all cached fingerprints. The Boot Loader exposes this via the bResetFingerprintOnBeginPlay checkbox. Use it during development when you want to guarantee the warmup runs.
Setting up the Demo
PSO Autopilot includes built-in C++ architecture to create a "Torture Test" demo, allowing you to visually prove the USPs to your team or clients.
- Create a new level (e.g.,
Demo_PSOTorture). - In your plugin's
Content/Demofolder, create a Widget Blueprint namedWBP_PSOAutopilotHUDand reparent it to the C++ classPSOAutopilotDemoWidget. - Add the following elements to your widget, naming them exactly:
SpinnerImage(Image) — This will automatically rotate at 60fps to prove USP 2.ProgressBar(ProgressBar) — Auto-binds to completion percentage.StatusText(TextBlock) — Auto-binds to live telemetry.TimerText(TextBlock) — Visualizes how fast USP 3 (Zero-Redundancy) skips loading.
- Drag a
PSOAutopilotDemoManageractor into your level. - In the Details panel of the Manager actor, set the
HUDClassto yourWBP_PSOAutopilotHUD. - Point your Project Settings at a folder filled with massive, uncompiled assets, and press Play!
📦 Demo vs. Production
The PSOAutopilotDemoManager is designed for demonstrations and testing only. It temporarily overrides your Project Settings (batch size, frame budget, minimum duration) and restores them when done. It is automatically disabled in Shipping builds. For production use, use the APSOAutopilotBootLoader instead.
Fallback Widget
If no HUDClass is set on the Demo Manager, it automatically falls back to UPSOAutopilotDemoWidget's C++ fallback UI, which procedurally generates a full telemetry panel with progress bar, status text, timer, batch metrics, cache comparison, and a 60fps spinner.
Best Practices
Target Precisely
Add only the directories that contain materials your players will see during gameplay. Scanning /Game/ on a large project will waste time on audio, data tables, and other non-visual assets. Typical targets:
/Game/Characters— player and NPC materials/Game/Weapons— weapon skins and attachments/Game/Environment— world materials and foliage/Game/VFX— particle and Niagara effects/Game/UI— only if you have material-based UI effects
Tune Batch Size to Your Target Hardware
The default batch size of 100 works well for mid-range PCs with 16GB RAM. Adjust based on your target:
- Console / Mobile (8GB or less): Batch size 25–50
- Mid-range PC (16GB): Batch size 50–100
- High-end PC (32GB+): Batch size 100–200
Monitor your peak memory using stat memory or an external profiler during the warmup cycle to find the sweet spot.
Use a Dedicated Loading Level
For the cleanest integration, create a minimal level that contains only a BP_BootLoader actor and a sky/background. Set LevelToOpenOnComplete to your main menu or gameplay level. This ensures:
- The warmup runs before any gameplay assets compete for memory.
- The player sees a polished loading screen, not a half-loaded world.
- Level transition automatically handles cleanup of warmup resources.
Test in Standalone Game Mode
The Editor handles PSOs differently than a deployed executable. For accurate results:
- Use
-gamemode:UnrealEditor.exe MyProject.uproject MyMap.umap -game -log -windowed - Or create a packaged Development build.
- Watch the
LogPSOAutopilotcategory in the output log for detailed telemetry.
Troubleshooting FAQ
Startup & Scanning
Q: The progress bar stays at 0% for a long time on boot.
A: Unreal Engine's Asset Registry initializes asynchronously in the background when the game boots. PSO Autopilot waits for this background scan to finish before querying assets to ensure none are missed. If your project is very large, this initial wait is normal. You can monitor progress in the log under LogPSOAutopilot: once the Asset Registry is ready, scanning begins immediately.
Q: The plugin instantly finishes and warns "DirectoriesToScan is empty!"
A: This is Blanket Scan Protection working as intended. If the targeting directories array is empty, the plugin aborts to prevent querying the entire Asset Registry. Add at least one directory (e.g., /Game) in Project Settings > Plugins > PSO Autopilot > Directories To Scan.
Q: The scan finds 0 assets even though my directories are set correctly.
A: Check for these common causes:
1. Empty path entry: If DefaultGame.ini contains +DirectoriesToScan=(Path=""), this empty entry causes the Asset Registry filter to fail silently. Remove it.
2. Wrong path format: Paths must use the /Game/ prefix, not filesystem paths. Use /Game/Characters, not Content/Characters.
3. Asset Registry not ready: In -game mode, the background asset scan may not have started yet. PSO Autopilot handles this with a synchronous scan fallback, but verify you're on v1.2 or later.
Q: Scanning is very slow in the Editor.
A: In Editor builds, PSO Autopilot queries filesystem modification timestamps for every discovered asset to build the fingerprint. This is necessary to detect material changes but adds I/O overhead. In packaged builds this step is skipped, and scanning is significantly faster. To speed up Editor iteration, narrow your DirectoriesToScan to only the folders you're actively working on.
Shader Compilation
Q: I see "Compiling PSOs..." in the log, but no shaders are actually building.
A: Ensure your project is configured to generate shader caches. In DefaultEngine.ini, verify that bShareMaterialShaderCode=True is set under [/Script/Engine.RendererSettings]. Also test in a Packaged Build or -game mode—the Editor handles PSOs differently than a deployed executable.
Q: Which vertex factories does PSO Autopilot cover?
A: The plugin submits PSO precache requests for these vertex factory types:
• Local Vertex Factory — Standard static meshes
• Nanite Vertex Factory — Nanite-enabled meshes (UE 5.x)
• Particle Sprite — GPU sprite particles
• Beam/Trail — Beam and trail particle emitters
• Mesh Particle — Mesh-based particle emitters
Skeletal mesh vertex factories are covered when the corresponding materials are scanned. Landscape and other specialized factories rely on the Engine's own PSO collection at draw time.
Memory & Performance
Q: My loading screen stutters or drops below 60fps during warmup.
A: The MaxProcessingTimeMsPerFrame setting controls how much game-thread time the plugin uses per frame. The default of 5.0ms should leave ~11.6ms for rendering at 60fps. If you're still seeing hitches:
1. Lower MaxProcessingTimeMsPerFrame to 2.0–3.0ms.
2. Reduce BatchSize—smaller batches mean less per-frame work.
3. Check if other systems (level streaming, audio loading) are competing for the game thread.
Q: RAM usage spikes during warmup. How do I reduce peak memory?
A: Three levers control memory usage:
1. Reduce BatchSize — Fewer assets loaded simultaneously means lower peak RAM. Try 25–50 for constrained platforms.
2. Enable GC Between Batches — Ensure bGarbageCollectBetweenBatches is true. The plugin performs a full-purge GC after each batch to aggressively reclaim memory.
3. Target fewer directories — Only scan folders with materials the player will actually see. Reducing total asset count is the most effective way to lower peak memory.
Q: The warmup takes too long. How can I speed it up?
A: Warmup speed is a tradeoff with memory and UI smoothness:
1. Increase BatchSize to 150–200 (if RAM allows).
2. Increase MaxProcessingTimeMsPerFrame to 8–10ms (loading animations may be slightly choppier).
3. Disable texture pre-heating if visual pop-in is acceptable: set bPreHeatTextureStreaming and bPreHeatVirtualTextures to false.
4. Narrow your scan targets to only critical directories.
Texture Streaming
Q: The log shows "Texture streaming timed out." Is this a problem?
A: The plugin imposes a 30-second timeout on the texture streaming phase per batch. If some textures haven't finished streaming by then, the plugin advances to the next batch rather than waiting indefinitely. This is a safety mechanism. If you see this frequently:
1. Your batch size may be too large for your I/O bandwidth. Reduce BatchSize.
2. Virtual Textures with very large page tables may need more time. The timeout is generous enough for most projects.
3. The textures will still stream in during gameplay—this timeout just means they weren't fully resident before the loading screen dropped.
Q: Textures still pop in blurry after the loading screen finishes.
A: Ensure both bPreHeatTextureStreaming and bPreHeatVirtualTextures are enabled in Project Settings. If the issue persists:
1. The materials causing pop-in may be outside your scanned directories. Add their parent folders to DirectoriesToScan.
2. Texture streaming may have timed out (see above). Check the log for timeout warnings.
3. If using World Partition or level streaming, textures in streamed sub-levels are not covered by PSO Autopilot's pre-heat—they are managed by Unreal's runtime streaming system.
Fingerprint & Cache
Q: The warmup runs every time I launch, even though nothing changed.
A: The fingerprint may be changing between launches. Common causes:
1. Editor timestamp drift: In Editor/PIE, filesystem timestamps are included in the fingerprint. If your source control or build system touches file modification dates, the hash changes. This does not happen in packaged builds.
2. GameUserSettings.ini not saved: The fingerprint is written to GameUserSettings.ini. If the game crashes before this file is flushed, the cache is lost. Check that the file is writable.
3. bResetFingerprintOnBeginPlay is enabled: The Boot Loader or Demo Manager may be forcing a reset. Check the actor's properties.
Q: I changed some materials but the warmup was skipped. Stale cache?
A: In Editor builds, PSO Autopilot includes filesystem timestamps in the fingerprint, so saving a material should invalidate the cache. If it doesn't:
1. Verify the changed material is inside one of your DirectoriesToScan directories.
2. The material may be a Material Instance whose parent hasn't changed. PSO Autopilot fingerprints the scanned assets, not their dependency chains. Re-save the parent material to force a new timestamp.
3. As a workaround, enable bResetFingerprintOnBeginPlay on your Boot Loader during development to always force the warmup.
Q: How do I manually clear the fingerprint cache?
A: Two methods:
1. At runtime: Call ResetCachedWarmupFingerprint() on the PSOAutopilotSubsystem before starting the warmup.
2. Manually: Open GameUserSettings.ini (in your project's Saved/Config/ folder) and delete the [PSOAutopilot] section.
Q: I have multiple Boot Loaders with different scan directories. Will they conflict?
A: No. PSO Autopilot stores up to 8 unique fingerprints using LRU eviction. Each Boot Loader generates its own fingerprint based on its scan configuration, and they are independently cached. The 9th unique fingerprint will evict the oldest entry.
Boot Loader
Q: The Boot Loader warns "LevelToOpenOnComplete was not found."
A: The level name you entered doesn't match any package on disk. The Boot Loader validates the level before attempting the transition to prevent crashes. Check that:
1. The level name matches exactly (case-sensitive on some platforms).
2. The level is included in your packaged build's list of maps (Project Settings > Packaging > List of maps to include).
3. You're using the short name (e.g., MainMenu), not the full path.
Q: The loading widget doesn't appear.
A: Check the following:
1. Ensure a valid Player Controller exists. The Boot Loader requires a local player controller to create widgets.
2. If using a custom LoadingScreenClass, verify it's a valid Widget Blueprint that compiles without errors.
3. Check the output log for LogPSOAutopilot messages—the Boot Loader logs whether widget creation succeeded or failed.
Q: My Project Settings get permanently changed after using the Boot Loader.
A: This should not happen. The Boot Loader captures a snapshot of your settings before applying overrides and restores them when warmup completes or when the actor is destroyed. If settings appear stuck:
1. Check if the game crashed before RestoreSettingsOverrides() ran. In that case, the CDO may have been modified but the INI file was not overwritten.
2. Restart the Editor to reload settings from DefaultGame.ini.
3. Verify that bApplySettingsOverride is actually enabled—if it's false, no snapshot is taken and nothing is restored.
Batch Processing
Q: The log shows "Batch load timed out." What happened?
A: A 60-second watchdog timer protects against stuck async loads. If an FStreamableManager::RequestAsyncLoad call doesn't complete within 60 seconds, the plugin cancels the load, marks the batch as failed, and advances to the next batch. Causes include:
1. Corrupted or excessively large assets that take too long to load.
2. Disk I/O contention (e.g., antivirus scanning, another application thrashing the disk).
3. The assets have external dependencies that trigger cascading loads. This is rare but can happen with deeply nested Blueprint references.
The warmup will continue with remaining batches. Failed batches are counted and reported in the completion log.
Q: The warmup completes but reports some failed batches. Should I worry?
A: A small number of failed batches (1–2 out of many) is usually harmless—those specific materials may have compilation issues unrelated to PSO Autopilot. The shaders for those materials will be compiled on-demand at draw time (with a potential micro-stutter). If many batches fail, investigate the assets in those batches for corruption or unsupported material features.
Integration & Platform
Q: Can I call StartWarmup() from C++ instead of using the Boot Loader?
A: Yes. Get the subsystem from your GameInstance and call StartWarmup() directly:
UGameInstance* GI = UGameplayStatics::GetGameInstance(this);
UPSOAutopilotSubsystem* PSO = GI->GetSubsystem<UPSOAutopilotSubsystem>();
PSO->OnWarmupComplete.AddDynamic(this, &AMyActor::OnWarmupDone);
PSO->StartWarmup();
Q: Does PSO Autopilot work on consoles (PlayStation, Xbox, Switch)?
A: PSO Autopilot is a pure C++ plugin with no platform-specific code. It uses only standard Unreal Engine APIs (FStreamableManager, PrecachePSOs, FShaderPipelineCache). It will compile and run on any platform that UE5 supports. However, you should tune BatchSize aggressively downward on consoles (25–50) to stay within their tighter memory budgets.
Q: Is the plugin safe to use in Shipping builds?
A: Yes. The core subsystem (UPSOAutopilotSubsystem) and Boot Loader (APSOAutopilotBootLoader) work in all build configurations including Shipping. The Demo Manager (APSOAutopilotDemoManager) is automatically disabled in Shipping builds via a compile-time guard.
Q: Can I run the warmup in a background thread instead of the game thread?
A: No. PSO precaching (PrecachePSOs) must happen on the game thread because it interacts with the rendering subsystem and material proxies. This is an Unreal Engine requirement, not a PSO Autopilot limitation. The time-slicing architecture ensures the game thread is only occupied for a configurable number of milliseconds per frame, keeping your UI responsive.
Logging & Debugging
Q: How do I enable detailed logging?
A: All PSO Autopilot messages use the LogPSOAutopilot log category. To see them:
1. In-Editor: Open the Output Log and filter by LogPSOAutopilot.
2. In -game mode: Add -log to your launch arguments to open the log window.
3. In packaged builds: Add -log or check the saved log file in Saved/Logs/.
The plugin logs state transitions, batch progress, asset counts, fingerprint values, timing data, and any warnings or errors.
Q: The log shows "IsWarmupRunning() is true, ignoring StartWarmup call."
A: You called StartWarmup() while a warmup is already in progress. The plugin guards against re-entrant calls. Wait for OnWarmupComplete to fire before starting another warmup, or check IsWarmupRunning() before calling.
Q: The warmup seems stuck in "Processing Batch" for a very long time.
A: This state is time-sliced, so it only runs for MaxProcessingTimeMsPerFrame per tick. If you have thousands of materials with complex shader permutations, this phase can take minutes. Check the log for the PSO remaining count—if it's decreasing, the plugin is working normally. If it's truly stuck at a fixed number, there may be a shader compilation issue with a specific material. Try reducing your scan scope to isolate the problematic asset.
Copyright © 2026 GregOrigin. All Rights Reserved.