Repository navigation
OpenGL Sampler Objects
Lifecycle: Performance - Unproven · Type: Sampling-state separation and cache
Reviewed source:322986f4c5502b3fa887a9605ac8cd88e9b2c579
State: The backend already caches several texture parameters, but sampling state remains attached to texture objects and anisotropy is reapplied whenever the parameter routine runs.
OpenGL candidate directory · Direct surface binding · OpenGL Renderer
OpenGL texture objects currently hold both image storage and sampling parameters. apply_texture_parameters() compares and caches minification, magnification, LOD bias, wrap modes, and border color on each TextureBinding, but it writes anisotropy whenever the extension is available. Disabled stages also unbind four texture targets individually.
Sampler objects separate effective sampling state from image storage. The candidate builds a compact sampler key, creates/reuses GLuint sampler objects, and binds the sampler for each texture unit only when the effective state changes.
This is not the Vulkan “split sampler fields out of the texture-content key” issue. The OpenGL texture cache already excludes ordinary sampling parameters from image-content identity. The opportunity is reducing texture-object mutation and allowing one image to be sampled differently on several units safely.
-
hw/xbox/nv2a/pgraph/gl/texture.capply_texture_parameters()pgraph_gl_bind_textures()- texture binding state and cache lifetime
- OpenGL renderer init/finalize for sampler-object capability and cache ownership.
- Internal render/display helpers that bind textures and may require explicit sampler restoration or isolation.
flowchart TD
A[Bind texture stage] --> B[Bind texture object]
B --> C[Decode effective filter/wrap/LOD/border/anisotropy]
C --> D[Compare fields stored on TextureBinding]
D --> E[Call glTexParameter* for changed fields]
E --> F[Always apply anisotropy when supported]
F --> G[Draw samples texture object state]
The texture object accumulates the last applied sampling state. Using the same image with different state on two units requires repeated mutation or distinct texture objects.
flowchart TD
A[Bind texture stage] --> B[Build effective sampler key]
B --> C[Lookup/create sampler object]
C --> D{Sampler already bound to unit?}
D -->|Yes| E[Skip sampler bind]
D -->|No| F[glBindSampler unit, sampler]
F --> E
E --> G[Bind image texture only if image changed]
G --> H[Draw]
Illustrative key:
typedef struct GLSamplerKey {
GLenum min_filter;
GLenum mag_filter;
GLenum wrap_s;
GLenum wrap_t;
GLenum wrap_r;
float lod_bias;
float max_anisotropy;
uint32_t border_color;
bool uses_border_color;
} GLSamplerKey;Creation:
GLuint create_sampler(const GLSamplerKey *key)
{
GLuint sampler;
glGenSamplers(1, &sampler);
glSamplerParameteri(sampler, GL_TEXTURE_MIN_FILTER, key->min_filter);
glSamplerParameteri(sampler, GL_TEXTURE_MAG_FILTER, key->mag_filter);
glSamplerParameteri(sampler, GL_TEXTURE_WRAP_S, key->wrap_s);
glSamplerParameteri(sampler, GL_TEXTURE_WRAP_T, key->wrap_t);
glSamplerParameteri(sampler, GL_TEXTURE_WRAP_R, key->wrap_r);
glSamplerParameterf(sampler, GL_TEXTURE_LOD_BIAS, key->lod_bias);
if (anisotropy_supported) {
glSamplerParameterf(sampler, GL_TEXTURE_MAX_ANISOTROPY_EXT,
key->max_anisotropy);
}
if (key->uses_border_color) {
glSamplerParameterfv(sampler, GL_TEXTURE_BORDER_COLOR,
unpack_color(key->border_color));
}
return sampler;
}Not every texture parameter belongs in a sampler object. The candidate must keep texture-storage/view state separate, including:
- base/max mip level where it affects the image view;
- swizzle state;
- immutable/mutable storage representation;
- target and dimensionality;
- border pixels physically present in the image;
- depth/stencil texture mode where applicable.
A sampler cache does not authorize removing those updates from texture objects.
Guest state can map several register encodings to the same host sampler. Normalize before hashing:
Guest minification mode
-> linear-texture correction
-> host GLenum
Guest anisotropy exponent
-> supported host range clamp
Unused T/R wrap dimensions
-> canonical value
Border color not used
-> excluded/canonicalized
Without normalization, the cache creates duplicate sampler objects that produce identical host behavior.
Current disabled stages bind zero to cube, 1D, 2D, and 3D targets. A state shadow can reduce those calls. Sampler objects add another explicit disabled-state rule:
if (!enabled) {
if (bound_sampler[unit] != 0) {
glBindSampler(unit, 0);
bound_sampler[unit] = 0;
}
bind_no_image_for_unit(unit);
}Sampler unbinding does not replace image-target cleanup.
Required fixture:
unit 0 samples image A with nearest + clamp
unit 1 samples image A with linear + repeat
Both units must retain their own effective state without mutating the shared image between draw setup steps. This is especially important for a future Direct Surface Binding route.
- Repeated
glTexParameter*()calls on texture binds. - Unconditional anisotropy writes.
- Texture-object mutations when only sampling state changes.
- Duplicate image objects created only to preserve different sampling state.
- Some state restoration after internal copy/display passes.
- Image/storage state updates.
- Correct guest-to-host filter/wrap normalization.
- Capability clamping for anisotropy and border support.
- Correct binding per texture unit and context.
- Sampler cache lifetime and deletion.
- Invalidation on context recreation.
- Reference texture-parameter path when sampler objects are unavailable.
- Cleanly separates image identity from sampling policy.
- Supports one image with several simultaneous sampling modes.
- Reduces mutable state on render-surface textures.
- Provides a small, hashable object cache.
- Helps direct surface aliasing and a broader render-state shadow.
- Adds cache and binding state per context/unit.
- Cache can grow without normalization or capacity policy.
- Driver may already suppress redundant texture-parameter work.
- Texture-only state can be accidentally moved into the sampler key.
- Internal display/surface helpers can leave sampler bindings inconsistent.
- Some old/limited contexts may lack the capability or have driver issues.
sampler_key_builds
sampler_cache_hits
sampler_cache_misses
sampler_objects_created
sampler_evictions
sampler_binds
sampler_bind_skips
texture_parameter_calls{parameter}
anisotropy_writes
shared_image_multi_sampler_draws
disabled_stage_sampler_unbinds
| Scenario | Required result |
|---|---|
| Stable sampling across many draws | Sampler hit and bind skip |
| Change one filter/wrap field | New/cached sampler selected |
| Same image on two units with different state | Both units render correctly |
| Border color enabled/disabled | Correct key and output |
| Linear texture with illegal mip filter | Same normalized host behavior |
| Anisotropy unsupported or clamped | Safe fallback/canonicalization |
| Internal surface-copy/display pass | Guest sampler state restored or shadow invalidated |
| Context recreation | Old sampler names not reused |
| Cache pressure | Bounded eviction without in-flight use |
| Reference texture-parameter mode | Pixel-identical comparison |
Promote to Researched when route counters show high redundant parameter activity or shared-image state churn, output remains identical, and Release measurements reduce OpenGL call/CPU cost or enable a broader direct-surface optimization.
Reject or keep only as infrastructure if driver-side redundancy elimination makes the direct performance effect negligible and no dependent optimization benefits from sampler separation.
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