Repository navigation
Hot Path Vulkan Frame Scoped Texture Trust
Lifecycle: Performance - Unproven · Type: Approximate shortcut
State: Source-backed; runtime value is not established.
Status: Applicable approximation candidate; not implemented, not benchmarked, and unsuitable as an unlabeled default.
Mechanism class: Assumption-based shortcut / deferred validation.
Reviewed source:
322986f4c5502b3fa887a9605ac8cd88e9b2c579Backend: Vulkan.
Current Vulkan texture validation can test and clear guest-memory dirty pages, propagate possibly_dirty state through active texture-cache entries, inspect surface overlap, hash content, and upload changed data. The proposed shortcut validates an admitted RAM-backed texture once at a defined guest-frame boundary, then bypasses repeated validation for later uses in the same frame.
This is not equivalent behavior when the guest rewrites texture or palette memory after the first validation and samples it again before the next boundary. The proposal is useful only as an explicit compatibility/performance approximation with a measured stale-content window.
On an admitted same-frame hit, xemu would bypass:
- dirty-page test-and-clear work;
- propagation through active cache entries;
- surface-overlap searches;
- content hashing triggered by possible dirtiness;
- upload/rebind work that the skipped validation might otherwise request.
The shortcut must not clear dirty evidence merely because it chose not to inspect it.
flowchart TD
A[Texture stage used] --> B[Resolve source, palette and current binding]
B --> C{Binding/state already potentially reusable?}
C -->|No| R[Run normal create/update path]
C -->|Yes| D[Test and clear texture/palette dirty pages]
D --> E[Propagate possibly-dirty state to overlapping cached entries]
E --> F{Surface overlap, source change or content change?}
F -->|Yes| R
F -->|No| G[Retain validated binding]
R --> H[Hash/upload/copy/bind as required]
G --> I[Draw]
H --> I
check_texture_possibly_dirty() is not a pure predicate: it consumes dirty-memory evidence and can mark multiple cache entries. That side effect is part of the reference semantics and makes careless A/B instrumentation invalid.
flowchart TD
A[Texture stage used] --> B{Narrow texture class admitted?}
B -->|No| R[Run maintained reference validation]
B -->|Yes| C{Binding version and trusted frame match?}
C -->|No| R
C -->|Yes| D{Policy permits frame trust?}
D -->|No| R
D -->|Yes| E[Retain existing binding without memory validation]
R --> F{Reference validation succeeds?}
F -->|Yes| G[Publish trusted frame and binding version]
F -->|No| H[Preserve retry/dirty state]
E --> I[Draw with possibly stale contents]
G --> I
A first experiment should admit only textures that are:
- RAM-backed rather than surface-sourced;
- non-paletted;
- represented by an existing complete binding;
- using the same effective texture state and DMA address;
- not known
possibly_dirtyat the first validation; - not overlapping a current or retained render surface;
- not crossing a snapshot restore, renderer reset, or resource recreation;
- not shared through another binding whose writes require independent invalidation.
Palette textures, surface aliases, dynamic DMA remaps, and same-address resource reuse should begin on the reference route. Expanding the admitted subset is a later experiment.
A “guest frame” must be defined precisely. A display-write or pg->frame_time transition may be a useful serial, but neither automatically proves that the title treats all texture writes within that interval as deferred to the next frame.
The required contract is not merely “refresh eventually.” It must state:
- which event expires trust;
- whether dirty evidence remains pending;
- the maximum intended stale interval;
- what happens when no normal frame boundary occurs;
- how pause, snapshot, reset, and skipped presentation affect the serial.
1. Upload red texture bytes.
2. Draw the texture and complete reference validation.
3. Overwrite the same guest bytes with blue without rebinding.
4. Draw again before the trust boundary expires.
5. Advance the defined boundary.
6. Draw again.
The exact route establishes when blue becomes visible. The approximate route is expected to expose its difference at step 4 and must recover at the documented boundary. If blue never appears, dirty evidence or trust invalidation has been lost.
Repeat the fixture with:
- palette-only writes;
- a second binding sharing the same memory;
- texture DMA descriptor remapping;
- GPU-written surface content;
- same-address resource destruction/recreation;
- snapshot restore without advancing the serial.
The physical NV2A can observe memory changes according to its own fetch/cache behavior. Current xemu uses guest-memory dirty tracking, hashes, host images, and explicit surface aliases to approximate that behavior.
This shortcut does not claim improved hardware accuracy. It deliberately trades same-frame texture freshness for less host validation work.
The opportunity is:
repeated uses after first validation
× cost of dirty-page checks, cache propagation, overlap scans and hashes
− trust/version bookkeeping
It is worth continuing only if counters show frequent repeated validation of unchanged admitted bindings and meaningful renderer CPU time in the removed work.
The expensive operations and side effects are source-confirmed. No current benchmark proves that repeated same-frame validation is a material bottleneck or that affected titles tolerate delayed visibility.
The existing Clean Texture Stages shortcut is exact under its guards and should not be confused with this proposal. Clean-stage skipping still consults the relevant current validation state; frame trust intentionally stops consulting memory after the first admitted validation.
Frame-scoped resource validity is common in engines that own all resource mutations. That precedent is weaker for an emulator because guest software can modify memory through paths the host renderer does not directly own. Therefore this must remain an approximation unless all same-frame mutation sources become tracked.
texture_validation_requests
frame_trust_opportunities
frame_trust_hits
frame_trust_reference_calls
frame_trust_reject_surface
frame_trust_reject_palette
frame_trust_reject_dma_change
frame_trust_reject_possible_dirty
memory_dirty_tests
cache_entries_visited
bytes_hashed
upload_bytes
stale_oracle_differences
frames_until_refresh
renderer_cpu_ns
- Persistent stale content because dirty evidence was consumed or lost.
- A frame serial that does not match the title’s resource lifetime.
- Palette or alias writes escaping the binding version.
- DMA remap without texture-state write.
- Snapshot restore preserving stale trust stamps.
- GPU-produced contents changing without a RAM dirty event.
- Local CPU savings offset by later upload bursts or additional rendering errors.
- A compatibility option being mislabeled as an exact optimization.
- Implement the stale-content fixture and recovery oracle first.
- Keep reference and candidate fixtures independently seeded; reference validation mutates dirty state.
- Add per-reason admission counters without per-draw text logging.
- Run texture, palette, alias, DMA-remap, reset, restore, eviction, and teardown tests.
- Run Vulkan validation and full XISO correctness coverage.
- Use texture-heavy representative titles and compare renderer CPU, frame p95/p99, uploads, hashes, and visual differences.
- Define a title or compatibility scope before any product exposure.
- Reject the shortcut if the stale interval is not bounded and recoverable.
Applicable only as an explicitly approximate, opt-in research shortcut. It must never be described as equivalent merely because most tested frames appear unchanged.
- Clean Texture Stages
- Vulkan Texture Image and Sampler Separation
- Assumption-Based Shortcut Validation
- Using Hot-Path Shortcuts
Primary reference: This subject page is the design and research reference for Frame-Scoped Texture Trust. Pull requests are implementation/test history only.
Lifecycle: Performance - Unproven · Mechanism: Explicit stale-within-frame approximation
Reviewed source:322986f4c5502b3fa887a9605ac8cd88e9b2c579· Acceptance class: intended exact or behavior-preserving for its admitted scope
Validate an admitted RAM-backed texture on first use in a guest frame, then bypass further dirty-page, overlap, and content checks until the defined next validation boundary.
This entry remains Unproven: the source path and opportunity are concrete, but no accepted xemu runtime result has established that the candidate improves representative workloads. The page defines what must be bypassed, what remains mandatory, and how the hypothesis can be rejected.
| File / function | Role |
|---|---|
hw/xbox/nv2a/pgraph/vk/texture.c |
check_texture_possibly_dirty() and binding validation |
flowchart TD
N0["Texture use"]
N1["Dirty-page test-and-clear"]
N0 --> N1
N2["Propagate possibly-dirty state"]
N1 --> N2
N3["Surface-overlap/content checks"]
N2 --> N3
N4["Hash/upload/rebind if needed"]
N3 --> N4
N5["Repeat on later use"]
N4 --> N5
flowchart TD
N0["First admitted use in frame: full reference validation"]
N1["Record frame serial and binding version"]
N0 --> N1
N2["Later same-frame use: trust retained binding"]
N1 --> N2
N3["Revalidate at next frame or invalidation"]
N2 --> N3
Many textures are unchanged between uses, but current validation protects same-frame guest writes and aliasing. The proposed route intentionally permits a bounded stale interval and is therefore an approximation. It is useful as a cost-removal experiment and perhaps a compatibility mode, not as an exact optimization unless stronger write tracking is added.
- Repeated dirty-page checks
- Repeated surface-overlap searches
- Repeated content validation/hashing on trusted later uses
- First-use validation
- Texture binding and sampling
- Next-boundary refresh
- Immediate invalidation for tracked destructive events
- Reference route for palette/surface/DMA complexity
if (policy == TEXTURE_TRUST_FRAME && binding->admitted &&
binding->validation_frame == pg->guest_frame_serial &&
binding->state_version == current_state_version) {
stats.frame_trust_hits++;
return retain_existing_binding(binding);
}
bool ok = validate_and_bind_reference(pg, stage);
if (ok && binding_is_admitted(binding)) {
binding->validation_frame = pg->guest_frame_serial;
binding->state_version = current_state_version;
}The sketch defines the intended boundary; it is not a complete patch and does not replace source review, ownership design, or focused tests.
- The allowed stale interval must be explicit and measurable.
- Skipped validation must not clear dirty evidence.
- Snapshot/reset/recreation and frame-serial wrap must invalidate stamps.
- Palette, surface-backed, remapped DMA, and shared-memory cases need separate admission or fallback.
Trust stamps belong to the renderer binding. They are invalidated on frame advance, binding/state version change, restore/reset, resource recreation, and any tracked write/alias event chosen by the policy.
The maintained reference path remains the fallback whenever admission, capability, lifetime, or validation is uncertain. A fast result with an unproven dependency is not acceptable as an exact optimization.
- Can remove substantial repeated coherency work
- Very clear same-binary reference route
- Useful for quantifying validation cost
- Bounded approximation is easier to characterize than indefinite staleness
- Same-frame writes can produce stale pixels
- Dirty test-and-clear ordering can be corrupted
- Multiple bindings sharing memory complicate recovery
- May hide real invalidation bugs
Counters must be cheap, subsystem-owned, and snapshotted outside the hot loop. Record at least:
- texture_validation_requests
- first_frame_validations
- frame_trust_hits
- dirty_pages_tested
- surface_overlap_queries
- hash_bytes
- uploads
- stale_frames_detected
A local reduction is not enough. Evidence must connect route reachability and removed work to fixed guest progress, CPU/GPU time where applicable, and p95/p99 behavior.
- Red draw, overwrite same bytes blue, draw again same frame, advance frame, draw
- Palette-only changes
- Shared-memory bindings
- DMA remap
- GPU-written content
- Same-address resource reuse
- Snapshot restore without frame advance
- Long frame and serial wrap tests
Correctness runs may use validation layers, detailed comparisons, and fault injection. Performance acceptance must use optimized Release builds with matching symbols and minimal instrumentation.
Accept only as an explicitly approximate mode when cost reduction is material and stale duration/recovery match a documented contract.
Reject as exact/default when same-frame changes are common, refresh can be missed, dirty evidence is lost, or the path produces persistent corruption.
Vulkan-Renderer · Performance-Unproven · Hot-Path-Vulkan-Clean-Texture-Stages · Using-Hot-Path-Shortcuts
PR pages may be linked as supporting evidence, but they are not substitutes for this reference.
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