Skip to content

OpenGL Completed Display Reuse

github-actions[bot] edited this page Sep 15, 2026 · 1 revision

OpenGL Completed Display Reuse

Lifecycle: Performance - Unproven · Type: Retained-result shortcut
Reviewed source: 322986f4c5502b3fa887a9605ac8cd88e9b2c579
State: The current OpenGL display path recomposes on each accepted framebuffer request. A complete reuse key and invalidation contract have not been implemented.

OpenGL candidate directory · Asynchronous display handoff · Vulkan unchanged scanout

Purpose

The OpenGL framebuffer interface asks the PGRAPH thread to synchronize and render the display composition before returning r->gl_display_buffer. When the source surface, scanout parameters, output size, interlace state, scaling, and PVIDEO inputs are unchanged, repeating that work cannot produce a different host image.

This shortcut retains the last completed composition and returns it again only when a full identity/version key proves that every input remains valid.

It is separate from asynchronous context handoff:

  • Asynchronous handoff changes when the CPU waits for a new output.
  • Completed display reuse avoids producing a new output at all.

Source seams

  • hw/xbox/nv2a/pgraph/gl/display.c
    • pgraph_gl_sync()
    • pgraph_gl_get_framebuffer_surface()
    • render_display()
    • render_display_pvideo_overlay()
  • Surface lifetime/content metadata from the OpenGL surface cache.
  • VGA/CRTC scanout parameters, interlace mode, surface scale, and PVIDEO register state.
  • Context/display-resource generation from init, resize, and teardown paths.

Current execution flow

flowchart TD
    A[Frontend requests framebuffer] --> B[Find surface at current scanout]
    B --> C[Mark source frame time]
    C --> D[Signal PGRAPH sync request]
    D --> E[Prepare/upload source]
    E --> F[Wait render context]
    F --> G[Switch to display context]
    G --> H[Render display and PVIDEO composition]
    H --> I[Wait display completion]
    I --> J[Return gl_display_buffer]
Loading

This route is correct for changing output, but it repeats even when the completed display image is already exactly the required result.

Candidate execution flow

flowchart TD
    A[Framebuffer request] --> B[Build current display reuse key]
    B --> C{Completed key valid and equal?}
    C -->|Yes| D[Return retained completed output]
    C -->|No| E[Invalidate prior key]
    E --> F[Prepare source and compose display]
    F --> G[Wait or publish completion according to handoff contract]
    G --> H{Output remains reusable?}
    H -->|Yes| I[Publish key + output generation]
    H -->|No| J[Leave key invalid]
    I --> K[Return output]
    J --> K
Loading

Illustrative key:

typedef struct GLDisplayReuseKey {
    uint64_t renderer_generation;
    uint64_t surface_lifetime_id;
    uint64_t surface_content_version;
    uint64_t display_resource_generation;
    hwaddr scanout_address;
    uint32_t line_offset;
    uint32_t output_width;
    uint32_t output_height;
    uint32_t surface_scale;
    uint32_t interlace_mode;
    uint64_t pvideo_generation;
    bool pvideo_enabled;
} GLDisplayReuseKey;

A real key should contain only state that affects output, but it must contain all of it. Using a framebuffer address or texture name alone is not sufficient.

Required key dimensions

Source identity and content

  • Surface lifetime ID, not merely VRAM address.
  • Surface draw/content version.
  • Pending CPU upload or guest-memory authority changes.
  • Surface format, pitch, dimensions, and scale when not captured by lifetime.

Scanout and composition

  • CRTC start address and line offset.
  • Requested display width/height.
  • Interlace mode and field interpretation.
  • Surface scale factor.
  • Display texture/resource generation.

PVIDEO

  • Enabled/disabled state.
  • Input base/offset/pitch/size/crop.
  • Output rectangle and scale.
  • Color format and color-key state.
  • A content generation for the underlying guest video bytes.

Lifecycle

  • Renderer/context generation.
  • Resize/fullscreen resource generation.
  • Snapshot/reset generation.

Why address-only reuse fails

surface A at address 0x100000 renders red
A is destroyed
surface B is created at address 0x100000 and renders blue
address-only key matches
old red display is incorrectly reused

A surface lifetime ID or generation breaks that false match.

What may disappear

  • Source preparation when no pending upload/freshness work exists.
  • Render-to-display draw.
  • PVIDEO conversion/composition for unchanged overlay state.
  • Context switch and host synchronization for unchanged output.
  • Repeated display uniform and state calls.

What remains mandatory

  • Frontend ownership of the retained texture.
  • Completion of the output before first publication.
  • Correct invalidation on any source/composition change.
  • Guest flip/timing semantics; a reused host output does not imply skipping guest events.
  • Recomposition after resize, context recreation, PVIDEO changes, or source version changes.
  • Fallback when the key cannot prove identity.

Policy transition

If reuse becomes an Advanced or laboratory control, disabling it live must invalidate the retained key and force the next request through the reference composition route. Re-enabling it may publish a new key only after a fresh composition completes.

void set_display_reuse_policy(bool enabled)
{
    if (runtime_policy.display_reuse != enabled) {
        runtime_policy.display_reuse = enabled;
        display.reuse_key_valid = false;
        display.policy_generation++;
    }
}

Advantages

  • Removes the complete host display-production path on a hit.
  • Particularly useful when host refresh requests outnumber guest output changes.
  • Small hot-path decision once generations are available.
  • Maintains the existing composition path as a full reference fallback.
  • Composes naturally with asynchronous display handoff.

Costs and risks

  • Requires authoritative source and PVIDEO generations.
  • The key can become large or expensive if generations do not already exist.
  • A missing invalidation produces stale output rather than a clear crash.
  • Host output reuse can hide a guest-progress bug if guest events are incorrectly tied to recomposition.
  • Frontend texture lifetime must remain valid across repeated returns.
  • A driver/context reset invalidates OpenGL names even if guest state is unchanged.

Required counters

display_requests
reuse_key_attempts
reuse_hits
reuse_misses{reason}
forced_reference_hits
display_compositions
pvideo_compositions
source_uploads_avoided
render_context_waits_avoided
display_context_waits_avoided
retained_output_age_requests

Suggested miss reasons:

no_completed_output
surface_lifetime_changed
surface_content_changed
pending_upload
scanout_changed
size_or_interlace_changed
pvideo_changed
resource_generation_changed
policy_forced_reference

Qualification matrix

Scenario Required result
Repeated request with no guest output change Hit and identical texture/output
Host requests faster than guest flips High hit rate without skipping guest events
Same address, new surface lifetime Miss and fresh composition
CPU upload to source Miss before stale output can be returned
PVIDEO byte/register change Miss and correct overlay
Resize/fullscreen/interlace change Miss and resource recreation
Snapshot restore/reset Old key invalidated
Policy Auto → Disabled → Auto Forced reference, then fresh republish
Delayed frontend consumer Retained output not overwritten
Alternating red/blue source versions Exact version observed every request

Acceptance rule

Promote to Researched when route evidence shows repeated unchanged requests in real workloads, output hashes/screenshots remain identical under aggressive invalidation tests, and Release measurements reduce composition/wait CPU or tail time.

Rejection rule

Reject the shortcut if a complete key requires scanning or hashing more state than the composition costs, if real workloads almost never request unchanged output, or if frontend ownership prevents safe retention.

Related

Clone this wiki locally