Ryujinx/Ryujinx.Graphics.OpenGL/VertexArray.cs

193 lines
5.9 KiB
C#
Raw Normal View History

2019-10-13 08:02:07 +02:00
using OpenTK.Graphics.OpenGL;
2019-12-29 18:41:50 +01:00
using Ryujinx.Graphics.GAL;
2019-10-13 08:02:07 +02:00
using System;
2021-01-26 22:44:07 +01:00
using System.Runtime.CompilerServices;
2019-10-13 08:02:07 +02:00
namespace Ryujinx.Graphics.OpenGL
{
class VertexArray : IDisposable
{
2019-12-31 23:09:49 +01:00
public int Handle { get; private set; }
2019-10-13 08:02:07 +02:00
private bool _needsAttribsUpdate;
private readonly VertexAttribDescriptor[] _vertexAttribs;
private readonly VertexBufferDescriptor[] _vertexBuffers;
private int _vertexAttribsCount;
private int _vertexBuffersCount;
2019-10-13 08:02:07 +02:00
2021-01-26 22:44:07 +01:00
private uint _vertexAttribsInUse;
private uint _vertexBuffersInUse;
2019-10-13 08:02:07 +02:00
public VertexArray()
{
Handle = GL.GenVertexArray();
_vertexAttribs = new VertexAttribDescriptor[Constants.MaxVertexAttribs];
_vertexBuffers = new VertexBufferDescriptor[Constants.MaxVertexBuffers];
2019-10-13 08:02:07 +02:00
}
public void Bind()
{
GL.BindVertexArray(Handle);
}
public void SetVertexBuffers(ReadOnlySpan<VertexBufferDescriptor> vertexBuffers)
2019-10-13 08:02:07 +02:00
{
2021-01-26 22:44:07 +01:00
int bindingIndex;
for (bindingIndex = 0; bindingIndex < vertexBuffers.Length; bindingIndex++)
2019-10-13 08:02:07 +02:00
{
2021-01-26 22:44:07 +01:00
VertexBufferDescriptor vb = vertexBuffers[bindingIndex];
2019-10-13 08:02:07 +02:00
if (vb.Buffer.Handle != BufferHandle.Null)
{
GL.BindVertexBuffer(bindingIndex, vb.Buffer.Handle.ToInt32(), (IntPtr)vb.Buffer.Offset, vb.Stride);
2019-10-13 08:02:07 +02:00
GL.VertexBindingDivisor(bindingIndex, vb.Divisor);
2021-01-26 22:44:07 +01:00
_vertexBuffersInUse |= 1u << bindingIndex;
2019-10-13 08:02:07 +02:00
}
else
{
2021-01-26 22:44:07 +01:00
if ((_vertexBuffersInUse & (1u << bindingIndex)) != 0)
{
GL.BindVertexBuffer(bindingIndex, 0, IntPtr.Zero, 0);
_vertexBuffersInUse &= ~(1u << bindingIndex);
}
2019-10-13 08:02:07 +02:00
}
2021-01-26 22:44:07 +01:00
_vertexBuffers[bindingIndex] = vb;
2019-10-13 08:02:07 +02:00
}
_vertexBuffersCount = bindingIndex;
2019-10-13 08:02:07 +02:00
_needsAttribsUpdate = true;
}
public void SetVertexAttributes(ReadOnlySpan<VertexAttribDescriptor> vertexAttribs)
2019-10-13 08:02:07 +02:00
{
int index = 0;
2019-10-13 08:02:07 +02:00
for (; index < vertexAttribs.Length; index++)
2019-10-13 08:02:07 +02:00
{
VertexAttribDescriptor attrib = vertexAttribs[index];
2021-01-26 22:44:07 +01:00
if (attrib.Equals(_vertexAttribs[index]))
{
continue;
}
2019-10-13 08:02:07 +02:00
FormatInfo fmtInfo = FormatTable.GetFormatInfo(attrib.Format);
if (attrib.IsZero)
{
// Disabling the attribute causes the shader to read a constant value.
// The value is configurable, but by default is a vector of (0, 0, 0, 1).
2021-01-26 22:44:07 +01:00
DisableVertexAttrib(index);
}
else
{
2021-01-26 22:44:07 +01:00
EnableVertexAttrib(index);
}
2019-10-13 08:02:07 +02:00
int offset = attrib.Offset;
int size = fmtInfo.Components;
bool isFloat = fmtInfo.PixelType == PixelType.Float ||
fmtInfo.PixelType == PixelType.HalfFloat;
if (isFloat || fmtInfo.Normalized || fmtInfo.Scaled)
{
VertexAttribType type = (VertexAttribType)fmtInfo.PixelType;
GL.VertexAttribFormat(index, size, type, fmtInfo.Normalized, offset);
2019-10-13 08:02:07 +02:00
}
else
{
VertexAttribIntegerType type = (VertexAttribIntegerType)fmtInfo.PixelType;
GL.VertexAttribIFormat(index, size, type, offset);
2019-10-13 08:02:07 +02:00
}
GL.VertexAttribBinding(index, attrib.BufferIndex);
2019-10-13 08:02:07 +02:00
_vertexAttribs[index] = attrib;
2019-10-13 08:02:07 +02:00
}
_vertexAttribsCount = index;
for (; index < Constants.MaxVertexAttribs; index++)
2019-10-13 08:02:07 +02:00
{
2021-01-26 22:44:07 +01:00
DisableVertexAttrib(index);
2019-10-13 08:02:07 +02:00
}
}
public void SetIndexBuffer(BufferHandle buffer)
2019-10-13 08:02:07 +02:00
{
GL.BindBuffer(BufferTarget.ElementArrayBuffer, buffer.ToInt32());
2019-10-13 08:02:07 +02:00
}
public void Validate()
{
for (int attribIndex = 0; attribIndex < _vertexAttribsCount; attribIndex++)
2019-10-13 08:02:07 +02:00
{
VertexAttribDescriptor attrib = _vertexAttribs[attribIndex];
2021-01-26 22:44:07 +01:00
if (!attrib.IsZero)
2019-10-13 08:02:07 +02:00
{
2021-01-26 22:44:07 +01:00
if ((uint)attrib.BufferIndex >= _vertexBuffersCount)
{
DisableVertexAttrib(attribIndex);
continue;
}
if (_vertexBuffers[attrib.BufferIndex].Buffer.Handle == BufferHandle.Null)
{
DisableVertexAttrib(attribIndex);
continue;
}
if (_needsAttribsUpdate)
{
EnableVertexAttrib(attribIndex);
}
2019-10-13 08:02:07 +02:00
}
2021-01-26 22:44:07 +01:00
}
2019-10-13 08:02:07 +02:00
2021-01-26 22:44:07 +01:00
_needsAttribsUpdate = false;
}
2019-10-13 08:02:07 +02:00
2021-01-26 22:44:07 +01:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void EnableVertexAttrib(int index)
{
uint mask = 1u << index;
2019-10-13 08:02:07 +02:00
2021-01-26 22:44:07 +01:00
if ((_vertexAttribsInUse & mask) == 0)
{
_vertexAttribsInUse |= mask;
GL.EnableVertexAttribArray(index);
2019-10-13 08:02:07 +02:00
}
2021-01-26 22:44:07 +01:00
}
2019-10-13 08:02:07 +02:00
2021-01-26 22:44:07 +01:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void DisableVertexAttrib(int index)
{
uint mask = 1u << index;
if ((_vertexAttribsInUse & mask) != 0)
{
_vertexAttribsInUse &= ~mask;
GL.DisableVertexAttribArray(index);
}
2019-10-13 08:02:07 +02:00
}
public void Dispose()
{
2019-12-31 23:09:49 +01:00
if (Handle != 0)
{
GL.DeleteVertexArray(Handle);
Handle = 0;
}
2019-10-13 08:02:07 +02:00
}
}
}