namespace AcDream.App.Rendering; /// /// Campaign V slice V4a bridge: memoizes a for the /// most recent raw GL colour-texture name a still-unmigrated private-viewport /// renderer (, /// ) produced, so /// UiViewport.TextureHandle — now a — has /// something to draw. Those renderers still allocate their FBO colour /// attachment directly on GL (V4g's scope: "PrivateEntityViewportRenderer /// → IGpuRenderTarget"), so this bridge — not their own campaign slice — is /// what lets the RETAINED UI side of the seam move onto the RHI now. /// /// Registers lazily and only re-registers when the producer hands back a /// DIFFERENT raw name (the FBO's colour texture is stable across frames at a /// fixed viewport size and only regenerates on resize) — a naive /// register-every-frame would exhaust the 16384-slot table in seconds. /// Deleted at slice V4g once those renderers publish a real /// directly. /// internal sealed class ExternalViewportTextureBridge { private readonly IGpuDevice _device; private readonly IGpuSampler _sampler; private uint _lastRawName; private GpuTextureSlot _lastSlot = GpuTextureSlot.Unassigned; public ExternalViewportTextureBridge(IGpuDevice device) { _device = device ?? throw new ArgumentNullException(nameof(device)); // Matches the FBO colour attachment's own fixed GL_LINEAR / CLAMP_TO_EDGE // parameters (PrivateEntityViewportRenderer.EnsureFramebuffer, // PaperdollViewportRenderer's equivalent): a bindless handle's // filtering comes from the bound SAMPLER object, not the texture's // own — now irrelevant — TEXTURE_MIN_FILTER/TEXTURE_MAG_FILTER. _sampler = device.CreateSampler(GpuSamplerDescription.WorldClamp); } /// /// Resolves (0 = nothing rendered /// this call, matching the producers' existing "0 = no texture" return) /// to a texture-table slot, registering it once per distinct name. /// public GpuTextureSlot Resolve(uint rawGlColorTextureName) { if (rawGlColorTextureName == 0) { Release(); return GpuTextureSlot.Unassigned; } if (rawGlColorTextureName == _lastRawName && _lastSlot.IsAssigned) return _lastSlot; Release(); if (_device is not Gpu.Gl.GlGpuDevice glDevice) { throw new NotSupportedException( "ExternalViewportTextureBridge only supports the GL backend. " + "Slice V4g removes this bridge before any other backend ships."); } _lastSlot = glDevice.RegisterExternalColorTexture(rawGlColorTextureName, _sampler); _lastRawName = rawGlColorTextureName; return _lastSlot; } private void Release() { if (_lastSlot.IsAssigned) _device.ReleaseTextureSlot(_lastSlot); _lastSlot = GpuTextureSlot.Unassigned; _lastRawName = 0; } }