Skip to content

Commit

Permalink
Fix another test
Browse files Browse the repository at this point in the history
The assertions are kinda dodgy in this case, but it is what it is. This
is the only assertion in `Renderer`, so it's maybe even a matter for the
implementations to resolve by not doing draw-thread-requiring calls in
the ctor.
  • Loading branch information
smoogipoo committed Aug 8, 2024
1 parent 3f06897 commit 0750044
Show file tree
Hide file tree
Showing 8 changed files with 79 additions and 48 deletions.
101 changes: 55 additions & 46 deletions osu.Framework.Tests/Graphics/ShaderStorageBufferObjectStackTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,39 +2,41 @@
// See the LICENCE file in the repository root for full licence text.

using System;
using System.Runtime.InteropServices;
using NUnit.Framework;
using osu.Framework.Graphics.Rendering;
using osu.Framework.Graphics.Rendering.Dummy;
using osu.Framework.Graphics.Shaders.Types;

namespace osu.Framework.Tests.Graphics
{
public class ShaderStorageBufferObjectStackTest
{
private const int size = 10;

private ShaderStorageBufferObjectStack<int> stack = null!;
private ShaderStorageBufferObjectStack<TestUniformData> stack = null!;

[SetUp]
public void Setup()
{
stack = new ShaderStorageBufferObjectStack<int>(new DummyRenderer(), 2, size);
stack = new ShaderStorageBufferObjectStack<TestUniformData>(new DummyRenderer(), 2, size);
}

[Test]
public void TestBufferMustBeAtLeast2Elements()
{
Assert.Throws<ArgumentOutOfRangeException>(() => _ = new ShaderStorageBufferObjectStack<int>(new DummyRenderer(), 1, 100));
Assert.Throws<ArgumentOutOfRangeException>(() => _ = new ShaderStorageBufferObjectStack<int>(new DummyRenderer(), 100, 1));
Assert.DoesNotThrow(() => _ = new ShaderStorageBufferObjectStack<int>(new DummyRenderer(), 2, 100));
Assert.DoesNotThrow(() => _ = new ShaderStorageBufferObjectStack<int>(new DummyRenderer(), 100, 2));
Assert.Throws<ArgumentOutOfRangeException>(() => _ = new ShaderStorageBufferObjectStack<TestUniformData>(new DummyRenderer(), 1, 100));
Assert.Throws<ArgumentOutOfRangeException>(() => _ = new ShaderStorageBufferObjectStack<TestUniformData>(new DummyRenderer(), 100, 1));
Assert.DoesNotThrow(() => _ = new ShaderStorageBufferObjectStack<TestUniformData>(new DummyRenderer(), 2, 100));
Assert.DoesNotThrow(() => _ = new ShaderStorageBufferObjectStack<TestUniformData>(new DummyRenderer(), 100, 2));
}

[Test]
public void TestInitialState()
{
Assert.That(stack.CurrentOffset, Is.Zero);
Assert.That(stack.CurrentBuffer, Is.Not.Null);
Assert.That(stack.CurrentBuffer[stack.CurrentOffset], Is.EqualTo(0));
Assert.That(stack.CurrentBuffer[stack.CurrentOffset].Int.Value, Is.EqualTo(0));
}

[Test]
Expand All @@ -48,11 +50,11 @@ public void TestAddInitialItem()
{
var firstBuffer = stack.CurrentBuffer;

stack.Push(1);
stack.Push(new TestUniformData { Int = 1 });

Assert.That(stack.CurrentOffset, Is.Zero);
Assert.That(stack.CurrentBuffer, Is.EqualTo(firstBuffer));
Assert.That(stack.CurrentBuffer[stack.CurrentOffset], Is.EqualTo(1));
Assert.That(stack.CurrentBuffer[stack.CurrentOffset].Int.Value, Is.EqualTo(1));
}

[Test]
Expand All @@ -63,26 +65,26 @@ public void TestPushToFillOneBuffer()

for (int i = 0; i < size; i++)
{
stack.Push(i);
stack.Push(new TestUniformData { Int = i });
Assert.That(stack.CurrentOffset, Is.EqualTo(expectedIndex++));
Assert.That(stack.CurrentBuffer, Is.EqualTo(firstBuffer));
Assert.That(stack.CurrentBuffer[stack.CurrentOffset], Is.EqualTo(i));
Assert.That(stack.CurrentBuffer[stack.CurrentOffset].Int.Value, Is.EqualTo(i));
}
}

[Test]
public void TestPopEntireBuffer()
{
for (int i = 0; i < size; i++)
stack.Push(i);
stack.Push(new TestUniformData { Int = i });

var firstBuffer = stack.CurrentBuffer;

for (int i = size - 1; i >= 0; i--)
{
Assert.That(stack.CurrentOffset, Is.EqualTo(i));
Assert.That(stack.CurrentBuffer, Is.EqualTo(firstBuffer));
Assert.That(stack.CurrentBuffer[stack.CurrentOffset], Is.EqualTo(i));
Assert.That(stack.CurrentBuffer[stack.CurrentOffset].Int.Value, Is.EqualTo(i));
stack.Pop();
}
}
Expand All @@ -91,47 +93,47 @@ public void TestPopEntireBuffer()
public void TestTransitionToBufferOnPush()
{
for (int i = 0; i < size; i++)
stack.Push(i);
stack.Push(new TestUniformData { Int = i });

var firstBuffer = stack.CurrentBuffer;
int copiedItem = stack.CurrentBuffer[stack.CurrentOffset];
int copiedItem = stack.CurrentBuffer[stack.CurrentOffset].Int.Value;

// Transition to a new buffer...
stack.Push(size);
stack.Push(new TestUniformData { Int = size });
Assert.That(stack.CurrentBuffer, Is.Not.EqualTo(firstBuffer));

// ... where the "hack" employed by the queue means that after a transition, the new item is added at index 1...
Assert.That(stack.CurrentOffset, Is.EqualTo(1));
Assert.That(stack.CurrentBuffer[1], Is.EqualTo(size));
Assert.That(stack.CurrentBuffer[1].Int.Value, Is.EqualTo(size));

// ... and the first item in the new buffer is a copy of the last referenced item before the push.
Assert.That(stack.CurrentBuffer[0], Is.EqualTo(copiedItem));
Assert.That(stack.CurrentBuffer[0].Int.Value, Is.EqualTo(copiedItem));
}

[Test]
public void TestTransitionToBufferOnPop()
{
for (int i = 0; i < size; i++)
stack.Push(i);
stack.Push(new TestUniformData { Int = i });

var firstBuffer = stack.CurrentBuffer;
int copiedItem = stack.CurrentBuffer[stack.CurrentOffset];
int copiedItem = stack.CurrentBuffer[stack.CurrentOffset].Int.Value;

// Transition to the new buffer.
stack.Push(size);
stack.Push(new TestUniformData { Int = size });

// The "hack" employed means that on the first pop, the index moves to the 0th index in the new buffer.
stack.Pop();
Assert.That(stack.CurrentBuffer, Is.Not.EqualTo(firstBuffer));
Assert.That(stack.CurrentOffset, Is.Zero);
Assert.That(stack.CurrentBuffer[stack.CurrentOffset], Is.EqualTo(copiedItem));
Assert.That(stack.CurrentBuffer[stack.CurrentOffset].Int.Value, Is.EqualTo(copiedItem));

// After a subsequent pop, we transition to the previous buffer and move to the index prior to the copied item.
// We've already seen the copied item in the new buffer with the above pop, so we should not see it again here.
stack.Pop();
Assert.That(stack.CurrentBuffer, Is.EqualTo(firstBuffer));
Assert.That(stack.CurrentOffset, Is.EqualTo(copiedItem - 1));
Assert.That(stack.CurrentBuffer[stack.CurrentOffset], Is.EqualTo(copiedItem - 1));
Assert.That(stack.CurrentBuffer[stack.CurrentOffset].Int.Value, Is.EqualTo(copiedItem - 1));

// Popping once again should move the index further backwards.
stack.Pop();
Expand All @@ -143,7 +145,7 @@ public void TestTransitionToBufferOnPop()
public void TestTransitionToAndFromNewBufferFromMiddle()
{
for (int i = 0; i < size; i++)
stack.Push(i);
stack.Push(new TestUniformData { Int = i });

// Move to the middle of the current buffer (it can not take up any new items at this point).
stack.Pop();
Expand All @@ -153,13 +155,13 @@ public void TestTransitionToAndFromNewBufferFromMiddle()
int copiedItem = stack.CurrentOffset;

// Transition to the new buffer...
stack.Push(size);
stack.Push(new TestUniformData { Int = size });

// ... and as above, we arrive at index 1 in the new buffer.
Assert.That(stack.CurrentBuffer, Is.Not.EqualTo(firstBuffer));
Assert.That(stack.CurrentOffset, Is.EqualTo(1));
Assert.That(stack.CurrentBuffer[1], Is.EqualTo(size));
Assert.That(stack.CurrentBuffer[0], Is.EqualTo(copiedItem));
Assert.That(stack.CurrentBuffer[1].Int.Value, Is.EqualTo(size));
Assert.That(stack.CurrentBuffer[0].Int.Value, Is.EqualTo(copiedItem));

// Transition to the previous buffer...
stack.Pop();
Expand All @@ -168,7 +170,7 @@ public void TestTransitionToAndFromNewBufferFromMiddle()
// ... noting that this is the same as the above "normal" pop case, except that item arrived at is in the middle of the previous buffer.
Assert.That(stack.CurrentBuffer, Is.EqualTo(firstBuffer));
Assert.That(stack.CurrentOffset, Is.EqualTo(copiedItem - 1));
Assert.That(stack.CurrentBuffer[stack.CurrentOffset], Is.EqualTo(copiedItem - 1));
Assert.That(stack.CurrentBuffer[stack.CurrentOffset].Int.Value, Is.EqualTo(copiedItem - 1));

// Popping once again from this state should move further backwards.
stack.Pop();
Expand All @@ -180,19 +182,19 @@ public void TestTransitionToAndFromNewBufferFromMiddle()
public void TestMoveToAndFromMiddleOfNewBuffer()
{
for (int i = 0; i < size; i++)
stack.Push(i);
stack.Push(new TestUniformData { Int = i });

var lastBuffer = stack.CurrentBuffer;
int copiedItem1 = stack.CurrentBuffer[stack.CurrentOffset];
int copiedItem1 = stack.CurrentBuffer[stack.CurrentOffset].Int.Value;

// Transition to the middle of the new buffer.
stack.Push(size);
stack.Push(size + 1);
stack.Push(new TestUniformData { Int = size });
stack.Push(new TestUniformData { Int = size + 1 });
Assert.That(stack.CurrentBuffer, Is.Not.EqualTo(lastBuffer));
Assert.That(stack.CurrentOffset, Is.EqualTo(2));
Assert.That(stack.CurrentBuffer[2], Is.EqualTo(size + 1));
Assert.That(stack.CurrentBuffer[1], Is.EqualTo(size));
Assert.That(stack.CurrentBuffer[0], Is.EqualTo(copiedItem1));
Assert.That(stack.CurrentBuffer[2].Int.Value, Is.EqualTo(size + 1));
Assert.That(stack.CurrentBuffer[1].Int.Value, Is.EqualTo(size));
Assert.That(stack.CurrentBuffer[0].Int.Value, Is.EqualTo(copiedItem1));

// Transition to the previous buffer.
stack.Pop();
Expand All @@ -201,23 +203,23 @@ public void TestMoveToAndFromMiddleOfNewBuffer()
Assert.That(stack.CurrentBuffer, Is.EqualTo(lastBuffer));

// The item that will be copied into the new buffer.
int copiedItem2 = stack.CurrentBuffer[stack.CurrentOffset];
int copiedItem2 = stack.CurrentBuffer[stack.CurrentOffset].Int.Value;

// Transition to the new buffer...
stack.Push(size + 2);
stack.Push(new TestUniformData { Int = size + 2 });
Assert.That(stack.CurrentBuffer, Is.Not.EqualTo(lastBuffer));

// ... noting that this is the same as the normal case of transitioning to a new buffer, except arriving in the middle of it...
Assert.That(stack.CurrentOffset, Is.EqualTo(4));
Assert.That(stack.CurrentBuffer[4], Is.EqualTo(size + 2));
Assert.That(stack.CurrentBuffer[4].Int.Value, Is.EqualTo(size + 2));

// ... where this is the copied item as a result of the immediate push...
Assert.That(stack.CurrentBuffer[3], Is.EqualTo(copiedItem2));
Assert.That(stack.CurrentBuffer[3].Int.Value, Is.EqualTo(copiedItem2));

// ... and these are the same items from the first pushes above.
Assert.That(stack.CurrentBuffer[2], Is.EqualTo(size + 1));
Assert.That(stack.CurrentBuffer[1], Is.EqualTo(size));
Assert.That(stack.CurrentBuffer[0], Is.EqualTo(copiedItem1));
Assert.That(stack.CurrentBuffer[2].Int.Value, Is.EqualTo(size + 1));
Assert.That(stack.CurrentBuffer[1].Int.Value, Is.EqualTo(size));
Assert.That(stack.CurrentBuffer[0].Int.Value, Is.EqualTo(copiedItem1));

// Transition to the previous buffer...
stack.Pop();
Expand All @@ -230,7 +232,7 @@ public void TestMoveToAndFromMiddleOfNewBuffer()
// 3. From index N-2 -> transition to new buffer.
// 4. Transition to old buffer, arrive at index N-3 (N-2 was copied into the new buffer).
Assert.That(stack.CurrentOffset, Is.EqualTo(size - 3));
Assert.That(stack.CurrentBuffer[stack.CurrentOffset], Is.EqualTo(size - 3));
Assert.That(stack.CurrentBuffer[stack.CurrentOffset].Int.Value, Is.EqualTo(size - 3));
}

[Test]
Expand All @@ -241,18 +243,25 @@ public void TestTransitionFromEmptyStack()
var lastBuffer = stack.CurrentBuffer;

// Push one item.
stack.Push(i);
stack.Push(new TestUniformData { Int = i });

// On a buffer transition, test that the item at the 0-th index of the first buffer was correct copied to the new buffer.
if (stack.CurrentBuffer != lastBuffer)
Assert.That(stack.CurrentBuffer[stack.CurrentOffset - 1], Is.EqualTo(0));
Assert.That(stack.CurrentBuffer[stack.CurrentOffset - 1].Int.Value, Is.EqualTo(0));

// Test that the item was correctly placed in the new buffer
Assert.That(stack.CurrentBuffer[stack.CurrentOffset], Is.EqualTo(i));
Assert.That(stack.CurrentBuffer[stack.CurrentOffset].Int.Value, Is.EqualTo(i));

// Return to an empty stack.
stack.Pop();
}
}

[StructLayout(LayoutKind.Sequential, Pack = 1)]
private record struct TestUniformData
{
public UniformInt Int;
private UniformPadding12 pad;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
// See the LICENCE file in the repository root for full licence text.

using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using osu.Framework.Development;
using osu.Framework.Graphics.Rendering;
using osuTK.Graphics.ES30;

Expand All @@ -20,6 +22,8 @@ internal class GLShaderStorageBufferObject<TData> : IShaderStorageBufferObject<T

public GLShaderStorageBufferObject(GLRenderer renderer, int uboSize, int ssboSize)
{
Trace.Assert(ThreadSafety.IsDrawThread);

Id = GL.GenBuffer();
Size = renderer.UseStructuredBuffers ? ssboSize : uboSize;
data = new TData[Size];
Expand Down
4 changes: 4 additions & 0 deletions osu.Framework/Graphics/OpenGL/Buffers/GLUniformBuffer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
// See the LICENCE file in the repository root for full licence text.

using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using osu.Framework.Development;
using osu.Framework.Graphics.Rendering;
using osu.Framework.Statistics;
using osuTK.Graphics.ES30;
Expand All @@ -20,6 +22,8 @@ internal class GLUniformBuffer<TData> : IUniformBuffer<TData>, IGLUniformBuffer

public GLUniformBuffer(GLRenderer renderer)
{
Trace.Assert(ThreadSafety.IsDrawThread);

this.renderer = renderer;

size = Marshal.SizeOf(default(TData));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
// See the LICENCE file in the repository root for full licence text.

using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using osu.Framework.Development;
using osu.Framework.Graphics.Rendering.Deferred.Allocation;
using osu.Framework.Graphics.Rendering.Deferred.Events;
using osu.Framework.Graphics.Veldrid.Buffers;
Expand All @@ -22,6 +24,8 @@ internal class DeferredShaderStorageBufferObject<TData> : IShaderStorageBufferOb

public DeferredShaderStorageBufferObject(DeferredRenderer renderer, int ssboSize)
{
Trace.Assert(ThreadSafety.IsDrawThread);

this.renderer = renderer;

elementSize = Unsafe.SizeOf<TData>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

using System;
using System.Collections.Generic;
using System.Diagnostics;
using osu.Framework.Development;
using osu.Framework.Graphics.Rendering.Deferred.Allocation;
using osu.Framework.Graphics.Rendering.Deferred.Events;
using osu.Framework.Graphics.Veldrid.Buffers;
Expand All @@ -24,6 +26,8 @@ internal class DeferredUniformBuffer<TData> : IUniformBuffer<TData>, IDeferredUn

public DeferredUniformBuffer(DeferredRenderer renderer)
{
Trace.Assert(ThreadSafety.IsDrawThread);

this.renderer = renderer;
}

Expand Down
2 changes: 0 additions & 2 deletions osu.Framework/Graphics/Rendering/Renderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1263,8 +1263,6 @@ IShaderStorageBufferObject<TData> IRenderer.CreateShaderStorageBufferObject<TDat

private void validateUniformLayout<TData>()
{
Trace.Assert(ThreadSafety.IsDrawThread);

if (validUboTypes.Contains(typeof(TData)))
return;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
// See the LICENCE file in the repository root for full licence text.

using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using osu.Framework.Development;
using osu.Framework.Graphics.Rendering;
using Veldrid;

Expand All @@ -20,6 +22,8 @@ internal class VeldridShaderStorageBufferObject<TData> : IShaderStorageBufferObj

public VeldridShaderStorageBufferObject(VeldridRenderer renderer, int uboSize, int ssboSize)
{
Trace.Assert(ThreadSafety.IsDrawThread);

this.renderer = renderer;

elementSize = (uint)Marshal.SizeOf(default(TData));
Expand Down
Loading

0 comments on commit 0750044

Please sign in to comment.