Skip to content

Performance Research G01 Warm Shader Uniform Work

github-actions[bot] edited this page Sep 18, 2026 · 2 revisions

Warm texture/shader uniform work

G01 — Implementation and validation notes

Field Value
Evidence state Historical repository measurements; residual work must be re-profiled on current main
Inspected source 322986f4c5502b3fa887a9605ac8cd88e9b2c579
First experiment Avoid unchanged derived uniform work, not only UBO writes
Scope Addendum dated September 15, 2026; not a current-main benchmark or implementation status

Unproven performance research · Performance research — common test protocol · Performance research — reproducible checks

Evidence and implementation reasoning

Existing evidence. Issue #79 records an older instrumented PGR2 shader-binding cost of 4.540 ms per guest frame across about 4,771 calls. Uniform value/copy work was 50.4% of the sampled wrapper. Its narrower PR #80 repair subsequently reported 7.40%/6.88% lower texture-binding CPU in order-reversed PGR2 comparisons and 1.98%/1.04% better Morrowind display-write cadence. These are different metrics and workloads, not a universal FPS claim. Issue #79.

Additional detail. Split four concepts: image-content changes, effective image/sampler binding identity, shader-affecting texture state, and uniform-value changes. A content upload does not necessarily change a descriptor; an unchanged descriptor does not prove a scale or derived uniform stayed unchanged.

Implementation and gain. Cache the last effective values, avoid recomputing/copying unchanged values, and clear dirty state only after successful application. The old diagnostic's uniform attribution is about 2.29 ms/frame; eliminating half of that would save about 1.14 ms locally in that diagnostic—not a forecast for current main. Khronos' constant-data sample explicitly demonstrates that the best delivery mechanism depends on the platform. Constant data.

Acceptance. Test enable/disable, palette-only updates, shared dirty pages, content-only updates, surface-backed textures, upload failures, descriptor reuse, and effective scale changes. Measure checks separately from actual UBO writes; otherwise “fewer checks” may merely move work.

First patch boundary

Separate effective values from content dirtiness and descriptor identity. Retain failed-upload retry state and shader-affecting changes.

guest texture state -> content/binding/shader/value classifications -> only required preparation and publication

Locate the inspected seam before editing; names or ownership may have changed since the pinned review:

git grep -n -E 'pgraph_vk_bind_shaders|update_shader_uniforms|texture_bindings_changed|check_textures_dirty' -- hw/xbox/nv2a/pgraph

Proposed focused tests

These are implementation gates to add or exercise, not claims that production tests already exist or passed. Retained standalone checks are on the checks page.

Test ID Setup / deliberate control Required oracle
G01.01 Repeated identical draws plus a content-only texture update with unchanged binding identity. Reference UBO bytes/rendered output match; only truly unchanged value preparation is skipped.
G01.02 Toggle stages; change palette, scale, surface-backed source, shared dirty pages and shader-affecting fields. Each required dependency triggers the correct update.
G01.03 Force first upload and cached upload failure, then retry successfully. Dirty/retry state is retained until success; no stale descriptor/value is published.

Counters and rejection criteria

Collect: bind_calls, uniform_checks, actual_ubo_writes, descriptor_updates, value_prepare_ns, bind_cpu_ns, gpu_ns, total_wait_ns. Keep exact counts separate from sampled durations; use an uninstrumented build for performance qualification.

Reject or hold: Reject a stale UBO or retry failure. Record texture CPU and shader CPU separately; historical 7.40%/6.88% texture CPU reductions are not current FPS forecasts.

Follow the common protocol for source identities, previous-main/fixed-baseline controls, raw results, confidence and retail/XISO qualification. No gain becomes proven from a model, cache hit, local operation count, or shifted wait label alone.

Recent evidence — deterministic producers and consumer-owned reconciliation

PRs #138 and #135 sharpen this investigation.

PR #138 found that reflected stage-zero bump fields were not initialized. They are semantically unused for bump luminance, but both renderers can compare/copy complete reflected arrays. Identical guest state could therefore appear dirty because prior storage differed.

semantic field unused by guest feature
        !=
byte may remain undefined when downstream compares/copies the reflected field
flowchart LR
    A[Guest state] --> B[Deterministic complete uniform value]
    B --> C[Renderer derived values]
    C --> D{Published bytes differ?}
    D -->|No| E[Skip staging]
    D -->|Yes| F[Stage and publish after success]
Loading

Retain the #138 sentinel oracle: prefill two output structures with different canaries, run the production producer with identical state, then compare every reflected byte range consumed by the renderer.

PR #135 separates descriptor-visible texture identity from shader-uniform inputs. Reconcile the four effective texture-scale values at the uniform consumer rather than rebuilding every fragment uniform. If another condition already guarantees a full vertex-uniform refresh, do not scan dirty arrays merely to rediscover the same decision.

The earlier claim that fewer reconciliation calls necessarily reduce UBO uploads was withdrawn because the parent already compares bytes before staging. Track actual PSH/VSH writes, staged bytes, descriptor writes, and capacity requests separately from preparation calls.

Reviewed heads: #138 merged prerequisite 0dc89c00; #135 draft 071c1d06. #135 remains bounded research evidence.

Clone this wiki locally