using System.Reflection; namespace AcDream.App.Rendering.Gpu.Gl; /// /// The single source of truth mapping each /// field to the GLSL uniform name the GL backend binds it to — the names /// documented on the fields themselves. /// reads these constants (not string literals of its own) when it calls /// GL.GetUniformLocation, and lets a /// test prove the table cannot silently drop a field that a later slice adds /// to the shared struct. /// internal static class GlPushConstantUniformNames { public const string ViewProjection = "uViewProjection"; public const string DrawIdOffset = "uDrawIDOffset"; public const string LightingMode = "uLightingMode"; public const string RenderPass = "uRenderPass"; public const string LightDebug = "uLightDebug"; public const string TextureIndexA = "uTextureIndexA"; public const string TextureIndexB = "uTextureIndexB"; public const string ParamA = "uParamA"; public const string ParamB = "uParamB"; /// /// Field name (as declared on ) to GLSL /// uniform name, built from the same constants the binder applies with — /// so the binder and this completeness table can never disagree. /// public static IReadOnlyDictionary ByFieldName { get; } = new Dictionary { [nameof(GpuPushConstants.ViewProjection)] = ViewProjection, [nameof(GpuPushConstants.DrawIdOffset)] = DrawIdOffset, [nameof(GpuPushConstants.LightingMode)] = LightingMode, [nameof(GpuPushConstants.RenderPass)] = RenderPass, [nameof(GpuPushConstants.LightDebug)] = LightDebug, [nameof(GpuPushConstants.TextureIndexA)] = TextureIndexA, [nameof(GpuPushConstants.TextureIndexB)] = TextureIndexB, [nameof(GpuPushConstants.ParamA)] = ParamA, [nameof(GpuPushConstants.ParamB)] = ParamB, }; /// /// Throws if declares a public instance /// field this table does not map — the drift guard the campaign spec asks /// for. Called from a unit test, not from production code. /// internal static void AssertMapsEveryField() { FieldInfo[] fields = typeof(GpuPushConstants).GetFields( BindingFlags.Public | BindingFlags.Instance); foreach (FieldInfo field in fields) { if (!ByFieldName.ContainsKey(field.Name)) { throw new InvalidOperationException( $"GpuPushConstants.{field.Name} has no mapped GLSL uniform name in " + $"{nameof(GlPushConstantUniformNames)}."); } } if (ByFieldName.Count != fields.Length) { throw new InvalidOperationException( $"{nameof(GlPushConstantUniformNames)} maps {ByFieldName.Count} names but " + $"{nameof(GpuPushConstants)} declares {fields.Length} fields — a stale entry " + "survives a field rename or removal."); } } }