public sealed class TextureStreamerMip tails in, a byte budget held, and the coarser picture when it cannot be.
Remarks
Doc 08's streaming manager, textures only, and the third consumer PageResidency was built for. The service owns the queue, the budget and the eviction order; TexturePagePool owns where the bytes go and how they are read; and this owns the one thing neither can know — what a frame actually wants, and therefore which pages to ask for.
What drives residency is a wanted width, and that is the narrowest seam that works. A caller says how many texels across it needs a texture to be — WantedWidth computes that from a bounding radius and a view, which is the same screen-coverage estimate mesh LOD selection uses — and this turns it into a level and asks for the pages that cover it. Sampling feedback would be a better signal and there is no feedback buffer to read; an authored per-texture priority would be a worse one, because it cannot know where the camera is. When a feedback buffer exists it replaces Want and nothing else.
What says the wanted width is TextureDemand. It surveys the frame's visible drawables, takes the maximum over every user of a texture, and quantises that onto a ladder of mip widths with a dead band — because a wanted width that oscillates at a level boundary is a swap on alternate frames, and a swap is an upload.
MipBias is consumed here rather than on the sampler, and that is a portability decision. SamplerDescription.LodBias reaches the API on Vulkan only — OpenGL drops it on every GLES profile and WebGPU has no such field — so a streamer that expressed pressure as a sampler bias would express it on one backend of three. A bias applied to the wanted width is arithmetic, works everywhere, and has the effect the knob is named for: a positive bias asks for a coarser tail and frees the budget it would have taken.
⚠ Eviction is least-recently-used over pages and not over textures. A page evicted from the middle of a texture's prefix drops that texture's resident level immediately, and leaves the pages above it resident and useless until they age out in their turn. That self-corrects — an unusable page is never touched, so it is the next victim — and the alternative is a second eviction policy that knows about textures, which is the beginning of the per-consumer budget this design exists to not have.
Fields and properties (10)
public long BudgetHow many bytes of mip tail may be resident at once.
public long ResidentBytesHow many are.
public int PageSizeHow many bytes one page is.
public long LoadsHow many pages have been loaded since this was created.
public long EvictionsHow many have been evicted.
public long RejectionsHow many requests were dropped because nothing could be evicted to make room.
public int LoadingHow many loads are in flight.
public int PendingRequestsHow many requests are waiting.
public int TexturesHow many textures are registered.
public float MipBiasLevels added to every wanted width, positive for coarser.
Methods (12)
public TextureStreamer(ITextureStreamSource source, long budgetBytes, int pageSize = 65536)Creates a streamer over a source, with a budget.
public bool Register(int texture, Ktx2Layout layout)Says a texture is streamable, and pins the page that is always resident.
public bool IsRegistered(int texture)Whether a texture is one this streams.
public int PinnedLevel(int texture)The coarsest level a texture is guaranteed, whatever the budget.
public int ResidentLevel(int texture)The largest level of a texture that is completely resident.
public void Want(int texture, int width)Asks for a texture at a width, and says its pages were used this frame.
public int Service(int maxLoads = 8)Places what has arrived and starts what there is room for.
public void ClearRequests()Drops every request that has not started. What a camera that jumped calls.
public int CopyTail(int texture, int firstLevel, Span<byte> destination)Copies a resident mip tail out of the pool, in file order.
public static int WantedWidth(float radius, float distance, float viewportHeight, float verticalFieldOfView)The texture width a view wants of an object it can see.
public static int WantedWidth(in BoundingSphere bounds, RenderView view, float viewportHeight)The same estimate, from the numbers a frame actually holds.
public void Dispose()Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
Used by (6)
- ArenaThirdPersonShooter
- AssetTextureSourceVixen.Engine.Renderer
- AssetTextureStreamingTestsVixen.Engine.Renderer.Tests
- TextureDemandVixen.Engine.Renderer
- TextureDemandTestsVixen.Engine.Renderer.Tests
- TextureStreamingTestsVixen.Engine.Renderer.Tests