using AcDream.App.Rendering.Gpu; namespace AcDream.App.Rendering; /// /// Campaign V slice V6d: the encoding the retained UI passes textures around /// with — a ONE-BASED index into the device's global texture table, where 0 /// means "no texture". /// /// Why an encoding rather than the slot itself. Until this slice /// the UI's currency was a raw GL texture name: TextureCache handed one /// out, sixty-odd widget call sites carried it, and TextRenderer.DrawSprite /// bound it to texture unit 0. That name means nothing on Vulkan, so the /// currency has to become a . But /// is internal to the pinned RHI contract while /// UiRenderContext.DrawSprite, TextureCache.GetOrUploadRenderSurface /// and a dozen widget properties are public, so the slot cannot itself travel /// through those signatures without either publishing a contract type or /// converting the whole retained-UI surface to internal. Both were out of scope /// for this slice, and the second is explicitly forbidden by the campaign's /// rule against visibility sweeps. /// /// Why one-based. The old currency already had the property that /// zero means nothing — GL texture name 0 is "no texture" — and every widget in /// the tree guards on it (if (tex == 0) return;). Slot 0 is a perfectly /// valid table index, so handing out raw slot indices would turn every one of /// those guards into a silent false negative. Shifting by one preserves the /// guard exactly, needs no call-site change, and keeps the sentinel loud rather /// than aliasing onto a real texture. /// /// Retired when the retained UI's public surface can name a /// directly. /// internal static class UiTextureTableHandle { /// No texture. What every widget's tex == 0 guard tests for. public const uint None = 0; /// Encodes a registered slot. An unassigned slot encodes to . public static uint FromSlot(GpuTextureSlot slot) => slot.IsAssigned ? slot.Index + 1 : None; /// /// Decodes a handle. decodes to /// , which the retained UI's shader /// reads as "draw the vertex colour" rather than sampling anything. /// public static GpuTextureSlot ToSlot(uint handle) => handle == None ? GpuTextureSlot.Unassigned : new GpuTextureSlot(handle - 1); }