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;
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
2020-05-23 11:46:09 +02:00
|
|
|
private readonly VertexAttribDescriptor[] _vertexAttribs;
|
|
|
|
private readonly VertexBufferDescriptor[] _vertexBuffers;
|
|
|
|
|
|
|
|
private int _vertexAttribsCount;
|
|
|
|
private int _vertexBuffersCount;
|
2019-10-13 08:02:07 +02:00
|
|
|
|
|
|
|
public VertexArray()
|
|
|
|
{
|
|
|
|
Handle = GL.GenVertexArray();
|
2020-05-23 11:46:09 +02:00
|
|
|
|
|
|
|
_vertexAttribs = new VertexAttribDescriptor[Constants.MaxVertexAttribs];
|
|
|
|
_vertexBuffers = new VertexBufferDescriptor[Constants.MaxVertexBuffers];
|
2019-10-13 08:02:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public void Bind()
|
|
|
|
{
|
|
|
|
GL.BindVertexArray(Handle);
|
|
|
|
}
|
|
|
|
|
2020-05-23 11:46:09 +02:00
|
|
|
public void SetVertexBuffers(ReadOnlySpan<VertexBufferDescriptor> vertexBuffers)
|
2019-10-13 08:02:07 +02:00
|
|
|
{
|
|
|
|
int bindingIndex = 0;
|
|
|
|
|
2020-05-23 11:46:09 +02:00
|
|
|
for (int index = 0; index < vertexBuffers.Length; index++)
|
2019-10-13 08:02:07 +02:00
|
|
|
{
|
2020-05-23 11:46:09 +02:00
|
|
|
VertexBufferDescriptor vb = vertexBuffers[index];
|
2019-10-13 08:02:07 +02:00
|
|
|
|
2020-05-23 11:46:09 +02:00
|
|
|
if (vb.Buffer.Handle != 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);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
GL.BindVertexBuffer(bindingIndex, 0, IntPtr.Zero, 0);
|
|
|
|
}
|
|
|
|
|
2020-05-23 11:46:09 +02:00
|
|
|
_vertexBuffers[index] = vb;
|
|
|
|
|
2019-10-13 08:02:07 +02:00
|
|
|
bindingIndex++;
|
|
|
|
}
|
|
|
|
|
2020-05-23 11:46:09 +02:00
|
|
|
_vertexBuffersCount = bindingIndex;
|
2019-10-13 08:02:07 +02:00
|
|
|
|
|
|
|
_needsAttribsUpdate = true;
|
|
|
|
}
|
|
|
|
|
2020-05-23 11:46:09 +02:00
|
|
|
public void SetVertexAttributes(ReadOnlySpan<VertexAttribDescriptor> vertexAttribs)
|
2019-10-13 08:02:07 +02:00
|
|
|
{
|
2020-05-23 11:46:09 +02:00
|
|
|
int index = 0;
|
2019-10-13 08:02:07 +02:00
|
|
|
|
2020-05-23 11:46:09 +02:00
|
|
|
for (; index < vertexAttribs.Length; index++)
|
2019-10-13 08:02:07 +02:00
|
|
|
{
|
2020-05-23 11:46:09 +02:00
|
|
|
VertexAttribDescriptor attrib = vertexAttribs[index];
|
|
|
|
|
2019-10-13 08:02:07 +02:00
|
|
|
FormatInfo fmtInfo = FormatTable.GetFormatInfo(attrib.Format);
|
|
|
|
|
2020-03-30 04:11:24 +02:00
|
|
|
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).
|
2020-05-23 11:46:09 +02:00
|
|
|
GL.DisableVertexAttribArray(index);
|
2020-03-30 04:11:24 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-05-23 11:46:09 +02:00
|
|
|
GL.EnableVertexAttribArray(index);
|
2020-03-30 04:11:24 +02:00
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
|
2020-05-23 11:46:09 +02:00
|
|
|
GL.VertexAttribFormat(index, size, type, fmtInfo.Normalized, offset);
|
2019-10-13 08:02:07 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
VertexAttribIntegerType type = (VertexAttribIntegerType)fmtInfo.PixelType;
|
|
|
|
|
2020-05-23 11:46:09 +02:00
|
|
|
GL.VertexAttribIFormat(index, size, type, offset);
|
2019-10-13 08:02:07 +02:00
|
|
|
}
|
|
|
|
|
2020-05-23 11:46:09 +02:00
|
|
|
GL.VertexAttribBinding(index, attrib.BufferIndex);
|
2019-10-13 08:02:07 +02:00
|
|
|
|
2020-05-23 11:46:09 +02:00
|
|
|
_vertexAttribs[index] = attrib;
|
2019-10-13 08:02:07 +02:00
|
|
|
}
|
|
|
|
|
2020-05-23 11:46:09 +02:00
|
|
|
_vertexAttribsCount = index;
|
|
|
|
|
|
|
|
for (; index < Constants.MaxVertexAttribs; index++)
|
2019-10-13 08:02:07 +02:00
|
|
|
{
|
2020-05-23 11:46:09 +02:00
|
|
|
GL.DisableVertexAttribArray(index);
|
2019-10-13 08:02:07 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-23 11:46:09 +02:00
|
|
|
public void SetIndexBuffer(BufferHandle buffer)
|
2019-10-13 08:02:07 +02:00
|
|
|
{
|
2020-05-23 11:46:09 +02:00
|
|
|
GL.BindBuffer(BufferTarget.ElementArrayBuffer, buffer.ToInt32());
|
2019-10-13 08:02:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public void Validate()
|
|
|
|
{
|
2020-05-23 11:46:09 +02:00
|
|
|
for (int attribIndex = 0; attribIndex < _vertexAttribsCount; attribIndex++)
|
2019-10-13 08:02:07 +02:00
|
|
|
{
|
|
|
|
VertexAttribDescriptor attrib = _vertexAttribs[attribIndex];
|
|
|
|
|
2020-05-23 11:46:09 +02:00
|
|
|
if ((uint)attrib.BufferIndex >= _vertexBuffersCount)
|
2019-10-13 08:02:07 +02:00
|
|
|
{
|
|
|
|
GL.DisableVertexAttribArray(attribIndex);
|
|
|
|
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2020-05-23 11:46:09 +02:00
|
|
|
if (_vertexBuffers[attrib.BufferIndex].Buffer.Handle == null)
|
2019-10-13 08:02:07 +02:00
|
|
|
{
|
|
|
|
GL.DisableVertexAttribArray(attribIndex);
|
|
|
|
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2020-03-30 04:11:24 +02:00
|
|
|
if (_needsAttribsUpdate && !attrib.IsZero)
|
2019-10-13 08:02:07 +02:00
|
|
|
{
|
|
|
|
GL.EnableVertexAttribArray(attribIndex);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
_needsAttribsUpdate = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|