Repository navigation
Hot Path Vulkan Direct Surface Sampling
Lifecycle: Performance - Unproven · Type: Copy-bypass shortcut
State: Source-backed; runtime value is not established.
Status: Source-confirmed exact-subset shortcut candidate; not implemented and not benchmarked.
Mechanism class: Guarded shortcut / image-copy bypass.
Reviewed source:
322986f4c5502b3fa887a9605ac8cd88e9b2c579Backend: Vulkan.
When guest texture memory aliases a rendered color surface, current Vulkan code can copy the surface image into a separate texture image before sampling. The source explicitly notes that xemu should be able to skip that copy and sample the original surface image.
This is a real shortcut for a carefully admitted subset:
General route:
rendered surface
-> transitions
-> vkCmdCopyImage
-> separate texture image
-> sample copied image
Shortcut:
rendered surface
-> required dependency/layout transition
-> compatible image view
-> sample original image
The copy is bypassed; required ordering, visibility, representation, and image-version semantics are not.
Current surface images are created with sampled, transfer-source, and transfer-destination usage in addition to their attachment usage. The existing color copy path already transitions the source, issues vkCmdCopyImage(), transitions both resources, and tracks surface->draw_time versus the texture binding.
The source seam is therefore real. The unresolved work is determining when one surface image can stand in for the copied texture without changing which version of the pixels a guest draw observes.
flowchart TD
A[Texture source resolves to active surface] --> B{Compatible surface-to-texture case?}
B -->|No| R[Use RAM texture upload/reference path]
B -->|Yes| C{Copied texture already has current draw_time?}
C -->|Yes| D[Reuse copied texture image]
C -->|No| E[End/interrupt rendering as required]
E --> F[Transition surface to transfer source]
F --> G[Transition texture to transfer destination]
G --> H[vkCmdCopyImage]
H --> I[Restore surface attachment layout]
I --> J[Transition texture to shader-read layout]
J --> K[Publish copied texture draw_time]
D --> L[Bind copied texture]
K --> L
R --> L
flowchart TD
A[Texture source resolves to active surface] --> B{Direct-sampling admission valid?}
B -->|No| R[Run maintained copy route]
B -->|Yes| C{Required image version is still the current surface version?}
C -->|No| R
C -->|Yes| D{Surface is not simultaneously used as conflicting output?}
D -->|No| R
D -->|Yes| E[End render pass or insert required dependency]
E --> F[Transition original surface to shader-read layout]
F --> G[Bind compatible view of original surface]
G --> H[Draw samples original surface]
H --> I[Restore attachment layout before later writes]
A first implementation should admit only cases where all of the following are true:
- the source is a color surface;
- the surface image was created with sampled usage;
- sampled format and component interpretation are view-compatible;
- dimensions, mip level, layer, pitch interpretation, and scale need no conversion;
- no depth/stencil packing, swizzle conversion, crop, or scratch image is required;
- the draw is not a read/write feedback loop against the same active attachment;
- the required texture value is the current surface version, not an immutable earlier snapshot;
- surface lifetime/generation and draw time remain valid;
- the image/view and descriptors remain alive for all in-flight commands;
- the renderer can restore the correct attachment layout before later writes.
Unsupported or ambiguous cases use copy_surface_to_texture() unchanged.
A separate copied image can preserve one historical version while the source surface is later overwritten. Direct aliasing cannot do that automatically.
The decisive sequence is:
1. Render surface A red.
2. Sample A into output B.
3. Render A blue.
4. Sample A into output C.
5. Verify B retained red and C received blue.
This must be tested with multiple submissions in flight. If B’s draw samples the original image only after the later blue write becomes visible, the shortcut has changed ordering even though every individual layout transition is valid.
A safe implementation may need one or more of:
- admission only when consumption is ordered before any later write;
- command-buffer dependency and render-pass boundaries;
- surface-version or lifetime tracking;
- fallback copy when a historical version must survive;
- command-buffer-local pinning of the chosen view/version.
The guest sees NV2A render-to-texture behavior and command ordering. Vulkan images, views, descriptors, barriers, and copies are host implementation details.
The exact contract is:
The direct route must expose the same texels to every guest draw, in the same order, as the maintained copy route for the admitted subset.
Saving a copy while changing which render version is sampled is not an optimization; it is a rendering bug.
| Area | Role |
|---|---|
hw/xbox/nv2a/pgraph/vk/texture.c |
copy_surface_to_texture(), compatibility, texture binding and draw-time tracking |
hw/xbox/nv2a/pgraph/vk/surface.c |
Surface image creation, layouts, lifetime, dirty/readback behavior |
renderer.h |
Surface/texture binding ownership and in-flight state |
| Descriptor update path | Bind original image view and sampler |
| Render thread | Sole publisher of direct-versus-copy route |
| Command-buffer lifecycle | Pins image/view state until completion |
The direct route can avoid:
- an image-to-image copy command;
- copied bytes and associated GPU bandwidth;
- a duplicate texture image allocation;
- some image transitions;
- cache pressure and copied-image lifetime bookkeeping;
- possible render-pass interruption or submission pressure.
The potential benefit is workload dependent. A copy-free route that introduces more render-pass breaks, barriers, or serialized layout transitions can be slower.
The source FIXME and current copy command confirm a real opportunity. No existing evidence quantifies:
- surface-to-texture copy count;
- copied bytes;
- copy-induced pass breaks;
- duplicate allocation cost;
- titles where direct aliasing remains version-safe.
Those counters should precede a large ownership rewrite.
Vulkan permits images created with sampled usage to be read by shaders after the appropriate synchronization and layout transition. Render graphs and engines commonly alias or reuse image resources when lifetime and access dependencies are known.
That API precedent does not solve xemu’s guest-visible versioning. The emulator must prove that a direct alias represents the same logical NV2A texture version as the copied route.
surface_to_texture_requests
surface_copy_reference_calls
surface_copy_bytes
direct_sampling_opportunities
direct_sampling_hits
direct_sampling_reject_format
direct_sampling_reject_scale
direct_sampling_reject_feedback
direct_sampling_reject_version
direct_sampling_reject_lifetime
layout_transitions_by_route
render_pass_breaks_by_route
gpu_copy_time
- Red/blue version-order fixture across one and multiple command buffers.
- Binding before and after later surface writes.
- Same-address surface destruction/recreation.
- Repeated sampling without intervening writes.
- Channel swizzles and compatible/incompatible view formats.
- Scaled surfaces, pitch differences, and cases requiring copy conversion.
- Read/write feedback and self-sampling rejection.
- Cache eviction, reset, snapshot restore, renderer recreation, and teardown.
- Vulkan synchronization and validation layers.
- Full XISO plus representative render-to-texture titles.
- Sampling a newer surface version than the copied route would expose.
- Read/write feedback hazards.
- Missing or overbroad format compatibility.
- Layout thrashing that removes the expected gain.
- Descriptors referencing an image/view after eviction or recreation.
- Surface scaling or representation differences being silently ignored.
- Lower copied bytes but worse GPU/frame tails due to synchronization.
- Add route/copy counters to the current path.
- Implement the narrowest color, same-format, same-size case first.
- Keep the copy route intact and independently selectable in one binary.
- Pass deterministic version-order and lifetime oracles.
- Compare copied bytes, barriers, pass breaks, GPU time, CPU time, and frame p95/p99.
- Expand admission one representation class at a time.
- Reject any implementation that relies only on matching addresses or bytes-per-pixel.
Applicable as an exact shortcut for a narrowly proven subset. The current copy remains the maintained reference and mandatory fallback.
- Vulkan Renderer
- Memory & DMA
- Vulkan Color-Download Folding
- Assumption-Based Shortcut Validation
- Using Hot-Path Shortcuts
Primary reference: This subject page is the design and research reference for Direct Surface Sampling. Pull requests are implementation/test history only.
Lifecycle: Performance - Unproven · Mechanism: Guarded image-copy bypass
Reviewed source:322986f4c5502b3fa887a9605ac8cd88e9b2c579· Acceptance class: intended exact or behavior-preserving for its admitted scope
Sample a compatible rendered surface image directly instead of copying it into a separate texture image.
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 |
copy_surface_to_texture() and surface-backed texture binding |
hw/xbox/nv2a/pgraph/vk/surface.c |
surface lifetime, layout and draw-time tracking |
flowchart TD
N0["Render into surface image"]
N1["Transition surface to transfer source"]
N0 --> N1
N2["Transition texture image to transfer destination"]
N1 --> N2
N3["vkCmdCopyImage"]
N2 --> N3
N4["Restore/transition layouts"]
N3 --> N4
N5["Bind copied texture"]
N4 --> N5
flowchart TD
N0["Render into surface image"]
N1["Prove representation/version compatibility"]
N0 --> N1
N2["Create/reuse compatible view"]
N1 --> N2
N3["Add render-to-sample dependency"]
N2 --> N3
N4["Bind original surface image"]
N3 --> N4
The source explicitly notes that the copy may be avoidable. A direct route can remove image transfer, duplicate allocation, and some layout work, but it changes aliasing and version semantics: a copy preserves an earlier version even if the original surface is later overwritten.
- Intermediate image copy
- Duplicate texture-image storage for admitted cases
- Transfer-specific transitions around the copy
- Producer/consumer ordering
- Required layout transition or barrier
- Texture/sampler binding
- Copy route for incompatible format/scale/swizzle/feedback cases
if (view_plan.valid &&
view_plan.surface_lifetime == surface->lifetime_id &&
view_plan.surface_draw_time == surface->draw_time &&
!surface_is_current_output_attachment(surface)) {
prepare_surface_for_sampling(cmd, surface);
bind_surface_view(binding, view_plan.view);
stats.surface_copies_bypassed++;
} else {
copy_surface_to_texture(pg, surface, texture);
}The sketch defines the intended boundary; it is not a complete patch and does not replace source review, ownership design, or focused tests.
- The sampled representation must match format, component mapping, dimensions, scale, mip level, and guest interpretation.
- Earlier consumers must keep the version they were ordered to see.
- Feedback loops/current attachments must use a supported explicit route or fall back.
- Surface lifetime identity must defeat same-address reuse.
The view may be cached by surface lifetime plus representation key. It is invalidated on recreation, format/scale change, eviction, reset, and snapshot restore. In-flight command buffers retain references until completion.
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.
- Eliminates whole image copies
- Reduces duplicate memory
- Can lower transfer bandwidth and command count
- Narrow admitted subset can retain exact fallback
- Version/aliasing bugs are subtle
- May require extra barriers or render-pass breaks
- Not all formats/views are compatible
- Feedback and later surface writes can corrupt earlier expectations
Counters must be cheap, subsystem-owned, and snapshotted outside the hot loop. Record at least:
- surface_to_texture_requests
- direct_surface_eligible
- direct_surface_binds
- copy_fallbacks_by_reason
- bytes_copied
- extra_barriers
- GPU/frame time
- validation errors
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 surface sampled into B, overwrite surface blue, sample into C
- Several submissions in flight
- Same guest address with new lifetime
- Compatible and incompatible format views
- Scaling/swizzle/depth rejection
- Feedback/current-attachment cases
- Eviction/reset/snapshot
- Vulkan synchronization validation
Correctness runs may use validation layers, detailed comparisons, and fault injection. Performance acceptance must use optimized Release builds with matching symbols and minimal instrumentation.
Promote for the exact admitted subset when version-order tests and validation pass and copied bytes/GPU cost fall meaningfully.
Reject or narrow if it requires broader synchronization than the copy, cannot preserve version identity, or only shifts cost to barriers/pass breaks.
Vulkan-Renderer · Performance-Unproven · Vulkan-GPU-Resident-Surface-Consumers · Hot-Path-Vulkan-Texture-Image-Sampler-Separation
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