Files
ue-toolchain/plugins/ue-design-skills/skills/ue-streaming-and-platform-budgets/SKILL.md
T
MagentaDolphin ecd87ac96d feat(skills): ship ue-design-skills bundle, licensing and delivery gate
Phase 0 of the handoff plan, as a marketplace rather than a flat skills/
directory. Content moved out of the LyraResearch archive and depersonalised:
addresses stay in the archive, recipes ship.

- plugins/ue-design-skills: 17 skills, 232 failure-mode entries, each with the
  six required fields; catalog.json as the harness-neutral source of truth and
  .claude-plugin/ as one adapter over it.
- _gate: 16 rules, one poisoned fixture per rule, plus surface coverage so a
  declared file cannot silently miss the line rules.
- ADR-0002 (harness-neutral bundle behind a marketplace) and ADR-0003 (split
  licensing: CC BY-ND 4.0 prose, Apache-2.0 code and metadata).
- LICENSE files at both levels, CONTRIBUTING.md, docs/licensing-options.md as
  the material the licence decision grew from.

Verified: gate.py 0 violations; test_gate.py 16/16 rules redden on their
fixtures with a clean baseline and 2 root files reaching the line rules.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-05 23:48:55 +07:00

292 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
name: ue-streaming-and-platform-budgets
description: >-
Design or audit GPU and streaming budgets in Unreal Engine: texture, mesh and
virtual texture streaming, streaming pool sizing, texture LOD groups,
scalability buckets, device profiles and console-variable priority, world
partition and level instance lifetime, and the boundary between disk, CPU
memory and video memory. Use when targeting a platform memory ceiling, tuning
quality tiers, adding a background or preview level, or investigating why a
quality setting has no effect.
---
# UE streaming and platform budgets
The invariant:
> A streaming pool is a **permission**, not a measurement. A quality setting is a
> **request**, not an outcome. Both are arbitrated by device profiles and
> console-variable priority before anything reaches the GPU.
Measured patterns from a reference product: [patterns](references/patterns.md).
Detection recipes: [failure modes](references/failure-modes.md).
Related skills: `ue-asset-loading-and-memory`, `ue-game-settings-architecture`,
`ue-runtime-allocation-and-caching`.
Method, not architecture — how to check any claim in this bundle before repeating it: `ue-evidence-discipline`.
---
## 1. Four budgets, four instruments
| Budget | What it physically is | Instrument |
|---|---|---|
| **A. Disk / cook** | bytes in the shipped package | build and chunk sizes |
| **B. CPU memory** | object graph plus bulk data in system RAM | memory report, object listing |
| **C. Video memory** | live render resources: textures, buffers, render-target pool, virtual-texture pool, shadow pages, ray-tracing structures | platform GPU profiler |
| **D. Streaming pool** | an accounting **ceiling** the streamer tries to stay under | streaming stat |
Four rules that prevent most wrong conclusions:
- **A is not D.** Clamping a texture group's maximum size shrinks what is cooked.
The pool is unchanged.
- **D is not C.** The pool covers streamable mips only. Render targets, virtual
texture pools, shadow pages and acceleration structures are in C and invisible
to the streaming stat.
- **B is not C.** A loaded texture object need not have any resident mips.
- **Never report a pool size as memory used.** It is the single most common
error in this area, and it makes every downstream number meaningless.
---
## 2. Console-variable priority is the real arbiter
Effective value is not "last write wins"; sources are ranked. In practice:
```text
command line > console > device profile > system ini > project ini
> game setting > scalability > constructor
```
with one exception that matters enormously: a device profile applies variables
whose names begin with the scalability prefix at **scalability** priority, and
everything else at **device-profile** priority.
### The consequence
A value set by a device profile **cannot be changed** by anything the
scalability system does afterwards — which includes every in-game quality
setting. The same setting is therefore mutable on one tier and frozen on
another, with nothing in the UI explaining the difference. Recipe: ST-01.
### Gates
- [ ] every quality-affecting variable has a documented intended priority source;
- [ ] prefixed and unprefixed names are used deliberately, not by habit;
- [ ] per-tier overrides are complete across tiers, or partial with a comment
saying why;
- [ ] the settings UI can express "clamped by platform" rather than silently
failing;
- [ ] requested and effective values are both observable at runtime.
**The one command that settles it:** dump variables with their source. Anything
else is inference.
---
## 3. Pool sizing, and its detachment from real memory
Two knobs interact: the pool size, and whether the pool is clamped by actual
video memory.
The trap is structural rather than accidental: **the highest quality buckets
commonly disable the video-memory clamp**, and automatic detection promotes
hardware to the top bucket on a compute benchmark that does not consider memory
size at all. A fast card with modest memory therefore lands in the bucket where
the pool budget is largest and least constrained. Recipe: ST-02.
Rules:
- decide per platform whether the pool is derived from memory or fixed;
- if fixed, write down the assumed memory floor;
- benchmark thresholds must consider memory, not only throughput;
- test the top bucket on a low-memory card, not only on the reference machine.
### Sharing the pool
If mesh streaming is enabled and no separate mesh pool is configured, geometry
and textures compete inside one budget. That is a legitimate choice; it is not a
legitimate surprise. Check both values on every platform. Recipe: ST-03.
---
## 4. Texture groups are the per-content lever
Scalability moves everything at once; groups shape individual content classes.
Use them to encode intent: hero content larger, world content platform-scaled,
UI unstreamed and sized exactly, debug content excluded from cook.
Gates: every group has a stated purpose; mobile tiers override group caps rather
than only global quality; no content relies on a group it does not belong to;
streaming-exempt content is deliberate and small.
Watch for group settings that describe a delivery mechanism the project does not
have — optional mip levels configured with no chunk installation, for instance.
Configuration that cannot take effect is worse than absent configuration,
because it reads as a decision. Recipe: ST-08.
---
## 5. Build-level decisions that look like runtime knobs
Some streaming variables are read-only: their value is fixed at startup and
influences what is cooked. Changing them at runtime, or from a device profile,
does nothing and says nothing.
Before treating any streaming variable as tunable, check its flags. And never
A/B a read-only variable mid-session and compare the numbers — you are comparing
one configuration with itself. Recipe: ST-04.
Virtual textures belong in the same category. They change residency
characteristics fundamentally, their pool is separate from the streaming budget,
and a pool that does not grow on over-subscription produces thrashing rather
than an allocation. Enabling them for some content and not other content makes
budget comparisons invalid.
---
## 6. Device profiles: reachability before content
A profile hierarchy usually encodes platform base → tier → device. Three
failures recur, and all three are silent:
**A section that is never selected.** Defining a profile section does not make it
reachable; something must map to it. A tier section absent from the registry is
configuration that reviewers read as live. Recipe: ST-05.
**Headers that contradict assignment.** Comment banners grouping devices under a
tier label, while the devices beneath resolve to a different base profile. The
comment is documentation; the base profile is behaviour. Recipe: ST-06.
**An override list that no configuration populates.** A user-facing profile
variant list declared in code and set in no file means the selection logic
composes an empty name, the override is never applied, and the preset UI never
appears. Recipe: ST-07.
Gates: every profile section is reachable from the registry; tier assignment is
asserted by a dump, not read from comments; unknown hardware has a documented
fallback; every override hook has a real caller and real data.
---
## 7. Requested versus effective quality
A settings screen showing the user's request while a device profile clamps the
result is lying by omission. Model it explicitly:
```text
requested quality → platform clamp → effective quality → applied variables
```
Expose both, and give a reason when they differ.
### Unit-test every clamp at its range boundaries
The measured defect worth guarding against: a compatibility check comparing a
quality **level** (0–3) against a resolution **percentage** (default 100), so the
constraint can never fire. Its sibling function used the correct accessor, which
is what makes this findable — and what makes it invisible to review, since both
lines read identically. Recipe: ST-09.
Also check every normalisation for a zero denominator. A remap between two
ranges divides by their difference; a configuration that makes those equal is
reachable from data. Recipe: ST-10.
---
## 8. World content lifetime
### Level instances, not second worlds
Background and preview content is usually a level instanced into the **current**
world, not a second world. The cost is duplicated level content in one scene:
actors, components, primitives and their render resources.
Measure by scene composition — actor and primitive counts, visible material slots
— not by counting world contexts. "There is only one world" is true and
irrelevant.
### Ownership rules
Every streamed-in instance has one owner and an unload path; async handles are
retained and cancellable; failure surfaces a reason rather than a permanent wait;
teardown runs on travel, mode change and error.
### Hidden render targets
Scene-capture preview systems allocate render targets per capture object and may
keep rendering state resident between captures. Budget them explicitly: count ×
resolution × format, and verify release. A subsystem with no callers that still
instantiates per world and installs a ticker is paying for a feature nobody uses
— unused systems must decline creation.
### If runtime layer state is never set, it is not runtime streaming
Shipping editor-authored initial state is a valid choice. Describing it as
dynamic streaming is not, and a team that believes it has a reference
implementation will look for one that does not exist.
---
## 9. Review checklist
- [ ] Four budgets separated in every claim and every report.
- [ ] Pool settings never presented as consumption.
- [ ] Variable priority documented per quality knob, verified by a source dump.
- [ ] Tier overrides complete, or partial with a stated reason.
- [ ] Memory-clamp policy explicit per platform.
- [ ] Mesh and texture pool split decided per platform.
- [ ] Read-only variables identified before anyone tries to tune them.
- [ ] Every profile section reachable; assignment asserted, not commented.
- [ ] Requested and effective quality both visible, with a reason on divergence.
- [ ] Clamp logic unit-tested at both ends of its real range.
- [ ] Level instances owned, released and counted.
- [ ] Preview and capture render targets budgeted and released.
- [ ] Unused subsystems decline creation.
---
## 10. Measurement plan
Static first — cheap, and finds the structural problems:
1. Dump effective variables **with their source** per device profile, and diff
against intent.
2. Verify every profile section is reachable from the registry.
3. List texture groups and their per-tier caps.
4. Search for runtime streaming and layer-state calls to confirm what is
actually dynamic.
Runtime, on target hardware, in a packaged build:
- streaming stat for pool budget versus used and over-budget;
- platform GPU profiler for real video memory — the streaming stat cannot see
most of it;
- **fixed camera poses** for any comparison; view-dependent metrics are otherwise
noise;
- one run per tier on real devices, not emulated profiles alone;
- scene composition counts for level-instance cost.
**Do not compare numbers taken at different camera poses, different tiers, or
between editor and packaged builds.** Those comparisons look quantitative and
mean nothing.
---
## Provenance
The findings come from a configuration and source audit of Epic's Lyra Starter
Game on Unreal Engine 5.6, cross-read against the engine's own scalability and
device-profile configuration. Source addresses stay in the research archive that
produced this skill; each entry carries a stable identifier (`ST-01`, `ST-02`, …)
resolving back to the audited location there.
## Evidence boundary
Static configuration analysis only: no profiler was run, no device was measured,
and no number in the failure modes is a memory measurement. Engine defaults
quoted describe one engine version. The recipes are written to be re-run against
your own project and engine, which is the only way any of these values become
true for you.