using System.Text.Json; using AcDream.App.Platform; namespace AcDream.App.Tests.Platform; public sealed class GraphicalCapabilityRequirementsTests { [Fact] public void SupportedModernContextPasses() { GraphicalCapabilityRecord capabilities = CreateSupported(); Assert.Empty(GraphicalCapabilityRequirements.Evaluate(capabilities)); } [Theory] [InlineData("bindless")] [InlineData("draw-parameters")] [InlineData("mdi")] [InlineData("ssbo")] [InlineData("timer")] [InlineData("depth")] [InlineData("stencil")] [InlineData("srgb")] [InlineData("keyboard")] [InlineData("mouse")] public void MissingMandatoryCapabilityIsRejected(string missing) { GraphicalCapabilityRecord capabilities = CreateSupported(); capabilities = missing switch { "bindless" => capabilities with { HasBindlessTexture = false, }, "draw-parameters" => capabilities with { HasShaderDrawParameters = false, }, "mdi" => capabilities with { HasMultiDrawIndirect = false, }, "ssbo" => capabilities with { HasShaderStorageBuffer = false, }, "timer" => capabilities with { HasTimerQuery = false, }, "depth" => capabilities with { Framebuffer = capabilities.Framebuffer with { DepthBits = 16, }, }, "stencil" => capabilities with { Framebuffer = capabilities.Framebuffer with { StencilBits = 0, }, }, "srgb" => capabilities with { Framebuffer = capabilities.Framebuffer with { FramebufferSrgbApi = false, }, }, "keyboard" => capabilities with { Input = capabilities.Input with { KeyboardCount = 0, }, }, "mouse" => capabilities with { Input = capabilities.Input with { MouseCount = 0, }, }, _ => throw new ArgumentOutOfRangeException(nameof(missing)), }; Assert.NotEmpty(GraphicalCapabilityRequirements.Evaluate(capabilities)); } [Fact] public void AdvertisedBufferStorageRequiresSuccessfulPersistentProbe() { GraphicalCapabilityRecord capabilities = CreateSupported() with { FunctionProbe = CreateSupported().FunctionProbe with { PersistentBufferStorage = false, }, }; Assert.Contains( GraphicalCapabilityRequirements.Evaluate(capabilities), failure => failure.Contains( "persistent mapping", StringComparison.Ordinal)); } [Fact] public void MissingOptionalBufferStorageDoesNotRequireProbe() { GraphicalCapabilityRecord capabilities = CreateSupported() with { HasBufferStorage = false, FunctionProbe = CreateSupported().FunctionProbe with { PersistentBufferStorage = null, }, }; Assert.Empty(GraphicalCapabilityRequirements.Evaluate(capabilities)); } [Fact] public void UnsupportedMessageNamesDriverProtocolFailureAndReport() { GraphicalCapabilityRecord capabilities = CreateSupported() with { SupportFailures = ["GL_ARB_bindless_texture is required."], }; string message = GraphicalCapabilityGuard.FormatUnsupportedMessage( capabilities, "capabilities.json"); Assert.Contains("Mesa", message); Assert.Contains("RadeonSI", message); Assert.Contains("Wayland", message); Assert.Contains("GL_ARB_bindless_texture", message); Assert.Contains( Path.GetFullPath("capabilities.json"), message); } [Fact] public void ReportWriterAtomicallyOverwritesJson() { string directory = Path.Combine( Path.GetTempPath(), "acdream-capability-tests", Guid.NewGuid().ToString("N")); string path = Path.Combine(directory, "capabilities.json"); try { GraphicalCapabilityReportWriter.Write(path, CreateSupported()); GraphicalCapabilityReportWriter.Write( path, CreateSupported() with { GlRenderer = "second renderer", }); using JsonDocument report = JsonDocument.Parse( File.ReadAllText(path)); Assert.Equal( "second renderer", report.RootElement .GetProperty(nameof(GraphicalCapabilityRecord.GlRenderer)) .GetString()); Assert.Equal( "Wayland", report.RootElement .GetProperty(nameof( GraphicalCapabilityRecord.ActiveDisplayProtocol)) .GetString()); Assert.False(File.Exists(path + ".tmp")); } finally { if (Directory.Exists(directory)) Directory.Delete(directory, recursive: true); } } private static GraphicalCapabilityRecord CreateSupported() => new( DateTimeOffset.UnixEpoch, "linux-x64", GraphicalHostOperatingSystem.Linux, GraphicalDisplayProtocol.Wayland, GraphicalDisplayProtocol.Wayland, "test", "Silk.NET.Windowing.Glfw", "3.4.0", "Mesa", "RadeonSI", "4.6", "4.60", 4, 6, 1, 1, HasBindlessTexture: true, HasShaderDrawParameters: true, HasMultiDrawIndirect: true, HasShaderStorageBuffer: true, HasBufferStorage: true, HasTimerQuery: true, MaximumShaderStorageBufferBindings: 16, MaximumUniformBufferBindings: 72, MaximumTextureSize: 16_384, MaximumArrayTextureLayers: 2_048, MaximumCombinedTextureImageUnits: 192, new GraphicalFramebufferCapabilities( 8, 8, 8, 8, 24, 8, 1, 4, FramebufferSrgbApi: true), new GraphicalInputCapabilities( KeyboardCount: 1, MouseCount: 1, GamepadCount: 0, JoystickCount: 0), new GraphicalWindowCapabilities( 1280, 720, 2560, 1440, "test monitor", 144, VSync: false), new GraphicalAudioCapabilities( Requested: false, Available: false, PlaybackSubmitted: false, DisposalComplete: true, Backend: "not requested"), new GraphicalSmokeLifecycleCapabilities( OwnedWindowCount: 1, OwnedGlApiCount: 1, OwnedInputContextCount: 1, OwnedAudioEngineCount: 0, ShutdownComplete: false), [], new GraphicalFunctionProbeResult( BindlessTexture: true, ShaderDrawParameters: true, MultiDrawIndirect: true, ShaderStorageBuffer: true, TimerQuery: true, SrgbFramebuffer: true, PersistentBufferStorage: true, Failures: []), SupportFailures: []); }