using AcDream.App.Rendering.Gpu.Gl; namespace AcDream.App.Tests.Rendering.Gpu.Gl; public sealed class GlRingBufferStateTests { [Fact] public void FirstAllocationStartsAtZero() { var state = new GlRingBufferState(1024); uint offset = state.Allocate(64, alignmentBytes: 16); Assert.Equal(0u, offset); Assert.Equal(64u, state.AllocatedBytes); } [Fact] public void SubsequentAllocationsAlignUpToTheRequestedBoundary() { var state = new GlRingBufferState(1024); state.Allocate(12, alignmentBytes: 4); uint second = state.Allocate(64, alignmentBytes: 256); Assert.Equal(0u, second % 256); Assert.True(second >= 12); } [Fact] public void AllocationsMergeIntoOneDirtyRange() { var state = new GlRingBufferState(1024); state.Allocate(16, alignmentBytes: 4); state.Allocate(32, alignmentBytes: 4); (int start, int length) = state.TakeDirtyRange(); Assert.Equal(0, start); Assert.Equal(48, length); } [Fact] public void TakingTheDirtyRangeClearsItUntilTheNextWrite() { var state = new GlRingBufferState(1024); state.Allocate(16, alignmentBytes: 4); state.TakeDirtyRange(); (int start, int length) = state.TakeDirtyRange(); Assert.Equal(0, start); Assert.Equal(0, length); Assert.False(state.HasDirtyBytes); } [Fact] public void WritesAfterAFlushExtendANewDirtyRangeWithoutRewindingTheCursor() { var state = new GlRingBufferState(1024); state.Allocate(16, alignmentBytes: 4); state.TakeDirtyRange(); uint secondOffset = state.Allocate(8, alignmentBytes: 4); Assert.Equal(16u, secondOffset); (int start, int length) = state.TakeDirtyRange(); Assert.Equal(16, start); Assert.Equal(8, length); } [Fact] public void ResetRewindsTheCursorAndClearsDirtyState() { var state = new GlRingBufferState(1024); state.Allocate(64, alignmentBytes: 4); state.Reset(); Assert.Equal(0u, state.AllocatedBytes); Assert.False(state.HasDirtyBytes); Assert.Equal(0u, state.Allocate(4, alignmentBytes: 4)); } [Fact] public void OverCapacityRequestThrowsRatherThanTruncating() { var state = new GlRingBufferState(64); Assert.Throws(() => state.Allocate(128, alignmentBytes: 4)); } [Fact] public void AlignmentPushingPastCapacityAlsoThrows() { var state = new GlRingBufferState(64); state.Allocate(60, alignmentBytes: 4); Assert.Throws(() => state.Allocate(8, alignmentBytes: 4)); } [Theory] [InlineData(0u, 256u, 0u)] [InlineData(1u, 256u, 256u)] [InlineData(255u, 256u, 256u)] [InlineData(256u, 256u, 256u)] [InlineData(10u, 1u, 10u)] public void AlignUpMatchesStandardAlignmentArithmetic(uint value, uint alignment, uint expected) { Assert.Equal(expected, GlRingBufferState.AlignUp(value, alignment)); } [Fact] public void ZeroByteAllocationDoesNotMarkAnythingDirty() { var state = new GlRingBufferState(1024); state.Allocate(0, alignmentBytes: 4); Assert.False(state.HasDirtyBytes); } }