using System.Numerics; using System.Runtime.InteropServices; namespace AcDream.App.Rendering.Gpu; /// /// The single push-constant block shared by every acdream pipeline — 96 of the /// 128 bytes Vulkan guarantees, leaving 32 bytes of headroom for later slices. /// /// One shared block (rather than a per-shader block) is what lets every world /// pipeline share ONE pipeline layout, so switching pipelines mid-pass does not /// invalidate bound descriptor sets or push constants. Shaders declare only the /// fields they read; unused fields cost nothing. /// /// The GL backend maps each field to the correspondingly named uniform and skips /// any the program does not declare (location -1). The Vulkan backend writes the /// struct verbatim with one vkCmdPushConstants. /// /// Layout is asserted by GpuContractTests; changing it is a contract change /// that must land together with the matching edit to the shared GLSL preamble. /// [StructLayout(LayoutKind.Sequential, Pack = 4)] internal struct GpuPushConstants { /// /// GLSL uViewProjection. acdream's cameras build this with /// Matrix4x4.CreatePerspectiveFieldOfView, whose NDC z range is [0,1] — /// already Vulkan's convention (see PortalProjection.cs). No projection /// rework is needed for the migration, and Vulkan gains the half of the depth /// range GL was discarding. /// public Matrix4x4 ViewProjection; /// /// GLSL uDrawIDOffset. Issue #52: the draw index resets to 0 at the /// start of each multi-draw-indirect call, so a pass that begins partway into /// the batch array must offset its lookup. Vulkan's gl_DrawID resets /// identically per vkCmdDrawIndexedIndirect, so the pattern carries over /// unchanged. /// public int DrawIdOffset; /// GLSL uLightingMode: 0 = object (plain Lambert + sun), 1 = EnvCell (half-Lambert wrap, no sun). public int LightingMode; /// GLSL uRenderPass: 0 = opaque, 1 = translucent. public int RenderPass; /// GLSL uLightDebug: #176 stripe-hunt isolation modes; 0 = off. public int LightDebug; /// /// GLSL uTextureIndexA. Primary texture-table slot for pipelines whose /// texture is per-pass rather than per-batch — currently the terrain atlas. /// public uint TextureIndexA; /// GLSL uTextureIndexB. Secondary per-pass slot — currently the terrain alpha-mask array. public uint TextureIndexB; /// /// GLSL uParamA. Spare scalar, claimed at slice V6e by /// particle_mesh as the array layer its per-pass texture is sampled /// from — a value the shader converted to float anyway. /// public float ParamA; /// GLSL uParamB. Spare scalar; unclaimed at V0. public float ParamB; /// Neutral defaults: identity transform, opaque object lighting, no debug mode. public static GpuPushConstants Default => new() { ViewProjection = Matrix4x4.Identity, DrawIdOffset = 0, LightingMode = 0, RenderPass = 0, LightDebug = 0, TextureIndexA = 0, TextureIndexB = 0, ParamA = 0f, ParamB = 0f, }; }