namespace AcDream.App.Rendering.Gpu; /// /// Backend-neutral view of what the device can do. Both backends fill this from /// their own probe layer — GraphicalCapabilityRecord for GL, and its /// Vulkan sibling added at slice V5 — and the renderers consult only this. /// /// The alignment fields are load-bearing rather than informational: ring /// allocations must satisfy them, and getting one wrong produces a driver error /// on Vulkan and silently wrong data on some GL implementations. /// internal sealed record GpuCapabilityRecord { public required GpuBackendKind Backend { get; init; } /// Adapter name, e.g. "AMD Radeon RX 9070 XT". public required string DeviceName { get; init; } /// Driver identification string for diagnostics and bug reports. public required string DriverInfo { get; init; } /// API version actually in use, e.g. "OpenGL 4.6" or "Vulkan 1.3.280". public required string ApiVersion { get; init; } /// Simultaneously registerable texture-table slots. Must reach . public required uint MaxTextureTableSlots { get; init; } /// Storage-buffer bindings available. Must reach . public required uint MaxStorageBufferBindings { get; init; } /// Push-constant bytes available. Must reach . public required uint MaxPushConstantBytes { get; init; } /// Required alignment for a storage-buffer binding offset. public required uint MinStorageBufferOffsetAlignment { get; init; } /// Required alignment for a uniform-buffer binding offset. public required uint MinUniformBufferOffsetAlignment { get; init; } /// Clip distances usable by a shader. Phase U.3's per-cell clip gate needs 8. public required uint MaxClipDistances { get; init; } /// Highest supported multisample count for the backbuffer. public required uint MaxSampleCount { get; init; } /// Multi-draw-indirect. Mandatory — it is the entire draw architecture. public required bool SupportsMultiDrawIndirect { get; init; } /// Shader draw parameters (gl_DrawID). Mandatory — batch lookup depends on it. public required bool SupportsDrawParameters { get; init; } /// BC1/2/3 sampling. Mandatory — DAT surfaces upload as DXT without transcoding. public required bool SupportsTextureCompressionBc { get; init; } /// GPU timestamps. Optional: absence degrades profiling, not rendering. public required bool SupportsTimestampQueries { get; init; } /// /// Whether per-frame data can be written straight into mapped memory the GPU /// reads. Both backends report this; only Vulkan currently answers true, and /// it is the mechanism behind Campaign V's CPU-cost target. /// public required bool SupportsPersistentlyMappedRings { get; init; } /// /// Every mandatory capability this device fails to provide, phrased as /// operator-facing sentences. Empty means the device can run acdream. /// Startup turns a non-empty list into the same NotSupportedException /// and exit-code-4 contract the GL gate already publishes. /// public IReadOnlyList SupportFailures { get { List failures = []; if (!SupportsMultiDrawIndirect) failures.Add("Multi-draw-indirect is required to submit world geometry."); if (!SupportsDrawParameters) failures.Add("Shader draw parameters (gl_DrawID) are required to select per-draw batch data."); if (!SupportsTextureCompressionBc) failures.Add("BC (DXT) texture compression is required to upload DAT surfaces."); if (MaxTextureTableSlots < GpuBindingModel.TextureTableCapacity) { failures.Add( $"The texture table needs {GpuBindingModel.TextureTableCapacity} slots; " + $"this device provides {MaxTextureTableSlots}."); } if (MaxStorageBufferBindings < GpuBindingModel.StorageBindingCount) { failures.Add( $"{GpuBindingModel.StorageBindingCount} storage-buffer bindings are required; " + $"this device provides {MaxStorageBufferBindings}."); } if (MaxPushConstantBytes < GpuBindingModel.PushConstantBytes) { failures.Add( $"{GpuBindingModel.PushConstantBytes} push-constant bytes are required; " + $"this device provides {MaxPushConstantBytes}."); } if (MaxClipDistances < GpuBindingModel.ClipPlanesPerSlot) { failures.Add( $"{GpuBindingModel.ClipPlanesPerSlot} clip distances are required by the per-cell clip gate; " + $"this device provides {MaxClipDistances}."); } return failures; } } public bool IsSupported => SupportFailures.Count == 0; }