Repository navigation
Hot Path Vulkan Unchanged Scanout
Lifecycle: Performance - Implemented · Type: Retained-result shortcut
State: Present in currentmain.
| Field | State at reviewed main
|
|---|---|
| Underlying optimization | Implemented |
| Advanced control | Planned in issue #96, absent from reviewed main |
| Current behavior | Reuse automatically occurs when the full current key/eligibility matches |
| Planned modes | Auto / Disabled |
| Planned apply boundary | Live, with renderer-owned reuse invalidation on policy change |
| Maintained reference | Fresh display conversion/render/submission |
| Evidence counters | Planned; absent from reviewed main |
| Qualification | Source-confirmed route; isolated same-binary benefit not yet established |
| Reviewed source |
322986f4c5502b3fa887a9605ac8cd88e9b2c579, 2026-09-14 |
| Primary history | Current display implementation; issue #96 control/evidence plan; related issue #90 |
xemu's Vulkan display path converts the current guest scanout/surface state into a completed host display image used by the presenter. If the current display request is identical to the state that produced the already-completed image, repeating conversion and submission is unnecessary.
Current main retains a reuse key and simply returns without calling render_display() when:
- TCG mode permits the path;
- PVIDEO is not active;
- no surface upload is pending;
- display resources were not recreated;
- every field of the retained key matches.
On a miss, xemu invalidates the old key, renders a fresh display image, waits until it is externally usable, and publishes a new key only if the result remains reusable.
Issue #96 plans an Auto / Disabled control around the final reuse return. The route itself is already live; the control/counters are not.
The potential saving is:
repeated display updates with unchanged effective scanout
× avoided render_display conversion, command recording, submit/wait and image work
This can matter when the UI/presenter requests updates more often than guest-visible scanout changes, when the same rendered surface persists across guest frames, or when a display conversion is relatively expensive.
It will not help continuously changing scenes, active PVIDEO composition, pending uploads, resource recreation, non-TCG execution modes, or any state that changes one reuse-key field.
The route is source-confirmed in current main. The implementation compares a full key rather than only the scanout address and documents that render_display() waits until the display image is externally usable before the key is republished.
Issue #96 was created because the reviewed binary cannot force eligible hits through the fresh path or export reasoned reuse counters. Therefore current evidence cannot yet isolate the saved conversion cost with one executable.
Related presentation pattern: DXGI 1.2 dirty rectangles let an application tell the presentation system which regions changed while the system retains the rest of the prior frame: DXGI presentation improvements.
Related retained-frame pattern: The DXGI Desktop Duplication API reports dirty and moved regions relative to a retained desktop image so consumers process only changes: Desktop Duplication API.
These are related host presentation patterns, not direct emulator analogues. xemu's proof includes guest surface lifetime, draw time, frame time, scanout geometry, PVIDEO, upload state, and Vulkan resource completion.
Xbox-visible scanout and overlay state
↓
xemu surface/display state and change/lifetime proof
↓
Vulkan host image
reuse completed image OR render fresh image
↓
presenter consumes externally usable image
The retained Vulkan image is not Xbox hardware. Reusing it is valid only when it is the same output the current guest state would freshly produce.
| Location | Role | Owner |
|---|---|---|
hw/xbox/nv2a/pgraph/vk/display.c |
Reuse key compare/publish, eligibility, render_display, resource destruction |
Renderer/PFIFO thread |
PGRAPHVkDisplayState::reuse in renderer state |
Retained key validity and fields | Renderer |
SurfaceBinding |
Surface lifetime ID, draw time, upload state | Renderer surface owner |
| PVIDEO state | Overlay composition eligibility | PGRAPH/display owner |
| framebuffer/presenter handoff | Externally usable completed image | Renderer + UI presenter ownership |
ui/xemu-tweaks.[ch] |
Planned #96 effective bit/generation; absent at reviewed main | Future control layer |
flowchart TD
A[Display update requested] --> B[Resolve scanout surface and display parameters]
B --> C{Display resources recreated during update?}
C -->|Yes| R[Fresh path]
C -->|No| D{TCG enabled?}
D -->|No| R
D -->|Yes| E{PVIDEO disabled?}
E -->|No| R
E -->|Yes| F{Surface upload not pending?}
F -->|No| R
F -->|Yes| G{Retained key valid and every field matches?}
G -->|Yes| H[Return without render_display; current completed image remains]
G -->|No| R
R --> I[Invalidate old reuse key]
I --> J[render_display]
J --> K[Record/submit display conversion]
K --> L[Wait until display image is externally usable]
L --> M{Still TCG, PVIDEO off and no upload pending?}
M -->|Yes| N[Publish full new reuse key]
M -->|No| O[Leave reuse key invalid]
The reuse hit does not “return a cached image object” to new ownership; it leaves the already-current completed display image in place and omits fresh rendering.
Planned Disabled mode should be:
flowchart TD
A[All existing reuse guards and key fields match] --> B[Record reuse eligible]
B --> C{Planned policy Auto?}
C -->|Yes| D[Return with retained completed image]
C -->|Disabled| E[Invalidate diagnostic boundary]
E --> F[Render fresh display image]
F --> G[Wait for external usability]
G --> H[Publish new key under current policy/state]
A live policy change must also invalidate the old key before the next update so an image produced on one side of the A/B boundary cannot cross into the other unnoticed.
| Key/guard | Why required | Failure if removed |
|---|---|---|
reuse.valid |
Result must have completed/published history | Reuse uninitialized/stale image |
| Surface lifetime ID | Same address can hold a new object | Reuse prior surface generation |
| Surface draw time | Surface can change without moving | Stale rendered contents |
| Guest frame time | Display-visible state/progression may change | Reuse across guest output change |
| Scanout address | Source selection changed | Wrong framebuffer |
| VGA line offset/pitch state | Row interpretation changed | Distorted image |
| Width/height | Output geometry changed | Wrong dimensions |
| Surface scale factor | Conversion resolution changed | Wrong scaled image |
| Interlace mode | Field/progressive interpretation changed | Wrong lines/fields |
| TCG eligibility | Current route's assumptions are execution-mode-specific | Unsupported synchronization semantics |
| PVIDEO disabled | Overlay composition can change output | Missing/stale overlay |
| No pending upload | Host surface must contain current guest data | Present pre-upload image |
| No resource recreation | Retained image/descriptor/pipeline may be replaced | Invalid host object |
| Fresh render externally complete before publish | Key must represent a usable image | Presenter races incomplete image |
Address equality alone proves almost nothing.
The display state owns the completed image and a key describing the guest/host state that produced it. Destroying/recreating the display image sets reuse.valid = false.
Invalidators include:
- surface destruction/recreation/lifetime change;
- surface draw/change time;
- guest frame time;
- scanout address/line offset/dimensions/scale/interlace;
- PVIDEO enable/state;
- pending surface upload;
- display image/resource recreation;
- renderer teardown;
- planned policy-generation change.
The renderer thread must observe a live control change and invalidate its own state. The UI thread should not directly write renderer-owned key fields.
Any mismatch falls back to fresh rendering. A fresh render that ends in an ineligible state leaves the key invalid.
After #96 exists, a suitable static/repeated-output workload should show:
same display update requests
+ reuse_eligible > 0
Auto:
reuse_hits > 0
fewer render_display calls/conversions/submissions
Disabled:
forced_reference == eligible
fresh_conversions rise
A changing-scene workload may legitimately show zero eligible hits. It cannot judge the route.
Local improvement may appear as lower display conversion CPU/GPU, fewer submits/waits, or lower presenter preparation. End-to-end movement depends on display conversion being on the limiting path.
Planned minimum:
| Counter | Unit | Meaning |
|---|---|---|
vk.scanout.update_calls |
updates | Display path entered |
reuse_key_checks |
checks | Full key compared |
reuse_eligible |
updates | All guards/key matched |
reuse_hits |
updates | Retained image used |
reuse_forced_reference |
updates | Eligible but Disabled |
fresh_conversions |
updates |
render_display executed |
reuse_invalidations |
events | Key deliberately invalidated |
blocked_execution/pvideo/upload/recreated |
updates | Eligibility reasons |
key_mismatch_* |
checks | Lifetime/draw/frame/address/geometry/etc. |
| display render/submit/wait CPU/GPU | ns/us | Local work |
For a fixed-policy window:
reuse_eligible = reuse_hits + reuse_forced_reference
Key comparison should occur once; detailed mismatch counters should be returned by that comparison rather than rechecking state.
- Same address with a new surface lifetime is not the same image.
- A surface can be redrawn without address/geometry change.
- PVIDEO composition invalidates otherwise identical base scanout.
- Pending upload means the host resource is not current.
- Publishing the key before external completion lets the presenter race incomplete work.
- Live policy changes without invalidation contaminate A/B boundaries.
- UI/framebuffer ownership can block renderer lifecycle operations; PR #92 demonstrates that display ownership is not local to one function.
- Reuse can make a stale-image bug look like a performance gain.
- Planned detailed mismatch counters must not duplicate expensive/side-effectful work.
See issue #96, issue #90, PR #92, display/lifetime PR lessons, and Pull Request Lessons.
- Equal full key produces a hit; change each field independently to force fresh path.
- Same scanout address with new surface lifetime.
- Same address/lifetime with changed draw time.
- Guest frame-time change without geometry change.
- Line offset, dimensions, scale, and interlace changes.
- PVIDEO enable/change and color-key/overlay composition.
- Pending upload and resource recreation.
- Fresh render completion before key publication/presenter use.
- Planned live Auto/Disabled transition with owner-thread invalidation and first post-change fresh render.
- Exact output/image hash and Vulkan validation.
- Static/repeated-output workload proving nonzero eligibility plus changing-scene control.
- Display CPU/GPU/submit/wait counters and p50/p95/p99/max.
- PGR2/Morrowind, full Vulkan XISO, resize/scale, teardown, snapshot, renderer-switch/framebuffer ownership.
The route should remain Auto only if retained output is provably complete and identical; no amount of saved conversion work permits a stale frame.
DSP tooling guide and navigation updated November 2, 2026 for experimental PR #384, source 8f51d237. Capture/replay usage and limits.
The earlier wiki-wide review was published November 1, 2026. Emulator source: b7140848. Reviewed wiki content: 1d2b671. Current status · Release availability · Publication process.
- Home
- Current status
- Stable versus main
- Implemented mechanisms
- Controls and defaults
- Measured results and limits
- Complete change register
- System
- CPU and vCPU
- Memory and DMA
- Graphics / NV2A
- APU and audio
- Timing and timers
- Platform and I/O
- Hardware observations
- Fidelity boundaries
- Methodology
- PGR2 routes
- Debugging lag / hot paths
- Tools and commands
- DSP capture, replay and fuzzing
- HLE readiness and public XISO proof
- Concurrent DSP shadow and OpenAL proof
- DSP HLE operation inventory
- DSP HLE fix examples and testing
- Development
- Upstream shortlist
- Wiki maintenance
- Research / retired work
- Optimization catalog
- Hot-path shortcuts
- Researched experiments
- Unproven proposal directory
- PR lessons
- September26 snapshot
Repository · PRs · Issues