Skip to content

OpenGL Copy Image Surface Transfer

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

OpenGL Copy-Image Surface Transfer

Lifecycle: Performance - Unproven · Type: Exact copy subset
Reviewed source: 322986f4c5502b3fa887a9605ac8cd88e9b2c579
State: The current compatible surface-to-texture route is source-confirmed. The exact glCopyImageSubData() eligibility subset has not been qualified.

OpenGL candidate directory · Direct surface binding · OpenGL Renderer

Purpose

When a newer compatible render surface must update a texture, the current OpenGL fast route does not copy image storage directly. It redefines destination texture storage, attaches the destination to an FBO, changes substantial OpenGL state, clears the destination, and draws a full-screen triangle that samples the source surface.

The candidate keeps destination storage alive and uses glCopyImageSubData() for the subset where source and destination representations are copy compatible.

This is narrower and safer than direct surface binding. It still creates an independent texture version; it only replaces the way that version is materialized.

Source seams

Current execution flow

flowchart TD
    A[Surface newer than texture binding] --> B{Current compatibility check passes?}
    B -->|No| C[Download surface and upload texture]
    B -->|Yes| D[glTexImage2D NULL redefines destination]
    D --> E[Attach destination texture to temporary FBO]
    E --> F[Bind source surface as texture]
    F --> G[Change viewport/masks/tests/program/VAO]
    G --> H[Clear destination]
    H --> I[Draw full-screen triangle]
    I --> J[Restore selected GL state]
    J --> K[Publish texture draw_time]
Loading

This avoids a CPU round trip, but it still performs rendering work and disturbs global OpenGL state.

Candidate execution flow

flowchart TD
    A[Surface newer than texture binding] --> B{Copy-image compatibility key matches?}
    B -->|No| C[Current render-copy or slow fallback]
    B -->|Yes| D{Destination storage already compatible?}
    D -->|No| E[Allocate/redefine destination once]
    D -->|Yes| F[Keep existing storage]
    E --> G[glCopyImageSubData]
    F --> G
    G --> H[Publish independent texture version]
Loading

Illustrative call:

glCopyImageSubData(
    surface->gl_buffer, GL_TEXTURE_2D, 0,
    0, 0, 0,
    texture->gl_texture, texture->gl_target, 0,
    0, 0, 0,
    copy_width, copy_height, 1);

The actual target, mip level, face/layer, dimensions, internal formats, scaling, and border rules must be included in the guard.

Exact eligibility key

A safe first subset should require:

  • source is a color surface;
  • destination is a 2D texture, not a cubemap face or 3D layer;
  • one mip level is being updated;
  • source and destination dimensions match after the already-selected scale policy;
  • no filtering, scaling, swizzle conversion, border insertion, color remap, or alpha synthesis is required;
  • OpenGL internal formats are copy compatible according to the API rules;
  • source and destination are distinct objects or a proven legal non-overlapping region;
  • destination storage exists with the correct immutable/mutable representation;
  • no feedback loop or pending write/read hazard exists.

The existing surface_to_texture_can_fastpath() format pairs are a starting point, not a complete glCopyImageSubData() contract.

Destination storage lifetime

The current route calls glTexImage2D(..., NULL) before every compatible copy. The candidate needs a storage descriptor on the texture binding:

typedef struct GLCopyStorageKey {
    GLenum target;
    GLenum internal_format;
    unsigned width;
    unsigned height;
    unsigned levels;
    unsigned layers;
} GLCopyStorageKey;

If the key matches, retain storage. If it changes, reallocate before the copy. Storage identity must also reset when the texture object is recreated or evicted.

What may disappear

  • Repeated destination storage redefinition on same-shape updates.
  • FBO attachment and completeness work.
  • Destination clear.
  • Full-screen vertex/fragment execution.
  • Temporary shader/VAO/program binding.
  • Most render-state disturbance and restoration.

What remains mandatory

  • Independent destination image version.
  • Correct format/alpha/channel representation.
  • Correct dimensions and selected mip/layer.
  • Ordering from surface producer to copy and from copy to texture consumer.
  • Reference route for conversion/scaling/border/swizzle cases.
  • Storage recreation when the representation changes.
  • Texture-cache and draw-time/version updates.

Why this is not a generic copy replacement

The current shader route can perform effects that a raw image copy cannot:

  • sampling/filtering;
  • channel interpretation through the texture format;
  • scaling;
  • handling a destination with different representation;
  • border or coordinate behavior.

glCopyImageSubData() copies image data. It does not run the current conversion shader. Eligibility must prove that no conversion is needed.

State-shadow interaction

This candidate reduces state mutation, but the fallback render-copy path remains. A future OpenGL Render-State Shadow must account for both:

  • copy-image path, which should not disturb ordinary draw state;
  • render-copy path, which deliberately changes many states and restores only selected values.

Advantages

  • Exact for a well-defined representation-compatible subset.
  • Removes a complete internal draw and clear.
  • Reduces global state churn.
  • Retains independent texture lifetime, avoiding alias/version hazards.
  • Has clear output/version fixtures.

Costs and risks

  • Compatibility rules are stricter than the current visual fast path.
  • Driver support/capability must be checked.
  • Incorrect format compatibility can silently reorder channels or alpha.
  • Destination storage caching adds another lifetime key.
  • Copy may still serialize if source/destination hazards are not ordered efficiently.
  • The route may have low coverage if games frequently require conversion or scaling.

Required counters

surface_to_texture_requests
copy_image_eligible
copy_image_calls
copy_image_bytes
render_copy_fallbacks{reason}
slow_CPU_fallbacks{reason}
destination_storage_reuses
destination_storage_reallocations
internal_draws_avoided
FBO_setups_avoided
copy_image_us
render_copy_us

Qualification matrix

Scenario Required result
Exact same-format/same-size color copy Byte/pixel-identical result
XRGB/ARGB and channel-order pairs Only admitted pairs copy exactly
Scaled source or destination Reference route unless exact rule proven
Border/cubemap/mipmap case Reference route
Source red then blue, copies to B and C B remains red; C becomes blue
Destination reused with new representation Storage reallocated safely
Source modified after copy Destination retains independent older version
Multiple texture stages Each binding sees correct copied version
Context reset/cache eviction Storage key invalidated
Multiple drivers Capability and correctness recorded

Acceptance rule

Promote to Researched when a declared format/shape subset is pixel exact, route counters show useful coverage, and Release measurements reduce surface-to-texture CPU/GPU work or frame tails.

Rejection rule

Reject or narrow the route if compatibility checks become driver-specific and unreliable, if exact-copy coverage is negligible, or if the driver’s copy path is slower than the current full-screen draw in representative workloads.

Related

Clone this wiki locally