mirror of
https://github.com/SK-la/osu-framework.git
synced 2026-03-13 11:20:31 +00:00
Merge pull request #6350 from smoogipoo/fix-whitepixel-texture-wrap
Fix texture wrapping not updating on consecutive WhitePixel use
This commit is contained in:
30
osu.Framework.Tests/Graphics/RendererTest.cs
Normal file
30
osu.Framework.Tests/Graphics/RendererTest.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Graphics.Rendering.Dummy;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
|
||||
namespace osu.Framework.Tests.Graphics
|
||||
{
|
||||
public class RendererTest
|
||||
{
|
||||
[Test]
|
||||
public void TestWhitePixelReuseUpdatesTextureWrapping()
|
||||
{
|
||||
DummyRenderer renderer = new DummyRenderer();
|
||||
|
||||
renderer.BindTexture(renderer.WhitePixel, 0, WrapMode.None, WrapMode.None);
|
||||
Assert.That(renderer.CurrentWrapModeS, Is.EqualTo(WrapMode.None));
|
||||
Assert.That(renderer.CurrentWrapModeS, Is.EqualTo(WrapMode.None));
|
||||
|
||||
renderer.BindTexture(renderer.WhitePixel, 0, WrapMode.ClampToEdge, WrapMode.ClampToEdge);
|
||||
Assert.That(renderer.CurrentWrapModeS, Is.EqualTo(WrapMode.ClampToEdge));
|
||||
Assert.That(renderer.CurrentWrapModeS, Is.EqualTo(WrapMode.ClampToEdge));
|
||||
|
||||
renderer.BindTexture(renderer.WhitePixel, 0, WrapMode.None, WrapMode.None);
|
||||
Assert.That(renderer.CurrentWrapModeS, Is.EqualTo(WrapMode.None));
|
||||
Assert.That(renderer.CurrentWrapModeS, Is.EqualTo(WrapMode.None));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,9 +2,11 @@
|
||||
// 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
|
||||
{
|
||||
@@ -12,21 +14,21 @@ namespace osu.Framework.Tests.Graphics
|
||||
{
|
||||
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]
|
||||
@@ -34,7 +36,7 @@ namespace osu.Framework.Tests.Graphics
|
||||
{
|
||||
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]
|
||||
@@ -48,11 +50,11 @@ namespace osu.Framework.Tests.Graphics
|
||||
{
|
||||
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]
|
||||
@@ -63,10 +65,10 @@ namespace osu.Framework.Tests.Graphics
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,7 +76,7 @@ namespace osu.Framework.Tests.Graphics
|
||||
public void TestPopEntireBuffer()
|
||||
{
|
||||
for (int i = 0; i < size; i++)
|
||||
stack.Push(i);
|
||||
stack.Push(new TestUniformData { Int = i });
|
||||
|
||||
var firstBuffer = stack.CurrentBuffer;
|
||||
|
||||
@@ -82,7 +84,7 @@ namespace osu.Framework.Tests.Graphics
|
||||
{
|
||||
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();
|
||||
}
|
||||
}
|
||||
@@ -91,47 +93,47 @@ namespace osu.Framework.Tests.Graphics
|
||||
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();
|
||||
@@ -143,7 +145,7 @@ namespace osu.Framework.Tests.Graphics
|
||||
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();
|
||||
@@ -153,13 +155,13 @@ namespace osu.Framework.Tests.Graphics
|
||||
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();
|
||||
@@ -168,7 +170,7 @@ namespace osu.Framework.Tests.Graphics
|
||||
// ... 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();
|
||||
@@ -180,19 +182,19 @@ namespace osu.Framework.Tests.Graphics
|
||||
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();
|
||||
@@ -201,23 +203,23 @@ namespace osu.Framework.Tests.Graphics
|
||||
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();
|
||||
@@ -230,7 +232,7 @@ namespace osu.Framework.Tests.Graphics
|
||||
// 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]
|
||||
@@ -241,18 +243,25 @@ namespace osu.Framework.Tests.Graphics
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,13 +3,11 @@
|
||||
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Rendering;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Framework.Utils;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
@@ -18,8 +16,10 @@ namespace osu.Framework.Tests.Visual.Graphics
|
||||
{
|
||||
public partial class TestSceneVertexBatching : FrameworkTestScene
|
||||
{
|
||||
[Resolved]
|
||||
private GameHost host { get; set; } = null!;
|
||||
/// <summary>
|
||||
/// Max number of quads per batch in the default quad batch (Renderer.defaultQuadBatch).
|
||||
/// </summary>
|
||||
private const int max_boxes_per_batch = 100;
|
||||
|
||||
[Test]
|
||||
public void TestBatchUntilOverflow()
|
||||
@@ -28,8 +28,6 @@ namespace osu.Framework.Tests.Visual.Graphics
|
||||
{
|
||||
Clear();
|
||||
|
||||
int boxesPerBatch = host.Renderer.DefaultQuadBatch.Size;
|
||||
|
||||
Add(new FillFlowContainer
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
@@ -37,7 +35,7 @@ namespace osu.Framework.Tests.Visual.Graphics
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Margin = new MarginPadding(25f),
|
||||
Spacing = new Vector2(10f),
|
||||
ChildrenEnumerable = Enumerable.Range(0, boxesPerBatch * 2).Select(i => new Box
|
||||
ChildrenEnumerable = Enumerable.Range(0, max_boxes_per_batch * 2).Select(i => new Box
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
@@ -55,8 +53,6 @@ namespace osu.Framework.Tests.Visual.Graphics
|
||||
{
|
||||
Clear();
|
||||
|
||||
int boxesPerBatch = host.Renderer.DefaultQuadBatch.Size;
|
||||
|
||||
Add(new FillFlowContainer
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
@@ -64,7 +60,7 @@ namespace osu.Framework.Tests.Visual.Graphics
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Margin = new MarginPadding(25f),
|
||||
Spacing = new Vector2(10f),
|
||||
ChildrenEnumerable = Enumerable.Range(0, boxesPerBatch * 2).Select(i => new BoxWithFlush
|
||||
ChildrenEnumerable = Enumerable.Range(0, max_boxes_per_batch * 2).Select(i => new BoxWithFlush
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -20,6 +22,8 @@ namespace osu.Framework.Graphics.OpenGL.Buffers
|
||||
|
||||
public GLShaderStorageBufferObject(GLRenderer renderer, int uboSize, int ssboSize)
|
||||
{
|
||||
Trace.Assert(ThreadSafety.IsDrawThread);
|
||||
|
||||
Id = GL.GenBuffer();
|
||||
Size = renderer.UseStructuredBuffers ? ssboSize : uboSize;
|
||||
data = new TData[Size];
|
||||
|
||||
@@ -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;
|
||||
@@ -20,6 +22,8 @@ namespace osu.Framework.Graphics.OpenGL.Buffers
|
||||
|
||||
public GLUniformBuffer(GLRenderer renderer)
|
||||
{
|
||||
Trace.Assert(ThreadSafety.IsDrawThread);
|
||||
|
||||
this.renderer = renderer;
|
||||
|
||||
size = Marshal.SizeOf(default(TData));
|
||||
|
||||
@@ -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;
|
||||
@@ -22,6 +24,8 @@ namespace osu.Framework.Graphics.Rendering.Deferred
|
||||
|
||||
public DeferredShaderStorageBufferObject(DeferredRenderer renderer, int ssboSize)
|
||||
{
|
||||
Trace.Assert(ThreadSafety.IsDrawThread);
|
||||
|
||||
this.renderer = renderer;
|
||||
|
||||
elementSize = Unsafe.SizeOf<TData>();
|
||||
|
||||
@@ -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;
|
||||
@@ -24,6 +26,8 @@ namespace osu.Framework.Graphics.Rendering.Deferred
|
||||
|
||||
public DeferredUniformBuffer(DeferredRenderer renderer)
|
||||
{
|
||||
Trace.Assert(ThreadSafety.IsDrawThread);
|
||||
|
||||
this.renderer = renderer;
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace osu.Framework.Graphics.Rendering.Dummy
|
||||
|
||||
public DummyFrameBuffer(IRenderer renderer)
|
||||
{
|
||||
Texture = new Texture(new DummyNativeTexture(renderer), WrapMode.None, WrapMode.None);
|
||||
Texture = new Texture(new DummyNativeTexture(renderer, 1, 1), WrapMode.None, WrapMode.None);
|
||||
}
|
||||
|
||||
public void Bind()
|
||||
|
||||
@@ -14,8 +14,8 @@ namespace osu.Framework.Graphics.Rendering.Dummy
|
||||
|
||||
public string Identifier => string.Empty;
|
||||
public int MaxSize => 4096; // Sane default for testing purposes.
|
||||
public int Width { get; set; } = 1;
|
||||
public int Height { get; set; } = 1;
|
||||
public int Width { get; set; }
|
||||
public int Height { get; set; }
|
||||
public int? MipLevel { get; set; }
|
||||
public bool Available => true;
|
||||
public bool BypassTextureUploadQueueing { get; set; }
|
||||
@@ -23,9 +23,11 @@ namespace osu.Framework.Graphics.Rendering.Dummy
|
||||
public bool IsQueuedForUpload { get; set; }
|
||||
ulong INativeTexture.TotalBindCount { get; set; }
|
||||
|
||||
public DummyNativeTexture(IRenderer renderer)
|
||||
public DummyNativeTexture(IRenderer renderer, int width, int height)
|
||||
{
|
||||
Renderer = renderer;
|
||||
Width = width;
|
||||
Height = height;
|
||||
}
|
||||
|
||||
public void FlushUploads()
|
||||
|
||||
@@ -1,245 +1,142 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using osu.Framework.Graphics.Primitives;
|
||||
using osu.Framework.Graphics.Rendering.Vertices;
|
||||
using osu.Framework.Graphics.Shaders;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Framework.Threading;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
using SixLabors.ImageSharp;
|
||||
using SixLabors.ImageSharp.PixelFormats;
|
||||
using RectangleF = osu.Framework.Graphics.Primitives.RectangleF;
|
||||
|
||||
namespace osu.Framework.Graphics.Rendering.Dummy
|
||||
{
|
||||
/// <summary>
|
||||
/// An <see cref="IRenderer"/> that does nothing. May be used for tests that don't have a visual output.
|
||||
/// </summary>
|
||||
public sealed class DummyRenderer : IRenderer
|
||||
public sealed class DummyRenderer : Renderer
|
||||
{
|
||||
public int MaxTextureSize => int.MaxValue;
|
||||
public int MaxTexturesUploadedPerFrame { get; set; } = int.MaxValue;
|
||||
public int MaxPixelsUploadedPerFrame { get; set; } = int.MaxValue;
|
||||
protected internal override bool VerticalSync { get; set; } = true;
|
||||
protected internal override bool AllowTearing { get; set; }
|
||||
public override bool IsDepthRangeZeroToOne => true;
|
||||
public override bool IsUvOriginTopLeft => true;
|
||||
public override bool IsClipSpaceYInverted => true;
|
||||
|
||||
public bool IsDepthRangeZeroToOne => true;
|
||||
public bool IsUvOriginTopLeft => true;
|
||||
public bool IsClipSpaceYInverted => true;
|
||||
public ref readonly MaskingInfo CurrentMaskingInfo => ref maskingInfo;
|
||||
private readonly MaskingInfo maskingInfo;
|
||||
protected internal override Image<Rgba32> TakeScreenshot()
|
||||
=> new Image<Rgba32>(1, 1);
|
||||
|
||||
public RectangleI Viewport => RectangleI.Empty;
|
||||
public RectangleF Ortho => RectangleF.Empty;
|
||||
public RectangleI Scissor => RectangleI.Empty;
|
||||
public Vector2I ScissorOffset => Vector2I.Zero;
|
||||
public Matrix4 ProjectionMatrix => Matrix4.Identity;
|
||||
public DepthInfo CurrentDepthInfo => DepthInfo.Default;
|
||||
public StencilInfo CurrentStencilInfo => StencilInfo.Default;
|
||||
public WrapMode CurrentWrapModeS => WrapMode.None;
|
||||
public WrapMode CurrentWrapModeT => WrapMode.None;
|
||||
public bool IsMaskingActive => false;
|
||||
public bool UsingBackbuffer => false;
|
||||
public Texture WhitePixel { get; }
|
||||
DepthValue IRenderer.BackbufferDepth { get; } = new DepthValue();
|
||||
|
||||
public bool IsInitialised { get; private set; }
|
||||
|
||||
public DummyRenderer()
|
||||
{
|
||||
maskingInfo = default;
|
||||
WhitePixel = new TextureWhitePixel(new Texture(new DummyNativeTexture(this), WrapMode.None, WrapMode.None));
|
||||
}
|
||||
|
||||
public ulong FrameIndex { get; private set; }
|
||||
|
||||
bool IRenderer.VerticalSync { get; set; } = true;
|
||||
|
||||
bool IRenderer.AllowTearing { get; set; }
|
||||
|
||||
Storage? IRenderer.CacheStorage { set { } }
|
||||
|
||||
void IRenderer.Initialise(IGraphicsSurface graphicsSurface)
|
||||
{
|
||||
IsInitialised = true;
|
||||
}
|
||||
|
||||
void IRenderer.BeginFrame(Vector2 windowSize)
|
||||
{
|
||||
FrameIndex++;
|
||||
}
|
||||
|
||||
void IRenderer.FinishFrame()
|
||||
{
|
||||
}
|
||||
|
||||
void IRenderer.FlushCurrentBatch(FlushBatchSource? source)
|
||||
{
|
||||
}
|
||||
|
||||
void IRenderer.SwapBuffers()
|
||||
{
|
||||
}
|
||||
|
||||
void IRenderer.WaitUntilIdle()
|
||||
{
|
||||
}
|
||||
|
||||
void IRenderer.WaitUntilNextFrameReady()
|
||||
{
|
||||
}
|
||||
|
||||
void IRenderer.MakeCurrent()
|
||||
{
|
||||
}
|
||||
|
||||
void IRenderer.ClearCurrent()
|
||||
{
|
||||
}
|
||||
|
||||
public bool BindTexture(Texture texture, int unit = 0, WrapMode? wrapModeS = null, WrapMode? wrapModeT = null)
|
||||
=> true;
|
||||
|
||||
public void UseProgram(IShader? shader)
|
||||
{
|
||||
}
|
||||
|
||||
public void Clear(ClearInfo clearInfo)
|
||||
{
|
||||
}
|
||||
|
||||
public void PushScissorState(bool enabled)
|
||||
{
|
||||
}
|
||||
|
||||
public void PopScissorState()
|
||||
{
|
||||
}
|
||||
|
||||
public void SetBlend(BlendingParameters blendingParameters)
|
||||
{
|
||||
}
|
||||
|
||||
public void SetBlendMask(BlendingMask blendingMask)
|
||||
{
|
||||
}
|
||||
|
||||
public void PushViewport(RectangleI viewport)
|
||||
{
|
||||
}
|
||||
|
||||
public void PopViewport()
|
||||
{
|
||||
}
|
||||
|
||||
public void PushScissor(RectangleI scissor)
|
||||
{
|
||||
}
|
||||
|
||||
public void PopScissor()
|
||||
{
|
||||
}
|
||||
|
||||
public void PushScissorOffset(Vector2I offset)
|
||||
{
|
||||
}
|
||||
|
||||
public void PopScissorOffset()
|
||||
{
|
||||
}
|
||||
|
||||
public void PushProjectionMatrix(Matrix4 matrix)
|
||||
{
|
||||
}
|
||||
|
||||
public void PopProjectionMatrix()
|
||||
{
|
||||
}
|
||||
|
||||
public void PushMaskingInfo(in MaskingInfo maskingInfo, bool overwritePreviousScissor = false)
|
||||
{
|
||||
}
|
||||
|
||||
public void PopMaskingInfo()
|
||||
{
|
||||
}
|
||||
|
||||
public void PushDepthInfo(DepthInfo depthInfo)
|
||||
{
|
||||
}
|
||||
|
||||
public void PopDepthInfo()
|
||||
{
|
||||
}
|
||||
|
||||
public void PushStencilInfo(StencilInfo stencilInfo)
|
||||
{
|
||||
}
|
||||
|
||||
public void PopStencilInfo()
|
||||
{
|
||||
}
|
||||
|
||||
public void ScheduleExpensiveOperation(ScheduledDelegate operation) => operation.RunTask();
|
||||
|
||||
public void ScheduleDisposal<T>(Action<T> disposalAction, T target) => disposalAction(target);
|
||||
|
||||
Image<Rgba32> IRenderer.TakeScreenshot() => new Image<Rgba32>(1366, 768);
|
||||
|
||||
IShaderPart IRenderer.CreateShaderPart(IShaderStore manager, string name, byte[]? rawData, ShaderPartType partType)
|
||||
protected override IShaderPart CreateShaderPart(IShaderStore store, string name, byte[]? rawData, ShaderPartType partType)
|
||||
=> new DummyShaderPart();
|
||||
|
||||
IShader IRenderer.CreateShader(string name, IShaderPart[] parts)
|
||||
protected override IShader CreateShader(string name, IShaderPart[] parts, ShaderCompilationStore compilationStore)
|
||||
=> new DummyShader(this);
|
||||
|
||||
public IFrameBuffer CreateFrameBuffer(RenderBufferFormat[]? renderBufferFormats = null, TextureFilteringMode filteringMode = TextureFilteringMode.Linear)
|
||||
=> new DummyFrameBuffer(this);
|
||||
|
||||
public Texture CreateTexture(int width, int height, bool manualMipmaps = false, TextureFilteringMode filteringMode = TextureFilteringMode.Linear, WrapMode wrapModeS = WrapMode.None,
|
||||
WrapMode wrapModeT = WrapMode.None, Color4? initialisationColour = null)
|
||||
=> new Texture(new DummyNativeTexture(this) { Width = width, Height = height }, wrapModeS, wrapModeT);
|
||||
|
||||
public Texture CreateVideoTexture(int width, int height)
|
||||
=> CreateTexture(width, height);
|
||||
|
||||
public IVertexBatch<TVertex> CreateLinearBatch<TVertex>(int size, int maxBuffers, PrimitiveTopology topology) where TVertex : unmanaged, IEquatable<TVertex>, IVertex
|
||||
protected override IVertexBatch<TVertex> CreateLinearBatch<TVertex>(int size, int maxBuffers, PrimitiveTopology topology)
|
||||
=> new DummyVertexBatch<TVertex>();
|
||||
|
||||
public IVertexBatch<TVertex> CreateQuadBatch<TVertex>(int size, int maxBuffers) where TVertex : unmanaged, IEquatable<TVertex>, IVertex
|
||||
protected override IVertexBatch<TVertex> CreateQuadBatch<TVertex>(int size, int maxBuffers)
|
||||
=> new DummyVertexBatch<TVertex>();
|
||||
|
||||
public IUniformBuffer<TData> CreateUniformBuffer<TData>() where TData : unmanaged, IEquatable<TData>
|
||||
protected override IUniformBuffer<TData> CreateUniformBuffer<TData>()
|
||||
=> new DummyUniformBuffer<TData>();
|
||||
|
||||
public IShaderStorageBufferObject<TData> CreateShaderStorageBufferObject<TData>(int uboSize, int ssboSize) where TData : unmanaged, IEquatable<TData>
|
||||
protected override IShaderStorageBufferObject<TData> CreateShaderStorageBufferObject<TData>(int uboSize, int ssboSize)
|
||||
=> new DummyShaderStorageBufferObject<TData>(ssboSize);
|
||||
|
||||
void IRenderer.SetUniform<T>(IUniformWithValue<T> uniform)
|
||||
public Texture CreateTexture(int width, int height, bool manualMipmaps = false, TextureFilteringMode filteringMode = TextureFilteringMode.Linear, WrapMode wrapModeS = WrapMode.None)
|
||||
=> base.CreateTexture(width, height, manualMipmaps, filteringMode, wrapModeS, wrapModeS, null);
|
||||
|
||||
protected override INativeTexture CreateNativeTexture(int width, int height, bool manualMipmaps = false, TextureFilteringMode filteringMode = TextureFilteringMode.Linear,
|
||||
Color4? initialisationColour = null)
|
||||
=> new DummyNativeTexture(this, width, height);
|
||||
|
||||
protected override INativeTexture CreateNativeVideoTexture(int width, int height)
|
||||
=> new DummyNativeTexture(this, width, height);
|
||||
|
||||
protected override void Initialise(IGraphicsSurface graphicsSurface)
|
||||
{
|
||||
}
|
||||
|
||||
IVertexBatch<TexturedVertex2D> IRenderer.DefaultQuadBatch => new DummyVertexBatch<TexturedVertex2D>();
|
||||
|
||||
void IRenderer.PushQuadBatch(IVertexBatch<TexturedVertex2D> quadBatch)
|
||||
protected internal override void SwapBuffers()
|
||||
{
|
||||
}
|
||||
|
||||
void IRenderer.PopQuadBatch()
|
||||
protected internal override void WaitUntilIdle()
|
||||
{
|
||||
}
|
||||
|
||||
event Action<Texture>? IRenderer.TextureCreated
|
||||
protected internal override void WaitUntilNextFrameReady()
|
||||
{
|
||||
add
|
||||
{
|
||||
}
|
||||
remove
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
Texture[] IRenderer.GetAllTextures() => Array.Empty<Texture>();
|
||||
protected internal override void MakeCurrent()
|
||||
{
|
||||
}
|
||||
|
||||
protected internal override void ClearCurrent()
|
||||
{
|
||||
}
|
||||
|
||||
protected override void ClearImplementation(ClearInfo clearInfo)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void SetBlendImplementation(BlendingParameters blendingParameters)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void SetBlendMaskImplementation(BlendingMask blendingMask)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void SetViewportImplementation(RectangleI viewport)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void SetScissorImplementation(RectangleI scissor)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void SetScissorStateImplementation(bool enabled)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void SetDepthInfoImplementation(DepthInfo depthInfo)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void SetStencilInfoImplementation(StencilInfo stencilInfo)
|
||||
{
|
||||
}
|
||||
|
||||
protected override bool SetTextureImplementation(INativeTexture? texture, int unit)
|
||||
=> true;
|
||||
|
||||
protected override void SetFrameBufferImplementation(IFrameBuffer? frameBuffer)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void DeleteFrameBufferImplementation(IFrameBuffer frameBuffer)
|
||||
{
|
||||
}
|
||||
|
||||
public override void DrawVerticesImplementation(PrimitiveTopology topology, int vertexStart, int verticesCount)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void SetShaderImplementation(IShader shader)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void SetUniformImplementation<T>(IUniformWithValue<T> uniform)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void SetUniformBufferImplementation(string blockName, IUniformBuffer buffer)
|
||||
{
|
||||
}
|
||||
|
||||
public override IFrameBuffer CreateFrameBuffer(RenderBufferFormat[]? renderBufferFormats = null, TextureFilteringMode filteringMode = TextureFilteringMode.Linear)
|
||||
=> new DummyFrameBuffer(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -793,6 +793,8 @@ namespace osu.Framework.Graphics.Rendering
|
||||
|
||||
if (texture is TextureWhitePixel && lastBoundTextureIsAtlas[unit])
|
||||
{
|
||||
setWrapMode(wrapModeS ?? texture.WrapModeS, wrapModeT ?? texture.WrapModeT);
|
||||
|
||||
// We can use the special white space from any atlas texture.
|
||||
return true;
|
||||
}
|
||||
@@ -823,17 +825,7 @@ namespace osu.Framework.Graphics.Rendering
|
||||
if (!SetTextureImplementation(texture, unit))
|
||||
return false;
|
||||
|
||||
if (wrapModeS != CurrentWrapModeS)
|
||||
{
|
||||
CurrentWrapModeS = wrapModeS;
|
||||
globalUniformsChanged = true;
|
||||
}
|
||||
|
||||
if (wrapModeT != CurrentWrapModeT)
|
||||
{
|
||||
CurrentWrapModeT = wrapModeT;
|
||||
globalUniformsChanged = true;
|
||||
}
|
||||
setWrapMode(wrapModeS, wrapModeT);
|
||||
|
||||
lastBoundTexture[unit] = texture;
|
||||
lastBoundTextureIsAtlas[unit] = false;
|
||||
@@ -845,6 +837,25 @@ namespace osu.Framework.Graphics.Rendering
|
||||
return true;
|
||||
}
|
||||
|
||||
private void setWrapMode(WrapMode wrapModeS, WrapMode wrapModeT)
|
||||
{
|
||||
if (wrapModeS != CurrentWrapModeS)
|
||||
{
|
||||
FlushCurrentBatch(FlushBatchSource.BindTexture);
|
||||
|
||||
CurrentWrapModeS = wrapModeS;
|
||||
globalUniformsChanged = true;
|
||||
}
|
||||
|
||||
if (wrapModeT != CurrentWrapModeT)
|
||||
{
|
||||
FlushCurrentBatch(FlushBatchSource.BindTexture);
|
||||
|
||||
CurrentWrapModeT = wrapModeT;
|
||||
globalUniformsChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unbinds any bound texture.
|
||||
/// </summary>
|
||||
@@ -1252,8 +1263,6 @@ namespace osu.Framework.Graphics.Rendering
|
||||
|
||||
private void validateUniformLayout<TData>()
|
||||
{
|
||||
Trace.Assert(ThreadSafety.IsDrawThread);
|
||||
|
||||
if (validUboTypes.Contains(typeof(TData)))
|
||||
return;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -20,6 +22,8 @@ namespace osu.Framework.Graphics.Veldrid.Buffers
|
||||
|
||||
public VeldridShaderStorageBufferObject(VeldridRenderer renderer, int uboSize, int ssboSize)
|
||||
{
|
||||
Trace.Assert(ThreadSafety.IsDrawThread);
|
||||
|
||||
this.renderer = renderer;
|
||||
|
||||
elementSize = (uint)Marshal.SizeOf(default(TData));
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using osu.Framework.Development;
|
||||
using osu.Framework.Graphics.Rendering;
|
||||
using osu.Framework.Statistics;
|
||||
using Veldrid;
|
||||
@@ -37,6 +39,8 @@ namespace osu.Framework.Graphics.Veldrid.Buffers
|
||||
|
||||
public VeldridUniformBuffer(VeldridRenderer renderer)
|
||||
{
|
||||
Trace.Assert(ThreadSafety.IsDrawThread);
|
||||
|
||||
this.renderer = renderer;
|
||||
storages.Add(new VeldridUniformBufferStorage<TData>(this.renderer));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user