Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cleanup common Renderer methods #6186

Merged
merged 8 commits into from Feb 26, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
9 changes: 5 additions & 4 deletions osu.Framework/Graphics/OpenGL/Batches/GLLinearBatch.cs
Expand Up @@ -3,6 +3,7 @@

using System;
using osu.Framework.Graphics.OpenGL.Buffers;
using osu.Framework.Graphics.Rendering;
using osu.Framework.Graphics.Rendering.Vertices;
using osuTK.Graphics.ES30;

Expand All @@ -11,14 +12,14 @@ namespace osu.Framework.Graphics.OpenGL.Batches
internal class GLLinearBatch<T> : GLVertexBatch<T>
where T : unmanaged, IEquatable<T>, IVertex
{
private readonly PrimitiveType type;
private readonly PrimitiveTopology topology;

public GLLinearBatch(GLRenderer renderer, int size, int maxBuffers, PrimitiveType type)
public GLLinearBatch(GLRenderer renderer, int size, int maxBuffers, PrimitiveTopology topology)
: base(renderer, size, maxBuffers)
{
this.type = type;
this.topology = topology;
}

protected override GLVertexBuffer<T> CreateVertexBuffer(GLRenderer renderer) => new GLLinearBuffer<T>(renderer, Size, type, BufferUsageHint.DynamicDraw);
protected override GLVertexBuffer<T> CreateVertexBuffer(GLRenderer renderer) => new GLLinearBuffer<T>(renderer, Size, topology, BufferUsageHint.DynamicDraw);
}
}
6 changes: 3 additions & 3 deletions osu.Framework/Graphics/OpenGL/Buffers/GLLinearBuffer.cs
Expand Up @@ -28,11 +28,11 @@ internal class GLLinearBuffer<T> : GLVertexBuffer<T>
{
private readonly int amountVertices;

public GLLinearBuffer(GLRenderer renderer, int amountVertices, PrimitiveType type, BufferUsageHint usage)
public GLLinearBuffer(GLRenderer renderer, int amountVertices, PrimitiveTopology topology, BufferUsageHint usage)
: base(renderer, amountVertices, usage)
{
this.amountVertices = amountVertices;
Type = type;
Topology = topology;

Debug.Assert(amountVertices <= IRenderer.MAX_VERTICES);
}
Expand All @@ -57,6 +57,6 @@ protected override void Initialise()
}
}

protected override PrimitiveType Type { get; }
protected override PrimitiveTopology Topology { get; }
}
}
2 changes: 1 addition & 1 deletion osu.Framework/Graphics/OpenGL/Buffers/GLQuadBuffer.cs
Expand Up @@ -63,6 +63,6 @@ protected override void Initialise()

protected override int ToElementIndex(int vertexIndex) => 3 * vertexIndex / 2;

protected override PrimitiveType Type => PrimitiveType.Triangles;
protected override PrimitiveTopology Topology => PrimitiveTopology.Triangles;
}
}
4 changes: 2 additions & 2 deletions osu.Framework/Graphics/OpenGL/Buffers/GLVertexBuffer.cs
Expand Up @@ -118,7 +118,7 @@ public virtual void Unbind()

protected virtual int ToElementIndex(int vertexIndex) => vertexIndex;

protected abstract PrimitiveType Type { get; }
protected abstract PrimitiveTopology Topology { get; }

public void Draw()
{
Expand All @@ -128,7 +128,7 @@ public void Draw()
public void DrawRange(int startIndex, int endIndex)
{
Bind(true);
Renderer.DrawVertices(Type, ToElementIndex(startIndex), ToElements(endIndex - startIndex));
Renderer.DrawVertices(Topology, ToElementIndex(startIndex), ToElements(endIndex - startIndex));
}

public void Update()
Expand Down
9 changes: 3 additions & 6 deletions osu.Framework/Graphics/OpenGL/GLRenderer.cs
Expand Up @@ -278,12 +278,9 @@ public void BindUniformBuffer(string blockName, IGLUniformBuffer glBuffer)
boundUniformBuffers[blockName] = glBuffer;
}

public void DrawVertices(PrimitiveType type, int vertexStart, int verticesCount)
public override void DrawVerticesImplementation(PrimitiveTopology topology, int vertexStart, int verticesCount)
{
var glShader = (GLShader)Shader!;

glShader.BindUniformBlock("g_GlobalUniforms", GlobalUniformBuffer!);

int currentUniformBinding = 0;
int currentStorageBinding = 0;

Expand All @@ -308,7 +305,7 @@ public void DrawVertices(PrimitiveType type, int vertexStart, int verticesCount)
}
}

GL.DrawElements(type, verticesCount, DrawElementsType.UnsignedShort, vertexStart * sizeof(ushort));
GL.DrawElements(GLUtils.ToPrimitiveType(topology), verticesCount, DrawElementsType.UnsignedShort, vertexStart * sizeof(ushort));
}

protected override void SetScissorStateImplementation(bool enabled)
Expand Down Expand Up @@ -500,7 +497,7 @@ protected override IShaderStorageBufferObject<TData> CreateShaderStorageBufferOb
protected override INativeTexture CreateNativeVideoTexture(int width, int height) => new GLVideoTexture(this, width, height);

protected override IVertexBatch<TVertex> CreateLinearBatch<TVertex>(int size, int maxBuffers, PrimitiveTopology topology)
=> new GLLinearBatch<TVertex>(this, size, maxBuffers, GLUtils.ToPrimitiveType(topology));
=> new GLLinearBatch<TVertex>(this, size, maxBuffers, topology);

protected override IVertexBatch<TVertex> CreateQuadBatch<TVertex>(int size, int maxBuffers) => new GLQuadBatch<TVertex>(this, size, maxBuffers);
}
Expand Down
32 changes: 22 additions & 10 deletions osu.Framework/Graphics/Rendering/Renderer.cs
Expand Up @@ -131,7 +131,7 @@ public abstract class Renderer : IRenderer
private readonly Lazy<TextureWhitePixel> whitePixel;
private readonly LockedWeakList<Texture> allTextures = new LockedWeakList<Texture>();

protected IUniformBuffer<GlobalUniformData>? GlobalUniformBuffer { get; private set; }
private IUniformBuffer<GlobalUniformData>? globalUniformBuffer;
private IVertexBatch<TexturedVertex2D>? defaultQuadBatch;
private IVertexBatch? currentActiveBatch;
private MaskingInfo currentMaskingInfo;
Expand Down Expand Up @@ -190,8 +190,8 @@ protected internal virtual void BeginFrame(Vector2 windowSize)
foreach (var source in flush_source_statistics)
source.Value = 0;

GlobalUniformBuffer ??= ((IRenderer)this).CreateUniformBuffer<GlobalUniformData>();
GlobalUniformBuffer.Data = GlobalUniformBuffer.Data with
globalUniformBuffer ??= ((IRenderer)this).CreateUniformBuffer<GlobalUniformData>();
globalUniformBuffer.Data = globalUniformBuffer.Data with
{
IsDepthRangeZeroToOne = IsDepthRangeZeroToOne,
IsClipSpaceYInverted = IsClipSpaceYInverted,
Expand Down Expand Up @@ -602,7 +602,7 @@ private void setProjectionMatrix(Matrix4 matrix)

FlushCurrentBatch(FlushBatchSource.SetProjection);

GlobalUniformBuffer!.Data = GlobalUniformBuffer.Data with { ProjMatrix = matrix };
globalUniformBuffer!.Data = globalUniformBuffer.Data with { ProjMatrix = matrix };
ProjectionMatrix = matrix;
}

Expand Down Expand Up @@ -631,7 +631,7 @@ private void setMaskingInfo(MaskingInfo maskingInfo, bool isPushing, bool overwr

FlushCurrentBatch(FlushBatchSource.SetMasking);

GlobalUniformBuffer!.Data = GlobalUniformBuffer.Data with
globalUniformBuffer!.Data = globalUniformBuffer.Data with
{
IsMasking = IsMaskingActive,
MaskingRect = new Vector4(
Expand Down Expand Up @@ -665,14 +665,14 @@ private void setMaskingInfo(MaskingInfo maskingInfo, bool isPushing, bool overwr
maskingInfo.BorderColour.BottomRight.SRGB.G,
maskingInfo.BorderColour.BottomRight.SRGB.B,
maskingInfo.BorderColour.BottomRight.SRGB.A)
: GlobalUniformBuffer.Data.BorderColour,
: globalUniformBuffer.Data.BorderColour,
MaskingBlendRange = maskingInfo.BlendRange,
AlphaExponent = maskingInfo.AlphaExponent,
EdgeOffset = maskingInfo.EdgeOffset,
DiscardInner = maskingInfo.Hollow,
InnerCornerRadius = maskingInfo.Hollow
? maskingInfo.HollowCornerRadius
: GlobalUniformBuffer.Data.InnerCornerRadius
: globalUniformBuffer.Data.InnerCornerRadius
};

if (isPushing)
Expand Down Expand Up @@ -868,14 +868,14 @@ public bool BindTexture(INativeTexture texture, int unit = 0, WrapMode wrapModeS
if (wrapModeS != CurrentWrapModeS)
{
// Will flush the current batch internally.
GlobalUniformBuffer!.Data = GlobalUniformBuffer.Data with { WrapModeS = (int)wrapModeS };
globalUniformBuffer!.Data = globalUniformBuffer.Data with { WrapModeS = (int)wrapModeS };
CurrentWrapModeS = wrapModeS;
}

if (wrapModeT != CurrentWrapModeT)
{
// Will flush the current batch internally.
GlobalUniformBuffer!.Data = GlobalUniformBuffer.Data with { WrapModeT = (int)wrapModeT };
globalUniformBuffer!.Data = globalUniformBuffer.Data with { WrapModeT = (int)wrapModeT };
CurrentWrapModeT = wrapModeT;
}

Expand Down Expand Up @@ -953,7 +953,7 @@ private void setFrameBuffer(IFrameBuffer? frameBuffer, bool force = false)

SetFrameBufferImplementation(frameBuffer);

GlobalUniformBuffer!.Data = GlobalUniformBuffer.Data with { BackbufferDraw = UsingBackbuffer };
globalUniformBuffer!.Data = globalUniformBuffer.Data with { BackbufferDraw = UsingBackbuffer };

FrameBuffer = frameBuffer;
}
Expand All @@ -966,6 +966,18 @@ private void setFrameBuffer(IFrameBuffer? frameBuffer, bool force = false)

#endregion

public void DrawVertices(PrimitiveTopology topology, int vertexStart, int verticesCount)
{
if (Shader == null)
throw new InvalidOperationException("No shader bound.");
Comment on lines +987 to +988
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This guard is slightly out of left field... I'm hoping it's just there for general usage safety?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it's for general usage safety. It's probably not strictly required.


Shader.BindUniformBlock("g_GlobalUniforms", globalUniformBuffer!);

DrawVerticesImplementation(topology, vertexStart, verticesCount);
}

public abstract void DrawVerticesImplementation(PrimitiveTopology topology, int vertexStart, int verticesCount);

#region Shaders

public void BindShader(IShader shader)
Expand Down
Expand Up @@ -2,9 +2,9 @@
// See the LICENCE file in the repository root for full licence text.

using System;
using osu.Framework.Graphics.Rendering;
using osu.Framework.Graphics.Rendering.Vertices;
using osu.Framework.Graphics.Veldrid.Buffers;
using Veldrid;

namespace osu.Framework.Graphics.Veldrid.Batches
{
Expand Down
3 changes: 1 addition & 2 deletions osu.Framework/Graphics/Veldrid/Batches/VeldridQuadBatch.cs
Expand Up @@ -5,15 +5,14 @@
using osu.Framework.Graphics.Rendering;
using osu.Framework.Graphics.Rendering.Vertices;
using osu.Framework.Graphics.Veldrid.Buffers;
using PrimitiveTopology = Veldrid.PrimitiveTopology;

namespace osu.Framework.Graphics.Veldrid.Batches
{
internal class VeldridQuadBatch<T> : VeldridVertexBatch<T>
where T : unmanaged, IEquatable<T>, IVertex
{
public VeldridQuadBatch(VeldridRenderer renderer, int quads)
: base(renderer, quads * IRenderer.VERTICES_PER_QUAD, PrimitiveTopology.TriangleList, VeldridIndexLayout.Quad)
: base(renderer, quads * IRenderer.VERTICES_PER_QUAD, PrimitiveTopology.Triangles, VeldridIndexLayout.Quad)
{
if (quads > IRenderer.MAX_QUADS)
throw new OverflowException($"Attempted to initialise a {nameof(VeldridQuadBatch<T>)} with more than {nameof(IRenderer)}.{nameof(IRenderer.MAX_QUADS)} quads ({IRenderer.MAX_QUADS}).");
Expand Down
Expand Up @@ -8,7 +8,6 @@
using osu.Framework.Graphics.Veldrid.Buffers;
using osu.Framework.Platform;
using osu.Framework.Statistics;
using PrimitiveTopology = Veldrid.PrimitiveTopology;

namespace osu.Framework.Graphics.Veldrid.Batches
{
Expand Down
102 changes: 50 additions & 52 deletions osu.Framework/Graphics/Veldrid/VeldridRenderer.cs
Expand Up @@ -32,7 +32,7 @@
using Veldrid.OpenGLBinding;
using Image = SixLabors.ImageSharp.Image;
using PixelFormat = Veldrid.PixelFormat;
using PrimitiveTopology = Veldrid.PrimitiveTopology;
using PrimitiveTopology = osu.Framework.Graphics.Rendering.PrimitiveTopology;

namespace osu.Framework.Graphics.Veldrid
{
Expand Down Expand Up @@ -490,52 +490,7 @@ protected override void SetFrameBufferImplementation(IFrameBuffer? frameBuffer)
SetFramebuffer(framebuffer);
}

public void SetFramebuffer(Framebuffer framebuffer)
{
Commands.SetFramebuffer(framebuffer);
pipeline.Outputs = framebuffer.OutputDescription;
}

public void BindVertexBuffer<T>(IVeldridVertexBuffer<T> buffer)
where T : unmanaged, IEquatable<T>, IVertex
{
if (buffer == boundVertexBuffer)
return;

Commands.SetVertexBuffer(0, buffer.Buffer);
pipeline.ShaderSet.VertexLayouts[0] = IVeldridVertexBuffer<T>.LAYOUT;

FrameStatistics.Increment(StatisticsCounterType.VBufBinds);

boundVertexBuffer = buffer;
}

public void BindIndexBuffer(VeldridIndexLayout layout, int verticesCount)
{
ref var indexBuffer = ref layout == VeldridIndexLayout.Quad
? ref quadIndexBuffer
: ref linearIndexBuffer;

if (indexBuffer == null || indexBuffer.VertexCapacity < verticesCount)
{
indexBuffer?.Dispose();
indexBuffer = new VeldridIndexBuffer(this, layout, verticesCount);
}

Commands.SetIndexBuffer(indexBuffer.Buffer, VeldridIndexBuffer.FORMAT);
boundIndexBuffer = indexBuffer;
}

public void BindUniformBuffer(string blockName, IVeldridUniformBuffer veldridBuffer)
{
if (boundUniformBuffers.TryGetValue(blockName, out IVeldridUniformBuffer? current) && current == veldridBuffer)
return;

FlushCurrentBatch(FlushBatchSource.BindBuffer);
boundUniformBuffers[blockName] = veldridBuffer;
}

public void DrawVertices(PrimitiveTopology type, int vertexStart, int verticesCount)
public override void DrawVerticesImplementation(PrimitiveTopology topology, int vertexStart, int verticesCount)
{
// normally we would flush/submit all texture upload commands at the end of the frame, since no actual rendering by the GPU will happen until then,
// but turns out on macOS with non-apple GPU, this results in rendering corruption.
Expand All @@ -546,9 +501,7 @@ public void DrawVertices(PrimitiveTopology type, int vertexStart, int verticesCo

var veldridShader = (VeldridShader)Shader!;

veldridShader.BindUniformBlock("g_GlobalUniforms", GlobalUniformBuffer!);

pipeline.PrimitiveTopology = type;
pipeline.PrimitiveTopology = topology.ToPrimitiveTopology();
Array.Resize(ref pipeline.ResourceLayouts, veldridShader.LayoutCount);

// Activate texture layouts.
Expand Down Expand Up @@ -601,6 +554,51 @@ public void DrawVertices(PrimitiveTopology type, int vertexStart, int verticesCo
Commands.DrawIndexed((uint)indicesCount, 1, (uint)indexStart, 0, 0);
}

public void SetFramebuffer(Framebuffer framebuffer)
{
Commands.SetFramebuffer(framebuffer);
pipeline.Outputs = framebuffer.OutputDescription;
}

public void BindVertexBuffer<T>(IVeldridVertexBuffer<T> buffer)
where T : unmanaged, IEquatable<T>, IVertex
{
if (buffer == boundVertexBuffer)
return;

Commands.SetVertexBuffer(0, buffer.Buffer);
pipeline.ShaderSet.VertexLayouts[0] = IVeldridVertexBuffer<T>.LAYOUT;

FrameStatistics.Increment(StatisticsCounterType.VBufBinds);

boundVertexBuffer = buffer;
}

public void BindIndexBuffer(VeldridIndexLayout layout, int verticesCount)
{
ref var indexBuffer = ref layout == VeldridIndexLayout.Quad
? ref quadIndexBuffer
: ref linearIndexBuffer;

if (indexBuffer == null || indexBuffer.VertexCapacity < verticesCount)
{
indexBuffer?.Dispose();
indexBuffer = new VeldridIndexBuffer(this, layout, verticesCount);
}

Commands.SetIndexBuffer(indexBuffer.Buffer, VeldridIndexBuffer.FORMAT);
boundIndexBuffer = indexBuffer;
}

public void BindUniformBuffer(string blockName, IVeldridUniformBuffer veldridBuffer)
{
if (boundUniformBuffers.TryGetValue(blockName, out IVeldridUniformBuffer? current) && current == veldridBuffer)
return;

FlushCurrentBatch(FlushBatchSource.BindBuffer);
boundUniformBuffers[blockName] = veldridBuffer;
}

private void ensureTextureUploadCommandsBegan()
{
if (beganTextureUpdateCommands)
Expand Down Expand Up @@ -745,10 +743,10 @@ protected override IShader CreateShader(string name, IShaderPart[] parts, Shader
public override IFrameBuffer CreateFrameBuffer(RenderBufferFormat[]? renderBufferFormats = null, TextureFilteringMode filteringMode = TextureFilteringMode.Linear)
=> new VeldridFrameBuffer(this, renderBufferFormats?.ToPixelFormats(), filteringMode.ToSamplerFilter());

protected override IVertexBatch<TVertex> CreateLinearBatch<TVertex>(int size, int maxBuffers, Rendering.PrimitiveTopology primitiveType)
protected override IVertexBatch<TVertex> CreateLinearBatch<TVertex>(int size, int maxBuffers, PrimitiveTopology primitiveType)
{
// maxBuffers is ignored because batches are not allowed to wrap around in Veldrid.
return new VeldridLinearBatch<TVertex>(this, size, primitiveType.ToPrimitiveTopology());
return new VeldridLinearBatch<TVertex>(this, size, primitiveType);
}

protected override IVertexBatch<TVertex> CreateQuadBatch<TVertex>(int size, int maxBuffers)
Expand Down