Expand description
A recycling pool for the short-lived textures a frame renders into:
TexturePool, the PooledTexture it hands out, and the
TextureAllocator seam that keeps both host-testable.
An intermediate render target — a scratch surface a pass draws into and a later pass consumes — is allocated and dropped every frame if nothing recycles it. That is exactly the cost the hybrid renderer’s own TODO names (“we currently allocate a new strips buffer for each render pass”), and it is worst during a resize storm: dragging a window edge produces a new surface size every frame, so a pool keyed on the exact requested extent allocates a fresh texture per frame and parks the previous one forever.
Two decisions make the pool survive that storm.
- Quantization. A request’s extent is rounded up to the next multiple
of
SIZE_QUANTUM(256 px) before it becomes a key, so a drag through 4096 distinct widths lands on a couple of dozen keys instead. The caller gets a texture at least as large as it asked for and renders into the sub-rect it actually wants (PooledTexture::requested_size); Impeller’s coverage-size quantization is the same trade — a bounded amount of slack memory in exchange for reuse across a size that never stops changing. - Aging with slack. A free entry survives
DEFAULT_MAX_UNUSED_FRAMES(60) frames of disuse beforeTexturePool::agedrops it.frust-render’s compositor scratch ages out after 2 frames, which is right for one full-surface texture whose size is pinned to the surface, and far too aggressive here: a resize drag revisits a quantized size seconds later, and a two-frame window would evict every entry between visits and turn the pool back into a plain allocator. Grow-and-never-shrink is the other failure mode, so the window is finite and tunable (TexturePool::with_max_unused_frames).
§Recycled contents are never loaded
A pooled texture’s prior contents belong to whichever pass used it last,
so a pass targeting one must CLEAR, never LOAD — that is what
PooledTexture::color_attachment builds, and it is a correctness rule
before it is a bandwidth one. Pairing LoadOp::Clear with
StoreOp::Discard is also the precondition for
wgpu::TextureUsages::TRANSIENT_ATTACHMENT, which effective_usage
adds on an adapter that reports TierCaps::transient_saves_memory — a
write-only attachment can then live in tile memory and may never get
backing storage at all. TRANSIENT_ATTACHMENT is incompatible with every
other usage, so it is applied only to a texture whose whole usage set is
RENDER_ATTACHMENT; anything sampled or copied out afterwards keeps the
clear/discard policy and no flag.
§No GPU in the loop
Allocation goes through TextureAllocator rather than a wgpu::Device
borrow, so the pool’s keying, reuse, aging and statistics are exercised
against a counting fake with no device — the same pure-decision /
platform-lookup split crate::caps::TierCaps::fake gives adapter
capabilities. wgpu::Device implements the trait, and it is the only
implementation the engine itself ever passes.
Structs§
- PoolKey
- The configuration a pooled texture is interchangeable within: two requests that produce the same key may share one texture, and two that do not never can.
- Pool
Stats - A
TexturePool’s counters, as of theTexturePool::statscall. - Pooled
Texture - A texture checked out of a
TexturePool, the key it returns under, and the frame clock it ages against. - Texture
Pool - Recycles the intermediate textures a frame renders into, keyed by quantized configuration and aged by frame clock.
Constants§
- DEFAULT_
MAX_ UNUSED_ FRAMES - How many frames a free entry may go unused before
TexturePool::agedrops it: roughly a second of frames at 60 Hz, so a resize drag that revisits a quantized size still finds it parked. - SIZE_
QUANTUM - The multiple every pooled texture’s width and height is rounded up to before it is used as a pool key.
Traits§
- Texture
Allocator - Creates the texture/view pair a
TexturePoolhands out.
Functions§
- effective_
usage - The usage a pooled texture requested as
usageis actually created with. - quantize_
extent - Rounds
widthandheightup to the next multiple ofSIZE_QUANTUM, never pastmax_dimension.