public sealed class VirtualShadowPagesThe physical page pool behind a virtual shadow map, and the page table that finds it.
No guide page documents this yet — the page shows what the code says about itself.
Remarks
Improvement 6's second consumer, and the one that proves the seam was worth drawing. PageResidency was built in phase 2 with three consumers in view — geometry pages, texture mip tails and these — precisely so it would not come out geometry-shaped. What it owns is the request queue, the byte budget, the eviction order and the counters; what a store owns is where the bytes go and how they are read. A shadow page is the case that tests that division hardest, because there is nothing to read: a shadow page's content is rendered, not loaded, so LoadAsync here returns immediately with nothing and Place allocates rather than copies.
That is not the interface being bent. Everything the service does — dropping stale requests, refusing to exceed a budget, evicting least-recently-used, never evicting a pinned page — is exactly as meaningful for a page that is drawn as for one that is read, and it is the *only* part of either that a frame has to get right. What the store adds is a single extra fact the service has no opinion about: a page that has just been given a slot holds nothing yet, and somebody has to draw into it. TakePending is that fact.
Eviction is what makes the page table dangerous, so it is what the store handles most carefully. A slot handed to a new virtual page while a shading pass still points at it under the old one reads another part of the world's depth — a shadow of something that is not there, in the right place, at a plausible depth. Evict clears the table entry before the slot is reused, which is the frame boundary the service cannot see and this can.
Fields and properties (9)
public const int SourceThe one source id every shadow page carries in a PageKey.
public const int PageBytesHow many bytes a page notionally occupies, for the budget to be about something.
public int PagesPerSideHow many pages the physical atlas is on a side.
public int PageSizeHow many bytes one page occupies in the pool.
public int SlotCountHow many slots the pool has.
public int AtlasTexelsHow many texels the atlas is on a side.
public ReadOnlySpan<uint> TableThe page table a shading pass reads: one entry per virtual page, or PageAbsent.
public long AllocationsHow many pages have been allocated a slot since this was created.
public IReadOnlyList<int> PendingWhich resident pages hold nothing yet and have to be drawn.
Methods (10)
public VirtualShadowPages(int pagesPerSide = 32)Creates a pool of physical pages.
public bool TryGetAllocation(int page, out int slot)Which physical page a virtual one was allocated, drawn or not.
public bool Drawn(int page)Publishes a page's depths, now that something has drawn them.
public bool TryGetSlot(int page, out int slot)Where a virtual page's depths are, or false when nothing backs it.
public int[] TakePending(int most = 16)Takes the pages owed a draw, and forgets them.
public bool Invalidate(int page)Says a resident page's depths are stale and it has to be drawn again.
public void InvalidateAll()Says every resident page is stale.
public ValueTask<int> LoadAsync(PageKey key, Memory<byte> destination, CancellationToken cancellation)public bool Place(PageKey key, int slot, ReadOnlySpan<byte> bytes)Puts a loaded page's bytes into a slot.
public void Evict(PageKey key, int slot)Says a page is no longer resident, and its slot is about to be reused.
Used by (4)
- ArenaThirdPersonShooter
- VirtualShadowAtlasVixen.Rendering
- VirtualShadowPageTestsVixen.Rendering.Tests
- VirtualShadowRendererVixen.Rendering