namespace AcDream.App.Rendering.Gpu; /// /// Campaign V (V0): the PINNED binding model shared by the CPU renderers, the /// GLSL sources, and both RHI backends. Every number here appears in a shader /// file; changing one is a contract change that must land in the same commit as /// the matching shader edit. /// /// The model is deliberately Vulkan-shaped and dual-legal: /// /// set 0 — storage buffers, bindings 0..9. GLSL omits the set qualifier, and /// GL_KHR_vulkan_glsl defines an omitted set as set 0, so one source /// file compiles for both backends. /// set 1 — uniform buffers. Vulkan has ONE binding namespace per set, while /// GL keeps GL_SHADER_STORAGE_BUFFER and GL_UNIFORM_BUFFER tables /// separate. Today mesh_modern.vert exploits that: the BatchBuffer /// SSBO and the SceneLighting UBO both sit at binding=1. Moving UBOs /// to their own set preserves both numbers and removes the collision. /// set 2 — the global sampled-texture table that replaces ARB_bindless_texture. /// Vulkan binds it as one variable-count, partially-bound, /// update-after-bind descriptor array. GL emulates it with a storage /// buffer of uvec2 handles at set 0 binding 9 (), /// which is why both a set index and a storage binding exist here. /// /// A batch no longer carries a 64-bit bindless handle; it carries a /// index into the table. That single change is what /// makes the CPU-side data model backend-neutral (Campaign V slice V2), and it /// lands on GL — pixel-gated — long before any Vulkan code exists. /// internal static class GpuBindingModel { // ---- set 0: storage buffers (identical numbering to today's SSBO bindings) ---- /// Per-instance transforms. std430 InstanceData { mat4 transform; }. public const uint StorageInstances = 0; /// Per-draw batch metadata. std430 BatchData (see ). public const uint StorageBatches = 1; /// Phase U.3 shared per-frame clip regions (CellClip, 144 B/slot). Slot 0 = no-clip. public const uint StorageClipRegions = 2; /// Phase U.3 per-instance clip-slot index, parallel to . public const uint StorageClipSlots = 3; /// A7 Fix B global point/spot light array. public const uint StorageGlobalLights = 4; /// A7 Fix B per-instance light set: 8 indices into the global light array, -1 = unused. public const uint StorageInstanceLightSets = 5; /// #142 per-instance indoor flag (1 = parented to an EnvCell, skip the sun). public const uint StorageInstanceIndoor = 6; /// #188 per-instance opacity multiplier for TransparentPartHook fades. public const uint StorageInstanceAlpha = 7; /// Retail SmartBox selection lighting: one vec2 (luminosity, diffuse) per instance. public const uint StorageInstanceSelectionLighting = 8; /// /// GL-only emulation of the Vulkan texture table: a storage buffer of uvec2 /// bindless handles indexed by . The Vulkan /// backend binds instead and never uses this /// binding; it is deleted with the GL backend at slice V11. /// public const uint StorageTextureTable = 9; /// One past the highest storage binding — the count both backends must support. public const uint StorageBindingCount = 10; // ---- set 1: uniform buffers ---- /// /// SceneLighting std140 block. Keeps binding=1 so the existing shader source /// and SceneLightingUboBinding layout are untouched; the set index is /// what disambiguates it from under Vulkan. /// public const uint UniformSceneLighting = 1; /// Set index carrying every uniform buffer. public const uint UniformSet = 1; // ---- set 2: the global texture table ---- /// Set index of the sampled-texture descriptor array (Vulkan) / logical table (GL). public const uint TextureTableSet = 2; /// Binding of the descriptor array within . public const uint TextureTableBinding = 0; /// /// Upper bound on simultaneously registered textures. Vulkan requires /// maxDescriptorSetUpdateAfterBindSampledImages to reach this; the /// capability probe asserts it rather than discovering it at draw time. /// public const uint TextureTableCapacity = 16384; // ---- push constants ---- /// /// Bytes actually written by . Vulkan guarantees /// at least , so 32 bytes of headroom remain /// for later slices; any growth updates this constant and the shader block in /// the same commit. /// public const int PushConstantBytes = 96; /// The Vulkan-guaranteed minimum push-constant budget. A hard ceiling for us. public const int MaxPushConstantBytes = 128; // ---- shared layout facts the CPU writers and the shaders must agree on ---- /// /// std430 stride of BatchData. The bindless uvec2 textureHandle /// becomes uint textureIndex plus one pad word at slice V2, so the /// stride is unchanged and every existing CPU writer keeps its offsets. /// public const int GpuBatchDataStrideBytes = 16; /// Clip planes per CellClip slot; also the required gl_ClipDistance size. public const int ClipPlanesPerSlot = 8; /// std430 stride of one CellClip slot: 16 B header + 8 × vec4. public const int ClipRegionStrideBytes = 16 + (ClipPlanesPerSlot * 16); /// Lights selected per object by retail's minimize_object_lighting. public const int MaxLightsPerObject = 8; }